npmdata 0.10.3 → 0.12.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 +133 -58
- package/dist/cli/actions/check.d.ts +6 -0
- package/dist/cli/actions/check.d.ts.map +1 -0
- package/dist/cli/actions/check.js +57 -0
- package/dist/cli/actions/check.js.map +1 -0
- package/dist/cli/actions/extract.d.ts +7 -0
- package/dist/cli/actions/extract.d.ts.map +1 -0
- package/dist/cli/actions/extract.js +84 -0
- package/dist/cli/actions/extract.js.map +1 -0
- package/dist/cli/actions/init.d.ts +6 -0
- package/dist/cli/actions/init.d.ts.map +1 -0
- package/dist/cli/actions/init.js +36 -0
- package/dist/cli/actions/init.js.map +1 -0
- package/dist/cli/actions/list.d.ts +7 -0
- package/dist/cli/actions/list.d.ts.map +1 -0
- package/dist/cli/actions/list.js +42 -0
- package/dist/cli/actions/list.js.map +1 -0
- package/dist/cli/actions/purge.d.ts +6 -0
- package/dist/cli/actions/purge.d.ts.map +1 -0
- package/dist/cli/actions/purge.js +47 -0
- package/dist/cli/actions/purge.js.map +1 -0
- package/dist/cli/argv.d.ts +35 -0
- package/dist/cli/argv.d.ts.map +1 -0
- package/dist/cli/argv.js +125 -0
- package/dist/cli/argv.js.map +1 -0
- package/dist/cli/cli.d.ts +9 -0
- package/dist/cli/cli.d.ts.map +1 -0
- package/dist/cli/cli.js +69 -0
- package/dist/cli/cli.js.map +1 -0
- package/dist/cli/runner.d.ts +9 -0
- package/dist/cli/runner.d.ts.map +1 -0
- package/dist/cli/runner.js +106 -0
- package/dist/cli/runner.js.map +1 -0
- package/dist/cli/usage.d.ts +6 -0
- package/dist/cli/usage.d.ts.map +1 -0
- package/dist/cli/usage.js +126 -0
- package/dist/cli/usage.js.map +1 -0
- package/dist/fileset/check.d.ts +15 -0
- package/dist/fileset/check.d.ts.map +1 -0
- package/dist/fileset/check.js +68 -0
- package/dist/fileset/check.js.map +1 -0
- package/dist/fileset/constants.d.ts +13 -0
- package/dist/fileset/constants.d.ts.map +1 -0
- package/dist/fileset/constants.js +22 -0
- package/dist/fileset/constants.js.map +1 -0
- package/dist/fileset/diff.d.ts +16 -0
- package/dist/fileset/diff.d.ts.map +1 -0
- package/dist/fileset/diff.js +116 -0
- package/dist/fileset/diff.js.map +1 -0
- package/dist/fileset/execute.d.ts +29 -0
- package/dist/fileset/execute.d.ts.map +1 -0
- package/dist/fileset/execute.js +136 -0
- package/dist/fileset/execute.js.map +1 -0
- package/dist/fileset/gitignore.d.ts +16 -0
- package/dist/fileset/gitignore.d.ts.map +1 -0
- package/dist/fileset/gitignore.js +82 -0
- package/dist/fileset/gitignore.js.map +1 -0
- package/dist/fileset/index.d.ts +5 -0
- package/dist/fileset/index.d.ts.map +1 -0
- package/dist/fileset/index.js +21 -0
- package/dist/fileset/index.js.map +1 -0
- package/dist/fileset/list.d.ts +6 -0
- package/dist/fileset/list.d.ts.map +1 -0
- package/dist/fileset/list.js +11 -0
- package/dist/fileset/list.js.map +1 -0
- package/dist/fileset/markers.d.ts +22 -0
- package/dist/fileset/markers.d.ts.map +1 -0
- package/dist/fileset/markers.js +68 -0
- package/dist/fileset/markers.js.map +1 -0
- package/dist/fileset/package-files.d.ts +14 -0
- package/dist/fileset/package-files.d.ts.map +1 -0
- package/dist/fileset/package-files.js +81 -0
- package/dist/fileset/package-files.js.map +1 -0
- package/dist/fileset/purge.d.ts +12 -0
- package/dist/fileset/purge.d.ts.map +1 -0
- package/dist/fileset/purge.js +95 -0
- package/dist/fileset/purge.js.map +1 -0
- package/dist/fileset/test-utils.d.ts +12 -0
- package/dist/fileset/test-utils.d.ts.map +1 -0
- package/dist/fileset/test-utils.js +65 -0
- package/dist/fileset/test-utils.js.map +1 -0
- package/dist/index.d.ts +10 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -17
- package/dist/index.js.map +1 -1
- package/dist/main.js +9 -16
- package/dist/main.js.map +1 -1
- package/dist/npmdata-0.0.1.tgz +0 -0
- package/dist/package/action-check.d.ts +20 -0
- package/dist/package/action-check.d.ts.map +1 -0
- package/dist/package/action-check.js +61 -0
- package/dist/package/action-check.js.map +1 -0
- package/dist/package/action-extract.d.ts +21 -0
- package/dist/package/action-extract.d.ts.map +1 -0
- package/dist/package/action-extract.js +186 -0
- package/dist/package/action-extract.js.map +1 -0
- package/dist/package/action-init.d.ts +13 -0
- package/dist/package/action-init.d.ts.map +1 -0
- package/dist/package/action-init.js +77 -0
- package/dist/package/action-init.js.map +1 -0
- package/dist/package/action-list.d.ts +14 -0
- package/dist/package/action-list.d.ts.map +1 -0
- package/dist/package/action-list.js +46 -0
- package/dist/package/action-list.js.map +1 -0
- package/dist/package/action-purge.d.ts +21 -0
- package/dist/package/action-purge.d.ts.map +1 -0
- package/dist/package/action-purge.js +60 -0
- package/dist/package/action-purge.js.map +1 -0
- package/dist/package/config-merge.d.ts +18 -0
- package/dist/package/config-merge.d.ts.map +1 -0
- package/dist/package/config-merge.js +48 -0
- package/dist/package/config-merge.js.map +1 -0
- package/dist/package/config.d.ts +13 -0
- package/dist/package/config.d.ts.map +1 -0
- package/dist/package/config.js +29 -0
- package/dist/package/config.js.map +1 -0
- package/dist/package/content-replacements.d.ts +21 -0
- package/dist/package/content-replacements.d.ts.map +1 -0
- package/dist/package/content-replacements.js +96 -0
- package/dist/package/content-replacements.js.map +1 -0
- package/dist/package/index.d.ts +10 -0
- package/dist/package/index.d.ts.map +1 -0
- package/dist/package/index.js +16 -0
- package/dist/package/index.js.map +1 -0
- package/dist/package/symlinks.d.ts +17 -0
- package/dist/package/symlinks.d.ts.map +1 -0
- package/dist/package/symlinks.js +125 -0
- package/dist/package/symlinks.js.map +1 -0
- package/dist/types.d.ts +184 -270
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +0 -12
- package/dist/types.js.map +1 -1
- package/dist/utils.d.ts +25 -55
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +82 -181
- package/dist/utils.js.map +1 -1
- package/package.json +5 -2
- package/dist/cli.d.ts +0 -6
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js +0 -514
- package/dist/cli.js.map +0 -1
- package/dist/consumer.d.ts +0 -74
- package/dist/consumer.d.ts.map +0 -1
- package/dist/consumer.js +0 -820
- package/dist/consumer.js.map +0 -1
- package/dist/publisher.d.ts +0 -38
- package/dist/publisher.d.ts.map +0 -1
- package/dist/publisher.js +0 -164
- package/dist/publisher.js.map +0 -1
- package/dist/runner.d.ts +0 -102
- package/dist/runner.d.ts.map +0 -1
- package/dist/runner.js +0 -748
- package/dist/runner.js.map +0 -1
package/dist/runner.js
DELETED
|
@@ -1,748 +0,0 @@
|
|
|
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.buildCheckCommand = buildCheckCommand;
|
|
7
|
-
exports.buildListCommand = buildListCommand;
|
|
8
|
-
exports.buildPurgeCommand = buildPurgeCommand;
|
|
9
|
-
exports.collectAllTags = collectAllTags;
|
|
10
|
-
exports.printHelp = printHelp;
|
|
11
|
-
exports.parseOutputFromArgv = parseOutputFromArgv;
|
|
12
|
-
exports.parseDryRunFromArgv = parseDryRunFromArgv;
|
|
13
|
-
exports.parseSilentFromArgv = parseSilentFromArgv;
|
|
14
|
-
exports.parseVerboseFromArgv = parseVerboseFromArgv;
|
|
15
|
-
exports.parseNoGitignoreFromArgv = parseNoGitignoreFromArgv;
|
|
16
|
-
exports.parseUnmanagedFromArgv = parseUnmanagedFromArgv;
|
|
17
|
-
exports.parseTagsFromArgv = parseTagsFromArgv;
|
|
18
|
-
exports.filterEntriesByTags = filterEntriesByTags;
|
|
19
|
-
exports.applySymlinks = applySymlinks;
|
|
20
|
-
exports.applyContentReplacements = applyContentReplacements;
|
|
21
|
-
exports.checkContentReplacements = checkContentReplacements;
|
|
22
|
-
exports.run = run;
|
|
23
|
-
/* eslint-disable no-restricted-syntax */
|
|
24
|
-
const node_child_process_1 = require("node:child_process");
|
|
25
|
-
const node_fs_1 = __importDefault(require("node:fs"));
|
|
26
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
27
|
-
const minimatch_1 = require("minimatch");
|
|
28
|
-
const utils_1 = require("./utils");
|
|
29
|
-
/**
|
|
30
|
-
* Extract just the package name (without version specifier) from a package spec string.
|
|
31
|
-
* Delegates to the shared parsePackageSpec utility.
|
|
32
|
-
*/
|
|
33
|
-
function parseEntryPackageName(spec) {
|
|
34
|
-
const { name } = (0, utils_1.parsePackageSpec)(spec);
|
|
35
|
-
return { name };
|
|
36
|
-
}
|
|
37
|
-
function buildExtractCommand(cliPath, entry, cwd = process.cwd()) {
|
|
38
|
-
const outputFlag = ` --output "${node_path_1.default.resolve(cwd, entry.outputDir)}"`;
|
|
39
|
-
const forceFlag = entry.force ? ' --force' : '';
|
|
40
|
-
const keepExistingFlag = entry.keepExisting ? ' --keep-existing' : '';
|
|
41
|
-
const gitignoreFlag = entry.gitignore === false ? ' --no-gitignore' : '';
|
|
42
|
-
const unmanagedFlag = entry.unmanaged ? ' --unmanaged' : '';
|
|
43
|
-
const silentFlag = entry.silent ? ' --silent' : '';
|
|
44
|
-
const verboseFlag = entry.verbose ? ' --verbose' : '';
|
|
45
|
-
const dryRunFlag = entry.dryRun ? ' --dry-run' : '';
|
|
46
|
-
const upgradeFlag = entry.upgrade ? ' --upgrade' : '';
|
|
47
|
-
const filesFlag = entry.files && entry.files.length > 0 ? ` --files "${entry.files.join(',')}"` : '';
|
|
48
|
-
const contentRegexFlag = entry.contentRegexes && entry.contentRegexes.length > 0
|
|
49
|
-
? ` --content-regex "${entry.contentRegexes.join(',')}"`
|
|
50
|
-
: '';
|
|
51
|
-
return `node "${cliPath}" extract --packages "${entry.package}"${outputFlag}${forceFlag}${keepExistingFlag}${gitignoreFlag}${unmanagedFlag}${silentFlag}${verboseFlag}${dryRunFlag}${upgradeFlag}${filesFlag}${contentRegexFlag}`;
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Build a CLI command string that checks whether local files are in sync with the entry's package.
|
|
55
|
-
*/
|
|
56
|
-
function buildCheckCommand(cliPath, entry, cwd = process.cwd()) {
|
|
57
|
-
const outputFlag = ` --output "${node_path_1.default.resolve(cwd, entry.outputDir)}"`;
|
|
58
|
-
const verboseFlag = entry.verbose ? ' --verbose' : '';
|
|
59
|
-
const filesFlag = entry.files && entry.files.length > 0 ? ` --files "${entry.files.join(',')}"` : '';
|
|
60
|
-
const contentRegexFlag = entry.contentRegexes && entry.contentRegexes.length > 0
|
|
61
|
-
? ` --content-regex "${entry.contentRegexes.join(',')}"`
|
|
62
|
-
: '';
|
|
63
|
-
return `node "${cliPath}" check --packages "${entry.package}"${outputFlag}${verboseFlag}${filesFlag}${contentRegexFlag}`;
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Build a CLI command string that lists all managed files in the given output directory.
|
|
67
|
-
*/
|
|
68
|
-
function buildListCommand(cliPath, outputDir, cwd = process.cwd(), verbose = false) {
|
|
69
|
-
const resolvedOutput = node_path_1.default.resolve(cwd, outputDir);
|
|
70
|
-
const verboseFlag = verbose ? ' --verbose' : '';
|
|
71
|
-
return `node "${cliPath}" list --output "${resolvedOutput}"${verboseFlag}`;
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Build a CLI command string that purges (removes) all managed files for the entry's package
|
|
75
|
-
* from its output directory. No package installation is required.
|
|
76
|
-
*/
|
|
77
|
-
function buildPurgeCommand(cliPath, entry, cwd = process.cwd()) {
|
|
78
|
-
const { name } = parseEntryPackageName(entry.package);
|
|
79
|
-
const outputFlag = ` --output "${node_path_1.default.resolve(cwd, entry.outputDir)}"`;
|
|
80
|
-
// Propagate silent/dry-run/verbose settings from the entry if present.
|
|
81
|
-
const silentFlag = entry.silent ? ' --silent' : '';
|
|
82
|
-
const verboseFlag = entry.verbose ? ' --verbose' : '';
|
|
83
|
-
const dryRunFlag = entry.dryRun ? ' --dry-run' : '';
|
|
84
|
-
return `node "${cliPath}" purge --packages "${name}"${outputFlag}${silentFlag}${verboseFlag}${dryRunFlag}`;
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* Collects all unique tags that appear across the given npmdata entries, sorted alphabetically.
|
|
88
|
-
*/
|
|
89
|
-
function collectAllTags(entries) {
|
|
90
|
-
const tagSet = new Set();
|
|
91
|
-
for (const entry of entries) {
|
|
92
|
-
if (entry.tags) {
|
|
93
|
-
for (const tag of entry.tags) {
|
|
94
|
-
tagSet.add(tag);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
return Array.from(tagSet).sort();
|
|
99
|
-
}
|
|
100
|
-
/**
|
|
101
|
-
* Prints a help message to stdout, listing the extract action, all options, and available tags.
|
|
102
|
-
*/
|
|
103
|
-
function printHelp(packageName, availableTags) {
|
|
104
|
-
const tagsLine = availableTags.length > 0 ? availableTags.join(', ') : '(none defined in package.json)';
|
|
105
|
-
const exampleTag = availableTags.length > 0 ? availableTags[0] : 'my-tag';
|
|
106
|
-
process.stdout.write([
|
|
107
|
-
`Usage: ${packageName} <action> [options]`,
|
|
108
|
-
'',
|
|
109
|
-
'Actions:',
|
|
110
|
-
' extract Extract files from the source package(s) defined in package.json',
|
|
111
|
-
' check Verify local files are in sync with the source package(s)',
|
|
112
|
-
' list List all files managed by npmdata in the output directories',
|
|
113
|
-
' purge Remove all managed files previously extracted',
|
|
114
|
-
'',
|
|
115
|
-
'Options:',
|
|
116
|
-
' --help Show this help message',
|
|
117
|
-
' --output, -o <dir> Base directory for resolving all outputDir paths (default: cwd)',
|
|
118
|
-
' --dry-run Simulate changes without writing or deleting any files',
|
|
119
|
-
' --tags <tag1,tag2> Limit to entries whose tags overlap (comma-separated)',
|
|
120
|
-
' --no-gitignore Disable .gitignore management for every entry (overrides per-entry setting)',
|
|
121
|
-
' --unmanaged Run every entry in unmanaged mode (overrides per-entry setting)',
|
|
122
|
-
' --verbose, -v Print detailed progress information for each step',
|
|
123
|
-
'',
|
|
124
|
-
`Available tags: ${tagsLine}`,
|
|
125
|
-
'',
|
|
126
|
-
'Examples:',
|
|
127
|
-
` ${packageName} extract`,
|
|
128
|
-
' Extract files for all entries defined in package.json',
|
|
129
|
-
'',
|
|
130
|
-
` ${packageName} extract --output <dir>`,
|
|
131
|
-
' Extract files, resolving all outputDir paths relative to <dir> instead of cwd',
|
|
132
|
-
'',
|
|
133
|
-
` ${packageName} extract --dry-run`,
|
|
134
|
-
' Preview what would be extracted without writing any files',
|
|
135
|
-
'',
|
|
136
|
-
` ${packageName} extract --tags ${exampleTag}`,
|
|
137
|
-
` Extract files only for entries tagged "${exampleTag}"`,
|
|
138
|
-
'',
|
|
139
|
-
` ${packageName} check`,
|
|
140
|
-
' Check if local files are in sync with the source packages',
|
|
141
|
-
'',
|
|
142
|
-
` ${packageName} list`,
|
|
143
|
-
' List all files managed by npmdata in the output directories',
|
|
144
|
-
'',
|
|
145
|
-
` ${packageName} purge`,
|
|
146
|
-
' Remove all managed files from the output directories',
|
|
147
|
-
'',
|
|
148
|
-
].join('\n'));
|
|
149
|
-
}
|
|
150
|
-
/**
|
|
151
|
-
* Parses --output (or -o) from an argv array and returns the path string.
|
|
152
|
-
* Returns undefined when the flag is not present.
|
|
153
|
-
*/
|
|
154
|
-
function parseOutputFromArgv(argv) {
|
|
155
|
-
const idx = argv.findIndex((a) => a === '--output' || a === '-o');
|
|
156
|
-
if (idx === -1 || idx + 1 >= argv.length) {
|
|
157
|
-
// eslint-disable-next-line no-undefined
|
|
158
|
-
return undefined;
|
|
159
|
-
}
|
|
160
|
-
return argv[idx + 1];
|
|
161
|
-
}
|
|
162
|
-
/**
|
|
163
|
-
* Returns true when --dry-run appears in the argv array.
|
|
164
|
-
*/
|
|
165
|
-
function parseDryRunFromArgv(argv) {
|
|
166
|
-
return argv.includes('--dry-run');
|
|
167
|
-
}
|
|
168
|
-
/**
|
|
169
|
-
* Returns true when --silent appears in the argv array.
|
|
170
|
-
*/
|
|
171
|
-
function parseSilentFromArgv(argv) {
|
|
172
|
-
return argv.includes('--silent');
|
|
173
|
-
}
|
|
174
|
-
/**
|
|
175
|
-
* Returns true when --verbose or -v appears in the argv array.
|
|
176
|
-
*/
|
|
177
|
-
function parseVerboseFromArgv(argv) {
|
|
178
|
-
return argv.includes('--verbose') || argv.includes('-v');
|
|
179
|
-
}
|
|
180
|
-
/**
|
|
181
|
-
* Returns true when --no-gitignore appears in the argv array.
|
|
182
|
-
* When true, overrides the gitignore setting of every entry to false.
|
|
183
|
-
*/
|
|
184
|
-
function parseNoGitignoreFromArgv(argv) {
|
|
185
|
-
return argv.includes('--no-gitignore');
|
|
186
|
-
}
|
|
187
|
-
/**
|
|
188
|
-
* Returns true when --unmanaged appears in the argv array.
|
|
189
|
-
* When true, overrides the unmanaged setting of every entry to true.
|
|
190
|
-
*/
|
|
191
|
-
function parseUnmanagedFromArgv(argv) {
|
|
192
|
-
return argv.includes('--unmanaged');
|
|
193
|
-
}
|
|
194
|
-
/**
|
|
195
|
-
* Parses --tags from an argv array and returns the list of requested tags (split by comma).
|
|
196
|
-
* Returns an empty array when --tags is not present.
|
|
197
|
-
*/
|
|
198
|
-
function parseTagsFromArgv(argv) {
|
|
199
|
-
const idx = argv.indexOf('--tags');
|
|
200
|
-
if (idx === -1 || idx + 1 >= argv.length) {
|
|
201
|
-
return [];
|
|
202
|
-
}
|
|
203
|
-
return argv[idx + 1]
|
|
204
|
-
.split(',')
|
|
205
|
-
.map((t) => t.trim())
|
|
206
|
-
.filter(Boolean);
|
|
207
|
-
}
|
|
208
|
-
/**
|
|
209
|
-
* Filter entries by requested tags. When no tags are requested all entries pass through.
|
|
210
|
-
* When tags are requested only entries that share at least one tag with the requested list
|
|
211
|
-
* are included.
|
|
212
|
-
*/
|
|
213
|
-
function filterEntriesByTags(entries, requestedTags) {
|
|
214
|
-
if (requestedTags.length === 0) {
|
|
215
|
-
return entries;
|
|
216
|
-
}
|
|
217
|
-
return entries.filter((entry) => entry.tags && entry.tags.some((t) => requestedTags.includes(t)));
|
|
218
|
-
}
|
|
219
|
-
// ─── Managed path helpers ──────────────────────────────────────────────────────
|
|
220
|
-
/**
|
|
221
|
-
* From the flat list of managed file paths (relative to outputDir) recorded in
|
|
222
|
-
* the .npmdata marker, derive every unique path that can be symlinked: each
|
|
223
|
-
* file itself plus every intermediate ancestor directory.
|
|
224
|
-
*
|
|
225
|
-
* Example: 'skills/skill-a/README.md' yields
|
|
226
|
-
* 'skills', 'skills/skill-a', 'skills/skill-a/README.md'
|
|
227
|
-
*/
|
|
228
|
-
function managedPathsWithAncestors(managedFiles) {
|
|
229
|
-
const paths = new Set();
|
|
230
|
-
for (const mf of managedFiles) {
|
|
231
|
-
// eslint-disable-next-line functional/immutable-data
|
|
232
|
-
paths.add(mf.path);
|
|
233
|
-
const parts = mf.path.split('/');
|
|
234
|
-
// Add each ancestor directory by accumulating path segments.
|
|
235
|
-
parts.slice(0, -1).reduce((prefix, seg) => {
|
|
236
|
-
const ancestor = prefix ? `${prefix}/${seg}` : seg;
|
|
237
|
-
// eslint-disable-next-line functional/immutable-data
|
|
238
|
-
paths.add(ancestor);
|
|
239
|
-
return ancestor;
|
|
240
|
-
}, '');
|
|
241
|
-
}
|
|
242
|
-
return Array.from(paths);
|
|
243
|
-
}
|
|
244
|
-
/**
|
|
245
|
-
* Read the .npmdata marker from outputDir and return managed file metadata.
|
|
246
|
-
* Returns an empty array when the marker does not exist.
|
|
247
|
-
*/
|
|
248
|
-
function readManagedFiles(outputDir) {
|
|
249
|
-
const markerPath = node_path_1.default.join(outputDir, '.npmdata');
|
|
250
|
-
return node_fs_1.default.existsSync(markerPath) ? (0, utils_1.readCsvMarker)(markerPath) : [];
|
|
251
|
-
}
|
|
252
|
-
/**
|
|
253
|
-
* Collect all existing symlinks in `targetDir` whose resolved (or as-written)
|
|
254
|
-
* link target starts with `outputDir`. Returns a map of basename → resolved
|
|
255
|
-
* target path. Dead symlinks that still point into outputDir are included so
|
|
256
|
-
* that they can be cleaned up.
|
|
257
|
-
*/
|
|
258
|
-
function collectManagedSymlinks(targetDir, outputDir) {
|
|
259
|
-
const owned = new Map();
|
|
260
|
-
if (!node_fs_1.default.existsSync(targetDir))
|
|
261
|
-
return owned;
|
|
262
|
-
// Resolve outputDir through any intermediate symlinks (e.g. /var → /private/var on macOS)
|
|
263
|
-
// so prefix comparisons work correctly on all platforms.
|
|
264
|
-
// eslint-disable-next-line functional/no-let, functional/no-try-statements
|
|
265
|
-
let resolvedOutputDir = outputDir;
|
|
266
|
-
// eslint-disable-next-line functional/no-try-statements
|
|
267
|
-
try {
|
|
268
|
-
resolvedOutputDir = node_fs_1.default.realpathSync(outputDir);
|
|
269
|
-
}
|
|
270
|
-
catch {
|
|
271
|
-
// If outputDir does not exist, fall back to the raw path.
|
|
272
|
-
}
|
|
273
|
-
const normalizedOutput = resolvedOutputDir.endsWith(node_path_1.default.sep)
|
|
274
|
-
? resolvedOutputDir
|
|
275
|
-
: `${resolvedOutputDir}${node_path_1.default.sep}`;
|
|
276
|
-
for (const name of node_fs_1.default.readdirSync(targetDir)) {
|
|
277
|
-
const symlinkPath = node_path_1.default.join(targetDir, name);
|
|
278
|
-
const lstat = node_fs_1.default.lstatSync(symlinkPath);
|
|
279
|
-
if (lstat.isSymbolicLink()) {
|
|
280
|
-
// Try to resolve (handles live symlinks).
|
|
281
|
-
// eslint-disable-next-line functional/no-try-statements
|
|
282
|
-
try {
|
|
283
|
-
const resolved = node_fs_1.default.realpathSync(symlinkPath);
|
|
284
|
-
if (resolved === resolvedOutputDir || resolved.startsWith(normalizedOutput)) {
|
|
285
|
-
owned.set(name, resolved);
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
catch {
|
|
289
|
-
// Dead symlink – read the raw link target to see if it points into outputDir.
|
|
290
|
-
const rawTarget = node_fs_1.default.readlinkSync(symlinkPath);
|
|
291
|
-
const absTarget = node_path_1.default.resolve(targetDir, rawTarget);
|
|
292
|
-
const resolvedAbsTarget = absTarget; // raw path is enough for dead-link check
|
|
293
|
-
if (resolvedAbsTarget === outputDir ||
|
|
294
|
-
resolvedAbsTarget.startsWith(`${outputDir}${node_path_1.default.sep}`)) {
|
|
295
|
-
owned.set(name, absTarget);
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
return owned;
|
|
301
|
-
}
|
|
302
|
-
/**
|
|
303
|
-
* Determine the symlink action for a single target path.
|
|
304
|
-
* Returns 'create' when the path does not exist, 'update' when an out-of-date
|
|
305
|
-
* managed symlink exists, or 'skip' when nothing should be done.
|
|
306
|
-
*/
|
|
307
|
-
function symlinkAction(symlinkPath, sourcePath, isManaged) {
|
|
308
|
-
// eslint-disable-next-line functional/no-try-statements
|
|
309
|
-
try {
|
|
310
|
-
const lstat = node_fs_1.default.lstatSync(symlinkPath);
|
|
311
|
-
if (!lstat.isSymbolicLink())
|
|
312
|
-
return 'skip'; // Non-symlink – never clobber.
|
|
313
|
-
if (!isManaged)
|
|
314
|
-
return 'skip'; // Not managed by npmdata – leave alone.
|
|
315
|
-
// Managed symlink: only recreate if the target has drifted.
|
|
316
|
-
// eslint-disable-next-line functional/no-try-statements
|
|
317
|
-
try {
|
|
318
|
-
return node_fs_1.default.realpathSync(symlinkPath) === sourcePath ? 'skip' : 'update';
|
|
319
|
-
}
|
|
320
|
-
catch {
|
|
321
|
-
return 'update'; // Dead link – recreate.
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
catch {
|
|
325
|
-
return 'create'; // Path does not exist.
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
// ─── Post-extract operations ───────────────────────────────────────────────────
|
|
329
|
-
/**
|
|
330
|
-
* Apply the symlink configs from an extraction entry.
|
|
331
|
-
*
|
|
332
|
-
* For each config:
|
|
333
|
-
* 1. Expands the `source` glob inside the resolved `outputDir`.
|
|
334
|
-
* 2. Ensures the `target` directory exists.
|
|
335
|
-
* 3. Removes stale symlinks from the target dir that previously pointed into
|
|
336
|
-
* outputDir but are no longer matched by the current glob result.
|
|
337
|
-
* 4. Creates (or updates) symlinks for every matched file/directory.
|
|
338
|
-
*
|
|
339
|
-
* Only symlinks whose targets live inside outputDir are managed; any other
|
|
340
|
-
* symlinks in the target directory are left untouched.
|
|
341
|
-
*/
|
|
342
|
-
function applySymlinks(entry, cwd = process.cwd()) {
|
|
343
|
-
if (!entry.symlinks || entry.symlinks.length === 0)
|
|
344
|
-
return;
|
|
345
|
-
const outputDir = node_path_1.default.resolve(cwd, entry.outputDir);
|
|
346
|
-
const allManagedPaths = managedPathsWithAncestors(readManagedFiles(outputDir));
|
|
347
|
-
for (const cfg of entry.symlinks) {
|
|
348
|
-
const targetDir = node_path_1.default.resolve(cwd, cfg.target);
|
|
349
|
-
node_fs_1.default.mkdirSync(targetDir, { recursive: true });
|
|
350
|
-
// Build desired symlink map from managed paths (files + ancestor dirs) matching the source pattern.
|
|
351
|
-
const desired = new Map();
|
|
352
|
-
for (const relPath of allManagedPaths) {
|
|
353
|
-
if ((0, minimatch_1.minimatch)(relPath, cfg.source, { dot: true })) {
|
|
354
|
-
const absMatch = node_path_1.default.join(outputDir, relPath);
|
|
355
|
-
desired.set(node_path_1.default.basename(absMatch), absMatch);
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
// Remove stale managed symlinks that are no longer in the desired set.
|
|
359
|
-
const existing = collectManagedSymlinks(targetDir, outputDir);
|
|
360
|
-
for (const [basename] of existing) {
|
|
361
|
-
if (!desired.has(basename)) {
|
|
362
|
-
const symlinkPath = node_path_1.default.join(targetDir, basename);
|
|
363
|
-
node_fs_1.default.unlinkSync(symlinkPath);
|
|
364
|
-
if (!entry.silent) {
|
|
365
|
-
// eslint-disable-next-line no-console
|
|
366
|
-
console.log(`D\t${node_path_1.default.relative(cwd, symlinkPath)}`);
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
// Create or update symlinks.
|
|
371
|
-
for (const [basename, sourcePath] of desired) {
|
|
372
|
-
const symlinkPath = node_path_1.default.join(targetDir, basename);
|
|
373
|
-
const action = symlinkAction(symlinkPath, sourcePath, existing.has(basename));
|
|
374
|
-
if (action === 'update') {
|
|
375
|
-
node_fs_1.default.unlinkSync(symlinkPath);
|
|
376
|
-
node_fs_1.default.symlinkSync(sourcePath, symlinkPath);
|
|
377
|
-
if (!entry.silent) {
|
|
378
|
-
// eslint-disable-next-line no-console
|
|
379
|
-
console.log(`M\t${node_path_1.default.relative(cwd, symlinkPath)}`);
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
else if (action === 'create') {
|
|
383
|
-
node_fs_1.default.symlinkSync(sourcePath, symlinkPath);
|
|
384
|
-
if (!entry.silent) {
|
|
385
|
-
// eslint-disable-next-line no-console
|
|
386
|
-
console.log(`A\t${node_path_1.default.relative(cwd, symlinkPath)}`);
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
// 'skip' → do nothing
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
/**
|
|
394
|
-
* Apply the content-replacement configs from an extraction entry.
|
|
395
|
-
*
|
|
396
|
-
* For each config:
|
|
397
|
-
* 1. Expands the `files` glob inside `cwd`.
|
|
398
|
-
* 2. Reads each matched file.
|
|
399
|
-
* 3. Applies the regex replacement (global, multiline).
|
|
400
|
-
* 4. Writes the file back only when the content changed.
|
|
401
|
-
*/
|
|
402
|
-
function applyContentReplacements(entry, cwd = process.cwd()) {
|
|
403
|
-
if (!entry.contentReplacements || entry.contentReplacements.length === 0)
|
|
404
|
-
return;
|
|
405
|
-
const outputDir = node_path_1.default.resolve(cwd, entry.outputDir);
|
|
406
|
-
const managedFiles = readManagedFiles(outputDir);
|
|
407
|
-
for (const cfg of entry.contentReplacements) {
|
|
408
|
-
const regex = new RegExp(cfg.match, 'gm');
|
|
409
|
-
for (const mf of managedFiles) {
|
|
410
|
-
if ((0, minimatch_1.minimatch)(mf.path, cfg.files, { dot: true })) {
|
|
411
|
-
const filePath = node_path_1.default.join(outputDir, mf.path);
|
|
412
|
-
if (node_fs_1.default.existsSync(filePath)) {
|
|
413
|
-
const original = node_fs_1.default.readFileSync(filePath, 'utf8');
|
|
414
|
-
const updated = original.replace(regex, cfg.replace);
|
|
415
|
-
if (updated !== original) {
|
|
416
|
-
node_fs_1.default.writeFileSync(filePath, updated, 'utf8');
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
/**
|
|
424
|
-
* Check whether the content-replacement configs from an extraction entry are
|
|
425
|
-
* currently in effect in the workspace.
|
|
426
|
-
*
|
|
427
|
-
* Returns a list of file paths where the replacement pattern still matches
|
|
428
|
-
* (i.e. the replacement has not been applied or has drifted). An empty list
|
|
429
|
-
* means everything is in sync.
|
|
430
|
-
*/
|
|
431
|
-
function checkContentReplacements(entry, cwd = process.cwd()) {
|
|
432
|
-
if (!entry.contentReplacements || entry.contentReplacements.length === 0)
|
|
433
|
-
return [];
|
|
434
|
-
const outputDir = node_path_1.default.resolve(cwd, entry.outputDir);
|
|
435
|
-
const managedFiles = readManagedFiles(outputDir);
|
|
436
|
-
const outOfSync = [];
|
|
437
|
-
for (const cfg of entry.contentReplacements) {
|
|
438
|
-
const regex = new RegExp(cfg.match, 'gm');
|
|
439
|
-
for (const mf of managedFiles) {
|
|
440
|
-
if ((0, minimatch_1.minimatch)(mf.path, cfg.files, { dot: true })) {
|
|
441
|
-
const filePath = node_path_1.default.join(outputDir, mf.path);
|
|
442
|
-
if (node_fs_1.default.existsSync(filePath)) {
|
|
443
|
-
const content = node_fs_1.default.readFileSync(filePath, 'utf8');
|
|
444
|
-
// A file is out of sync when applying the replacement would change it.
|
|
445
|
-
const expected = content.replace(regex, cfg.replace);
|
|
446
|
-
if (expected !== content) {
|
|
447
|
-
// eslint-disable-next-line functional/immutable-data
|
|
448
|
-
outOfSync.push(filePath);
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
return outOfSync;
|
|
455
|
-
}
|
|
456
|
-
// ─── Action handlers ───────────────────────────────────────────────────────────
|
|
457
|
-
/**
|
|
458
|
-
* Run a shell command, capturing its stdout while inheriting stderr.
|
|
459
|
-
* The captured stdout is immediately written to process.stdout so the caller
|
|
460
|
-
* sees it in real time (well, after the child exits). Returns the full
|
|
461
|
-
* captured stdout string and the child's exit code. Non-zero exit codes do
|
|
462
|
-
* NOT throw; callers are responsible for checking exitCode.
|
|
463
|
-
*/
|
|
464
|
-
function runCommandCapture(command, cwd) {
|
|
465
|
-
// eslint-disable-next-line functional/no-try-statements
|
|
466
|
-
try {
|
|
467
|
-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
|
468
|
-
const stdout = (0, node_child_process_1.execSync)(command, {
|
|
469
|
-
encoding: 'utf8',
|
|
470
|
-
cwd,
|
|
471
|
-
stdio: ['inherit', 'pipe', 'inherit'],
|
|
472
|
-
}) ?? '';
|
|
473
|
-
process.stdout.write(stdout);
|
|
474
|
-
return { stdout, exitCode: 0 };
|
|
475
|
-
}
|
|
476
|
-
catch (error) {
|
|
477
|
-
const err = error;
|
|
478
|
-
const stdout = err.stdout ?? '';
|
|
479
|
-
process.stdout.write(stdout);
|
|
480
|
-
return { stdout, exitCode: err.status ?? 1 };
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
// eslint-disable-next-line complexity
|
|
484
|
-
function runExtract(entries, excludedEntries, cliPath, runCwd, dryRunFromArgv, silentFromArgv, verboseFromArgv, noGitignoreFromArgv, unmanagedFromArgv) {
|
|
485
|
-
if (verboseFromArgv) {
|
|
486
|
-
// eslint-disable-next-line no-console
|
|
487
|
-
console.log(`[verbose] extract: processing ${entries.length} entr${entries.length === 1 ? 'y' : 'ies'} (cwd: ${runCwd})`);
|
|
488
|
-
}
|
|
489
|
-
// eslint-disable-next-line functional/no-let
|
|
490
|
-
let totalAdded = 0;
|
|
491
|
-
// eslint-disable-next-line functional/no-let
|
|
492
|
-
let totalModified = 0;
|
|
493
|
-
// eslint-disable-next-line functional/no-let
|
|
494
|
-
let totalDeleted = 0;
|
|
495
|
-
// eslint-disable-next-line functional/no-let
|
|
496
|
-
let totalSkipped = 0;
|
|
497
|
-
// eslint-disable-next-line functional/no-let
|
|
498
|
-
let entryIndex = 0;
|
|
499
|
-
for (const entry of entries) {
|
|
500
|
-
const effectiveSilent = entry.silent || silentFromArgv;
|
|
501
|
-
if (entryIndex > 0 && !effectiveSilent) {
|
|
502
|
-
process.stdout.write('\n');
|
|
503
|
-
}
|
|
504
|
-
entryIndex += 1;
|
|
505
|
-
const effectiveEntry = {
|
|
506
|
-
...entry,
|
|
507
|
-
dryRun: entry.dryRun || dryRunFromArgv,
|
|
508
|
-
silent: effectiveSilent,
|
|
509
|
-
verbose: entry.verbose || verboseFromArgv,
|
|
510
|
-
...(noGitignoreFromArgv ? { gitignore: false } : {}),
|
|
511
|
-
...(unmanagedFromArgv ? { unmanaged: true } : {}),
|
|
512
|
-
};
|
|
513
|
-
if (verboseFromArgv) {
|
|
514
|
-
// eslint-disable-next-line no-console
|
|
515
|
-
console.log(`[verbose] extract: entry package=${entry.package} outputDir=${entry.outputDir}`);
|
|
516
|
-
}
|
|
517
|
-
node_fs_1.default.mkdirSync(node_path_1.default.resolve(runCwd, entry.outputDir), { recursive: true });
|
|
518
|
-
const command = buildExtractCommand(cliPath, effectiveEntry, runCwd);
|
|
519
|
-
if (verboseFromArgv) {
|
|
520
|
-
// eslint-disable-next-line no-console
|
|
521
|
-
console.log(`[verbose] extract: running command: ${command}`);
|
|
522
|
-
}
|
|
523
|
-
const { stdout: extractStdout, exitCode: extractExitCode } = runCommandCapture(command, runCwd);
|
|
524
|
-
if (extractExitCode !== 0) {
|
|
525
|
-
throw Object.assign(new Error('extract failed'), { status: extractExitCode });
|
|
526
|
-
}
|
|
527
|
-
const extractMatch = extractStdout.match(/Extraction complete:\s*(\d+) added,\s*(\d+) modified,\s*(\d+) deleted,\s*(\d+) skipped/);
|
|
528
|
-
if (extractMatch) {
|
|
529
|
-
totalAdded += Number.parseInt(extractMatch[1], 10);
|
|
530
|
-
totalModified += Number.parseInt(extractMatch[2], 10);
|
|
531
|
-
totalDeleted += Number.parseInt(extractMatch[3], 10);
|
|
532
|
-
totalSkipped += Number.parseInt(extractMatch[4], 10);
|
|
533
|
-
}
|
|
534
|
-
if (!effectiveEntry.dryRun) {
|
|
535
|
-
if (verboseFromArgv) {
|
|
536
|
-
// eslint-disable-next-line no-console
|
|
537
|
-
console.log(`[verbose] extract: applying symlinks for ${entry.package}`);
|
|
538
|
-
}
|
|
539
|
-
applySymlinks(effectiveEntry, runCwd);
|
|
540
|
-
if (verboseFromArgv) {
|
|
541
|
-
// eslint-disable-next-line no-console
|
|
542
|
-
console.log(`[verbose] extract: applying content replacements for ${entry.package}`);
|
|
543
|
-
}
|
|
544
|
-
applyContentReplacements(entry, runCwd);
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
// When a tag filter is active, purge managed files from excluded entries so that
|
|
548
|
-
// the output directory contains only files from the currently active tag group.
|
|
549
|
-
// Suppress the "Purging managed files..." banner for these implicit purges.
|
|
550
|
-
for (const entry of excludedEntries) {
|
|
551
|
-
if (verboseFromArgv) {
|
|
552
|
-
// eslint-disable-next-line no-console
|
|
553
|
-
console.log(`[verbose] extract: purging excluded entry ${entry.package} (tag filter active)`);
|
|
554
|
-
}
|
|
555
|
-
const effectiveEntry = {
|
|
556
|
-
...entry,
|
|
557
|
-
dryRun: entry.dryRun || dryRunFromArgv,
|
|
558
|
-
silent: true,
|
|
559
|
-
};
|
|
560
|
-
const command = buildPurgeCommand(cliPath, effectiveEntry, runCwd);
|
|
561
|
-
(0, node_child_process_1.execSync)(command, { stdio: 'inherit', cwd: runCwd });
|
|
562
|
-
}
|
|
563
|
-
if (!silentFromArgv && entries.length > 1) {
|
|
564
|
-
process.stdout.write(`\nTotal extracted: ${totalAdded} added, ${totalModified} modified, ${totalDeleted} deleted, ${totalSkipped} skipped${dryRunFromArgv ? ' (dry run)' : ''}\n`);
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
function runCheck(entries, cliPath, runCwd, verboseFromArgv) {
|
|
568
|
-
if (verboseFromArgv) {
|
|
569
|
-
// eslint-disable-next-line no-console
|
|
570
|
-
console.log(`[verbose] check: verifying ${entries.length} entr${entries.length === 1 ? 'y' : 'ies'} (cwd: ${runCwd})`);
|
|
571
|
-
}
|
|
572
|
-
// eslint-disable-next-line functional/no-let
|
|
573
|
-
let outOfSyncFiles = [];
|
|
574
|
-
// eslint-disable-next-line functional/no-let
|
|
575
|
-
let checkIndex = 0;
|
|
576
|
-
for (const entry of entries) {
|
|
577
|
-
if (checkIndex > 0) {
|
|
578
|
-
process.stdout.write('\n');
|
|
579
|
-
}
|
|
580
|
-
checkIndex += 1;
|
|
581
|
-
if (verboseFromArgv) {
|
|
582
|
-
// eslint-disable-next-line no-console
|
|
583
|
-
console.log(`[verbose] check: checking package=${entry.package} outputDir=${entry.outputDir}`);
|
|
584
|
-
}
|
|
585
|
-
const effectiveEntry = {
|
|
586
|
-
...entry,
|
|
587
|
-
verbose: entry.verbose || verboseFromArgv,
|
|
588
|
-
};
|
|
589
|
-
const command = buildCheckCommand(cliPath, effectiveEntry, runCwd);
|
|
590
|
-
if (verboseFromArgv) {
|
|
591
|
-
// eslint-disable-next-line no-console
|
|
592
|
-
console.log(`[verbose] check: running command: ${command}`);
|
|
593
|
-
}
|
|
594
|
-
const { exitCode: checkExitCode } = runCommandCapture(command, runCwd);
|
|
595
|
-
if (checkExitCode !== 0) {
|
|
596
|
-
throw Object.assign(new Error('check failed'), { status: checkExitCode });
|
|
597
|
-
}
|
|
598
|
-
if (verboseFromArgv) {
|
|
599
|
-
// eslint-disable-next-line no-console
|
|
600
|
-
console.log(`[verbose] check: checking content replacements for ${entry.package}`);
|
|
601
|
-
}
|
|
602
|
-
const entryOutOfSync = checkContentReplacements(entry, runCwd);
|
|
603
|
-
for (const f of entryOutOfSync) {
|
|
604
|
-
process.stderr.write(`content-replacement out of sync: ${f}\n`);
|
|
605
|
-
}
|
|
606
|
-
// eslint-disable-next-line functional/immutable-data
|
|
607
|
-
outOfSyncFiles = [...outOfSyncFiles, ...entryOutOfSync];
|
|
608
|
-
}
|
|
609
|
-
if (outOfSyncFiles.length > 0) {
|
|
610
|
-
throw Object.assign(new Error('content-replacements out of sync'), { status: 1 });
|
|
611
|
-
}
|
|
612
|
-
if (entries.length > 1) {
|
|
613
|
-
process.stdout.write(`\nTotal checked: ${entries.length} packages\n`);
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
function runList(allEntries, cliPath, runCwd, verboseFromArgv) {
|
|
617
|
-
// Collect unique resolved output dirs (tag filter not applied; list is informational).
|
|
618
|
-
const seenDirs = new Set();
|
|
619
|
-
if (verboseFromArgv) {
|
|
620
|
-
// eslint-disable-next-line no-console
|
|
621
|
-
console.log(`[verbose] list: listing managed files across ${allEntries.length} entr${allEntries.length === 1 ? 'y' : 'ies'} (cwd: ${runCwd})`);
|
|
622
|
-
}
|
|
623
|
-
for (const entry of allEntries) {
|
|
624
|
-
const resolvedDir = node_path_1.default.resolve(runCwd, entry.outputDir);
|
|
625
|
-
if (!seenDirs.has(resolvedDir)) {
|
|
626
|
-
seenDirs.add(resolvedDir);
|
|
627
|
-
if (verboseFromArgv) {
|
|
628
|
-
// eslint-disable-next-line no-console
|
|
629
|
-
console.log(`[verbose] list: scanning directory ${resolvedDir}`);
|
|
630
|
-
}
|
|
631
|
-
const command = buildListCommand(cliPath, entry.outputDir, runCwd, verboseFromArgv);
|
|
632
|
-
(0, node_child_process_1.execSync)(command, { stdio: 'inherit', cwd: runCwd });
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
// eslint-disable-next-line complexity
|
|
637
|
-
function runPurge(entries, cliPath, runCwd, dryRunFromArgv, silentFromArgv, verboseFromArgv) {
|
|
638
|
-
if (verboseFromArgv) {
|
|
639
|
-
// eslint-disable-next-line no-console
|
|
640
|
-
console.log(`[verbose] purge: processing ${entries.length} entr${entries.length === 1 ? 'y' : 'ies'} (cwd: ${runCwd})`);
|
|
641
|
-
}
|
|
642
|
-
// eslint-disable-next-line functional/no-let
|
|
643
|
-
let totalDeleted = 0;
|
|
644
|
-
// eslint-disable-next-line functional/no-let
|
|
645
|
-
let purgeIndex = 0;
|
|
646
|
-
for (const entry of entries) {
|
|
647
|
-
const effectiveSilent = entry.silent || silentFromArgv;
|
|
648
|
-
if (purgeIndex > 0 && !effectiveSilent) {
|
|
649
|
-
process.stdout.write('\n');
|
|
650
|
-
}
|
|
651
|
-
purgeIndex += 1;
|
|
652
|
-
const effectiveEntry = {
|
|
653
|
-
...entry,
|
|
654
|
-
dryRun: entry.dryRun || dryRunFromArgv,
|
|
655
|
-
silent: effectiveSilent,
|
|
656
|
-
verbose: entry.verbose || verboseFromArgv,
|
|
657
|
-
};
|
|
658
|
-
if (verboseFromArgv) {
|
|
659
|
-
// eslint-disable-next-line no-console
|
|
660
|
-
console.log(`[verbose] purge: entry package=${entry.package} outputDir=${entry.outputDir}`);
|
|
661
|
-
}
|
|
662
|
-
const command = buildPurgeCommand(cliPath, effectiveEntry, runCwd);
|
|
663
|
-
if (verboseFromArgv) {
|
|
664
|
-
// eslint-disable-next-line no-console
|
|
665
|
-
console.log(`[verbose] purge: running command: ${command}`);
|
|
666
|
-
}
|
|
667
|
-
const { stdout: purgeStdout, exitCode: purgeExitCode } = runCommandCapture(command, runCwd);
|
|
668
|
-
if (purgeExitCode !== 0) {
|
|
669
|
-
throw Object.assign(new Error('purge failed'), { status: purgeExitCode });
|
|
670
|
-
}
|
|
671
|
-
const purgeMatch = purgeStdout.match(/Purge complete:\s*(\d+) deleted/);
|
|
672
|
-
if (purgeMatch) {
|
|
673
|
-
totalDeleted += Number.parseInt(purgeMatch[1], 10);
|
|
674
|
-
}
|
|
675
|
-
if (!effectiveEntry.dryRun) {
|
|
676
|
-
if (verboseFromArgv) {
|
|
677
|
-
// eslint-disable-next-line no-console
|
|
678
|
-
console.log(`[verbose] purge: cleaning up symlinks for ${entry.package}`);
|
|
679
|
-
}
|
|
680
|
-
applySymlinks(effectiveEntry, runCwd);
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
if (!silentFromArgv && entries.length > 1) {
|
|
684
|
-
process.stdout.write(`\nTotal purged: ${totalDeleted}${dryRunFromArgv ? ' (dry run)' : ''}\n`);
|
|
685
|
-
}
|
|
686
|
-
}
|
|
687
|
-
/**
|
|
688
|
-
* Runs extraction for each entry defined in the publishable package's package.json "npmdata" array.
|
|
689
|
-
* Invokes the npmdata CLI once per entry so that all CLI output and error handling is preserved.
|
|
690
|
-
* Called from the minimal generated bin script with its own __dirname as binDir.
|
|
691
|
-
*
|
|
692
|
-
* Pass --tags <tag1,tag2> to limit processing to entries whose tags overlap with the given list.
|
|
693
|
-
*/
|
|
694
|
-
function run(binDir, argv = process.argv) {
|
|
695
|
-
const pkgJsonPath = node_path_1.default.join(binDir, '../package.json');
|
|
696
|
-
const pkg = JSON.parse(node_fs_1.default.readFileSync(pkgJsonPath).toString());
|
|
697
|
-
const allEntries = pkg.npmdata && pkg.npmdata.length > 0 ? pkg.npmdata : [{ package: pkg.name, outputDir: '.' }];
|
|
698
|
-
const userArgs = argv.slice(2);
|
|
699
|
-
if (userArgs.includes('--help')) {
|
|
700
|
-
printHelp(pkg.name, collectAllTags(allEntries));
|
|
701
|
-
return;
|
|
702
|
-
}
|
|
703
|
-
// Default to 'extract' when no action is provided or the first arg is a flag.
|
|
704
|
-
const action = userArgs.length === 0 || userArgs[0].startsWith('-') ? 'extract' : userArgs[0];
|
|
705
|
-
if (!['extract', 'check', 'list', 'purge'].includes(action)) {
|
|
706
|
-
process.stderr.write(`Error: unknown action '${action}'. Use 'extract', 'check', 'list', or 'purge'.\n\n`);
|
|
707
|
-
printHelp(pkg.name, collectAllTags(allEntries));
|
|
708
|
-
return;
|
|
709
|
-
}
|
|
710
|
-
const requestedTags = parseTagsFromArgv(argv);
|
|
711
|
-
const entries = filterEntriesByTags(allEntries, requestedTags);
|
|
712
|
-
const excludedEntries = requestedTags.length > 0 ? allEntries.filter((e) => !entries.includes(e)) : [];
|
|
713
|
-
const cliPath = require.resolve('npmdata/dist/main.js', { paths: [binDir] });
|
|
714
|
-
const parsedOutput = parseOutputFromArgv(userArgs);
|
|
715
|
-
const runCwd = parsedOutput ? node_path_1.default.resolve(process.cwd(), parsedOutput) : process.cwd();
|
|
716
|
-
const dryRunFromArgv = parseDryRunFromArgv(userArgs);
|
|
717
|
-
const silentFromArgv = parseSilentFromArgv(userArgs);
|
|
718
|
-
const verboseFromArgv = parseVerboseFromArgv(userArgs);
|
|
719
|
-
const noGitignoreFromArgv = parseNoGitignoreFromArgv(userArgs);
|
|
720
|
-
const unmanagedFromArgv = parseUnmanagedFromArgv(userArgs);
|
|
721
|
-
if (verboseFromArgv) {
|
|
722
|
-
// eslint-disable-next-line no-console
|
|
723
|
-
console.log(`[verbose] runner: action=${action} entries=${entries.length} cwd=${runCwd}`);
|
|
724
|
-
}
|
|
725
|
-
// eslint-disable-next-line functional/no-try-statements
|
|
726
|
-
try {
|
|
727
|
-
if (action === 'extract') {
|
|
728
|
-
runExtract(entries, excludedEntries, cliPath, runCwd, dryRunFromArgv, silentFromArgv, verboseFromArgv, noGitignoreFromArgv, unmanagedFromArgv);
|
|
729
|
-
}
|
|
730
|
-
else if (action === 'check') {
|
|
731
|
-
runCheck(entries, cliPath, runCwd, verboseFromArgv);
|
|
732
|
-
}
|
|
733
|
-
else if (action === 'list') {
|
|
734
|
-
runList(allEntries, cliPath, runCwd, verboseFromArgv);
|
|
735
|
-
}
|
|
736
|
-
else if (action === 'purge') {
|
|
737
|
-
runPurge(entries, cliPath, runCwd, dryRunFromArgv, silentFromArgv, verboseFromArgv);
|
|
738
|
-
}
|
|
739
|
-
}
|
|
740
|
-
catch (error) {
|
|
741
|
-
// The child process already printed the error via stdio:inherit.
|
|
742
|
-
// Exit with the child's exit code to suppress the Node.js stack trace.
|
|
743
|
-
const status = error?.status;
|
|
744
|
-
// eslint-disable-next-line unicorn/no-process-exit
|
|
745
|
-
process.exit(status ?? 1);
|
|
746
|
-
}
|
|
747
|
-
}
|
|
748
|
-
//# sourceMappingURL=runner.js.map
|