Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 73 additions & 2 deletions tests/cockpit-host/purity.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,10 @@ function extractModuleSpecifiers(source: string): readonly string[] {
// options argument (closing `)` or a comma introduces it).
/\bimport\s*\(\s*(?:\/\*[\s\S]*?\*\/\s*)?['"]([^'"]+)['"](?:\s|\/\*[\s\S]*?\*\/)*[,)]/g,
// re-export bindings: `export { x } from 'S'`, `export * from 'S'`, with
// optional block comments between `from` and the module string.
/\bexport\b(?:\/\*[\s\S]*?\*\/|[^'"])*?\bfrom\s+(?:\/\*[\s\S]*?\*\/\s*)*['"]([^'"]+)['"]/g,
// optional whitespace and/or block comments between `from` and the module
// string. The separator after `from` is `\s*`, not `\s+`, so a block comment
// (or the quote itself) may abut `from` directly, e.g. `from/* c */'S'`.
/\bexport\b(?:\/\*[\s\S]*?\*\/|[^'"])*?\bfrom\s*(?:\/\*[\s\S]*?\*\/\s*)*['"]([^'"]+)['"]/g,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restrict the match to an actual re-export clause

When any exported declaration is followed by a comment containing compact example text such as export const safe = true; // docs: from'../domain/example.js', the new \s* branch treats that comment text as a re-export and reports the example path as a real dependency. The prefix can scan across statement and comment boundaries, so this newly produces false purity failures for otherwise valid host source; ensure from belongs to the export clause or lexically exclude comments before accepting the adjacent quote.

Useful? React with 👍 / 👎.

];
const specifiers: string[] = [];
for (const pattern of patterns) {
Expand Down Expand Up @@ -361,3 +363,72 @@ describe('D3 host import scanner covers post-`from` re-export comments (D3-CR-F6
expect(extractModuleSpecifiers(source)).toEqual(['./local.js', '../cockpit/index.js']);
});
});

describe('D3 host import scanner covers `from`-abutting re-export comments (D3-CR-F7)', () => {
const forbiddenIn = (source: string): readonly string[] =>
extractModuleSpecifiers(source).filter((s) => /\.\.\/(?:domain|adapters)\//.test(s));

// D3-CR-F7: the F6 separator after `from` was `\s+`, so it still required at
// least one whitespace character before the block comment. A comment (or the
// quote itself) abutting `from` directly — `from/* note */'S'` — was missed,
// letting a forbidden dependency bypass the discipline check. The separator is
// now `\s*`, so no whitespace is required after `from`.
it('extracts a named re-export with a block comment abutting `from`', () => {
expect(forbiddenIn(`export { x } from/* note */'../domain/foo.js';`).length).toBeGreaterThan(0);
});

it('extracts an export-star with a block comment abutting `from`', () => {
expect(forbiddenIn(`export * from/* note */'../domain/foo.js';`).length).toBeGreaterThan(0);
});

it('extracts an `export type` with a block comment abutting `from`', () => {
expect(
forbiddenIn(`export type { T } from/* note */'../domain/foo.js';`).length,
).toBeGreaterThan(0);
});

it('extracts a double-quoted specifier with a block comment abutting `from`', () => {
expect(forbiddenIn(`export * from/* note */"../adapters/foo.js";`).length).toBeGreaterThan(0);
});

it('extracts a specifier across a multi-line block comment abutting `from`', () => {
const source = ['export { x } from/* multi', " line note */'../domain/foo.js';"].join('\n');
expect(forbiddenIn(source).length).toBeGreaterThan(0);
});

// Preservation: the F6 whitespace form must still be detected, and widening
// `\s+` to `\s*` must not misread an identifier that merely starts with
// `from`, capture across a statement boundary, or double-count.
it('preserves the F6 whitespace form after `from`', () => {
expect(forbiddenIn(`export { x } from /* note */ '../domain/foo.js';`).length).toBeGreaterThan(
0,
);
});

it('does not treat an identifier beginning with `from` as the re-export keyword', () => {
// `fromValues` is a local binding, not the `from` clause; only the real
// re-export specifier `../domain/foo.js` must surface — exactly once.
expect(extractModuleSpecifiers(`export { fromValues } from/* c */'../domain/foo.js';`)).toEqual([
'../domain/foo.js',
]);
});

it('extracts each `from`-abutting specifier once, without capturing across statements', () => {
const source = [
"export { a } from/* note */'./local.js';",
"export { b } from '../cockpit/index.js';",
].join('\n');
expect(extractModuleSpecifiers(source)).toEqual(['./local.js', '../cockpit/index.js']);
});

it('preserves static, dynamic, allowed, and import.meta behaviour', () => {
expect(forbiddenIn(`import /* note */ '../domain/foo.js';`).length).toBeGreaterThan(0);
expect(forbiddenIn(`import(/* note */ '../domain/foo.js')`).length).toBeGreaterThan(0);
expect(extractModuleSpecifiers(`import http from 'node:http';`)).toContain('node:http');
expect(extractModuleSpecifiers(`import { a } from "./local.js";`)).toContain('./local.js');
expect(extractModuleSpecifiers(`import { r } from '../cockpit/index.js';`)).toContain(
'../cockpit/index.js',
);
expect(extractModuleSpecifiers(`const isEntry = import.meta.url === x;`)).toEqual([]);
});
});
Loading