Files
wehub-resource-sync acf542cac6
Sync SKILL.md and rules / sync (push) Failing after 1s
chore: import upstream snapshot with attribution
2026-07-13 12:07:10 +08:00

59 lines
2.4 KiB
JavaScript

// Regression for #565: `irm .../install.ps1 | iex` crashed with
// "Cannot bind argument to parameter 'Path' because it is null."
//
// Two pipe-execution rules for install.ps1 (static checks — CI has no pwsh):
// 1. No top-level param() block. iex executes the file as a string, so a
// top-level param can never receive arguments and (depending on host)
// trips parsing. All logic lives in a function invoked at the bottom.
// 2. Script-path variables ($PSCommandPath / $MyInvocation.MyCommand.Path)
// are $null under iex — any use must be guarded, never passed straight
// into Split-Path (that was the #565 crash).
import { test } from 'node:test';
import assert from 'node:assert/strict';
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const HERE = path.dirname(fileURLToPath(import.meta.url));
const REPO_ROOT = path.resolve(HERE, '..', '..');
const PS1 = fs.readFileSync(path.join(REPO_ROOT, 'install.ps1'), 'utf8');
// Strip comment lines so doc mentions of param()/path vars don't false-positive.
const code = PS1.split('\n').filter(l => !/^\s*#/.test(l)).join('\n');
test('#565 install.ps1 has no top-level param block (everything inside a function)', () => {
const beforeFunction = code.slice(0, code.indexOf('function '));
assert.ok(code.includes('function '), 'install.ps1 must wrap its logic in a function for iex piping');
assert.ok(
!/param\s*\(/i.test(beforeFunction),
'install.ps1 must not declare a top-level param() — it cannot receive args under `irm | iex` (issue #565)',
);
});
test('#565 install.ps1 never uses $MyInvocation.MyCommand.Path (null under iex)', () => {
assert.ok(
!/\$MyInvocation\.MyCommand\.Path/i.test(code),
'install.ps1 must not rely on $MyInvocation.MyCommand.Path — it is $null when piped to iex (issue #565)',
);
});
test('#565 install.ps1 guards $PSCommandPath before Split-Path', () => {
if (/\$PSCommandPath/i.test(code)) {
assert.match(
code,
/if\s*\(\s*\$PSCommandPath\s*\)/i,
'$PSCommandPath is $null under `irm | iex` — it must be truthiness-guarded before use (issue #565)',
);
}
});
test('#565 install.ps1 invokes its function at the bottom (script still does something)', () => {
const lastLines = code.trim().split('\n').slice(-3).join('\n');
assert.match(
lastLines,
/Install-Caveman/,
'install.ps1 must actually invoke Install-Caveman after defining it',
);
});