/// <summary> /// Processes the <c>composer.json</c> file. /// </summary> public override bool Execute() { // parse the input JSON file: JSONNode json; try { json = JSON.Parse(File.ReadAllText(ComposerJsonPath)); } catch (JSONFormatException f) { LogError(ErrorCodes.ERR_SyntaxError, new Location { Start = f.Position }, f.Message); return(false); } catch (Exception ex) { Log.LogErrorFromException(ex); return(false); } // cleanup output properties Authors = Array.Empty <ITaskItem>(); Dependencies = Array.Empty <ITaskItem>(); Autoload_ClassMap = Array.Empty <ITaskItem>(); Autoload_ClassMap_Exclude = Array.Empty <ITaskItem>(); Autoload_PSR4 = Array.Empty <ITaskItem>(); Autoload_Files = Array.Empty <ITaskItem>(); // process the file: foreach (var node in json) { switch (node.Key.ToLowerInvariant()) { case "name": Name = GetName(node.Value); break; case "description": Description = GetDescription(node.Value); break; case "keywords": Tags = GetTags(node.Value); break; case "homepage": Homepage = GetHomepage(node.Value); break; case "license": License = SpdxHelpers.SanitizeSpdx(node.Value, out var spdxwarning); if (spdxwarning != null) { LogError(ErrorCodes.WRN_SPDX, node.Value.Location, spdxwarning); } break; case "version": /* * Note, in general it is recommended to omit this tag and infer the value from a build process. * Anyways, if it's there we should respect it. */ /* * This must follow the format of `X.Y.Z` or `vX.Y.Z` * with an optional suffix of `-dev`, `-patch` (-p), `-alpha` (-a), `-beta` (-b) or `-RC`. * The patch, alpha, beta and RC suffixes can also be followed by a number. */ Version = SanitizeVersionValue(node.Value.Value); break; case "time": ReleaseDate = GetReleaseDate(node.Value); break; case "authors": Authors = Authors.Concat(GetAuthors(node.Value.AsArray)).AsArray(); break; case "require": // { "name": "version constraint", } Dependencies = Dependencies.Concat(GetDependencies(node.Value)).AsArray(); break; case "require-dev": if (ComposerIncludeDevPackages) { // { "name": "version constraint", } Dependencies = Dependencies.Concat(GetDependencies(node.Value)).AsArray(); } break; case "suggest": if (ComposerIncludeSuggestPackages) { // CONSIDER: Suggest packages are only informative, does not make much sense to reference those "names" directly. // { "name": "description", } Dependencies = Dependencies.Concat(GetDependencies(node.Value, ignoreVersion: true)).AsArray(); } break; case "autoload": // "autoload" : { "psr-0", "psr-4", "classmap", "exclude-from-classmap", "files" } foreach (var autoload in node.Value) { switch (autoload.Key.ToLowerInvariant()) { case "psr-4": Autoload_PSR4 = Autoload_PSR4.Concat(GetAutoloadPsr4FromPsr4(autoload.Value.AsObject)).AsArray(); break; case "psr-0": Autoload_PSR4 = Autoload_PSR4.Concat(GetAutoloadPsr4FromPsr0(autoload.Value.AsObject)).AsArray(); break; case "classmap": Autoload_ClassMap = Autoload_ClassMap.Concat( GetAutoloadClassMapString(autoload.Value.AsArray, false).Select(path => new TaskItem(path))).ToArray(); break; case "exclude-from-classmap": Autoload_ClassMap_Exclude = Autoload_ClassMap_Exclude.Concat( GetAutoloadClassMapString(autoload.Value.AsArray, true).Select(path => new TaskItem(path))).ToArray(); break; case "files": if (autoload.Value is JSONArray files_array) { Autoload_Files = Autoload_Files.Concat( files_array .Select(node => node.Value?.Trim()) .Where(str => !string.IsNullOrEmpty(str)) .Select(path => new TaskItem(path))).ToArray(); } break; default: // ??? LogError(ErrorCodes.WRN_Unhandled, node.Value.Location, $"autoload \"{autoload.Key}\" key is not handled."); break; } } break; } } return(true); }