@redue/cli 0.1.0-alpha.17 → 0.1.0-alpha.19
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/CHANGELOG.md +101 -0
- package/README.md +9 -5
- package/bin/redue.mjs +26 -9
- package/docs/user/agents.md +11 -0
- package/docs/user/configuration.md +6 -0
- package/docs/user/direct-typescript.md +62 -5
- package/docs/user/getting-started.md +7 -7
- package/docs/user/node-script.md +153 -0
- package/docs/user/pilot.md +6 -5
- package/docs/user/supported-projects.md +26 -15
- package/docs/user/tests-direct.md +13 -3
- package/package.json +2 -2
- package/src/agent-integration.mjs +16 -8
- package/src/claude-hook.mjs +119 -34
- package/src/cli.mjs +34 -16
- package/src/daemon.mjs +23 -8
- package/src/declared-plan.mjs +9 -6
- package/src/direct-typescript-probe.mjs +5 -3
- package/src/direct-typescript.mjs +58 -11
- package/src/glob.mjs +8 -0
- package/src/index.mjs +10 -4
- package/src/node-onboarding.mjs +117 -37
- package/src/node-script.mjs +362 -0
- package/src/npm-integrity.mjs +124 -0
- package/src/npmrc.mjs +16 -0
- package/src/plan-worker.mjs +4 -1
- package/src/pnpm-inputs.mjs +63 -35
- package/src/pnpm-shim-templates.json +180 -0
- package/src/pnpm-shims.mjs +54 -0
- package/src/pnpm-typecheck-probe.mjs +11 -6
- package/src/presentation.mjs +8 -1
- package/src/test-direct.mjs +103 -21
- package/src/test-recorder.cjs +101 -14
- package/src/typescript-input-facts.mjs +7 -7
- package/src/typescript-invocation.mjs +92 -0
- package/src/typescript-list.mjs +2 -2
- package/src/typescript-qualification.mjs +8 -9
- package/src/workspace-manifests.mjs +3 -4
package/src/pnpm-inputs.mjs
CHANGED
|
@@ -7,16 +7,18 @@ import fs from 'node:fs';
|
|
|
7
7
|
import path from 'node:path';
|
|
8
8
|
import {createRequire} from 'node:module';
|
|
9
9
|
import {execFileSync,spawnSync} from 'node:child_process';
|
|
10
|
-
import micromatch from './glob.mjs';
|
|
10
|
+
import micromatch,{patternMatcher} from './glob.mjs';
|
|
11
11
|
import YAML from 'yaml';
|
|
12
12
|
import {resolveLinks} from './installed-inputs.mjs';
|
|
13
13
|
import {withinPath as within,realObservedPath,samePath} from './path-identity.mjs';
|
|
14
14
|
import {timing} from './decision-profile.mjs';
|
|
15
|
+
import {npmrc} from './npmrc.mjs';
|
|
16
|
+
import {runConfig,tscRun,tscRuns} from './typescript-invocation.mjs';
|
|
15
17
|
|
|
16
18
|
const rel=(root,file)=>path.relative(root,file).split(path.sep).join('/');
|
|
17
19
|
const read=file=>JSON.parse(fs.readFileSync(file,'utf8'));
|
|
18
20
|
const exists=file=>{try{fs.lstatSync(file);return true;}catch{return false;}};
|
|
19
|
-
function yaml(file){
|
|
21
|
+
export function yaml(file){
|
|
20
22
|
const doc=YAML.parseDocument(fs.readFileSync(file,'utf8'),{uniqueKeys:true});
|
|
21
23
|
if(doc.errors.length)throw Error(`${path.basename(file)} cannot be interpreted safely`);
|
|
22
24
|
return doc.toJS()||{};
|
|
@@ -41,20 +43,6 @@ const refused=[['modulesDir','modules-dir'],['virtualStoreDir','virtual-store-di
|
|
|
41
43
|
['enableGlobalVirtualStore','enable-global-virtual-store'],['injectWorkspacePackages','inject-workspace-packages'],
|
|
42
44
|
['sharedWorkspaceLockfile','shared-workspace-lockfile'],['pnpmfile','pnpmfile'],['globalPnpmfile','global-pnpmfile'],
|
|
43
45
|
['configDependencies','config-dependencies']];
|
|
44
|
-
// .npmrc read as pnpm's ini parser reads it: a BOM is dropped, a bare key is
|
|
45
|
-
// true, quotes are removed, and "true"/"false" become booleans.
|
|
46
|
-
function npmrc(file){
|
|
47
|
-
const settings={};
|
|
48
|
-
if(!exists(file))return settings;
|
|
49
|
-
for(const line of fs.readFileSync(file,'utf8').replace(/^\uFEFF/,'').split(/\r?\n/)){
|
|
50
|
-
const trimmed=line.trim();if(!trimmed||/^[#;]/.test(trimmed))continue;
|
|
51
|
-
const at=trimmed.indexOf('='),key=(at<0?trimmed:trimmed.slice(0,at)).trim();
|
|
52
|
-
let value=at<0?true:trimmed.slice(at+1).trim();
|
|
53
|
-
if(typeof value==='string'&&/^(["']).*\1$/.test(value))value=value.slice(1,-1);
|
|
54
|
-
settings[key]=value==='true'?true:value==='false'?false:value;
|
|
55
|
-
}
|
|
56
|
-
return settings;
|
|
57
|
-
}
|
|
58
46
|
// Whether a refused setting is set: present at all, except that only
|
|
59
47
|
// sharedWorkspaceLockfile=false and injectWorkspacePackages=true move files.
|
|
60
48
|
const setting=(key,value)=>value!==undefined&&
|
|
@@ -204,16 +192,37 @@ function packageAt(root,requester,name){
|
|
|
204
192
|
}
|
|
205
193
|
return {physical:null,candidates};
|
|
206
194
|
}
|
|
207
|
-
|
|
208
|
-
|
|
195
|
+
// Files TypeScript may consume from its own include: each directory its
|
|
196
|
+
// include patterns watch for new files (TypeScript's own
|
|
197
|
+
// wildcardDirectories), and each file it lists. node_modules below them is
|
|
198
|
+
// left out, as TypeScript's wildcards leave it out; installed files a program
|
|
199
|
+
// reads are installed inputs. `exclude` entries stay inputs: an import can
|
|
200
|
+
// still reach an excluded file.
|
|
201
|
+
const sourceFiles='*.{ts,tsx,mts,cts,js,jsx,mjs,cjs,json}';
|
|
202
|
+
function sourcePatterns(root,parsed){
|
|
203
|
+
const patterns=new Set(),excluded=new Set();
|
|
204
|
+
for(const [folder,flags] of Object.entries(parsed.wildcardDirectories||{})){
|
|
205
|
+
// TypeScript 4 lowercases these keys on case-insensitive file systems;
|
|
206
|
+
// the native realpath gives the directory's own spelling.
|
|
207
|
+
let at;try{at=fs.realpathSync.native(folder);}catch{at=path.resolve(folder);}
|
|
208
|
+
if(!within(at,root))throw Error('TypeScript source membership escapes the checkout');
|
|
209
|
+
const prefix=rel(root,at)?rel(root,at)+'/':'';
|
|
210
|
+
if(flags&1){patterns.add(`${prefix}**/${sourceFiles}`);excluded.add(`!${prefix}**/node_modules/**`);}
|
|
211
|
+
else patterns.add(prefix+sourceFiles);
|
|
212
|
+
}
|
|
213
|
+
const included=patternMatcher([...patterns,...excluded]);
|
|
214
|
+
for(const file of parsed.fileNames.map(name=>path.resolve(name))){
|
|
215
|
+
if(!within(file,root))throw Error('TypeScript source membership escapes the checkout');
|
|
216
|
+
if(!included(rel(root,file)))patterns.add(rel(root,file));
|
|
217
|
+
}
|
|
218
|
+
return [...patterns,...excluded];
|
|
219
|
+
}
|
|
220
|
+
function parsedTypeScript(root,dir,ts,configName='tsconfig.json'){
|
|
221
|
+
const config=path.join(root,dir,configName),reads=new Set();
|
|
209
222
|
const host={...ts.sys,readFile(file){reads.add(path.resolve(file));return ts.sys.readFile(file);},
|
|
210
223
|
onUnRecoverableConfigFileDiagnostic(){}};
|
|
211
224
|
const parsed=ts.getParsedCommandLineOfConfigFile(config,{},host);
|
|
212
225
|
if(!parsed||parsed.errors?.length)throw Error('TypeScript configuration unavailable');
|
|
213
|
-
const raw=ts.readConfigFile(config,ts.sys.readFile);
|
|
214
|
-
if(raw.error||!Array.isArray(raw.config?.include)||raw.config.include.length!==1||
|
|
215
|
-
!/^src(?:$|\/)/.test(raw.config.include[0]))
|
|
216
|
-
throw Error('TypeScript source file membership is outside the supported src include');
|
|
217
226
|
if(parsed.options.plugins?.length||parsed.options.incremental||parsed.options.composite||
|
|
218
227
|
parsed.projectReferences?.length||parsed.options.paths||parsed.options.baseUrl||
|
|
219
228
|
parsed.options.rootDirs?.length||parsed.options.typeRoots?.length||
|
|
@@ -225,12 +234,13 @@ function parsedTypeScript(root,dir,ts){
|
|
|
225
234
|
throw Error('TypeScript module resolver is outside the supported Node contract');
|
|
226
235
|
for(const file of reads)if(!within(realObservedPath(file),root))
|
|
227
236
|
throw Error('TypeScript configuration escapes the checkout');
|
|
228
|
-
return {parsed,configs:[...reads].map(file=>rel(root,file)).sort()
|
|
237
|
+
return {parsed,configs:[...reads].map(file=>rel(root,file)).sort(),
|
|
238
|
+
sourcePatterns:sourcePatterns(root,parsed)};
|
|
229
239
|
}
|
|
230
|
-
function listedTypeScriptFiles(root,selected,tsc){
|
|
240
|
+
function listedTypeScriptFiles(root,selected,tsc,configName){
|
|
231
241
|
// --listFilesOnly resolves the compiler's effective module/file set but
|
|
232
242
|
// performs no typecheck and emits no project outputs.
|
|
233
|
-
const out=spawnSync(process.execPath,[tsc,'-p',
|
|
243
|
+
const out=spawnSync(process.execPath,[tsc,'-p',configName,'--listFilesOnly'],
|
|
234
244
|
{cwd:path.join(root,selected.dir),env:process.env,encoding:'utf8',
|
|
235
245
|
// The native NTFS public workspace takes 3-5 s to list ~770 inputs;
|
|
236
246
|
// 5 s sometimes expired despite bounded, progressing compiler work.
|
|
@@ -267,17 +277,23 @@ function sharedHardlinkIn(folder){
|
|
|
267
277
|
}
|
|
268
278
|
return false;
|
|
269
279
|
}
|
|
270
|
-
|
|
280
|
+
// `run`: the check's {script, part, args}, or a script name for its only run.
|
|
281
|
+
export function pnpmTypecheckInputs(root,workspace,run,{captureQueries=false}={}){
|
|
271
282
|
const totalStarted=performance.now();
|
|
272
283
|
root=realObservedPath(root);
|
|
273
284
|
const install=pnpmInstallInfo(root),members=pnpmWorkspacePackages(root,install.patterns);
|
|
274
285
|
const selected=workspace==='.'?{name:'.',dir:'.',manifest:'package.json',
|
|
275
286
|
pkg:read(path.join(root,'package.json'))}:members.get(workspace);
|
|
276
287
|
if(!selected)throw Error(`workspace ${workspace} is not declared`);
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
288
|
+
// A script name stands for its only run.
|
|
289
|
+
if(typeof run==='string'){const runs=tscRuns(selected.pkg.scripts?.[run]);run={script:run,args:runs?.length===1?runs[0].args:[]};}
|
|
290
|
+
const {run:own,issue}=tscRun(selected.pkg.scripts,run);
|
|
291
|
+
if(issue)throw Error(`typecheck must be standalone TypeScript runs: ${issue}`);
|
|
292
|
+
// `tsc -p .` without --noEmit predates the other forms.
|
|
293
|
+
if(!own.noEmit&&!['-p .','-p tsconfig.json'].includes(run.args.join(' ')))
|
|
294
|
+
throw Error('typecheck must pass --noEmit');
|
|
295
|
+
const configName=runConfig(path.join(root,selected.dir),run.args);
|
|
296
|
+
if(!configName)throw Error('TypeScript project is outside the package');
|
|
281
297
|
const selectedDir=path.join(root,selected.dir),lookup=createRequire(path.join(selectedDir,'package.json'));
|
|
282
298
|
let tsPackage;try{tsPackage=realObservedPath(lookup.resolve('typescript/package.json'));}
|
|
283
299
|
catch{throw Error('installed TypeScript compiler cannot be resolved');}
|
|
@@ -286,7 +302,8 @@ export function pnpmTypecheckInputs(root,workspace,script,{captureQueries=false}
|
|
|
286
302
|
const tsc=path.join(tsRoot,'bin','tsc');
|
|
287
303
|
if(!exists(tsc))throw Error('installed TypeScript executable is missing');
|
|
288
304
|
const configStarted=performance.now();
|
|
289
|
-
const {configs}=parsedTypeScript(root,selected.dir,ts);
|
|
305
|
+
const {configs,sourcePatterns:sources}=parsedTypeScript(root,selected.dir,ts,configName);
|
|
306
|
+
const isSource=patternMatcher(sources);
|
|
290
307
|
timing('pnpm.ts_config',configStarted,{configs:configs.length});
|
|
291
308
|
const closure=new Map(),installed=new Set(),generated=new Set(),
|
|
292
309
|
links=new Set(),candidates=new Set(),absences=[],instances=new Map();
|
|
@@ -336,12 +353,12 @@ export function pnpmTypecheckInputs(root,workspace,script,{captureQueries=false}
|
|
|
336
353
|
resolutionMs:Math.round(resolutionMs),workspaceLinks:links.size,
|
|
337
354
|
candidates:candidates.size});
|
|
338
355
|
const listingStarted=performance.now();
|
|
339
|
-
const captured=captureQueries?compilerFiles(tsRoot,path.join(root,selected.dir)):null;
|
|
340
|
-
const files=captured?captured.files.map(realObservedPath):listedTypeScriptFiles(root,selected,tsc);
|
|
356
|
+
const captured=captureQueries?compilerFiles(tsRoot,path.join(root,selected.dir),configName):null;
|
|
357
|
+
const files=captured?captured.files.map(realObservedPath):listedTypeScriptFiles(root,selected,tsc,configName);
|
|
341
358
|
timing('pnpm.ts_input_listing',listingStarted,{files:files.length});
|
|
342
359
|
const mappingStarted=performance.now();
|
|
343
360
|
for(const file of files){
|
|
344
|
-
if(
|
|
361
|
+
if(isSource(rel(root,file))||
|
|
345
362
|
[...closure.values()].some(member=>within(file,path.join(root,member.dir))))continue;
|
|
346
363
|
const packageRoot=installedPackageRoot(root,file);
|
|
347
364
|
if(!packageRoot)throw Error(`TypeScript consumes a file outside the observed pnpm contract: ${rel(root,file)}`);
|
|
@@ -352,6 +369,16 @@ export function pnpmTypecheckInputs(root,workspace,script,{captureQueries=false}
|
|
|
352
369
|
}
|
|
353
370
|
timing('pnpm.input_mapping',mappingStarted,{instances:instances.size,
|
|
354
371
|
installedPatterns:installed.size});
|
|
372
|
+
// A config extended from an installed package is an installed input too:
|
|
373
|
+
// source patterns leave node_modules out.
|
|
374
|
+
for(const config of configs){
|
|
375
|
+
const file=realObservedPath(path.join(root,config));
|
|
376
|
+
if(!within(file,path.join(root,'node_modules')))continue;
|
|
377
|
+
const packageRoot=installedPackageRoot(root,file);
|
|
378
|
+
if(!packageRoot)throw Error(`TypeScript configuration ${config} is outside an installed package`);
|
|
379
|
+
installed.add(`${rel(root,packageRoot)}/**`);
|
|
380
|
+
installed.add(`!${rel(root,packageRoot)}/node_modules/**`);
|
|
381
|
+
}
|
|
355
382
|
installed.add(`${rel(root,tsRoot)}/**`);
|
|
356
383
|
installed.add(`!${rel(root,tsRoot)}/node_modules/**`);
|
|
357
384
|
if(!instances.has(tsRoot))instances.set(tsRoot,{name:'typescript',physicalRoot:rel(root,tsRoot)});
|
|
@@ -360,11 +387,12 @@ export function pnpmTypecheckInputs(root,workspace,script,{captureQueries=false}
|
|
|
360
387
|
timing('pnpm.hardlink_inspection',sharedStarted,{instances:instances.size,
|
|
361
388
|
shared:shared.length});
|
|
362
389
|
const source=[...new Set([...install.configurationInputs,selected.manifest,
|
|
363
|
-
...configs
|
|
390
|
+
...configs,...sources,
|
|
364
391
|
...closure.values().map(member=>member.manifest),...generated])];
|
|
365
392
|
timing('pnpm.total_discovery',totalStarted,{instances:instances.size,
|
|
366
393
|
inputFiles:files.length});
|
|
367
394
|
return {install,workspace:selected,closure:[...closure.values()],source,
|
|
395
|
+
sourcePatterns:sources,args:run.args,
|
|
368
396
|
installed:[...installed],generated:[...generated],
|
|
369
397
|
// The read-only state probe consumes this same resolved compiler file set.
|
|
370
398
|
// It is deliberately omitted from the persisted user-facing input plan.
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema": 1,
|
|
3
|
+
"templates": [
|
|
4
|
+
{
|
|
5
|
+
"versions": [
|
|
6
|
+
"8.0.0",
|
|
7
|
+
"8.1.1",
|
|
8
|
+
"8.2.0",
|
|
9
|
+
"8.3.1",
|
|
10
|
+
"8.4.0",
|
|
11
|
+
"8.5.1",
|
|
12
|
+
"8.6.12",
|
|
13
|
+
"8.7.6",
|
|
14
|
+
"8.8.0",
|
|
15
|
+
"8.9.2",
|
|
16
|
+
"8.10.5",
|
|
17
|
+
"8.11.0",
|
|
18
|
+
"8.12.1",
|
|
19
|
+
"8.13.1",
|
|
20
|
+
"8.14.3",
|
|
21
|
+
"8.15.9",
|
|
22
|
+
"9.0.6",
|
|
23
|
+
"9.1.4",
|
|
24
|
+
"9.2.0",
|
|
25
|
+
"9.3.0",
|
|
26
|
+
"9.4.0",
|
|
27
|
+
"9.5.0",
|
|
28
|
+
"9.6.0",
|
|
29
|
+
"9.7.1",
|
|
30
|
+
"9.8.0",
|
|
31
|
+
"9.9.0",
|
|
32
|
+
"9.10.0",
|
|
33
|
+
"9.11.0",
|
|
34
|
+
"9.12.3",
|
|
35
|
+
"9.13.2",
|
|
36
|
+
"9.14.4",
|
|
37
|
+
"9.15.4",
|
|
38
|
+
"9.15.9",
|
|
39
|
+
"10.0.0",
|
|
40
|
+
"10.1.0",
|
|
41
|
+
"10.2.1",
|
|
42
|
+
"10.3.0",
|
|
43
|
+
"10.4.1",
|
|
44
|
+
"10.5.2",
|
|
45
|
+
"10.6.5",
|
|
46
|
+
"10.7.1",
|
|
47
|
+
"10.8.1",
|
|
48
|
+
"10.9.0"
|
|
49
|
+
],
|
|
50
|
+
"template": "#!/bin/sh\nbasedir=$(dirname \"$(echo \"$0\" | sed -e 's,\\\\,/,g')\")\n\ncase `uname` in\n *CYGWIN*) basedir=`cygpath -w \"$basedir\"`;;\nesac\n\nif [ -z \"$NODE_PATH\" ]; then\n export NODE_PATH=\"@@NODE_PATH@@\"\nelse\n export NODE_PATH=\"@@NODE_PATH@@:$NODE_PATH\"\nfi\nif [ -x \"$basedir/node\" ]; then\n exec \"$basedir/node\" \"$basedir/@@TARGET@@\" \"$@\"\nelse\n exec node \"$basedir/@@TARGET@@\" \"$@\"\nfi\n"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"versions": [
|
|
54
|
+
"10.10.0",
|
|
55
|
+
"10.11.1",
|
|
56
|
+
"10.12.4",
|
|
57
|
+
"10.13.1",
|
|
58
|
+
"10.14.0",
|
|
59
|
+
"10.15.1",
|
|
60
|
+
"10.16.1",
|
|
61
|
+
"10.17.1",
|
|
62
|
+
"10.18.3",
|
|
63
|
+
"10.19.0",
|
|
64
|
+
"10.20.0",
|
|
65
|
+
"10.21.0",
|
|
66
|
+
"10.22.0",
|
|
67
|
+
"10.23.0",
|
|
68
|
+
"10.24.0",
|
|
69
|
+
"10.25.0",
|
|
70
|
+
"10.26.2",
|
|
71
|
+
"10.27.0",
|
|
72
|
+
"10.28.2",
|
|
73
|
+
"10.29.3",
|
|
74
|
+
"10.30.3",
|
|
75
|
+
"10.31.0",
|
|
76
|
+
"10.32.1",
|
|
77
|
+
"10.33.2",
|
|
78
|
+
"10.33.4",
|
|
79
|
+
"10.34.7"
|
|
80
|
+
],
|
|
81
|
+
"template": "#!/bin/sh\nbasedir=$(dirname \"$(echo \"$0\" | sed -e 's,\\\\,/,g')\")\n\ncase `uname` in\n *CYGWIN*|*MINGW*|*MSYS*)\n if command -v cygpath > /dev/null 2>&1; then\n basedir=`cygpath -w \"$basedir\"`\n fi\n ;;\nesac\n\nif [ -z \"$NODE_PATH\" ]; then\n export NODE_PATH=\"@@NODE_PATH@@\"\nelse\n export NODE_PATH=\"@@NODE_PATH@@:$NODE_PATH\"\nfi\nif [ -x \"$basedir/node\" ]; then\n exec \"$basedir/node\" \"$basedir/@@TARGET@@\" \"$@\"\nelse\n exec node \"$basedir/@@TARGET@@\" \"$@\"\nfi\n"
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"versions": [
|
|
85
|
+
"11.0.9",
|
|
86
|
+
"11.1.1",
|
|
87
|
+
"11.1.3",
|
|
88
|
+
"11.2.2",
|
|
89
|
+
"11.3.0",
|
|
90
|
+
"11.4.0",
|
|
91
|
+
"11.5.3",
|
|
92
|
+
"11.6.0"
|
|
93
|
+
],
|
|
94
|
+
"template": "#!/bin/sh\nbasedir=$(dirname \"$(echo \"$0\" | sed -e 's,\\\\,/,g')\")\n\ncase `uname` in\n *CYGWIN*|*MINGW*|*MSYS*)\n if command -v cygpath > /dev/null 2>&1; then\n basedir=`cygpath -w \"$basedir\"`\n fi\n ;;\nesac\n\nif [ -z \"$NODE_PATH\" ]; then\n export NODE_PATH=\"@@NODE_PATH@@\"\nelse\n export NODE_PATH=\"@@NODE_PATH@@:$NODE_PATH\"\nfi\nif [ -x \"$basedir/node\" ]; then\n exec \"$basedir/node\" \"$basedir/@@TARGET@@\" \"$@\"\nelse\n exec node \"$basedir/@@TARGET@@\" \"$@\"\nfi\n# cmd-shim-target=@@COMMENT@@\n"
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"versions": [
|
|
98
|
+
"11.7.0",
|
|
99
|
+
"11.8.0",
|
|
100
|
+
"11.9.0",
|
|
101
|
+
"11.10.0",
|
|
102
|
+
"11.11.0",
|
|
103
|
+
"11.12.0",
|
|
104
|
+
"11.13.1",
|
|
105
|
+
"11.14.0",
|
|
106
|
+
"11.15.1",
|
|
107
|
+
"11.16.0",
|
|
108
|
+
"11.17.0",
|
|
109
|
+
"11.18.0",
|
|
110
|
+
"11.19.0",
|
|
111
|
+
"11.20.0"
|
|
112
|
+
],
|
|
113
|
+
"template": "#!/bin/sh\nbasedir=$(dirname \"$(echo \"$0\" | sed -e 's,\\\\,/,g')\")\nbasedir_win=\"$basedir\"\nexe=\"\"\nmsys=\"\"\n\ncase `uname -a` in\n *CYGWIN*|*MINGW*|*MSYS*)\n if command -v cygpath > /dev/null 2>&1; then\n basedir_win=`cygpath -w \"$basedir\"`\n fi\n exe=\".exe\"\n msys=\"true\"\n ;;\n *WSL2*)\n if command -v wslpath > /dev/null 2>&1; then\n basedir_win=\"$(wslpath -w \"$basedir\" 2> /dev/null)\"\n if [ $? -ne 0 ] || [ -z \"$basedir_win\" ]; then\n basedir_win=\"$basedir\"\n else\n exe=\".exe\"\n fi\n fi\n ;;\nesac\n\nif [ -z \"$NODE_PATH\" ]; then\n export NODE_PATH=\"@@NODE_PATH@@\"\nelse\n export NODE_PATH=\"@@NODE_PATH@@:$NODE_PATH\"\nfi\nif [ -n \"$exe\" ] && [ -x \"$basedir/node.exe\" ]; then\n exec \"$basedir/node.exe\" \"$basedir_win/@@TARGET@@\" \"$@\"\nelif [ -x \"$basedir/node\" ]; then\n exec \"$basedir/node\" \"$basedir/@@TARGET@@\" \"$@\"\nelif command -v node >/dev/null 2>&1; then\n exec node \"$basedir/@@TARGET@@\" \"$@\"\nelif [ -n \"$exe\" ] && command -v node.exe >/dev/null 2>&1; then\n exec node.exe \"$basedir_win/@@TARGET@@\" \"$@\"\nelse\n exec node \"$basedir/@@TARGET@@\" \"$@\"\nfi\n# cmd-shim-target=@@COMMENT@@\n"
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"versions": [
|
|
117
|
+
"11.21.0",
|
|
118
|
+
"11.22.0",
|
|
119
|
+
"11.23.0",
|
|
120
|
+
"11.24.0",
|
|
121
|
+
"11.25.0",
|
|
122
|
+
"11.26.0",
|
|
123
|
+
"12.0.0",
|
|
124
|
+
"12.1.0",
|
|
125
|
+
"12.2.1",
|
|
126
|
+
"12.3.4"
|
|
127
|
+
],
|
|
128
|
+
"template": "#!/bin/sh\n# Resolve $0 through symlinks so basedir is the shim's real directory.\n# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim.\nlink=\"$0\"\nhops=0\nwhile [ -L \"$link\" ] && [ \"$hops\" -lt 40 ]; do\n hops=$((hops+1))\n target=$(readlink \"$link\")\n case \"$target\" in\n /*) link=\"$target\" ;;\n *) link=\"$(dirname \"$link\")/$target\" ;;\n esac\ndone\nbasedir=$(dirname \"$(echo \"$link\" | sed -e 's,\\\\,/,g')\")\nbasedir_win=\"$basedir\"\nexe=\"\"\nmsys=\"\"\n\ncase `uname -a` in\n *CYGWIN*|*MINGW*|*MSYS*)\n if command -v cygpath > /dev/null 2>&1; then\n basedir_win=`cygpath -w \"$basedir\"`\n fi\n exe=\".exe\"\n msys=\"true\"\n ;;\n *WSL2*)\n if command -v wslpath > /dev/null 2>&1; then\n basedir_win=\"$(wslpath -w \"$basedir\" 2> /dev/null)\"\n if [ $? -ne 0 ] || [ -z \"$basedir_win\" ]; then\n basedir_win=\"$basedir\"\n else\n exe=\".exe\"\n fi\n fi\n ;;\nesac\n\nif [ -z \"$NODE_PATH\" ]; then\n export NODE_PATH=\"@@NODE_PATH@@\"\nelse\n export NODE_PATH=\"@@NODE_PATH@@:$NODE_PATH\"\nfi\nif [ -n \"$exe\" ] && [ -x \"$basedir/node.exe\" ]; then\n exec \"$basedir/node.exe\" \"$basedir_win/@@TARGET@@\" \"$@\"\nelif [ -x \"$basedir/node\" ]; then\n exec \"$basedir/node\" \"$basedir/@@TARGET@@\" \"$@\"\nelif command -v node >/dev/null 2>&1; then\n exec node \"$basedir/@@TARGET@@\" \"$@\"\nelif [ -n \"$exe\" ] && command -v node.exe >/dev/null 2>&1; then\n exec node.exe \"$basedir_win/@@TARGET@@\" \"$@\"\nelse\n exec node \"$basedir/@@TARGET@@\" \"$@\"\nfi\n# cmd-shim-target=@@COMMENT@@\n"
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
"versions": [
|
|
132
|
+
"11.27.1"
|
|
133
|
+
],
|
|
134
|
+
"template": "#!/bin/sh\n# Resolve $0 through symlinks so basedir is the shim's real directory.\n# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim.\n#\n# A shim runs with node_modules/.bin at the front of PATH, so readlink, sed,\n# uname, and printf go through `command -p`, which searches the system default\n# path instead. A dependency's bin cannot stand in for one of them and take over\n# the shim before it reaches its target. Directories come from `${link%/*}`,\n# which needs no helper at all.\nlink=\"$0\"\n# `${link%/*}` needs a separator to strip. A bare name came from a PATH lookup\n# and stands for a file in the current directory.\ncase \"$link\" in\n */*|*\\\\*) ;;\n *) link=\"./$link\" ;;\nesac\nhops=0\nwhile [ -L \"$link\" ] && [ \"$hops\" -lt 40 ]; do\n hops=$((hops+1))\n target=$(command -p readlink \"$link\")\n case \"$target\" in\n /*) link=\"$target\" ;;\n *) link=\"${link%/*}/$target\" ;;\n esac\ndone\nbasedir=$(command -p printf '%s\\n' \"$link\" | command -p sed -e 's,\\\\,/,g')\nbasedir=\"${basedir%/*}\"\nbasedir_win=\"$basedir\"\nexe=\"\"\nmsys=\"\"\n\ncase `command -p uname -a` in\n *CYGWIN*|*MINGW*|*MSYS*)\n if converted=$(command -p cygpath -w \"$basedir\" 2>/dev/null) && [ -n \"$converted\" ]; then\n basedir_win=\"$converted\"\n elif command -v cygpath > /dev/null 2>&1; then\n basedir_win=`cygpath -w \"$basedir\"`\n fi\n exe=\".exe\"\n msys=\"true\"\n ;;\n *WSL2*)\n if converted=$(command -p wslpath -w \"$basedir\" 2>/dev/null) && [ -n \"$converted\" ]; then\n basedir_win=\"$converted\"\n exe=\".exe\"\n elif command -v wslpath > /dev/null 2>&1; then\n basedir_win=\"$(wslpath -w \"$basedir\" 2> /dev/null)\"\n if [ $? -ne 0 ] || [ -z \"$basedir_win\" ]; then\n basedir_win=\"$basedir\"\n else\n exe=\".exe\"\n fi\n fi\n ;;\nesac\n\nif [ -z \"$NODE_PATH\" ]; then\n export NODE_PATH=\"@@NODE_PATH@@\"\nelse\n export NODE_PATH=\"@@NODE_PATH@@:$NODE_PATH\"\nfi\nif [ -n \"$exe\" ] && [ -x \"$basedir/node.exe\" ]; then\n exec \"$basedir/node.exe\" \"$basedir_win/@@TARGET@@\" \"$@\"\nelif [ -x \"$basedir/node\" ]; then\n exec \"$basedir/node\" \"$basedir/@@TARGET@@\" \"$@\"\nelif command -v node >/dev/null 2>&1; then\n exec node \"$basedir/@@TARGET@@\" \"$@\"\nelif [ -n \"$exe\" ] && command -v node.exe >/dev/null 2>&1; then\n exec node.exe \"$basedir_win/@@TARGET@@\" \"$@\"\nelse\n exec node \"$basedir/@@TARGET@@\" \"$@\"\nfi\n# cmd-shim-target=@@COMMENT@@\n"
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
"versions": [
|
|
138
|
+
"11.28.2"
|
|
139
|
+
],
|
|
140
|
+
"template": "#!/bin/sh\n# Resolve $0 through symlinks so basedir is the shim's real directory.\n# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim.\n#\n# A shim runs with node_modules/.bin at the front of PATH, so readlink, sed,\n# uname, and printf go through `command -p`, which searches the system default\n# path instead. A dependency's bin cannot stand in for one of them and take over\n# the shim before it reaches its target. Directories come from `${link%/*}`,\n# which needs no helper at all.\n#\n# Where no default path is compiled in, as on Nix, `command -p` searches PATH\n# instead, so the helpers run with node_modules and relative entries dropped from\n# PATH.\ncaller_path_set=${PATH+set}\ncaller_path=${PATH-}\nhelper_path=\nrest=$caller_path:\nwhile [ -n \"$rest\" ]; do\n dir=${rest%%:*}\n rest=${rest#*:}\n case \"$dir\" in\n */node_modules/*|*/node_modules) ;;\n /*) helper_path=${helper_path:+$helper_path:}$dir ;;\n esac\ndone\n# An empty PATH searches the current directory.\nPATH=${helper_path:-/}\nlink=\"$0\"\n# `${link%/*}` needs a separator to strip. A bare name came from a PATH lookup\n# and stands for a file in the current directory.\ncase \"$link\" in\n */*|*\\\\*) ;;\n *) link=\"./$link\" ;;\nesac\nhops=0\nwhile [ -L \"$link\" ] && [ \"$hops\" -lt 40 ]; do\n hops=$((hops+1))\n target=$(command -p readlink \"$link\")\n case \"$target\" in\n /*) link=\"$target\" ;;\n *) link=\"${link%/*}/$target\" ;;\n esac\ndone\nbasedir=$(command -p printf '%s\\n' \"$link\" | command -p sed -e 's,\\\\,/,g')\nbasedir=\"${basedir%/*}\"\nbasedir_abs=$(CDPATH= cd -P -- \"$basedir\" && pwd -P) || exit $?\nbasedir=\"$basedir_abs\"\nbasedir_win=\"$basedir\"\nexe=\"\"\nmsys=\"\"\n\ncase `command -p uname -a` in\n *CYGWIN*|*MINGW*|*MSYS*)\n if converted=$(command -p cygpath -w \"$basedir\" 2>/dev/null) && [ -n \"$converted\" ]; then\n basedir_win=\"$converted\"\n elif command -v cygpath > /dev/null 2>&1; then\n basedir_win=`cygpath -w \"$basedir\"`\n fi\n exe=\".exe\"\n msys=\"true\"\n ;;\n *WSL2*)\n if converted=$(command -p wslpath -w \"$basedir\" 2>/dev/null) && [ -n \"$converted\" ]; then\n basedir_win=\"$converted\"\n exe=\".exe\"\n elif command -v wslpath > /dev/null 2>&1; then\n basedir_win=\"$(wslpath -w \"$basedir\" 2> /dev/null)\"\n if [ $? -ne 0 ] || [ -z \"$basedir_win\" ]; then\n basedir_win=\"$basedir\"\n else\n exe=\".exe\"\n fi\n fi\n ;;\nesac\nif [ -n \"$caller_path_set\" ]; then PATH=$caller_path; else unset PATH; fi\n\nif [ -z \"$NODE_PATH\" ]; then\n export NODE_PATH=\"@@NODE_PATH@@\"\nelse\n export NODE_PATH=\"@@NODE_PATH@@:$NODE_PATH\"\nfi\nif [ -n \"$exe\" ] && [ -x \"$basedir/node.exe\" ]; then\n exec \"$basedir/node.exe\" \"$basedir_win/@@TARGET@@\" \"$@\"\nelif [ -x \"$basedir/node\" ]; then\n exec \"$basedir/node\" \"$basedir_abs/@@TARGET@@\" \"$@\"\nelif [ -n \"$msys\" ] && command -v node >/dev/null 2>&1; then\n exec node \"$basedir_win/@@TARGET@@\" \"$@\"\nelif command -v node >/dev/null 2>&1; then\n exec node \"$basedir_abs/@@TARGET@@\" \"$@\"\nelif [ -n \"$exe\" ] && command -v node.exe >/dev/null 2>&1; then\n exec node.exe \"$basedir_win/@@TARGET@@\" \"$@\"\nelse\n exec node \"$basedir_abs/@@TARGET@@\" \"$@\"\nfi\n# cmd-shim-target=@@COMMENT@@\n"
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
"versions": [
|
|
144
|
+
"11.28.6",
|
|
145
|
+
"12.8.2",
|
|
146
|
+
"12.9.1",
|
|
147
|
+
"12.10.1",
|
|
148
|
+
"12.11.2",
|
|
149
|
+
"12.12.1",
|
|
150
|
+
"12.13.0",
|
|
151
|
+
"12.14.0"
|
|
152
|
+
],
|
|
153
|
+
"template": "#!/bin/sh\n# Resolve $0 through symlinks so basedir is the shim's real directory.\n# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim.\n#\n# A shim runs with node_modules/.bin at the front of PATH, so readlink, sed,\n# uname, and printf go through `command -p`, which searches the system default\n# path instead. A dependency's bin cannot stand in for one of them and take over\n# the shim before it reaches its target. Directories come from `${link%/*}`,\n# which needs no helper at all.\n#\n# A helper the default path lacks, as in a Nix build sandbox, comes from PATH\n# instead, with node_modules and relative entries dropped from it.\ncaller_path_set=${PATH+set}\ncaller_path=${PATH-}\nhelper_path=\nrest=$caller_path:\nwhile [ -n \"$rest\" ]; do\n dir=${rest%%:*}\n rest=${rest#*:}\n case \"$dir\" in\n */node_modules/*|*/node_modules) ;;\n /*) helper_path=${helper_path:+$helper_path:}$dir ;;\n esac\ndone\n# An empty PATH searches the current directory.\nPATH=${helper_path:-/}\n# A helper comes from PATH only when the default path lacks it and PATH has it.\n# The bash 3.2 that macOS ships as sh answers `command -p -v` from PATH.\nrun_helper() {\n if command -p -v \"$1\" >/dev/null 2>&1 || ! command -v \"$1\" >/dev/null 2>&1; then command -p \"$@\"; else command \"$@\"; fi\n}\nlink=\"$0\"\n# `${link%/*}` needs a separator to strip. A bare name came from a PATH lookup\n# and stands for a file in the current directory.\ncase \"$link\" in\n */*|*\\\\*) ;;\n *) link=\"./$link\" ;;\nesac\nhops=0\nwhile [ -L \"$link\" ] && [ \"$hops\" -lt 40 ]; do\n hops=$((hops+1))\n target=$(run_helper readlink \"$link\")\n case \"$target\" in\n /*) link=\"$target\" ;;\n *) link=\"${link%/*}/$target\" ;;\n esac\ndone\nbasedir=$(run_helper printf '%s\\n' \"$link\" | run_helper sed -e 's,\\\\,/,g')\nbasedir=\"${basedir%/*}\"\nbasedir_abs=$(CDPATH= cd -P -- \"$basedir\" && pwd -P) || exit $?\nbasedir=\"$basedir_abs\"\nbasedir_win=\"$basedir\"\nexe=\"\"\nmsys=\"\"\n\ncase `run_helper uname -a` in\n *CYGWIN*|*MINGW*|*MSYS*)\n if converted=$(command -p cygpath -w \"$basedir\" 2>/dev/null) && [ -n \"$converted\" ]; then\n basedir_win=\"$converted\"\n elif command -v cygpath > /dev/null 2>&1; then\n basedir_win=`cygpath -w \"$basedir\"`\n fi\n exe=\".exe\"\n msys=\"true\"\n ;;\n *WSL2*)\n if converted=$(command -p wslpath -w \"$basedir\" 2>/dev/null) && [ -n \"$converted\" ]; then\n basedir_win=\"$converted\"\n exe=\".exe\"\n elif command -v wslpath > /dev/null 2>&1; then\n basedir_win=\"$(wslpath -w \"$basedir\" 2> /dev/null)\"\n if [ $? -ne 0 ] || [ -z \"$basedir_win\" ]; then\n basedir_win=\"$basedir\"\n else\n exe=\".exe\"\n fi\n fi\n ;;\nesac\nif [ -n \"$caller_path_set\" ]; then PATH=$caller_path; else unset PATH; fi\n\nif [ -z \"$NODE_PATH\" ]; then\n export NODE_PATH=\"@@NODE_PATH@@\"\nelse\n export NODE_PATH=\"@@NODE_PATH@@:$NODE_PATH\"\nfi\nif [ -n \"$exe\" ] && [ -x \"$basedir/node.exe\" ]; then\n exec \"$basedir/node.exe\" \"$basedir_win/@@TARGET@@\" \"$@\"\nelif [ -x \"$basedir/node\" ]; then\n exec \"$basedir/node\" \"$basedir_abs/@@TARGET@@\" \"$@\"\nelif [ -n \"$msys\" ] && command -v node >/dev/null 2>&1; then\n exec node \"$basedir_win/@@TARGET@@\" \"$@\"\nelif command -v node >/dev/null 2>&1; then\n exec node \"$basedir_abs/@@TARGET@@\" \"$@\"\nelif [ -n \"$exe\" ] && command -v node.exe >/dev/null 2>&1; then\n exec node.exe \"$basedir_win/@@TARGET@@\" \"$@\"\nelse\n exec node \"$basedir_abs/@@TARGET@@\" \"$@\"\nfi\n# cmd-shim-target=@@COMMENT@@\n"
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
"versions": [
|
|
157
|
+
"12.4.2"
|
|
158
|
+
],
|
|
159
|
+
"template": "#!/bin/sh\n# Resolve $0 through symlinks so basedir is the shim's real directory.\n# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim.\n#\n# A shim runs with node_modules/.bin at the front of PATH, so readlink, sed, and\n# uname go through `command -p`, which searches the system default path instead.\n# A dependency's bin cannot stand in for one of them and take over the shim\n# before it reaches its target. Directories come from `${link%/*}`, which needs\n# no helper at all.\nlink=\"$0\"\n# `${link%/*}` needs a separator to strip. A bare name came from a PATH lookup\n# and stands for a file in the current directory.\ncase \"$link\" in\n */*|*\\\\*) ;;\n *) link=\"./$link\" ;;\nesac\nhops=0\nwhile [ -L \"$link\" ] && [ \"$hops\" -lt 40 ]; do\n hops=$((hops+1))\n target=$(command -p readlink \"$link\")\n case \"$target\" in\n /*) link=\"$target\" ;;\n *) link=\"${link%/*}/$target\" ;;\n esac\ndone\nbasedir=$(echo \"$link\" | command -p sed -e 's,\\\\,/,g')\nbasedir=\"${basedir%/*}\"\nbasedir_win=\"$basedir\"\nexe=\"\"\nmsys=\"\"\n\ncase `command -p uname -a` in\n *CYGWIN*|*MINGW*|*MSYS*)\n if command -v cygpath > /dev/null 2>&1; then\n basedir_win=`cygpath -w \"$basedir\"`\n fi\n exe=\".exe\"\n msys=\"true\"\n ;;\n *WSL2*)\n if command -v wslpath > /dev/null 2>&1; then\n basedir_win=\"$(wslpath -w \"$basedir\" 2> /dev/null)\"\n if [ $? -ne 0 ] || [ -z \"$basedir_win\" ]; then\n basedir_win=\"$basedir\"\n else\n exe=\".exe\"\n fi\n fi\n ;;\nesac\n\nif [ -z \"$NODE_PATH\" ]; then\n export NODE_PATH=\"@@NODE_PATH@@\"\nelse\n export NODE_PATH=\"@@NODE_PATH@@:$NODE_PATH\"\nfi\nif [ -n \"$exe\" ] && [ -x \"$basedir/node.exe\" ]; then\n exec \"$basedir/node.exe\" \"$basedir_win/@@TARGET@@\" \"$@\"\nelif [ -x \"$basedir/node\" ]; then\n exec \"$basedir/node\" \"$basedir/@@TARGET@@\" \"$@\"\nelif command -v node >/dev/null 2>&1; then\n exec node \"$basedir/@@TARGET@@\" \"$@\"\nelif [ -n \"$exe\" ] && command -v node.exe >/dev/null 2>&1; then\n exec node.exe \"$basedir_win/@@TARGET@@\" \"$@\"\nelse\n exec node \"$basedir/@@TARGET@@\" \"$@\"\nfi\n# cmd-shim-target=@@COMMENT@@\n"
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
"versions": [
|
|
163
|
+
"12.5.1"
|
|
164
|
+
],
|
|
165
|
+
"template": "#!/bin/sh\n# Resolve $0 through symlinks so basedir is the shim's real directory.\n# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim.\n#\n# A shim runs with node_modules/.bin at the front of PATH, so readlink, sed,\n# uname, and printf go through `command -p`, which searches the system default\n# path instead. A dependency's bin cannot stand in for one of them and take over\n# the shim before it reaches its target. Directories come from `${link%/*}`,\n# which needs no helper at all.\nlink=\"$0\"\n# `${link%/*}` needs a separator to strip. A bare name came from a PATH lookup\n# and stands for a file in the current directory.\ncase \"$link\" in\n */*|*\\\\*) ;;\n *) link=\"./$link\" ;;\nesac\nhops=0\nwhile [ -L \"$link\" ] && [ \"$hops\" -lt 40 ]; do\n hops=$((hops+1))\n target=$(command -p readlink \"$link\")\n case \"$target\" in\n /*) link=\"$target\" ;;\n *) link=\"${link%/*}/$target\" ;;\n esac\ndone\nbasedir=$(command -p printf '%s\\n' \"$link\" | command -p sed -e 's,\\\\,/,g')\nbasedir=\"${basedir%/*}\"\nbasedir_win=\"$basedir\"\nexe=\"\"\nmsys=\"\"\n\ncase `command -p uname -a` in\n *CYGWIN*|*MINGW*|*MSYS*)\n if command -v cygpath > /dev/null 2>&1; then\n basedir_win=`cygpath -w \"$basedir\"`\n fi\n exe=\".exe\"\n msys=\"true\"\n ;;\n *WSL2*)\n if command -v wslpath > /dev/null 2>&1; then\n basedir_win=\"$(wslpath -w \"$basedir\" 2> /dev/null)\"\n if [ $? -ne 0 ] || [ -z \"$basedir_win\" ]; then\n basedir_win=\"$basedir\"\n else\n exe=\".exe\"\n fi\n fi\n ;;\nesac\n\nif [ -z \"$NODE_PATH\" ]; then\n export NODE_PATH=\"@@NODE_PATH@@\"\nelse\n export NODE_PATH=\"@@NODE_PATH@@:$NODE_PATH\"\nfi\nif [ -n \"$exe\" ] && [ -x \"$basedir/node.exe\" ]; then\n exec \"$basedir/node.exe\" \"$basedir_win/@@TARGET@@\" \"$@\"\nelif [ -x \"$basedir/node\" ]; then\n exec \"$basedir/node\" \"$basedir/@@TARGET@@\" \"$@\"\nelif command -v node >/dev/null 2>&1; then\n exec node \"$basedir/@@TARGET@@\" \"$@\"\nelif [ -n \"$exe\" ] && command -v node.exe >/dev/null 2>&1; then\n exec node.exe \"$basedir_win/@@TARGET@@\" \"$@\"\nelse\n exec node \"$basedir/@@TARGET@@\" \"$@\"\nfi\n# cmd-shim-target=@@COMMENT@@\n"
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
"versions": [
|
|
169
|
+
"12.6.0"
|
|
170
|
+
],
|
|
171
|
+
"template": "#!/bin/sh\n# Resolve $0 through symlinks so basedir is the shim's real directory.\n# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim.\n#\n# A shim runs with node_modules/.bin at the front of PATH, so readlink, sed,\n# uname, and printf go through `command -p`, which searches the system default\n# path instead. A dependency's bin cannot stand in for one of them and take over\n# the shim before it reaches its target. Directories come from `${link%/*}`,\n# which needs no helper at all.\nlink=\"$0\"\n# `${link%/*}` needs a separator to strip. A bare name came from a PATH lookup\n# and stands for a file in the current directory.\ncase \"$link\" in\n */*|*\\\\*) ;;\n *) link=\"./$link\" ;;\nesac\nhops=0\nwhile [ -L \"$link\" ] && [ \"$hops\" -lt 40 ]; do\n hops=$((hops+1))\n target=$(command -p readlink \"$link\")\n case \"$target\" in\n /*) link=\"$target\" ;;\n *) link=\"${link%/*}/$target\" ;;\n esac\ndone\nbasedir=$(command -p printf '%s\\n' \"$link\" | command -p sed -e 's,\\\\,/,g')\nbasedir=\"${basedir%/*}\"\nbasedir_win=\"$basedir\"\nexe=\"\"\nmsys=\"\"\n\ncase `command -p uname -a` in\n *CYGWIN*|*MINGW*|*MSYS*)\n if converted=$(command -p cygpath -w \"$basedir\" 2>/dev/null) && [ -n \"$converted\" ]; then\n basedir_win=\"$converted\"\n elif command -v cygpath > /dev/null 2>&1; then\n basedir_win=`cygpath -w \"$basedir\"`\n fi\n exe=\".exe\"\n msys=\"true\"\n ;;\n *WSL2*)\n if converted=$(command -p wslpath -w \"$basedir\" 2>/dev/null) && [ -n \"$converted\" ]; then\n basedir_win=\"$converted\"\n exe=\".exe\"\n elif command -v wslpath > /dev/null 2>&1; then\n basedir_win=\"$(wslpath -w \"$basedir\" 2> /dev/null)\"\n if [ $? -ne 0 ] || [ -z \"$basedir_win\" ]; then\n basedir_win=\"$basedir\"\n else\n exe=\".exe\"\n fi\n fi\n ;;\nesac\n\nbasedir_abs=$(CDPATH= cd -P -- \"$basedir\" && pwd -P) || exit $?\nif [ -z \"$NODE_PATH\" ]; then\n export NODE_PATH=\"@@NODE_PATH@@\"\nelse\n export NODE_PATH=\"@@NODE_PATH@@:$NODE_PATH\"\nfi\nif [ -n \"$exe\" ] && [ -x \"$basedir/node.exe\" ]; then\n exec \"$basedir/node.exe\" \"$basedir_win/@@TARGET@@\" \"$@\"\nelif [ -x \"$basedir/node\" ]; then\n exec \"$basedir/node\" \"$basedir_abs/@@TARGET@@\" \"$@\"\nelif command -v node >/dev/null 2>&1; then\n exec node \"$basedir_abs/@@TARGET@@\" \"$@\"\nelif [ -n \"$exe\" ] && command -v node.exe >/dev/null 2>&1; then\n exec node.exe \"$basedir_win/@@TARGET@@\" \"$@\"\nelse\n exec node \"$basedir_abs/@@TARGET@@\" \"$@\"\nfi\n# cmd-shim-target=@@COMMENT@@\n"
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
"versions": [
|
|
175
|
+
"12.7.0"
|
|
176
|
+
],
|
|
177
|
+
"template": "#!/bin/sh\n# Resolve $0 through symlinks so basedir is the shim's real directory.\n# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim.\n#\n# A shim runs with node_modules/.bin at the front of PATH, so readlink, sed,\n# uname, and printf go through `command -p`, which searches the system default\n# path instead. A dependency's bin cannot stand in for one of them and take over\n# the shim before it reaches its target. Directories come from `${link%/*}`,\n# which needs no helper at all.\n#\n# Where no default path is compiled in, as on Nix, `command -p` searches PATH\n# instead, so the helpers run with node_modules and relative entries dropped from\n# PATH.\ncaller_path_set=${PATH+set}\ncaller_path=${PATH-}\nhelper_path=\nrest=$caller_path:\nwhile [ -n \"$rest\" ]; do\n dir=${rest%%:*}\n rest=${rest#*:}\n case \"$dir\" in\n */node_modules/*|*/node_modules) ;;\n /*) helper_path=${helper_path:+$helper_path:}$dir ;;\n esac\ndone\n# An empty PATH searches the current directory.\nPATH=${helper_path:-/}\nlink=\"$0\"\n# `${link%/*}` needs a separator to strip. A bare name came from a PATH lookup\n# and stands for a file in the current directory.\ncase \"$link\" in\n */*|*\\\\*) ;;\n *) link=\"./$link\" ;;\nesac\nhops=0\nwhile [ -L \"$link\" ] && [ \"$hops\" -lt 40 ]; do\n hops=$((hops+1))\n target=$(command -p readlink \"$link\")\n case \"$target\" in\n /*) link=\"$target\" ;;\n *) link=\"${link%/*}/$target\" ;;\n esac\ndone\nbasedir=$(command -p printf '%s\\n' \"$link\" | command -p sed -e 's,\\\\,/,g')\nbasedir=\"${basedir%/*}\"\nbasedir_win=\"$basedir\"\nexe=\"\"\nmsys=\"\"\n\ncase `command -p uname -a` in\n *CYGWIN*|*MINGW*|*MSYS*)\n if converted=$(command -p cygpath -w \"$basedir\" 2>/dev/null) && [ -n \"$converted\" ]; then\n basedir_win=\"$converted\"\n elif command -v cygpath > /dev/null 2>&1; then\n basedir_win=`cygpath -w \"$basedir\"`\n fi\n exe=\".exe\"\n msys=\"true\"\n ;;\n *WSL2*)\n if converted=$(command -p wslpath -w \"$basedir\" 2>/dev/null) && [ -n \"$converted\" ]; then\n basedir_win=\"$converted\"\n exe=\".exe\"\n elif command -v wslpath > /dev/null 2>&1; then\n basedir_win=\"$(wslpath -w \"$basedir\" 2> /dev/null)\"\n if [ $? -ne 0 ] || [ -z \"$basedir_win\" ]; then\n basedir_win=\"$basedir\"\n else\n exe=\".exe\"\n fi\n fi\n ;;\nesac\nif [ -n \"$caller_path_set\" ]; then PATH=$caller_path; else unset PATH; fi\n\nbasedir_abs=$(CDPATH= cd -P -- \"$basedir\" && pwd -P) || exit $?\nif [ -z \"$NODE_PATH\" ]; then\n export NODE_PATH=\"@@NODE_PATH@@\"\nelse\n export NODE_PATH=\"@@NODE_PATH@@:$NODE_PATH\"\nfi\nif [ -n \"$exe\" ] && [ -x \"$basedir/node.exe\" ]; then\n exec \"$basedir/node.exe\" \"$basedir_win/@@TARGET@@\" \"$@\"\nelif [ -x \"$basedir/node\" ]; then\n exec \"$basedir/node\" \"$basedir_abs/@@TARGET@@\" \"$@\"\nelif command -v node >/dev/null 2>&1; then\n exec node \"$basedir_abs/@@TARGET@@\" \"$@\"\nelif [ -n \"$exe\" ] && command -v node.exe >/dev/null 2>&1; then\n exec node.exe \"$basedir_win/@@TARGET@@\" \"$@\"\nelse\n exec node \"$basedir_abs/@@TARGET@@\" \"$@\"\nfi\n# cmd-shim-target=@@COMMENT@@\n"
|
|
178
|
+
}
|
|
179
|
+
]
|
|
180
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// pnpm's launchers. On macOS and Linux, pnpm writes each node_modules/.bin
|
|
2
|
+
// entry as a `#!/bin/sh` script that finds its own directory (with sed,
|
|
3
|
+
// dirname, readlink, uname or printf, depending on the pnpm release), sets
|
|
4
|
+
// NODE_PATH and execs Node on the package's bin file. A launcher is trusted only
|
|
5
|
+
// when its text is one of the templates pnpm releases write
|
|
6
|
+
// (pnpm-shim-templates.json, built by eval/pnpm-shim-templates.mjs), with only
|
|
7
|
+
// the NODE_PATH value, the bin file and the trailing target comment filled in.
|
|
8
|
+
import fs from 'node:fs';
|
|
9
|
+
import path from 'node:path';
|
|
10
|
+
|
|
11
|
+
const templates=JSON.parse(fs.readFileSync(new URL('pnpm-shim-templates.json',import.meta.url),'utf8')).templates;
|
|
12
|
+
const known=new Set(templates.map(row=>row.template));
|
|
13
|
+
// A value with no quote, expansion, escape or line break: it stays literal in
|
|
14
|
+
// the shell.
|
|
15
|
+
const literal=/^[^"$`\\\n]*$/;
|
|
16
|
+
|
|
17
|
+
// The launcher's text as a template, with the values it fills in, or null
|
|
18
|
+
// when it does not have pnpm's form.
|
|
19
|
+
export function shimTemplate(text){
|
|
20
|
+
if(typeof text!=='string'||!text.startsWith('#!/bin/sh\n'))return null;
|
|
21
|
+
let template=text,nodePath=null;
|
|
22
|
+
// NODE_PATH, set alone or in front of the caller's.
|
|
23
|
+
const alone=/\n export NODE_PATH="([^"\n]*)"\n/.exec(text);
|
|
24
|
+
if(alone){
|
|
25
|
+
nodePath=alone[1];
|
|
26
|
+
// Each entry is literal, or relative to the launcher's own directory
|
|
27
|
+
// ($basedir_abs, which pnpm 12.6 and later write).
|
|
28
|
+
if(!nodePath.split(':').every(entry=>literal.test(entry.replace(/^\$basedir(?:_abs)?\//,'')))||
|
|
29
|
+
!text.includes(`\n export NODE_PATH="${nodePath}:$NODE_PATH"\n`))return null;
|
|
30
|
+
template=template.split(`\n export NODE_PATH="${nodePath}:$NODE_PATH"\n`).join('\n export NODE_PATH="@@NODE_PATH@@:$NODE_PATH"\n')
|
|
31
|
+
.split(`\n export NODE_PATH="${nodePath}"\n`).join('\n export NODE_PATH="@@NODE_PATH@@"\n');
|
|
32
|
+
}
|
|
33
|
+
// The bin file, relative to the launcher's directory, after $basedir,
|
|
34
|
+
// $basedir_abs or $basedir_win; `node` and `node.exe` there are Node itself.
|
|
35
|
+
const targets=new Set([...template.matchAll(/"\$basedir(?:_abs|_win)?\/([^"\n]+)"/g)].map(match=>match[1])
|
|
36
|
+
.filter(value=>value!=='node'&&value!=='node.exe'));
|
|
37
|
+
if(targets.size!==1)return null;
|
|
38
|
+
const [target]=targets;
|
|
39
|
+
if(!literal.test(target))return null;
|
|
40
|
+
for(const prefix of ['$basedir','$basedir_abs','$basedir_win'])
|
|
41
|
+
template=template.split(`"${prefix}/${target}"`).join(`"${prefix}/@@TARGET@@"`);
|
|
42
|
+
// pnpm 11 and later end with a comment naming the target.
|
|
43
|
+
template=template.replace(/\n# cmd-shim-target=[^\n]*\n?$/,'\n# cmd-shim-target=@@COMMENT@@\n');
|
|
44
|
+
return {template,nodePath,target};
|
|
45
|
+
}
|
|
46
|
+
// The bin file a pnpm launcher runs with Node, as an absolute path, or null
|
|
47
|
+
// when `file` is not a launcher pnpm writes.
|
|
48
|
+
export function pnpmShimTarget(file,text=null){
|
|
49
|
+
try{
|
|
50
|
+
text??=fs.readFileSync(file,'utf8');
|
|
51
|
+
const shim=shimTemplate(text);
|
|
52
|
+
return shim&&known.has(shim.template)?path.resolve(path.dirname(file),shim.target):null;
|
|
53
|
+
}catch{return null;}
|
|
54
|
+
}
|
|
@@ -7,14 +7,17 @@ import fs from 'node:fs';
|
|
|
7
7
|
import path from 'node:path';
|
|
8
8
|
import {createHash} from 'node:crypto';
|
|
9
9
|
import {pnpmTypecheckInputs} from './pnpm-inputs.mjs';
|
|
10
|
+
import {patternMatcher} from './glob.mjs';
|
|
10
11
|
import {withinPath as within,realObservedPath} from './path-identity.mjs';
|
|
12
|
+
import {runFromArgv} from './typescript-invocation.mjs';
|
|
11
13
|
|
|
12
|
-
const [rootArg,workspace
|
|
14
|
+
const [rootArg,workspace,...rest]=process.argv.slice(2).filter(value=>!value.startsWith('--redue-'));
|
|
13
15
|
const hash=value=>createHash('sha256').update(value).digest('hex');
|
|
14
16
|
const digest=file=>hash(fs.readFileSync(file));
|
|
15
17
|
const fail=code=>{throw Object.assign(Error(code),{code});};
|
|
16
18
|
try{
|
|
17
|
-
if(!rootArg||!workspace
|
|
19
|
+
if(!rootArg||!workspace)fail('probe-arguments');
|
|
20
|
+
const run=runFromArgv(rest);
|
|
18
21
|
const root=realObservedPath(rootArg);
|
|
19
22
|
if(process.env.NODE_OPTIONS||process.env.NODE_PATH||process.env.BASH_ENV||
|
|
20
23
|
process.env.ENV||Object.entries(process.env).some(([key,value])=>{
|
|
@@ -24,23 +27,25 @@ try{
|
|
|
24
27
|
return /^(PNPM_|COREPACK_|npm_config_|DYLD_|TSGO_)/i.test(key);
|
|
25
28
|
}))
|
|
26
29
|
fail('pnpm-execution-environment-unsupported');
|
|
27
|
-
const contextHash=hash(JSON.stringify([root,workspace,
|
|
30
|
+
const contextHash=hash(JSON.stringify([root,workspace,run,process.version]));
|
|
28
31
|
if(contextOnly(contextHash))process.exit(0);
|
|
29
|
-
const contract=pnpmTypecheckInputs(root,workspace,
|
|
32
|
+
const contract=pnpmTypecheckInputs(root,workspace,run,{captureQueries:process.argv.includes('--redue-checkpoint')});
|
|
30
33
|
if(contract.limitations.length)fail('pnpm-input-coverage-unavailable');
|
|
31
34
|
const selected=path.join(root,contract.workspace.dir),tsc=contract.tsc;
|
|
32
35
|
const inputs=contract.listedFiles;
|
|
33
36
|
if(!inputs.length)fail('typescript-input-list-unavailable');
|
|
34
|
-
const inputRoots=[
|
|
37
|
+
const inputRoots=[...contract.generated.map(pattern=>
|
|
35
38
|
path.join(root,pattern.slice(0,-3))),...contract.installed.filter(p=>!p.startsWith('!'))
|
|
36
39
|
.map(pattern=>path.join(root,pattern.slice(0,-3)))];
|
|
40
|
+
const isSource=patternMatcher(contract.sourcePatterns);
|
|
37
41
|
for(const file of inputs)if(!within(file,root)||
|
|
42
|
+
!isSource(path.relative(root,file).split(path.sep).join('/'))&&
|
|
38
43
|
!inputRoots.some(boundary=>within(file,boundary)))
|
|
39
44
|
fail('typescript-input-outside-pnpm-contract');
|
|
40
45
|
const files=[...new Set(inputs)].sort().map(file=>
|
|
41
46
|
[hash(path.relative(root,file)),digest(file)]);
|
|
42
47
|
const configs=contract.configs.map(file=>[hash(file),digest(path.join(root,file))]);
|
|
43
|
-
probeResult(hash(JSON.stringify({schema:1,workspace,
|
|
48
|
+
probeResult(hash(JSON.stringify({schema:1,workspace,run,
|
|
44
49
|
files,configs,node:process.version,tsc:digest(tsc),
|
|
45
50
|
packageManager:contract.install.version,linker:contract.install.linker})),contextHash,contract.discoveryQueries);
|
|
46
51
|
}catch(e){console.error(`VSTATE_REASON:${e.code&&/^[a-z-]+$/.test(e.code)?e.code:
|
package/src/presentation.mjs
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
// Presentation consumes evidence; it never grants applicability.
|
|
2
|
+
// The recipe that made a receipt, by the qualification it names.
|
|
3
|
+
const recipes={'npm-typescript-direct-v1':'direct TypeScript recipe','npm-tests-direct-v1':'direct test recipe',
|
|
4
|
+
'node-script-v1':'general recipe','pnpm-tsc-v1':'pnpm TypeScript recipe','yarn-workspace-tsc-v1':'Yarn workspace TypeScript recipe',
|
|
5
|
+
'typescript-noemit-v1':'npm TypeScript recipe'};
|
|
6
|
+
export const recipeLabel=recipe=>recipes[recipe]??null;
|
|
2
7
|
export function checkLabel(row) {
|
|
3
8
|
return row.result==='FAIL'?'FAILED':row.freshness;
|
|
4
9
|
}
|
|
@@ -21,7 +26,8 @@ export function renderStatus(value,{short=false}={}) {
|
|
|
21
26
|
const label=checkLabel(row),symbol=label==='CURRENT'&&row.result==='PASS'?'✓':label==='FAILED'?'✗':'?';
|
|
22
27
|
const mark=label==='STALE'?'⚠':symbol;
|
|
23
28
|
const historical=row.result?` / ${row.result}`:'';
|
|
24
|
-
|
|
29
|
+
const recipe=label==='CURRENT'?recipeLabel(row.recipe):null;
|
|
30
|
+
lines.push(`${mark} ${row.name} ${label}${historical}${recipe?` (${recipe})`:''}`);
|
|
25
31
|
if(label!=='CURRENT')lines.push(` ${row.result==='FAIL'?`Historical failure; applicability ${row.freshness}. `:''}${explanation(row)}`);
|
|
26
32
|
}
|
|
27
33
|
if(!lines.length)lines.push('UNVERIFIED — observation is initializing; no check state is available yet.');
|
|
@@ -34,6 +40,7 @@ export function renderExplain(value,name) {
|
|
|
34
40
|
const lines=[`${row.name}: ${checkLabel(row)}${row.result?` / ${row.result}`:''}`];
|
|
35
41
|
if(row.result==='FAIL')lines.push(`Historical failure; applicability: ${row.freshness}.`);
|
|
36
42
|
if(row.verification_recipe==='npm-direct-typescript@1')lines.push('Recorded recipe: direct local TypeScript compiler; npm and lifecycle scripts were not executed.');
|
|
43
|
+
else if(recipeLabel(row.recipe))lines.push(`Recorded recipe: ${recipeLabel(row.recipe)}.`);
|
|
37
44
|
lines.push(explanation(row));
|
|
38
45
|
if(row.changed_inputs?.length)lines.push('Relevant inputs changed:',...row.changed_inputs.map(file=>` ${file}`));
|
|
39
46
|
if(row.freshness==='STALE')lines.push(`Due again when verification is needed: redue run ${JSON.stringify(row.name)}`);
|