super-productivity/tools/check-file.js
Kamil c385477f93
fix(tools): make checkFile work on Windows (#9132)
tools/check-file.js spawned npm/npx via execFileSync, which fails on Windows: npm and npx are .cmd shims there and Node refuses to spawn .cmd without a shell since the CVE-2024-27980 fix, so every `npm run checkFile <file>` died before running prettier or lint.

Invoke each tool's JS entry point with process.execPath instead - no npm/npx shims and no shell on any platform, so argv stays literal. Also fixes invocation from a subdirectory (npm run resolved package.json from cwd) and surfaces prettier diagnostics that the npm banner previously swallowed.
2026-07-21 11:58:44 +02:00

60 lines
2 KiB
JavaScript

#!/usr/bin/env node
// NOTE: the tools are invoked via their JS entry points with process.execPath
// instead of the npm/npx wrappers: on Windows those wrappers are .cmd shims,
// which Node refuses to spawn without a shell (EINVAL/ENOENT since the
// CVE-2024-27980 fix), and going through a shell instead would make the file
// path subject to shell expansion. execFileSync + node keeps argv literal on
// every platform.
const { execFileSync } = require('child_process');
const path = require('path');
const file = process.argv[2];
if (!file) {
console.error('❌ Please provide a file path');
process.exit(1);
}
// Get absolute path
const absolutePath = path.resolve(file);
const repoRoot = path.join(__dirname, '..');
// require.resolve('<pkg>/package.json') instead of deep paths: stylelint's
// "exports" map blocks resolving bin files directly.
const binOf = (pkg, rel) =>
path.join(path.dirname(require.resolve(`${pkg}/package.json`)), rel);
const run = (jsEntry, args) =>
execFileSync(process.execPath, [jsEntry, ...args], {
stdio: 'pipe',
encoding: 'utf8',
// ng lint needs to find angular.json regardless of the caller's directory
cwd: repoRoot,
});
try {
// Run prettier
console.log(`🎨 Formatting ${path.basename(file)}...`);
run(binOf('prettier', 'bin/prettier.cjs'), ['--write', absolutePath]);
// Run lint based on file type
console.log(`🔍 Linting ${path.basename(file)}...`);
if (file.endsWith('.scss')) {
// Use stylelint for SCSS files
run(binOf('stylelint', 'bin/stylelint.mjs'), [absolutePath]);
} else {
// Use ng lint for TypeScript/JavaScript files
run(binOf('@angular/cli', 'bin/ng.js'), [
'lint',
'--lint-file-patterns',
absolutePath,
]);
}
// If we get here, both commands succeeded
console.log(`${path.basename(file)} - All checks passed!`);
} catch (error) {
// If there's an error, show the full output
console.error('\n❌ Errors found:\n');
console.error(error.stdout || error.stderr || error.message);
process.exit(1);
}