prodex 1.4.11 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/LICENSE +20 -20
  2. package/README.md +240 -234
  3. package/bin/prodex.js +0 -0
  4. package/dist/app/execute-run.d.ts +2 -0
  5. package/dist/app/execute-run.js +74 -0
  6. package/dist/app/project-context.d.ts +12 -0
  7. package/dist/app/project-context.js +48 -0
  8. package/dist/app/run-plans.d.ts +11 -0
  9. package/dist/app/run-plans.js +61 -0
  10. package/dist/cache/cache-keys.d.ts +9 -0
  11. package/dist/cache/cache-manager.d.ts +9 -0
  12. package/dist/{core/managers/cache.js → cache/cache-manager.js} +5 -18
  13. package/dist/cli/cli-input.d.ts +2 -0
  14. package/dist/cli/cli-input.js +138 -124
  15. package/dist/cli/flag-specs.d.ts +12 -0
  16. package/dist/cli/flag-specs.js +28 -0
  17. package/dist/cli/help.d.ts +2 -0
  18. package/dist/cli/help.js +83 -0
  19. package/dist/cli/report-command.d.ts +2 -0
  20. package/dist/cli/report-command.js +101 -0
  21. package/dist/cli/reporter.d.ts +2 -0
  22. package/dist/cli/reporter.js +8 -0
  23. package/dist/commands/init-command.d.ts +1 -0
  24. package/dist/commands/init-command.js +9 -0
  25. package/dist/commands/migrate-command.d.ts +7 -0
  26. package/dist/commands/migrate-command.js +76 -0
  27. package/dist/commands/profiles-command.d.ts +6 -0
  28. package/dist/commands/profiles-command.js +16 -0
  29. package/dist/commands/run-command.d.ts +11 -0
  30. package/dist/commands/run-command.js +17 -0
  31. package/dist/config/build-config.d.ts +13 -0
  32. package/dist/config/build-config.js +127 -0
  33. package/dist/config/create-default-config.d.ts +9 -0
  34. package/dist/config/create-default-config.js +25 -0
  35. package/dist/config/default-config.d.ts +2 -0
  36. package/dist/config/default-config.js +23 -0
  37. package/dist/config/json.d.ts +2 -0
  38. package/dist/config/json.js +10 -0
  39. package/dist/config/load.d.ts +9 -0
  40. package/dist/config/load.js +48 -0
  41. package/dist/config/migration/detect.d.ts +4 -0
  42. package/dist/config/migration/detect.js +22 -0
  43. package/dist/config/migration/index.d.ts +4 -0
  44. package/dist/{shared → config/migration}/index.js +4 -3
  45. package/dist/config/migration/messages.d.ts +2 -0
  46. package/dist/config/migration/messages.js +35 -0
  47. package/dist/config/migration/transform.d.ts +2 -0
  48. package/dist/config/migration/transform.js +80 -0
  49. package/dist/config/migration/types.d.ts +16 -0
  50. package/dist/config/string-list.d.ts +2 -0
  51. package/dist/config/string-list.js +17 -0
  52. package/dist/diagnostics/logger.d.ts +3 -0
  53. package/dist/diagnostics/logger.js +33 -0
  54. package/dist/filesystem/glob-scan.d.ts +4 -0
  55. package/dist/filesystem/glob-scan.js +26 -0
  56. package/dist/filesystem/inspect.d.ts +1 -0
  57. package/dist/filesystem/inspect.js +15 -0
  58. package/dist/filesystem/path.d.ts +2 -0
  59. package/dist/filesystem/path.js +11 -0
  60. package/dist/filesystem/read-file.d.ts +8 -0
  61. package/dist/{shared/io.js → filesystem/read-file.js} +0 -25
  62. package/dist/filesystem/stat-cache.d.ts +1 -0
  63. package/dist/filesystem/stat-cache.js +22 -0
  64. package/dist/index.d.ts +3 -0
  65. package/dist/index.js +76 -83
  66. package/dist/output/markdown.d.ts +12 -0
  67. package/dist/output/markdown.js +150 -0
  68. package/dist/output/naming.d.ts +2 -0
  69. package/dist/output/naming.js +30 -0
  70. package/dist/output/produce-output.d.ts +2 -0
  71. package/dist/output/produce-output.js +35 -0
  72. package/dist/output/render-constants.d.ts +21 -0
  73. package/dist/{constants → output}/render-constants.js +2 -1
  74. package/dist/output/text.d.ts +2 -0
  75. package/dist/output/text.js +14 -0
  76. package/dist/resolvers/js/extract-imports.d.ts +1 -0
  77. package/dist/resolvers/js/js-resolver.d.ts +2 -0
  78. package/dist/resolvers/js/js-resolver.js +45 -89
  79. package/dist/resolvers/js/resolve-alias.d.ts +2 -0
  80. package/dist/resolvers/js/resolve-alias.js +12 -20
  81. package/dist/resolvers/php/bindings.d.ts +8 -0
  82. package/dist/resolvers/php/bindings.js +8 -9
  83. package/dist/resolvers/php/extract-imports.d.ts +13 -0
  84. package/dist/resolvers/php/extract-imports.js +1 -1
  85. package/dist/resolvers/php/php-resolver.d.ts +2 -0
  86. package/dist/resolvers/php/php-resolver.js +61 -90
  87. package/dist/resolvers/php/psr4.d.ts +5 -0
  88. package/dist/resolvers/php/psr4.js +7 -7
  89. package/dist/resolvers/resolver-constants.d.ts +4 -0
  90. package/dist/resolvers/resolver-constants.js +7 -0
  91. package/dist/resolvers/resolver-result.d.ts +5 -0
  92. package/dist/resolvers/resolver-result.js +18 -0
  93. package/dist/tracing/exclude.d.ts +6 -0
  94. package/dist/{shared/patterns.js → tracing/exclude.js} +4 -4
  95. package/dist/tracing/follow-chain.d.ts +5 -0
  96. package/dist/tracing/follow-chain.js +63 -0
  97. package/dist/tracing/include-files.d.ts +2 -0
  98. package/dist/tracing/include-files.js +36 -0
  99. package/dist/tracing/resolver-registry.d.ts +5 -0
  100. package/dist/tracing/resolver-registry.js +20 -0
  101. package/dist/tracing/trace-run.d.ts +2 -0
  102. package/dist/tracing/trace-run.js +21 -0
  103. package/dist/tracing/trace-stats.d.ts +4 -0
  104. package/dist/tracing/trace-stats.js +16 -0
  105. package/dist/types/app.types.d.ts +62 -0
  106. package/dist/types/app.types.js +2 -0
  107. package/dist/types/cli.types.d.ts +22 -0
  108. package/dist/types/cli.types.js +0 -10
  109. package/dist/types/config.types.d.ts +34 -0
  110. package/dist/types/index.d.ts +7 -0
  111. package/dist/types/index.js +3 -1
  112. package/dist/types/output.types.d.ts +6 -0
  113. package/dist/types/output.types.js +2 -0
  114. package/dist/types/resolver.types.d.ts +23 -0
  115. package/dist/types/tracing.types.d.ts +23 -0
  116. package/dist/types/tracing.types.js +2 -0
  117. package/dist/types/utils.types.d.ts +10 -0
  118. package/package.json +35 -12
  119. package/schema/prodex.schema.json +122 -0
  120. package/dist/cli/init.js +0 -21
  121. package/dist/cli/picker.js +0 -83
  122. package/dist/cli/summary.js +0 -32
  123. package/dist/constants/config.js +0 -27
  124. package/dist/constants/default-config.js +0 -43
  125. package/dist/constants/flags.js +0 -79
  126. package/dist/constants/index.js +0 -20
  127. package/dist/core/combine.js +0 -56
  128. package/dist/core/dependency.js +0 -98
  129. package/dist/core/helpers.js +0 -85
  130. package/dist/core/managers/config.js +0 -140
  131. package/dist/core/output.js +0 -49
  132. package/dist/core/renderers.js +0 -210
  133. package/dist/debug.js +0 -15
  134. package/dist/lib/logger.js +0 -42
  135. package/dist/lib/polyfills.js +0 -17
  136. package/dist/lib/prompt.js +0 -34
  137. package/dist/lib/questions.js +0 -28
  138. package/dist/lib/utils.js +0 -46
  139. package/dist/shared/collections.js +0 -33
  140. package/dist/store.js +0 -15
  141. /package/dist/{constants → cache}/cache-keys.js +0 -0
  142. /package/dist/{types/core.types.js → config/migration/types.js} +0 -0
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.loadProjectContext = loadProjectContext;
7
+ exports.resolveRoot = resolveRoot;
8
+ exports.validateRoot = validateRoot;
9
+ const fs_1 = __importDefault(require("fs"));
10
+ const path_1 = __importDefault(require("path"));
11
+ const load_1 = require("../config/load");
12
+ function loadProjectContext(rootArg, cwd = process.cwd()) {
13
+ const root = resolveRoot(rootArg, cwd);
14
+ const warnings = [];
15
+ const errors = validateRoot(root, rootArg);
16
+ if (errors.length) {
17
+ return {
18
+ root,
19
+ config: {},
20
+ configPath: path_1.default.join(root, "prodex.json"),
21
+ configExists: false,
22
+ warnings,
23
+ errors,
24
+ };
25
+ }
26
+ const loaded = (0, load_1.loadConfig)(root);
27
+ return fromLoadedConfig(root, loaded);
28
+ }
29
+ function resolveRoot(rootArg, cwd = process.cwd()) {
30
+ return rootArg ? path_1.default.resolve(cwd, rootArg) : cwd;
31
+ }
32
+ function validateRoot(root, rootArg) {
33
+ if (!fs_1.default.existsSync(root))
34
+ return [`Invalid root path "${rootArg}".`];
35
+ if (!fs_1.default.statSync(root).isDirectory())
36
+ return [`Root path "${rootArg}" is not a directory.`];
37
+ return [];
38
+ }
39
+ function fromLoadedConfig(root, loaded) {
40
+ return {
41
+ root,
42
+ config: loaded.config,
43
+ configPath: loaded.path,
44
+ configExists: loaded.exists,
45
+ warnings: [...loaded.warnings],
46
+ errors: [...loaded.errors],
47
+ };
48
+ }
@@ -0,0 +1,11 @@
1
+ import type { ProdexFlags, RunPlan } from "../types";
2
+ export interface CreateRunPlansResult {
3
+ plans: RunPlan[];
4
+ warnings: string[];
5
+ errors: string[];
6
+ }
7
+ export declare function createRunPlans(params: {
8
+ rootArg?: string;
9
+ flags?: Partial<ProdexFlags>;
10
+ cwd?: string;
11
+ }): CreateRunPlansResult;
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createRunPlans = createRunPlans;
4
+ const build_config_1 = require("../config/build-config");
5
+ const project_context_1 = require("./project-context");
6
+ function createRunPlans(params) {
7
+ const project = (0, project_context_1.loadProjectContext)(params.rootArg, params.cwd);
8
+ const warnings = [...project.warnings];
9
+ const errors = [...project.errors];
10
+ const flags = params.flags ?? {};
11
+ if (errors.length)
12
+ return { plans: [], warnings, errors };
13
+ const profileNames = resolveProfileNames(flags, project.config.profiles ?? {}, errors);
14
+ if (errors.length)
15
+ return { plans: [], warnings, errors };
16
+ const plans = [];
17
+ for (const profileName of profileNames.length ? profileNames : [undefined]) {
18
+ const runFlags = flagsForProfileRun(flags, profileName);
19
+ const built = (0, build_config_1.buildConfig)({
20
+ root: project.root,
21
+ userConfig: project.config,
22
+ flags: runFlags,
23
+ profileName,
24
+ });
25
+ warnings.push(...built.warnings);
26
+ errors.push(...built.errors);
27
+ if (!built.config)
28
+ continue;
29
+ plans.push({
30
+ root: project.root,
31
+ config: built.config,
32
+ flags: runFlags,
33
+ outputName: built.config.name,
34
+ profile: profileName,
35
+ });
36
+ }
37
+ return { plans, warnings, errors };
38
+ }
39
+ function resolveProfileNames(flags, profiles, errors) {
40
+ if (flags.allProfiles) {
41
+ const names = Object.keys(profiles);
42
+ if (!names.length)
43
+ errors.push("No profiles are defined in prodex.json.");
44
+ return names;
45
+ }
46
+ if (Array.isArray(flags.profiles) && flags.profiles.length)
47
+ return unique(flags.profiles);
48
+ return [];
49
+ }
50
+ function flagsForProfileRun(flags, profile) {
51
+ if (!profile)
52
+ return flags;
53
+ return {
54
+ ...flags,
55
+ profiles: undefined,
56
+ allProfiles: false,
57
+ };
58
+ }
59
+ function unique(values) {
60
+ return [...new Set(values.map((value) => value.trim()).filter(Boolean))];
61
+ }
@@ -0,0 +1,9 @@
1
+ export declare const CACHE_KEYS: {
2
+ readonly ALIASES: "aliases";
3
+ readonly JS_IMPORTS: "js:imports";
4
+ readonly JS_STATS: "js:stats";
5
+ readonly PHP_PSR4: "php:psr4";
6
+ readonly PHP_BINDINGS: "php:bindings";
7
+ readonly PHP_FILECACHE: "php:fileCache";
8
+ };
9
+ export type CacheNamespace = (typeof CACHE_KEYS)[keyof typeof CACHE_KEYS];
@@ -0,0 +1,9 @@
1
+ export declare class CacheManager {
2
+ private static registry;
3
+ private static ns;
4
+ static set<T = any>(ns: string, key: string, val: T): void;
5
+ static get<T = any>(ns: string, key: string): T | undefined;
6
+ static clear(ns?: string): void;
7
+ static dump(ns: string): Record<string, any>;
8
+ static stats(): Record<string, number>;
9
+ }
@@ -1,48 +1,35 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.CacheManager = void 0;
4
- const logger_1 = require("../../lib/logger");
5
- /**
6
- * 🧩 CacheManager
7
- * Unified in-memory registry for all runtime maps.
8
- *
9
- * - Namespaced storage (e.g., "aliases", "stats", "resolver")
10
- * - Purely in-memory (no file I/O)
11
- * - Static API for symmetry with ConfigManager
12
- */
4
+ const logger_1 = require("../diagnostics/logger");
5
+ const inspect_1 = require("../filesystem/inspect");
13
6
  class CacheManager {
14
7
  static registry = new Map();
15
- /** Ensure namespace map exists and return it */
16
8
  static ns(ns) {
17
9
  if (!this.registry.has(ns))
18
10
  this.registry.set(ns, new Map());
19
11
  return this.registry.get(ns);
20
12
  }
21
- /** Set or update a cached entry */
22
13
  static set(ns, key, val) {
23
14
  this.ns(ns).set(key, val);
24
- logger_1.logger.debug(`🧩 [cache:${ns}] set ${key} \n ${_2j(val)}`);
15
+ logger_1.logger.debug(`[cache:${ns}] set ${key}\n-> ${(0, inspect_1.inspectValue)(val)}`);
25
16
  }
26
- /** Retrieve a cached entry */
27
17
  static get(ns, key) {
28
18
  return this.ns(ns).get(key);
29
19
  }
30
- /** Remove all entries from one namespace or from all */
31
20
  static clear(ns) {
32
21
  if (ns) {
33
22
  this.ns(ns).clear();
34
- logger_1.logger.debug(`🧩 [cache:${ns}] cleared`);
23
+ logger_1.logger.debug(`[cache:${ns}] cleared`);
35
24
  }
36
25
  else {
37
26
  this.registry.forEach((m) => m.clear());
38
- logger_1.logger.debug("🧩 [cache] cleared all namespaces");
27
+ logger_1.logger.debug("[cache] cleared all namespaces");
39
28
  }
40
29
  }
41
- /** Export a namespace as a plain object (for persistence or inspection) */
42
30
  static dump(ns) {
43
31
  return Object.fromEntries(this.ns(ns).entries());
44
32
  }
45
- /** Return count of entries per namespace */
46
33
  static stats() {
47
34
  const summary = {};
48
35
  for (const [name, map] of this.registry)
@@ -0,0 +1,2 @@
1
+ import type { CliParseResult } from "../types";
2
+ export declare function parseCliInput(argv?: string[]): CliParseResult;
@@ -1,145 +1,159 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.parseCliInput = parseCliInput;
7
- const sade_1 = __importDefault(require("sade"));
8
- const path_1 = __importDefault(require("path"));
9
- const package_json_1 = __importDefault(require("../../package.json"));
10
- const fs_1 = __importDefault(require("fs"));
11
- const flags_1 = require("../constants/flags");
12
- function extractShortcutTokens(argv) {
13
- const cleaned = [];
14
- const shortcuts = [];
15
- let shortcutAll = false;
16
- for (const arg of argv) {
17
- if (arg === "@") {
18
- shortcutAll = true;
4
+ const string_list_1 = require("../config/string-list");
5
+ const flag_specs_1 = require("./flag-specs");
6
+ function parseCliInput(argv = process.argv) {
7
+ const tokens = stripExecutable(argv);
8
+ const warnings = [];
9
+ const errors = [];
10
+ const flags = {};
11
+ if (!tokens.length) {
12
+ errors.push("Missing command. Use `prodex run`, `prodex init`, `prodex profiles`, or `prodex migrate`.");
13
+ return { warnings, errors };
14
+ }
15
+ if (tokens.includes("--version") || tokens.includes("-v")) {
16
+ return { command: { kind: "version" }, warnings, errors };
17
+ }
18
+ if (tokens[0] === "--help" || tokens[0] === "-h") {
19
+ return { command: { kind: "help" }, warnings, errors };
20
+ }
21
+ const commandName = tokens[0];
22
+ if (!isCommand(commandName)) {
23
+ errors.push(`Unknown command "${commandName}". Use run, init, profiles, or migrate.`);
24
+ return { warnings, errors };
25
+ }
26
+ let rootArg;
27
+ for (let i = 1; i < tokens.length; i++) {
28
+ const token = tokens[i];
29
+ if (!token)
30
+ continue;
31
+ if (token.startsWith("--")) {
32
+ const consumed = readLongFlag(tokens, i, flags, errors);
33
+ i += consumed;
19
34
  continue;
20
35
  }
21
- if (arg?.startsWith("@")) {
22
- const name = arg.slice(1).trim();
23
- if (!name)
24
- shortcutAll = true;
25
- else
26
- shortcuts.push(name);
36
+ if (token.startsWith("-") && token !== "-") {
37
+ const consumed = readShortFlag(tokens, i, flags, errors);
38
+ i += consumed;
27
39
  continue;
28
40
  }
29
- cleaned.push(arg);
41
+ if (rootArg) {
42
+ errors.push(`Unexpected positional argument "${token}". Only one root path is accepted.`);
43
+ continue;
44
+ }
45
+ rootArg = token;
30
46
  }
31
- return { argv: cleaned, shortcutAll, shortcuts };
47
+ if (flags.help)
48
+ return { command: { kind: "help", topic: commandName }, warnings, errors };
49
+ if (commandName === "init")
50
+ return { command: { kind: "init", rootArg }, warnings, errors };
51
+ if (commandName === "profiles")
52
+ return { command: { kind: "profiles", rootArg }, warnings, errors };
53
+ if (commandName === "migrate") {
54
+ return { command: { kind: "migrate", rootArg, write: !!flags.write, check: !!flags.check }, warnings, errors };
55
+ }
56
+ return { command: { kind: "run", rootArg, flags }, warnings, errors };
32
57
  }
33
- /**
34
- * Unified CLI parser powered by Sade and FLAG_MAP.
35
- * Returns { root, flags, warnings, errors }.
36
- */
37
- function parseCliInput(argv = process.argv) {
38
- if (argv.includes("-v") || argv.includes("--version")) {
39
- console.log(`prodex v${package_json_1.default.version}`);
40
- process.exit(0);
41
- }
42
- const extracted = extractShortcutTokens(argv);
43
- const argvCleaned = extracted.argv;
44
- const program = (0, sade_1.default)("prodex [root]");
45
- registerFlags(program);
46
- let parsed = { rootArg: "", root: undefined, flags: {} };
47
- program.action((root, opts) => {
48
- const cwd = process.cwd();
49
- parsed = {
50
- rootArg: root,
51
- root: root ? path_1.default.resolve(cwd, root) : cwd,
52
- flags: { ...opts },
53
- };
54
- });
55
- program.parse(argvCleaned);
56
- // Merge shortcut tokens (@a @b @c / @) with existing --shortcut usage.
57
- const fromTokens = extracted.shortcuts;
58
- const shortcutAll = extracted.shortcutAll;
59
- const fromFlag = typeof parsed.flags.shortcut === "string" ? parsed.flags.shortcut.trim() : "";
60
- const selected = [...fromTokens, ...(fromFlag ? [fromFlag] : [])].filter(Boolean);
61
- const uniq = Array.from(new Set(selected));
62
- if (shortcutAll)
63
- parsed.flags.shortcutAll = true;
64
- if (uniq.length)
65
- parsed.flags.shortcuts = uniq;
66
- if (!shortcutAll && uniq.length === 1)
67
- parsed.flags.shortcut = uniq[0];
68
- else if (uniq.length > 1 || shortcutAll)
69
- delete parsed.flags.shortcut;
70
- const warnings = [];
71
- const errors = [];
72
- parsed.flags = normalizeFlags(parsed.flags, warnings, errors);
73
- validateArgs(parsed, warnings, errors);
74
- return { ...parsed, warnings, errors };
58
+ function stripExecutable(argv) {
59
+ const [first, second, ...rest] = argv;
60
+ const firstBase = first ? basename(first) : "";
61
+ const secondBase = second ? basename(second) : "";
62
+ if (/^node(\.exe)?$/.test(firstBase))
63
+ return rest;
64
+ if (secondBase.startsWith("prodex") && firstBase)
65
+ return rest;
66
+ if (firstBase.startsWith("prodex"))
67
+ return argv.slice(1);
68
+ return argv;
75
69
  }
76
- function registerFlags(program) {
77
- for (const [key, meta] of Object.entries(flags_1.FLAG_MAP)) {
78
- const short = meta.short ? `-${meta.short}, ` : "";
79
- const defaultVal = meta.type === "boolean" ? false : undefined;
80
- program.option(`${short}--${key}`, meta.description, defaultVal);
81
- }
70
+ function basename(value) {
71
+ return value.split(/[\\/]/).pop()?.toLowerCase() ?? "";
82
72
  }
83
- function normalizeFlags(flags, warnings, errors) {
84
- // Remap short aliases (-i/-f/-d) to long keys (include/files/debug)
85
- for (const [short, longKey] of Object.entries(flags_1.FLAG_SHORT_MAP)) {
86
- if (flags[longKey] === undefined && flags[short] !== undefined) {
87
- flags[longKey] = flags[short];
88
- delete flags[short];
89
- }
73
+ function isCommand(token) {
74
+ return flag_specs_1.COMMANDS.includes(token);
75
+ }
76
+ function readLongFlag(tokens, index, flags, errors) {
77
+ const token = tokens[index];
78
+ const raw = token.slice(2);
79
+ const equalsAt = raw.indexOf("=");
80
+ const rawName = equalsAt === -1 ? raw : raw.slice(0, equalsAt);
81
+ const name = flag_specs_1.FLAG_ALIASES[rawName] ?? rawName;
82
+ const inlineValue = equalsAt === -1 ? undefined : raw.slice(equalsAt + 1);
83
+ const spec = flag_specs_1.FLAGS_BY_LONG.get(name);
84
+ if (!spec) {
85
+ errors.push(`Unknown flag "--${rawName}".`);
86
+ return 0;
90
87
  }
91
- for (const [key, meta] of Object.entries(flags_1.FLAG_MAP)) {
92
- const raw = flags[key];
93
- if (raw === undefined)
94
- continue;
95
- switch (meta.type) {
96
- case "number": {
97
- const num = Number(raw);
98
- if (Number.isNaN(num))
99
- errors.push(`Flag --${key} expected a number but got "${raw}"`);
100
- else
101
- flags[key] = num;
102
- break;
103
- }
104
- case "list": {
105
- flags[key] = String(raw)
106
- .split(",")
107
- .map((v) => v.trim())
108
- .filter(Boolean);
109
- break;
110
- }
111
- case "boolean": {
112
- flags[key] = Boolean(raw);
113
- break;
88
+ if (spec.type === "boolean") {
89
+ flags[spec.long] = inlineValue === undefined ? true : coerceBoolean(inlineValue);
90
+ return 0;
91
+ }
92
+ const value = inlineValue ?? tokens[index + 1];
93
+ if (value === undefined || value.startsWith("-")) {
94
+ errors.push(`Flag "--${rawName}" expects a value.`);
95
+ return 0;
96
+ }
97
+ assignFlag(flags, spec, value, errors);
98
+ return inlineValue === undefined ? 1 : 0;
99
+ }
100
+ function readShortFlag(tokens, index, flags, errors) {
101
+ const token = tokens[index];
102
+ const cluster = token.slice(1);
103
+ if (cluster.length > 1) {
104
+ for (const ch of cluster) {
105
+ const spec = flag_specs_1.FLAGS_BY_SHORT.get(ch);
106
+ if (!spec) {
107
+ errors.push(`Unknown flag "-${ch}".`);
108
+ continue;
114
109
  }
115
- default: {
116
- if (meta.type === "string")
117
- flags[key] = String(raw);
110
+ if (spec.type !== "boolean") {
111
+ errors.push(`Flag "-${ch}" expects a value and cannot be used in a short flag cluster.`);
112
+ continue;
118
113
  }
114
+ flags[spec.long] = true;
119
115
  }
116
+ return 0;
117
+ }
118
+ const spec = flag_specs_1.FLAGS_BY_SHORT.get(cluster);
119
+ if (!spec) {
120
+ errors.push(`Unknown flag "-${cluster}".`);
121
+ return 0;
122
+ }
123
+ if (spec.type === "boolean") {
124
+ flags[spec.long] = true;
125
+ return 0;
126
+ }
127
+ const value = tokens[index + 1];
128
+ if (value === undefined || value.startsWith("-")) {
129
+ errors.push(`Flag "-${cluster}" expects a value.`);
130
+ return 0;
120
131
  }
121
- return flags;
132
+ assignFlag(flags, spec, value, errors);
133
+ return 1;
122
134
  }
123
- /** Validate path argument and report unrecognized flags. */
124
- function validateArgs(parsed, warnings, errors) {
125
- const { rootArg } = parsed;
126
- if (rootArg) {
127
- if (!fs_1.default.existsSync(parsed.root)) {
128
- errors.push(`Invalid path "${rootArg}"`);
129
- }
130
- else if (!fs_1.default.statSync(parsed.root).isDirectory()) {
131
- errors.push(`Path argument "${rootArg}" is not a directory.`);
132
- }
135
+ function assignFlag(flags, spec, value, errors) {
136
+ if (spec.type === "number") {
137
+ const numeric = Number(value);
138
+ if (!Number.isFinite(numeric))
139
+ errors.push(`Flag "--${spec.long}" expected a number but got "${value}".`);
140
+ else
141
+ flags[spec.long] = numeric;
142
+ return;
133
143
  }
134
- const unknown = parsed.flags?._ || [];
135
- if (unknown.length) {
136
- warnings.push(`Unrecognized arguments detected [${unknown.join(", ")}]- They were ignored.`);
144
+ if (spec.type === "list") {
145
+ const values = (0, string_list_1.splitStringList)(value);
146
+ const target = spec.long === "profile" ? "profiles" : spec.long;
147
+ const current = (flags[target] ?? []);
148
+ flags[target] = [...current, ...values];
149
+ return;
137
150
  }
138
- if (warnings.length)
139
- console.warn("Warnings:", warnings);
140
- if (errors.length) {
141
- for (const err of errors)
142
- console.error(err);
143
- process.exit(1);
151
+ if (spec.long === "format" && !["md", "txt"].includes(value)) {
152
+ errors.push(`Flag "--format" expected "md" or "txt" but got "${value}".`);
153
+ return;
144
154
  }
155
+ flags[spec.long] = value;
156
+ }
157
+ function coerceBoolean(value) {
158
+ return !["0", "false", "no", "off"].includes(value.toLowerCase());
145
159
  }
@@ -0,0 +1,12 @@
1
+ import type { ProdexFlags } from "../types";
2
+ export type FlagName = keyof ProdexFlags | "help" | "version" | "profile" | "write" | "check";
3
+ export type FlagSpec = {
4
+ long: FlagName;
5
+ short?: string;
6
+ type: "boolean" | "string" | "number" | "list";
7
+ };
8
+ export declare const COMMANDS: readonly ["run", "init", "profiles", "migrate"];
9
+ export declare const FLAGS: FlagSpec[];
10
+ export declare const FLAG_ALIASES: Record<string, FlagName>;
11
+ export declare const FLAGS_BY_LONG: Map<FlagName, FlagSpec>;
12
+ export declare const FLAGS_BY_SHORT: Map<string, FlagSpec>;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FLAGS_BY_SHORT = exports.FLAGS_BY_LONG = exports.FLAG_ALIASES = exports.FLAGS = exports.COMMANDS = void 0;
4
+ exports.COMMANDS = ["run", "init", "profiles", "migrate"];
5
+ exports.FLAGS = [
6
+ { long: "entry", short: "e", type: "list" },
7
+ { long: "include", short: "i", type: "list" },
8
+ { long: "exclude", short: "x", type: "list" },
9
+ { long: "profile", short: "p", type: "list" },
10
+ { long: "allProfiles", short: "a", type: "boolean" },
11
+ { long: "name", short: "n", type: "string" },
12
+ { long: "format", short: "F", type: "string" },
13
+ { long: "maxDepth", type: "number" },
14
+ { long: "maxFiles", type: "number" },
15
+ { long: "debug", short: "d", type: "boolean" },
16
+ { long: "write", type: "boolean" },
17
+ { long: "check", type: "boolean" },
18
+ { long: "help", short: "h", type: "boolean" },
19
+ { long: "version", short: "v", type: "boolean" },
20
+ ];
21
+ exports.FLAG_ALIASES = {
22
+ all: "allProfiles",
23
+ "all-profiles": "allProfiles",
24
+ "max-depth": "maxDepth",
25
+ "max-files": "maxFiles",
26
+ };
27
+ exports.FLAGS_BY_LONG = new Map(exports.FLAGS.map((flag) => [flag.long, flag]));
28
+ exports.FLAGS_BY_SHORT = new Map(exports.FLAGS.filter((flag) => flag.short).map((flag) => [flag.short, flag]));
@@ -0,0 +1,2 @@
1
+ export declare function renderHelp(topic?: string): string;
2
+ export declare function renderVersion(): string;
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.renderHelp = renderHelp;
7
+ exports.renderVersion = renderVersion;
8
+ const package_json_1 = __importDefault(require("../../package.json"));
9
+ function renderHelp(topic) {
10
+ if (topic === "run")
11
+ return renderRunHelp();
12
+ if (topic === "init")
13
+ return renderInitHelp();
14
+ if (topic === "profiles")
15
+ return renderProfilesHelp();
16
+ if (topic === "migrate")
17
+ return renderMigrateHelp();
18
+ return [
19
+ "Usage:",
20
+ " prodex run [root] [options]",
21
+ " prodex init [root]",
22
+ " prodex profiles [root]",
23
+ " prodex migrate [root] [--write|--check]",
24
+ "",
25
+ "Global options:",
26
+ " -h, --help Show help.",
27
+ " -v, --version Show version.",
28
+ "",
29
+ "Run `prodex <command> --help` for command-specific help.",
30
+ ].join("\n");
31
+ }
32
+ function renderVersion() {
33
+ return `prodex v${package_json_1.default.version}`;
34
+ }
35
+ function renderRunHelp() {
36
+ return [
37
+ "Usage:",
38
+ " prodex run [root] [options]",
39
+ "",
40
+ "Options:",
41
+ " -e, --entry <glob> Entry file/glob. Repeatable and comma-aware.",
42
+ " -i, --include <glob> Extra file/glob to append. Repeatable and comma-aware.",
43
+ " -x, --exclude <glob> File/glob to skip. Repeatable and comma-aware.",
44
+ " -p, --profile <name> Run a named profile. Repeatable.",
45
+ " -a, --all Run every configured profile.",
46
+ " --all-profiles Alias for --all.",
47
+ " -n, --name <name> Output basename for this run.",
48
+ " -F, --format <md|txt> Output format.",
49
+ " --max-depth <number> Maximum dependency traversal depth.",
50
+ " --max-files <number> Maximum traced file count.",
51
+ " -h, --help Show run help.",
52
+ ].join("\n");
53
+ }
54
+ function renderInitHelp() {
55
+ return [
56
+ "Usage:",
57
+ " prodex init [root]",
58
+ "",
59
+ "Create a prodex.json file in the target root.",
60
+ ].join("\n");
61
+ }
62
+ function renderProfilesHelp() {
63
+ return [
64
+ "Usage:",
65
+ " prodex profiles [root]",
66
+ "",
67
+ "List configured profile keys without running Prodex.",
68
+ ].join("\n");
69
+ }
70
+ function renderMigrateHelp() {
71
+ return [
72
+ "Usage:",
73
+ " prodex migrate [root]",
74
+ " prodex migrate [root] --write",
75
+ " prodex migrate [root] --check",
76
+ "",
77
+ "Preview, check, or write a prodex.json migration to config version 4.",
78
+ "",
79
+ "Options:",
80
+ " --write Back up and update prodex.json.",
81
+ " --check Exit nonzero if migration is required.",
82
+ ].join("\n");
83
+ }
@@ -0,0 +1,2 @@
1
+ import type { CommandResult } from "../types";
2
+ export declare function reportCommandResult(result: CommandResult): void;