qwen-code/scripts/tests/no-core-root-barrel-import.test.js
易良 10c647f320
refactor(core): remove root barrel self-imports and enforce the boundary (#9635)
* refactor(core): remove root barrel self-imports

* fix(core): activate root barrel boundary rule

* test(core): cover root barrel export visitors

* fix(core): remove unused boundary constant

* fix(core): correct misplaced imports flagged by root barrel rule

coreToolScheduler: ToolExecutionStatus is exported from core/turn.ts, not
tools/tools.ts; was also duplicated in the tools import block.
nonInteractiveToolExecutor: RuntimeContentGeneratorView is exported from
agents/runtime/agent-context.ts, not core/contentGenerator.ts.

Both were surfaced by the new no-core-root-barrel-import rule in #9152.

* fix(core): complete telemetry mock and harden barrel rule edge cases

extensionManager.test: the ../telemetry/loggers.js mock was missing
logExtensionInstallEvent, logExtensionUninstall, and logExtensionDisable,
which the source now imports from that path after the barrel cleanup.
This caused 53 test failures.

no-core-root-barrel-import.js: added package-specifier detection
(@qwen-code/qwen-code-core), template-literal dynamic import support,
depth-0 ./index.js handling, and __tests__ exemption parity with the
test-file check. Added trailing newline.

Tests: added coverage for all new edge cases in both rule test files.

Refs #9152

* fix(core): close package-level barrel gap and coverage holes

The barrel rule blocked only specifiers resolving to the src-level
index.{js,ts}; the package-level barrel (packages/core/index.ts, which
re-exports the src barrel) remained reachable via one extra ../ hop.
Match ../index.{js,ts} so core production files cannot re-import the
root barrel through that path.

Also: hoist the duplicated src-root marker to a single constant, reword
the rule message so it no longer hardcodes ../index.js, pin the .ts
spelling branch, fix the vacuous fixtures-exemption case, and add a
cross-directory flat-config fixture so a narrowed files glob fails the
integration test.

Refs #9152

* fix(core): flag barrel subpaths and inline type imports in the root barrel rule

* fix(core): harden no-core-root-barrel-import rule

Anchor the source-root marker on its last occurrence so nested checkouts resolve correctly, reject relative imports of the compiled dist barrel, and treat .spec files as tests. Adds regression coverage for each.
2026-08-22 13:42:10 +00:00

138 lines
4.2 KiB
JavaScript

import { describe, expect, it } from 'vitest';
import { Linter } from 'eslint';
import rule from '../../eslint-rules/no-core-root-barrel-import.js';
function runRule(code, filename) {
const linter = new Linter({ configType: 'eslintrc' });
linter.defineRule('architecture/no-core-root-barrel-import', rule);
return linter.verify(
code,
{
parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
rules: { 'architecture/no-core-root-barrel-import': 'error' },
},
{ filename },
);
}
describe('no-core-root-barrel-import', () => {
it.each([
['packages/core/src/core/client.ts', '../index.js'],
['packages/core/src/a/b/c/module.ts', '../../../index.js'],
// depth-0: src-root module importing the barrel from the same directory
['packages/core/src/index.ts', './index.js'],
// package-level barrel (packages/core/index.js) via an extra directory hop
['packages/core/src/core/client.ts', '../../index.js'],
// .ts spelling of the src barrel
['packages/core/src/core/client.ts', '../index.ts'],
// nested checkout: a parent directory also contains the marker, so the
// rule must anchor on the LAST occurrence to derive the correct source root
[
'/tmp/packages/core/src/checkout/repo/packages/core/src/core/client.ts',
'../index.js',
],
// exports-map subpaths that reach the same root barrel
[
'packages/core/src/core/client.ts',
'@qwen-code/qwen-code-core/src/index.js',
],
[
'packages/core/src/core/client.ts',
'@qwen-code/qwen-code-core/dist/index.js',
],
// .ts spelling of the exports-map src subpath
[
'packages/core/src/core/client.ts',
'@qwen-code/qwen-code-core/src/index.ts',
],
// relative import of the compiled barrel
['packages/core/src/core/client.ts', '../../dist/index.js'],
])('rejects root barrel imports from %s', (filename, importedPath) => {
expect(
runRule(`import value from '${importedPath}';`, filename),
).toHaveLength(1);
});
it('rejects export and dynamic root barrel sources', () => {
expect(
runRule(
"export { value } from '../index.js';",
'packages/core/src/core/client.ts',
),
).toHaveLength(1);
expect(
runRule(
"export * from '../index.js';",
'packages/core/src/core/client.ts',
),
).toHaveLength(1);
expect(
runRule("import('../index.js');", 'packages/core/src/core/client.ts'),
).toHaveLength(1);
});
it('rejects package-specifier barrel imports from core production', () => {
expect(
runRule(
"import value from '@qwen-code/qwen-code-core';",
'packages/core/src/core/client.ts',
),
).toHaveLength(1);
});
it('rejects static template-literal dynamic barrel imports', () => {
expect(
runRule('import(`../index.js`);', 'packages/core/src/core/client.ts'),
).toHaveLength(1);
});
it('allows tests, fixtures, __tests__, and non-core consumers', () => {
expect(
runRule(
"import value from '../index.js';",
'packages/core/src/core/client.test.ts',
),
).toHaveLength(0);
expect(
runRule(
"import value from '../index.js';",
'packages/core/src/core/client.spec.ts',
),
).toHaveLength(0);
expect(
runRule(
"import value from '../index.js';",
'packages/core/src/fixtures/client.ts',
),
).toHaveLength(0);
expect(
runRule(
"import value from '../index.js';",
'packages/core/src/__tests__/helper.ts',
),
).toHaveLength(0);
// non-core consumers can import the package specifier freely
expect(
runRule(
"import value from '@qwen-code/qwen-code-core';",
'packages/cli/src/index.ts',
),
).toHaveLength(0);
// non-barrel package subpaths stay allowed even inside core production
expect(
runRule(
"import { memoryScopes } from '@qwen-code/qwen-code-core/memoryScopes';",
'packages/core/src/core/client.ts',
),
).toHaveLength(0);
});
it('allows direct owner imports', () => {
expect(
runRule(
"import value from '../tools/tools.js';",
'packages/core/src/core/client.ts',
),
).toHaveLength(0);
});
});