prodex 2.0.0 → 2.1.0
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.
- package/README.md +369 -146
- package/dist/app/dependency-source-provider.d.ts +2 -0
- package/dist/app/dependency-source-provider.js +66 -0
- package/dist/app/entry-resolver.d.ts +7 -0
- package/dist/app/entry-resolver.js +26 -0
- package/dist/app/execute-run.d.ts +2 -2
- package/dist/app/execute-run.js +138 -36
- package/dist/app/git-source-provider.d.ts +4 -0
- package/dist/app/git-source-provider.js +551 -0
- package/dist/app/grep-source-provider.d.ts +2 -0
- package/dist/app/grep-source-provider.js +226 -0
- package/dist/app/planner.d.ts +12 -0
- package/dist/app/planner.js +106 -0
- package/dist/app/planners/attachment-options.d.ts +2 -0
- package/dist/app/planners/attachment-options.js +39 -0
- package/dist/app/planners/git-plan.d.ts +13 -0
- package/dist/app/planners/git-plan.js +141 -0
- package/dist/app/planners/grep-plan.d.ts +13 -0
- package/dist/app/planners/grep-plan.js +115 -0
- package/dist/app/planners/list-utils.d.ts +1 -0
- package/dist/app/planners/list-utils.js +6 -0
- package/dist/app/planners/pack-plan.d.ts +13 -0
- package/dist/app/planners/pack-plan.js +65 -0
- package/dist/app/planners/scope-plan.d.ts +17 -0
- package/dist/app/planners/scope-plan.js +143 -0
- package/dist/app/planners/trace-plan.d.ts +13 -0
- package/dist/app/planners/trace-plan.js +77 -0
- package/dist/app/source-collector.d.ts +5 -0
- package/dist/app/source-collector.js +33 -0
- package/dist/app/target-resolver.d.ts +7 -0
- package/dist/app/target-resolver.js +110 -0
- package/dist/cli/cli-input.js +70 -19
- package/dist/cli/flag-specs.d.ts +7 -3
- package/dist/cli/flag-specs.js +58 -7
- package/dist/cli/help-specs.d.ts +205 -0
- package/dist/cli/help-specs.js +136 -0
- package/dist/cli/help.js +107 -28
- package/dist/cli/report-command.js +59 -26
- package/dist/commands/{run-command.d.ts → git-command.d.ts} +3 -3
- package/dist/commands/git-command.js +7 -0
- package/dist/commands/grep-command.d.ts +11 -0
- package/dist/commands/grep-command.js +7 -0
- package/dist/commands/pack-command.d.ts +11 -0
- package/dist/commands/pack-command.js +7 -0
- package/dist/commands/scope-command.d.ts +12 -0
- package/dist/commands/scope-command.js +7 -0
- package/dist/commands/shared-runner.d.ts +12 -0
- package/dist/commands/shared-runner.js +30 -0
- package/dist/commands/trace-command.d.ts +11 -0
- package/dist/commands/trace-command.js +7 -0
- package/dist/config/default-config.js +7 -11
- package/dist/config/load.d.ts +1 -0
- package/dist/config/load.js +269 -4
- package/dist/config/migration/detect.d.ts +2 -1
- package/dist/config/migration/detect.js +10 -2
- package/dist/config/migration/messages.js +12 -11
- package/dist/config/migration/transform.js +77 -32
- package/dist/filesystem/binary.d.ts +2 -0
- package/dist/filesystem/binary.js +30 -0
- package/dist/filesystem/entry-discovery.d.ts +14 -0
- package/dist/filesystem/entry-discovery.js +78 -0
- package/dist/filesystem/file-set.d.ts +7 -0
- package/dist/filesystem/file-set.js +57 -0
- package/dist/filesystem/glob-scan.d.ts +6 -2
- package/dist/filesystem/glob-scan.js +12 -7
- package/dist/filesystem/path-patterns.d.ts +20 -0
- package/dist/filesystem/path-patterns.js +70 -0
- package/dist/index.js +51 -29
- package/dist/output/markdown-sections.d.ts +5 -0
- package/dist/output/markdown-sections.js +103 -0
- package/dist/output/markdown-toc.d.ts +31 -0
- package/dist/output/markdown-toc.js +287 -0
- package/dist/output/markdown.d.ts +5 -8
- package/dist/output/markdown.js +80 -127
- package/dist/output/produce-output.d.ts +4 -1
- package/dist/output/produce-output.js +6 -7
- package/dist/output/render-helpers.d.ts +4 -0
- package/dist/output/render-helpers.js +14 -0
- package/dist/output/text.d.ts +2 -2
- package/dist/output/text.js +47 -8
- package/dist/resolvers/js/resolve-alias.js +10 -41
- package/dist/resolvers/php/bindings.js +6 -6
- package/dist/resolvers/php/extract-imports.d.ts +19 -7
- package/dist/resolvers/php/extract-imports.js +146 -26
- package/dist/resolvers/php/php-resolver.js +55 -24
- package/dist/resolvers/php/psr4.d.ts +1 -1
- package/dist/resolvers/php/psr4.js +7 -1
- package/dist/runtime/shell-command-runner.d.ts +5 -0
- package/dist/runtime/shell-command-runner.js +118 -0
- package/dist/tracing/collect-trace.d.ts +10 -0
- package/dist/tracing/collect-trace.js +23 -0
- package/dist/tracing/exclude.d.ts +0 -5
- package/dist/tracing/exclude.js +16 -12
- package/dist/tracing/follow-chain.js +2 -2
- package/dist/types/app.types.d.ts +38 -8
- package/dist/types/artifact.types.d.ts +50 -0
- package/dist/types/artifact.types.js +2 -0
- package/dist/types/cli.types.d.ts +52 -4
- package/dist/types/config.types.d.ts +37 -20
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.js +2 -0
- package/dist/types/output.types.d.ts +12 -3
- package/dist/types/planner.types.d.ts +76 -0
- package/dist/types/planner.types.js +2 -0
- package/dist/types/resolver.types.d.ts +1 -1
- package/dist/types/tracing.types.d.ts +0 -11
- package/package.json +2 -2
- package/schema/prodex.schema.json +59 -41
- package/dist/app/run-plans.d.ts +0 -11
- package/dist/app/run-plans.js +0 -61
- package/dist/commands/profiles-command.d.ts +0 -6
- package/dist/commands/profiles-command.js +0 -16
- package/dist/commands/run-command.js +0 -17
- package/dist/config/build-config.d.ts +0 -13
- package/dist/config/build-config.js +0 -127
- package/dist/tracing/include-files.d.ts +0 -2
- package/dist/tracing/include-files.js +0 -36
- package/dist/tracing/trace-run.d.ts +0 -2
- package/dist/tracing/trace-run.js +0 -21
|
@@ -3,14 +3,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.configVersionError = configVersionError;
|
|
4
4
|
exports.legacyConfigShapeError = legacyConfigShapeError;
|
|
5
5
|
const detect_1 = require("./detect");
|
|
6
|
-
const
|
|
7
|
-
"Prodex
|
|
8
|
-
" entry
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
" resolve.
|
|
13
|
-
"
|
|
6
|
+
const V5_CHANGES = [
|
|
7
|
+
"Prodex v5 changed the config shape:",
|
|
8
|
+
" entry -> scopes.default.entry",
|
|
9
|
+
" include -> scopes.default.include",
|
|
10
|
+
" profiles -> scopes",
|
|
11
|
+
" profiles.*.name -> scopes.*.name",
|
|
12
|
+
" resolve.aliases -> aliases",
|
|
13
|
+
" resolve.maxDepth -> depth",
|
|
14
|
+
" resolve.maxFiles -> maxFiles",
|
|
14
15
|
"",
|
|
15
16
|
"Preview migration:",
|
|
16
17
|
" prodex migrate",
|
|
@@ -23,13 +24,13 @@ function configVersionError(version) {
|
|
|
23
24
|
return [
|
|
24
25
|
`prodex.json uses config version ${label}, but this Prodex version requires config version ${detect_1.REQUIRED_CONFIG_VERSION}.`,
|
|
25
26
|
"",
|
|
26
|
-
...
|
|
27
|
+
...V5_CHANGES,
|
|
27
28
|
].join("\n");
|
|
28
29
|
}
|
|
29
30
|
function legacyConfigShapeError() {
|
|
30
31
|
return [
|
|
31
|
-
"prodex.json contains legacy config fields that must be migrated to config version
|
|
32
|
+
"prodex.json contains legacy config fields that must be migrated to config version 5.",
|
|
32
33
|
"",
|
|
33
|
-
...
|
|
34
|
+
...V5_CHANGES,
|
|
34
35
|
].join("\n");
|
|
35
36
|
}
|
|
@@ -15,41 +15,86 @@ function migrateConfig(input) {
|
|
|
15
15
|
};
|
|
16
16
|
}
|
|
17
17
|
const changes = [];
|
|
18
|
+
const inputOutput = input.output ?? {};
|
|
18
19
|
const output = {
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
dir: inputOutput.dir !== undefined ? String(inputOutput.dir) : default_config_1.DEFAULT_PRODEX_CONFIG.output.dir,
|
|
21
|
+
versioned: inputOutput.versioned !== undefined ? Boolean(inputOutput.versioned) : default_config_1.DEFAULT_PRODEX_CONFIG.output.versioned,
|
|
22
|
+
format: (inputOutput.format === "md" || inputOutput.format === "txt") ? inputOutput.format : default_config_1.DEFAULT_PRODEX_CONFIG.output.format,
|
|
21
23
|
};
|
|
22
|
-
delete output.prefix;
|
|
23
24
|
if (input.output?.prefix !== undefined) {
|
|
24
|
-
changes.push("output.prefix removed; use
|
|
25
|
+
changes.push("output.prefix removed; use scope.name when you need to override scope output names.");
|
|
26
|
+
}
|
|
27
|
+
const aliases = input.aliases ?? input.resolve?.aliases ?? default_config_1.DEFAULT_PRODEX_CONFIG.aliases;
|
|
28
|
+
if (input.resolve?.aliases !== undefined)
|
|
29
|
+
changes.push("resolve.aliases -> aliases");
|
|
30
|
+
const depth = input.depth ?? input.resolve?.maxDepth ?? input.resolve?.depth ?? default_config_1.DEFAULT_PRODEX_CONFIG.depth;
|
|
31
|
+
if (input.resolve?.maxDepth !== undefined || input.resolve?.depth !== undefined)
|
|
32
|
+
changes.push("resolve.maxDepth -> depth");
|
|
33
|
+
const maxFiles = input.maxFiles ?? input.resolve?.maxFiles ?? input.resolve?.limit ?? default_config_1.DEFAULT_PRODEX_CONFIG.maxFiles;
|
|
34
|
+
if (input.resolve?.maxFiles !== undefined || input.resolve?.limit !== undefined)
|
|
35
|
+
changes.push("resolve.maxFiles -> maxFiles");
|
|
36
|
+
const exclude = (0, string_list_1.toStringList)(input.exclude ?? input.resolve?.exclude ?? default_config_1.DEFAULT_PRODEX_CONFIG.exclude);
|
|
37
|
+
if (input.resolve?.exclude !== undefined)
|
|
38
|
+
changes.push("resolve.exclude -> exclude");
|
|
39
|
+
if (input.profiles !== undefined) {
|
|
40
|
+
changes.push("profiles -> scopes");
|
|
41
|
+
let hasProfileName = false;
|
|
42
|
+
for (const key of Object.keys(input.profiles)) {
|
|
43
|
+
if (input.profiles[key]?.name !== undefined) {
|
|
44
|
+
hasProfileName = true;
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (hasProfileName) {
|
|
49
|
+
changes.push("profiles.*.name -> scopes.*.name");
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (input.shortcuts !== undefined)
|
|
53
|
+
changes.push("shortcuts -> scopes");
|
|
54
|
+
const scopes = migrateScopes(input.scopes ?? input.profiles ?? input.shortcuts ?? {}, changes);
|
|
55
|
+
const entryList = input.entry !== undefined ? (0, string_list_1.toStringList)(input.entry?.files ?? input.entry) : [];
|
|
56
|
+
const includeList = (input.include !== undefined || input.resolve?.include !== undefined)
|
|
57
|
+
? (0, string_list_1.toStringList)(input.include ?? input.resolve?.include)
|
|
58
|
+
: [];
|
|
59
|
+
const hasRootEntry = entryList.length > 0;
|
|
60
|
+
const hasRootInclude = includeList.length > 0;
|
|
61
|
+
if (hasRootEntry || hasRootInclude) {
|
|
62
|
+
if (!scopes.default) {
|
|
63
|
+
scopes.default = {};
|
|
64
|
+
}
|
|
65
|
+
const defScope = scopes.default;
|
|
66
|
+
if (hasRootEntry) {
|
|
67
|
+
const existingEntry = defScope.entry ?? [];
|
|
68
|
+
defScope.entry = unique([...existingEntry, ...entryList]);
|
|
69
|
+
changes.push("entry -> scopes.default.entry");
|
|
70
|
+
}
|
|
71
|
+
if (hasRootInclude) {
|
|
72
|
+
const existingInclude = defScope.include ?? [];
|
|
73
|
+
defScope.include = unique([...existingInclude, ...includeList]);
|
|
74
|
+
changes.push("include -> scopes.default.include");
|
|
75
|
+
}
|
|
76
|
+
if (input.output?.prefix !== undefined && defScope.name === undefined) {
|
|
77
|
+
defScope.name = input.output.prefix;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
if (input.entry !== undefined) {
|
|
82
|
+
changes.push("entry -> scopes.default.entry");
|
|
83
|
+
}
|
|
84
|
+
if (input.include !== undefined || input.resolve?.include !== undefined) {
|
|
85
|
+
changes.push("include -> scopes.default.include");
|
|
86
|
+
}
|
|
25
87
|
}
|
|
26
|
-
const resolve = {
|
|
27
|
-
aliases: input.resolve?.aliases ?? default_config_1.DEFAULT_PRODEX_CONFIG.resolve.aliases,
|
|
28
|
-
maxDepth: input.resolve?.maxDepth ?? input.resolve?.depth ?? default_config_1.DEFAULT_PRODEX_CONFIG.resolve.maxDepth,
|
|
29
|
-
maxFiles: input.resolve?.maxFiles ?? input.resolve?.limit ?? default_config_1.DEFAULT_PRODEX_CONFIG.resolve.maxFiles,
|
|
30
|
-
};
|
|
31
88
|
const config = {
|
|
32
89
|
version: detect_1.REQUIRED_CONFIG_VERSION,
|
|
33
90
|
$schema: input.$schema ?? default_config_1.DEFAULT_PRODEX_CONFIG.$schema,
|
|
34
91
|
output,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
92
|
+
exclude,
|
|
93
|
+
aliases,
|
|
94
|
+
depth,
|
|
95
|
+
maxFiles,
|
|
96
|
+
scopes,
|
|
40
97
|
};
|
|
41
|
-
if (input.entry?.files !== undefined)
|
|
42
|
-
changes.push("entry.files -> entry");
|
|
43
|
-
if (input.resolve?.include !== undefined)
|
|
44
|
-
changes.push("resolve.include -> include");
|
|
45
|
-
if (input.resolve?.exclude !== undefined)
|
|
46
|
-
changes.push("resolve.exclude -> exclude");
|
|
47
|
-
if (input.resolve?.depth !== undefined)
|
|
48
|
-
changes.push("resolve.depth -> resolve.maxDepth");
|
|
49
|
-
if (input.resolve?.limit !== undefined)
|
|
50
|
-
changes.push("resolve.limit -> resolve.maxFiles");
|
|
51
|
-
if (input.shortcuts !== undefined)
|
|
52
|
-
changes.push("shortcuts -> profiles");
|
|
53
98
|
return {
|
|
54
99
|
needed: true,
|
|
55
100
|
fromVersion: typeof input?.version === "number" ? input.version : undefined,
|
|
@@ -58,10 +103,10 @@ function migrateConfig(input) {
|
|
|
58
103
|
config,
|
|
59
104
|
};
|
|
60
105
|
}
|
|
61
|
-
function
|
|
62
|
-
const
|
|
106
|
+
function migrateScopes(input, changes) {
|
|
107
|
+
const scopes = {};
|
|
63
108
|
for (const [key, value] of Object.entries(input || {})) {
|
|
64
|
-
|
|
109
|
+
scopes[key] = {
|
|
65
110
|
...(value?.prefix ? { name: value.prefix } : {}),
|
|
66
111
|
...(value?.name ? { name: value.name } : {}),
|
|
67
112
|
...(value?.files || value?.entry ? { entry: (0, string_list_1.toStringList)(value.entry ?? value.files) } : {}),
|
|
@@ -69,11 +114,11 @@ function migrateProfiles(input, changes) {
|
|
|
69
114
|
...(value?.exclude ? { exclude: (0, string_list_1.toStringList)(value.exclude) } : {}),
|
|
70
115
|
};
|
|
71
116
|
if (value?.prefix !== undefined)
|
|
72
|
-
changes.push("shortcuts.*.prefix ->
|
|
117
|
+
changes.push("shortcuts.*.prefix -> scopes.*.name");
|
|
73
118
|
if (value?.files !== undefined)
|
|
74
|
-
changes.push("shortcuts.*.files ->
|
|
119
|
+
changes.push("shortcuts.*.files -> scopes.*.entry");
|
|
75
120
|
}
|
|
76
|
-
return
|
|
121
|
+
return scopes;
|
|
77
122
|
}
|
|
78
123
|
function unique(items) {
|
|
79
124
|
return [...new Set(items)];
|
|
@@ -0,0 +1,30 @@
|
|
|
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.isBinaryFile = isBinaryFile;
|
|
7
|
+
exports.isBinaryBuffer = isBinaryBuffer;
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
function isBinaryFile(filePath) {
|
|
10
|
+
try {
|
|
11
|
+
const stat = fs_1.default.statSync(filePath);
|
|
12
|
+
if (!stat.isFile())
|
|
13
|
+
return false;
|
|
14
|
+
const fd = fs_1.default.openSync(filePath, "r");
|
|
15
|
+
const buffer = Buffer.alloc(1024);
|
|
16
|
+
const bytesRead = fs_1.default.readSync(fd, buffer, 0, 1024, 0);
|
|
17
|
+
fs_1.default.closeSync(fd);
|
|
18
|
+
for (let i = 0; i < bytesRead; i++) {
|
|
19
|
+
if (buffer[i] === 0)
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function isBinaryBuffer(buffer) {
|
|
29
|
+
return buffer.subarray(0, 1024).includes(0);
|
|
30
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare const ENTRY_RESOLVE_EXTS: string[];
|
|
2
|
+
/**
|
|
3
|
+
* Perform exact/glob match search.
|
|
4
|
+
*/
|
|
5
|
+
export declare function scanGlob(patterns: string[], root: string): Promise<string[]>;
|
|
6
|
+
/**
|
|
7
|
+
* For a given path-like input, generate possible extensionless path expansions.
|
|
8
|
+
* Returns only files that physically exist.
|
|
9
|
+
*/
|
|
10
|
+
export declare function expandPathLike(pattern: string, root: string): string[];
|
|
11
|
+
/**
|
|
12
|
+
* Searches the workspace for files that match the bare name stem exactly.
|
|
13
|
+
*/
|
|
14
|
+
export declare function discoverBareName(bareName: string, root: string, caseSensitive?: boolean): Promise<string[]>;
|
|
@@ -0,0 +1,78 @@
|
|
|
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.ENTRY_RESOLVE_EXTS = void 0;
|
|
7
|
+
exports.scanGlob = scanGlob;
|
|
8
|
+
exports.expandPathLike = expandPathLike;
|
|
9
|
+
exports.discoverBareName = discoverBareName;
|
|
10
|
+
const fs_1 = __importDefault(require("fs"));
|
|
11
|
+
const path_1 = __importDefault(require("path"));
|
|
12
|
+
const glob_scan_1 = require("./glob-scan");
|
|
13
|
+
exports.ENTRY_RESOLVE_EXTS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".php"];
|
|
14
|
+
/**
|
|
15
|
+
* Perform exact/glob match search.
|
|
16
|
+
*/
|
|
17
|
+
async function scanGlob(patterns, root) {
|
|
18
|
+
const { files } = await (0, glob_scan_1.globScan)(patterns, { cwd: root });
|
|
19
|
+
return files;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* For a given path-like input, generate possible extensionless path expansions.
|
|
23
|
+
* Returns only files that physically exist.
|
|
24
|
+
*/
|
|
25
|
+
function expandPathLike(pattern, root) {
|
|
26
|
+
const candidates = [];
|
|
27
|
+
for (const ext of exports.ENTRY_RESOLVE_EXTS) {
|
|
28
|
+
candidates.push(path_1.default.resolve(root, pattern + ext));
|
|
29
|
+
candidates.push(path_1.default.resolve(root, pattern, "index" + ext));
|
|
30
|
+
}
|
|
31
|
+
return candidates.filter((candidate) => {
|
|
32
|
+
try {
|
|
33
|
+
const stat = fs_1.default.statSync(candidate);
|
|
34
|
+
return stat.isFile();
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Searches the workspace for files that match the bare name stem exactly.
|
|
43
|
+
*/
|
|
44
|
+
async function discoverBareName(bareName, root, caseSensitive = false) {
|
|
45
|
+
const searchPatterns = [
|
|
46
|
+
`**/${bareName}`,
|
|
47
|
+
...exports.ENTRY_RESOLVE_EXTS.map((ext) => `**/${bareName}${ext}`),
|
|
48
|
+
...exports.ENTRY_RESOLVE_EXTS.map((ext) => `**/${bareName}/index${ext}`),
|
|
49
|
+
];
|
|
50
|
+
const { files } = await (0, glob_scan_1.globScan)(searchPatterns, {
|
|
51
|
+
cwd: root,
|
|
52
|
+
caseSensitiveMatch: caseSensitive,
|
|
53
|
+
});
|
|
54
|
+
const resolvedMatches = new Set();
|
|
55
|
+
const targetStem = caseSensitive ? bareName : bareName.toLowerCase();
|
|
56
|
+
for (const file of files) {
|
|
57
|
+
const absFile = path_1.default.resolve(file);
|
|
58
|
+
const ext = path_1.default.extname(absFile);
|
|
59
|
+
const extLower = ext.toLowerCase();
|
|
60
|
+
// Ensure extension is empty or is one of the supported extensions
|
|
61
|
+
if (extLower !== "" && !exports.ENTRY_RESOLVE_EXTS.includes(extLower)) {
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
const stemRaw = path_1.default.basename(absFile, ext);
|
|
65
|
+
const stem = caseSensitive ? stemRaw : stemRaw.toLowerCase();
|
|
66
|
+
if (stem === targetStem) {
|
|
67
|
+
resolvedMatches.add(absFile);
|
|
68
|
+
}
|
|
69
|
+
else if (stem === "index") {
|
|
70
|
+
const parentDirRaw = path_1.default.basename(path_1.default.dirname(absFile));
|
|
71
|
+
const parentDir = caseSensitive ? parentDirRaw : parentDirRaw.toLowerCase();
|
|
72
|
+
if (parentDir === targetStem) {
|
|
73
|
+
resolvedMatches.add(absFile);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return Array.from(resolvedMatches);
|
|
78
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
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.buildFinalFileSet = buildFinalFileSet;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const glob_scan_1 = require("./glob-scan");
|
|
10
|
+
const path_2 = require("./path");
|
|
11
|
+
const exclude_1 = require("../tracing/exclude");
|
|
12
|
+
async function buildFinalFileSet(params) {
|
|
13
|
+
const { root, sources, include, exclude } = params;
|
|
14
|
+
const absoluteFiles = new Set();
|
|
15
|
+
// 1. Start with selected source files
|
|
16
|
+
for (const src of sources) {
|
|
17
|
+
absoluteFiles.add((0, path_2.normalizePath)(path_1.default.resolve(root, src)));
|
|
18
|
+
}
|
|
19
|
+
// 2. Resolve and add include path/glob inputs
|
|
20
|
+
const patterns = [];
|
|
21
|
+
for (const inc of include) {
|
|
22
|
+
const candidate = String(inc ?? "").trim();
|
|
23
|
+
if (!candidate)
|
|
24
|
+
continue;
|
|
25
|
+
const normalized = (0, path_2.normalizePath)(candidate);
|
|
26
|
+
if (path_1.default.isAbsolute(normalized)) {
|
|
27
|
+
try {
|
|
28
|
+
if (fs_1.default.statSync(normalized).isFile()) {
|
|
29
|
+
absoluteFiles.add((0, path_2.normalizePath)(path_1.default.resolve(normalized)));
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
// Treat unreadable absolute paths as glob patterns
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
patterns.push(normalized);
|
|
38
|
+
}
|
|
39
|
+
if (patterns.length > 0) {
|
|
40
|
+
const { files: scanFiles } = await (0, glob_scan_1.globScan)(patterns, { cwd: root });
|
|
41
|
+
for (const f of scanFiles) {
|
|
42
|
+
absoluteFiles.add((0, path_2.normalizePath)(f));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// 3. Deduplicate (Set takes care of this)
|
|
46
|
+
let list = Array.from(absoluteFiles);
|
|
47
|
+
// 4. Apply exclude path/glob inputs
|
|
48
|
+
list = list.filter((p) => !(0, exclude_1.isExcluded)(p, exclude, root));
|
|
49
|
+
// 5. Sort deterministically by root-relative normalized path
|
|
50
|
+
list.sort((a, b) => {
|
|
51
|
+
const relA = (0, path_2.normalizePath)(path_1.default.relative(root, a));
|
|
52
|
+
const relB = (0, path_2.normalizePath)(path_1.default.relative(root, b));
|
|
53
|
+
return relA.localeCompare(relB);
|
|
54
|
+
});
|
|
55
|
+
// 6. Return absolute paths
|
|
56
|
+
return list;
|
|
57
|
+
}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
export interface GlobScanOptions {
|
|
2
|
+
cwd?: string;
|
|
3
|
+
caseSensitiveMatch?: boolean;
|
|
4
|
+
ignore?: string[];
|
|
5
|
+
}
|
|
6
|
+
export declare function globScan(patterns: string[], opts?: GlobScanOptions): Promise<{
|
|
3
7
|
files: string[];
|
|
4
8
|
}>;
|
|
@@ -8,19 +8,24 @@ const path_1 = __importDefault(require("path"));
|
|
|
8
8
|
const fast_glob_1 = __importDefault(require("fast-glob"));
|
|
9
9
|
const logger_1 = require("../diagnostics/logger");
|
|
10
10
|
const inspect_1 = require("./inspect");
|
|
11
|
-
const
|
|
12
|
-
async function globScan(patterns, opts) {
|
|
13
|
-
const {
|
|
11
|
+
const path_2 = require("./path");
|
|
12
|
+
async function globScan(patterns, opts = {}) {
|
|
13
|
+
const { cwd = process.cwd(), caseSensitiveMatch, ignore } = opts;
|
|
14
14
|
if (!patterns?.length)
|
|
15
15
|
return { files: [] };
|
|
16
|
-
const
|
|
16
|
+
const rawFiles = await (0, fast_glob_1.default)(patterns, {
|
|
17
17
|
cwd,
|
|
18
18
|
extglob: true,
|
|
19
19
|
dot: true,
|
|
20
20
|
onlyFiles: true,
|
|
21
|
-
ignore
|
|
22
|
-
absolute,
|
|
23
|
-
|
|
21
|
+
ignore,
|
|
22
|
+
absolute: true,
|
|
23
|
+
caseSensitiveMatch,
|
|
24
|
+
});
|
|
25
|
+
// Slash normalization & absolute path resolution
|
|
26
|
+
const files = rawFiles.map((file) => (0, path_2.normalizePath)(path_1.default.resolve(cwd, file)));
|
|
27
|
+
// Deterministic file sorting
|
|
28
|
+
files.sort();
|
|
24
29
|
logger_1.logger.debug("globScan ->", (0, inspect_1.inspectValue)(files));
|
|
25
30
|
return { files };
|
|
26
31
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export declare function isGlobPattern(str: string): boolean;
|
|
2
|
+
export interface NormalizationOptions {
|
|
3
|
+
role?: "entry" | "include" | "exclude" | "skip" | "within";
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Normalizes a path or glob pattern.
|
|
7
|
+
*
|
|
8
|
+
* For "exclude" or "skip" roles:
|
|
9
|
+
* - If the pattern is not a glob and does not exist as a file, and has no extension,
|
|
10
|
+
* it is assumed to be a directory shorthand and is expanded recursively (e.g., "dist" -> "dist/**").
|
|
11
|
+
* - Note: Ambiguous extensionless filenames (such as "README", "LICENSE", "Dockerfile", "Makefile")
|
|
12
|
+
* are also treated as directories and expanded recursively if they do not exist on disk.
|
|
13
|
+
*
|
|
14
|
+
* For "entry" or "include" roles:
|
|
15
|
+
* - Non-existing directory-like inputs are NOT expanded and are kept as literal paths to preserve strictness.
|
|
16
|
+
*
|
|
17
|
+
* For all roles:
|
|
18
|
+
* - Existing directories are always expanded recursively (e.g., "src" -> "src/**").
|
|
19
|
+
*/
|
|
20
|
+
export declare function normalizePathOrGlob(pattern: string, root: string, options?: NormalizationOptions): string;
|
|
@@ -0,0 +1,70 @@
|
|
|
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.isGlobPattern = isGlobPattern;
|
|
7
|
+
exports.normalizePathOrGlob = normalizePathOrGlob;
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const path_2 = require("./path");
|
|
11
|
+
function isGlobPattern(str) {
|
|
12
|
+
return str.includes("*") || str.includes("?") || str.includes("[") || str.includes("{");
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Normalizes a path or glob pattern.
|
|
16
|
+
*
|
|
17
|
+
* For "exclude" or "skip" roles:
|
|
18
|
+
* - If the pattern is not a glob and does not exist as a file, and has no extension,
|
|
19
|
+
* it is assumed to be a directory shorthand and is expanded recursively (e.g., "dist" -> "dist/**").
|
|
20
|
+
* - Note: Ambiguous extensionless filenames (such as "README", "LICENSE", "Dockerfile", "Makefile")
|
|
21
|
+
* are also treated as directories and expanded recursively if they do not exist on disk.
|
|
22
|
+
*
|
|
23
|
+
* For "entry" or "include" roles:
|
|
24
|
+
* - Non-existing directory-like inputs are NOT expanded and are kept as literal paths to preserve strictness.
|
|
25
|
+
*
|
|
26
|
+
* For all roles:
|
|
27
|
+
* - Existing directories are always expanded recursively (e.g., "src" -> "src/**").
|
|
28
|
+
*/
|
|
29
|
+
function normalizePathOrGlob(pattern, root, options) {
|
|
30
|
+
const trimmed = String(pattern ?? "").trim();
|
|
31
|
+
if (!trimmed)
|
|
32
|
+
return "";
|
|
33
|
+
// 1. If it has glob characters, return normalized pattern
|
|
34
|
+
if (isGlobPattern(trimmed)) {
|
|
35
|
+
return (0, path_2.normalizePath)(trimmed);
|
|
36
|
+
}
|
|
37
|
+
// 2. Resolve absolute path to check disk status
|
|
38
|
+
const absPath = path_1.default.resolve(root, trimmed);
|
|
39
|
+
let isDir = false;
|
|
40
|
+
let isFile = false;
|
|
41
|
+
try {
|
|
42
|
+
const stat = fs_1.default.statSync(absPath);
|
|
43
|
+
isDir = stat.isDirectory();
|
|
44
|
+
isFile = stat.isFile();
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// Path does not exist or cannot be read
|
|
48
|
+
}
|
|
49
|
+
// 3. Existing directories are expanded recursively
|
|
50
|
+
if (isDir) {
|
|
51
|
+
const normalized = (0, path_2.normalizePath)(trimmed);
|
|
52
|
+
if (normalized.endsWith("/")) {
|
|
53
|
+
return normalized + "**";
|
|
54
|
+
}
|
|
55
|
+
return normalized + "/**";
|
|
56
|
+
}
|
|
57
|
+
// 4. Role-aware normalization for exclude/skip roles (Option B)
|
|
58
|
+
const role = options?.role;
|
|
59
|
+
if (role === "exclude" || role === "skip") {
|
|
60
|
+
if (!isFile) {
|
|
61
|
+
const normalized = (0, path_2.normalizePath)(trimmed);
|
|
62
|
+
const hasExtension = path_1.default.extname(trimmed) !== "";
|
|
63
|
+
// Expand if it ends with a slash or has no extension
|
|
64
|
+
if (normalized.endsWith("/") || !hasExtension) {
|
|
65
|
+
return normalized.endsWith("/") ? normalized + "**" : normalized + "/**";
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return (0, path_2.normalizePath)(trimmed);
|
|
70
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -4,8 +4,11 @@ exports.default = startProdex;
|
|
|
4
4
|
exports.runProdexCommand = runProdexCommand;
|
|
5
5
|
const init_command_1 = require("./commands/init-command");
|
|
6
6
|
const migrate_command_1 = require("./commands/migrate-command");
|
|
7
|
-
const
|
|
8
|
-
const
|
|
7
|
+
const pack_command_1 = require("./commands/pack-command");
|
|
8
|
+
const trace_command_1 = require("./commands/trace-command");
|
|
9
|
+
const scope_command_1 = require("./commands/scope-command");
|
|
10
|
+
const git_command_1 = require("./commands/git-command");
|
|
11
|
+
const grep_command_1 = require("./commands/grep-command");
|
|
9
12
|
const cli_input_1 = require("./cli/cli-input");
|
|
10
13
|
const reporter_1 = require("./cli/reporter");
|
|
11
14
|
async function startProdex(args = process.argv) {
|
|
@@ -38,19 +41,6 @@ async function runProdexCommand(args = process.argv, cwd = process.cwd()) {
|
|
|
38
41
|
runs: [],
|
|
39
42
|
};
|
|
40
43
|
}
|
|
41
|
-
if (parsed.command.kind === "profiles") {
|
|
42
|
-
const listed = (0, profiles_command_1.profilesCommand)(parsed.command.rootArg, cwd);
|
|
43
|
-
warnings.push(...listed.warnings);
|
|
44
|
-
errors.push(...listed.errors);
|
|
45
|
-
return {
|
|
46
|
-
ok: !errors.length,
|
|
47
|
-
exitCode: errors.length ? 1 : 0,
|
|
48
|
-
profiles: errors.length ? undefined : listed.profiles,
|
|
49
|
-
warnings,
|
|
50
|
-
errors,
|
|
51
|
-
runs: [],
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
44
|
if (parsed.command.kind === "migrate") {
|
|
55
45
|
const migration = (0, migrate_command_1.migrateCommand)({
|
|
56
46
|
rootArg: parsed.command.rootArg,
|
|
@@ -67,21 +57,53 @@ async function runProdexCommand(args = process.argv, cwd = process.cwd()) {
|
|
|
67
57
|
runs: [],
|
|
68
58
|
};
|
|
69
59
|
}
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
cwd
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
60
|
+
const kind = parsed.command.kind;
|
|
61
|
+
if (kind === "pack" || kind === "trace" || kind === "scope" || kind === "git" || kind === "grep") {
|
|
62
|
+
let cmdRes;
|
|
63
|
+
const params = { rootArg: parsed.command.rootArg, flags: parsed.command.flags, cwd };
|
|
64
|
+
if (kind === "pack") {
|
|
65
|
+
cmdRes = await (0, pack_command_1.packCommand)(params);
|
|
66
|
+
}
|
|
67
|
+
else if (kind === "trace") {
|
|
68
|
+
cmdRes = await (0, trace_command_1.traceCommand)(params);
|
|
69
|
+
}
|
|
70
|
+
else if (kind === "scope") {
|
|
71
|
+
cmdRes = await (0, scope_command_1.scopeCommand)(params);
|
|
72
|
+
}
|
|
73
|
+
else if (kind === "git") {
|
|
74
|
+
cmdRes = await (0, git_command_1.gitCommand)(params);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
cmdRes = await (0, grep_command_1.grepCommand)(params);
|
|
78
|
+
}
|
|
79
|
+
warnings.push(...cmdRes.warnings);
|
|
80
|
+
errors.push(...cmdRes.errors);
|
|
81
|
+
if (errors.length)
|
|
82
|
+
return { ok: false, exitCode: 1, warnings, errors, runs: [] };
|
|
83
|
+
if (kind === "scope" && cmdRes.scopes) {
|
|
84
|
+
return {
|
|
85
|
+
ok: true,
|
|
86
|
+
exitCode: 0,
|
|
87
|
+
scopes: cmdRes.scopes,
|
|
88
|
+
warnings,
|
|
89
|
+
errors,
|
|
90
|
+
runs: [],
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
const ok = cmdRes.runs.every((item) => item.ok);
|
|
94
|
+
return {
|
|
95
|
+
ok,
|
|
96
|
+
exitCode: ok ? 0 : 1,
|
|
97
|
+
warnings,
|
|
98
|
+
errors,
|
|
99
|
+
runs: cmdRes.runs,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
80
102
|
return {
|
|
81
|
-
ok,
|
|
82
|
-
exitCode:
|
|
103
|
+
ok: false,
|
|
104
|
+
exitCode: 1,
|
|
83
105
|
warnings,
|
|
84
|
-
errors,
|
|
85
|
-
runs:
|
|
106
|
+
errors: [...errors, "Unknown command kind"],
|
|
107
|
+
runs: [],
|
|
86
108
|
};
|
|
87
109
|
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ArtifactSection, CommandOutputResult, FileSnapshot } from "../types";
|
|
2
|
+
export declare function getDynamicFence(output: string): string;
|
|
3
|
+
export declare function renderFileSection(file: FileSnapshot, index: number, root: string, navLine: string): string;
|
|
4
|
+
export declare function renderGenericSection(sec: ArtifactSection, index: number, navLine: string): string;
|
|
5
|
+
export declare function renderMdCmdResults(cmdResults?: CommandOutputResult[], root?: string, totalCount?: number, sectionCount?: number, orderedAnchors?: string[]): string;
|