fix: resolve build imports before linting
Resolve dist imports in runtime scripts against their TypeScript sources. Keep missing-module checks enabled and cover absent build output in the lint gate. Verified npm ci, prisma generate and full verify with dist absent at startup.
This commit is contained in:
@@ -60,6 +60,18 @@ export default defineConfig(
|
|||||||
files: ['**/*.mjs'],
|
files: ['**/*.mjs'],
|
||||||
extends: [node.configs['flat/recommended-module']],
|
extends: [node.configs['flat/recommended-module']],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
files: ['scripts/generate-openapi.cjs', 'test/fixtures/tbank-sync-crash.cjs', 'test/runtime-check.cjs'],
|
||||||
|
rules: {
|
||||||
|
// These scripts run after build; lint validates their source paths before dist exists.
|
||||||
|
'n/no-missing-require': ['error', {
|
||||||
|
resolverConfig: {
|
||||||
|
alias: { '../dist': import.meta.dirname, '../../dist': import.meta.dirname },
|
||||||
|
extensionAlias: { '.js': ['.ts', '.js'] },
|
||||||
|
},
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
files: ['**/*.ts'],
|
files: ['**/*.ts'],
|
||||||
extends: [tseslint.configs.recommendedTypeChecked, importX.flatConfigs.typescript],
|
extends: [tseslint.configs.recommendedTypeChecked, importX.flatConfigs.typescript],
|
||||||
|
|||||||
@@ -1,9 +1,38 @@
|
|||||||
const { ESLint } = require('eslint');
|
const { ESLint } = require('eslint');
|
||||||
const assert = require('node:assert/strict');
|
const assert = require('node:assert/strict');
|
||||||
|
const { mkdtempSync, rmSync, writeFileSync } = require('node:fs');
|
||||||
|
const { basename, join } = require('node:path');
|
||||||
const { test } = require('node:test');
|
const { test } = require('node:test');
|
||||||
|
|
||||||
const eslint = new ESLint();
|
const eslint = new ESLint();
|
||||||
|
|
||||||
|
test('runtime scripts resolve build imports against sources before dist exists', async () => {
|
||||||
|
const directory = mkdtempSync(join(process.cwd(), '.eslint-require-'));
|
||||||
|
try {
|
||||||
|
// eslint-disable-next-line security/detect-non-literal-fs-filename -- Test-owned temporary source with no compiled counterpart.
|
||||||
|
writeFileSync(join(directory, 'entry.ts'), 'export const value = true;');
|
||||||
|
for (const [filePath, prefix] of [
|
||||||
|
['scripts/generate-openapi.cjs', '../'],
|
||||||
|
['test/runtime-check.cjs', '../'],
|
||||||
|
['test/fixtures/tbank-sync-crash.cjs', '../../'],
|
||||||
|
]) {
|
||||||
|
const source = `${prefix}dist/${basename(directory)}/entry`;
|
||||||
|
const [result] = await eslint.lintText(
|
||||||
|
`require('${source}.js'); require('${source}'); require('node:fs'); require('eslint'); require('${source}-missing.js'); require('${prefix}missing-local.cjs'); require('wealthledger-missing-package');`,
|
||||||
|
{ filePath },
|
||||||
|
);
|
||||||
|
assert.equal(result.fatalErrorCount, 0, filePath);
|
||||||
|
const missing = result.messages.filter(({ ruleId }) => ruleId === 'n/no-missing-require');
|
||||||
|
assert.equal(missing.length, 3, filePath);
|
||||||
|
for (const target of [`${source}-missing.js`, `${prefix}missing-local.cjs`, 'wealthledger-missing-package']) {
|
||||||
|
assert.ok(missing.some(({ message }) => message.includes(`'${target}'`)), target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
rmSync(directory, { recursive: true, force: true });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Protect the quality gate's file scopes when configs or plugin versions change.
|
// Protect the quality gate's file scopes when configs or plugin versions change.
|
||||||
test('typed application code enforces async and unsafe-type checks', async () => {
|
test('typed application code enforces async and unsafe-type checks', async () => {
|
||||||
const [result] = await eslint.lintText(
|
const [result] = await eslint.lintText(
|
||||||
|
|||||||
Reference in New Issue
Block a user