Files
qwen-code/scripts/tests/web-shell-publish-artifacts.test.js
a8eb74fdf5 fix(web-shell): polish files and trim preview resources (#14143)
* fix(web-shell): polish files and trim preview resources

* test(cli): observe pending child Hook promises

* fix(web-shell): address Files browser review findings

* fix(vscode): sync Pierre modification notices

* chore: ignore the repo-local .pnpm-store fallback directory

pnpm falls back to a project-local store at .pnpm-store/ when the global
store directory is not writable (e.g. sandboxed CI runners). It is a
regenerable cache that node_modules hard-links into; its thousands of
untracked files otherwise dirty the working tree and fail deterministic
workspace-clean verification.

Co-authored-by: Qwen-Coder <[email protected]>

* fix(web-shell): address Pierre preview and file display review findings

- getPreviewLanguage folds case on the extension only, so README.MD and
  config.YML highlight while whole-name detector keys (Gemfile, BUILD)
  keep their case-sensitive behavior
- formatFileName strips the full Default_Ignorable_Code_Point class so
  zero-advance Hangul fillers and variation selectors cannot desync the
  tree search projection from the rendered name
- pin the previously unwitnessed pierre-build guards: redirected Shiki
  subpaths count toward the 4 MiB budget, getModuleInfo may return null
  for redirected ids, emitted assets are skipped, and entry-module
  resolveId calls carry no importer
- pin the theme name->module mapping with exact token colors and give
  the formatFileName display sites discriminating coverage with
  repeated-space names

---------

Co-authored-by: 钉萁 <[email protected]>
Co-authored-by: qwen-code[bot] <qwen-code[bot]@users.noreply.github.com>
Co-authored-by: Qwen-Coder <[email protected]>
Co-authored-by: qwen-code-dev-bot <[email protected]>
2026-10-16 16:45:56 +08:00

457 lines
16 KiB
JavaScript

/**
* @license
* Copyright 2026 Qwen Team
* SPDX-License-Identifier: Apache-2.0
*/
import { spawnSync } from 'node:child_process';
import { cpSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { describe, expect, it } from 'vitest';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const root = path.resolve(__dirname, '..', '..');
const verifier = path.join(
root,
'packages',
'web-shell',
'scripts',
'verify-publish-artifacts.mjs',
);
// A published version cannot be replaced, so the guard is driven here the way
// `prepublishOnly` drives it: the real script copied into a throwaway package
// root that carries only the shape under test. Nothing imports the workspace,
// and `npm pack` answers for the fixture's own `files` globs.
function runVerifier(build, getEnv = () => ({})) {
const fixture = mkdtempSync(path.join(tmpdir(), 'web-shell-publish-'));
try {
build(fixture);
mkdirSync(path.join(fixture, 'scripts'), { recursive: true });
cpSync(
verifier,
path.join(fixture, 'scripts', 'verify-publish-artifacts.mjs'),
);
return spawnSync(
process.execPath,
['scripts/verify-publish-artifacts.mjs'],
{
cwd: fixture,
encoding: 'utf8',
env: { ...process.env, ...getEnv(fixture) },
timeout: 120_000,
},
);
} finally {
rmSync(fixture, { recursive: true, force: true });
}
}
function write(fixture, name, contents) {
const target = path.join(fixture, name);
mkdirSync(path.dirname(target), { recursive: true });
writeFileSync(
target,
name.endsWith('package.json')
? `${JSON.stringify(contents, null, 2)}\n`
: contents,
);
}
// The real manifest's `files`: `dist/*.js` does not cross a `/`, so anything
// the build emits below `dist/` is on disk yet absent from the tarball.
const files = ['dist/*.js', 'dist/types'];
function declarePackage(
fixture,
exports,
packageFiles = files,
dependencies = {},
) {
write(fixture, 'NOTICES.txt', 'Bundled dependency licenses');
write(fixture, 'package.json', {
name: 'fixture-web-shell',
version: '0.0.0',
type: 'module',
files: ['NOTICES.txt', ...packageFiles],
exports,
dependencies,
});
}
describe('web-shell publish artifact verifier', () => {
it.each(['shiki-files/core', '@shikijs/types'])(
'refuses declarations depending on undeclared %s',
(specifier) => {
const result = runVerifier((fixture) => {
declarePackage(fixture, { '.': './dist/index.js' });
write(fixture, 'dist/index.js', 'export {};');
write(
fixture,
'dist/types/private.d.ts',
`export type X = typeof import('${specifier}');`,
);
});
expect(result.status).toBe(1);
expect(result.stderr).toContain(
`private.d.ts imports the repo-only ${specifier}`,
);
},
);
it('accepts self, relative, builtin and declared type dependencies', () => {
const result = runVerifier((fixture) => {
declarePackage(fixture, { '.': './dist/index.js' }, files, {
shiki: '*',
'@types/hast': '*',
});
write(fixture, 'dist/index.js', 'export {};');
write(
fixture,
'dist/types/index.d.ts',
`export type A = typeof import('fixture-web-shell/daemon-react-sdk');
export type B = typeof import('./relative');
export type C = typeof import('node:fs');
export type D = typeof import('shiki/core');
export type E = import('hast').Root;`,
);
});
expect(result.status).toBe(0);
});
it('refuses bundled dependency notices excluded from the npm package', () => {
const result = runVerifier((fixture) => {
write(fixture, 'NOTICES.txt', 'Bundled dependency licenses');
write(fixture, 'dist/index.js', 'export {};');
write(fixture, 'package.json', {
name: 'fixture-web-shell',
version: '0.0.0',
type: 'module',
files,
exports: { '.': './dist/index.js' },
});
});
expect(result.status).toBe(1);
expect(result.stderr).toContain(
'NOTICES.txt is missing from the npm package',
);
});
it('refuses an export target that exists on disk but is left out of the tarball', () => {
const result = runVerifier((fixture) => {
declarePackage(fixture, {
'.': {
types: './dist/types/index.d.ts',
import: './dist/nested/index.js',
},
});
write(fixture, 'dist/nested/index.js', 'export default 1;\n');
write(
fixture,
'dist/types/index.d.ts',
'export declare const a: number;\n',
);
});
expect(result.status).toBe(1);
expect(result.stderr).toContain('./dist/nested/index.js');
expect(result.stderr).toContain('not included in the npm package');
});
it('refuses a relative chunk that lands in a subdirectory `files` does not reach', () => {
const result = runVerifier((fixture) => {
declarePackage(fixture, { '.': { import: './dist/index.js' } });
write(
fixture,
'dist/index.js',
'import { chunk } from "./nested/chunk.js";\nexport default chunk;\n',
);
write(fixture, 'dist/nested/chunk.js', 'export const chunk = 1;\n');
});
expect(result.status).toBe(1);
expect(result.stderr).toContain('./nested/chunk.js');
expect(result.stderr).toContain('not included in the npm package');
});
it('still fails closed on an export target that was never built', () => {
const result = runVerifier((fixture) => {
declarePackage(fixture, {
'.': {
types: './dist/types/index.d.ts',
import: './dist/absent.js',
},
});
write(
fixture,
'dist/types/index.d.ts',
'export declare const a: number;\n',
);
});
expect(result.status).toBe(1);
expect(result.stderr).toContain('missing ./dist/absent.js');
});
it('accepts a wildcard export pattern whose targets are packed', () => {
const result = runVerifier((fixture) => {
declarePackage(fixture, {
'.': { import: './dist/index.js' },
'./*': './dist/*',
});
write(fixture, 'dist/index.js', 'export default 1;\n');
write(fixture, 'dist/daemon-react-sdk.js', 'export default 2;\n');
});
expect(result.status).toBe(0);
expect(result.stderr).toBe('');
});
it('refuses a wildcard target under a literal exports key', () => {
const result = runVerifier((fixture) => {
declarePackage(fixture, {
'.': { import: './dist/index.js' },
'./foo': './dist/*.js',
});
write(fixture, 'dist/index.js', 'export default 1;\n');
write(fixture, 'dist/bar.js', 'export default 2;\n');
});
// Node gives `*` pattern meaning only when the exports KEY carries it: a
// wildcard target under a literal key resolves to a literal path, so the
// verifier must keep the literal checks for it instead of pattern-matching
// it against whatever the package happens to contain.
expect(result.status).toBe(1);
expect(result.stderr).toContain('missing ./dist/*.js');
});
it('refuses an exports key that carries more than one star', () => {
const result = runVerifier((fixture) => {
declarePackage(fixture, {
'.': { import: './dist/index.js' },
'./*/*': './dist/*',
});
write(fixture, 'dist/index.js', 'export default 1;\n');
});
// Node honours a pattern key only when it carries exactly one `*`; a
// two-star key matches nothing at all, so the pair must fall through to
// the literal checks and be refused like the base verifier refused it.
expect(result.status).toBe(1);
expect(result.stderr).toContain('missing ./dist/*');
});
it('refuses a star-bearing exports key that is not a subpath key', () => {
const result = runVerifier((fixture) => {
declarePackage(fixture, {
'.': { import: './dist/index.js' },
'dist/*': './dist/*',
});
write(fixture, 'dist/index.js', 'export default 1;\n');
write(fixture, 'dist/other.js', 'export default 2;\n');
});
// `"dist/*"` carries exactly one star and its target is packed, so a
// star-count gate alone would pattern-match it and certify the publish.
// Node never gives a key pattern meaning unless it is a `./`-prefixed
// subpath key: mixed with `"."` it rejects the whole manifest with
// ERR_INVALID_PACKAGE_CONFIG for every specifier, the root import
// included. It must fall through to the literal checks and be refused the
// way the base verifier refused it.
expect(result.status).toBe(1);
expect(result.stderr).toContain('missing ./dist/*');
});
it('refuses a multi-star target whose capture cannot match every star', () => {
const result = runVerifier((fixture) => {
// `files: ['dist']` packs dist/a/b.js, so the refusal cannot be
// explained by an unpacked file: Node substitutes the one captured
// substring into BOTH stars (`./a` -> `dist/a/a.js`), and only a
// back-referencing regex rejects the packed `dist/a/b.js` here.
declarePackage(fixture, { './*': './dist/*/*.js' }, ['dist']);
write(fixture, 'dist/a/b.js', 'export default 1;\n');
});
expect(result.status).toBe(1);
expect(result.stderr).toContain('matches no file in the npm package');
});
it('accepts a multi-star target when one capture satisfies every star', () => {
const result = runVerifier((fixture) => {
declarePackage(fixture, { './*': './dist/*/*.js' }, ['dist']);
write(fixture, 'dist/a/a.js', 'export default 1;\n');
});
// Positive control: the same-capture shape Node actually resolves, so the
// gate must not be a blanket refusal of multi-star targets.
expect(result.status).toBe(0);
expect(result.stderr).toBe('');
});
it('accepts a multi-star target whose star is followed by a digit', () => {
const result = runVerifier((fixture) => {
declarePackage(fixture, { './*': './dist/*/*1.js' }, ['dist']);
write(fixture, 'dist/a/a1.js', 'export default 42;\n');
});
// Node substitutes one capture into every star, so `./a` resolves to
// `dist/a/a1.js` and the import succeeds. A positional `\1` here would
// compile as `\11` — the Annex B octal escape U+0009, since the pattern
// has only one group — which no packed path can satisfy, refusing a
// publishable manifest. The back-reference has to be named.
expect(result.status).toBe(0);
expect(result.stderr).toBe('');
});
it('accepts a wildcard pattern whose only packed match is nested', () => {
const result = runVerifier((fixture) => {
// `files: ['dist']`: the suite default `dist/*.js` never packs a nested
// file, so here the family's only packed member lives in a subdirectory
// and the `*` capture has to cross a `/` to reach it — the property
// Node's resolver has and this branch depends on.
declarePackage(fixture, { './*': './dist/*' }, ['dist']);
write(fixture, 'dist/nested/sdk.js', 'export default 1;\n');
});
expect(result.status).toBe(0);
expect(result.stderr).toBe('');
});
it('refuses an exports target carrying a dot segment', () => {
const result = runVerifier((fixture) => {
declarePackage(fixture, { './*': './dist/../dist/*.js' }, ['dist']);
write(fixture, 'dist/a.js', 'export default 1;\n');
});
// `join` normalizes `./dist/../dist/*.js` down to `dist/*.js`, which the
// packed `dist/a.js` satisfies — but Node throws
// ERR_INVALID_PACKAGE_TARGET for every subpath through that key, so the
// DECLARED string is what has to be validated, not the normalized path.
expect(result.status).toBe(1);
expect(result.stderr).toContain('not a valid "exports" target');
});
it('refuses an exports target that is not ./-relative', () => {
const result = runVerifier((fixture) => {
declarePackage(fixture, { './*': 'dist/*' }, ['dist']);
write(fixture, 'dist/a.js', 'export default 1;\n');
});
// `dist/*` normalizes through `packPath` to exactly what the well-formed
// `./dist/*` does, so the packed-list check alone cannot tell them apart,
// yet Node rejects a non-relative target for every specifier through it.
expect(result.status).toBe(1);
expect(result.stderr).toContain('not a valid "exports" target');
});
it('checks a target advertised by both a pattern key and a literal key', () => {
const result = runVerifier((fixture) => {
declarePackage(fixture, { './*': './dist/*', './foo': './dist/*' });
write(fixture, 'dist/index.js', 'export default 1;\n');
});
expect(result.status).toBe(1);
expect(result.stderr).toContain('missing ./dist/*');
});
it('keeps the literal checks for a pattern key with a literal target', () => {
const result = runVerifier((fixture) => {
declarePackage(fixture, { './*': './dist/entry.js' });
write(
fixture,
'dist/entry.js',
'import { chunk } from "./nested/chunk.js";\nexport default chunk;\n',
);
write(fixture, 'dist/nested/chunk.js', 'export const chunk = 1;\n');
});
expect(result.status).toBe(1);
expect(result.stderr).toContain('not included in the npm package');
});
it('still fails closed on a wildcard pattern that matches nothing packed', () => {
const result = runVerifier((fixture) => {
declarePackage(fixture, {
'.': { import: './dist/index.js' },
'./*': './dist/absent/*',
});
write(fixture, 'dist/index.js', 'export default 1;\n');
// On disk but not packed: `dist/*.js` does not cross a `/`, so this
// keeps the fixture discriminating between the packed-list oracle and a
// filesystem-existence oracle.
write(fixture, 'dist/absent/sdk.js', 'export const sdk = 1;\n');
});
expect(result.status).toBe(1);
expect(result.stderr).toContain('./dist/absent/*');
expect(result.stderr).toContain('matches no file in the npm package');
});
it('accepts the shape the published package actually ships', () => {
const result = runVerifier((fixture) => {
declarePackage(fixture, {
'.': {
types: './dist/types/index.d.ts',
import: './dist/index.js',
},
'./daemon-react-sdk': {
types: './dist/types/daemon-react-sdk.d.ts',
import: './dist/daemon-react-sdk.js',
},
'./transcript': {
types: './dist/types/transcript.d.ts',
import: './dist/transcript.js',
},
});
write(
fixture,
'dist/index.js',
'import { chunk } from "./chunk.js";\nexport default chunk;\n',
);
write(fixture, 'dist/chunk.js', 'export const chunk = 1;\n');
write(fixture, 'dist/daemon-react-sdk.js', 'export default 2;\n');
write(fixture, 'dist/transcript.js', 'export default 3;\n');
write(
fixture,
'dist/types/index.d.ts',
'export declare const a: number;\n',
);
write(
fixture,
'dist/types/daemon-react-sdk.d.ts',
'export declare const b: number;\n',
);
write(
fixture,
'dist/types/transcript.d.ts',
'export declare const c: number;\n',
);
});
expect(result.status).toBe(0);
expect(result.stderr).toBe('');
});
it('keeps npm warnings out of the verifier output', () => {
const result = runVerifier(
(fixture) => {
declarePackage(fixture, {
'.': { import: './dist/index.js' },
});
write(fixture, 'dist/index.js', 'export default 1;\n');
write(
fixture,
'unknown.npmrc',
'ELECTRON_MIRROR=https://mirror.invalid\n',
);
},
(fixture) => ({
NPM_CONFIG_USERCONFIG: path.join(fixture, 'unknown.npmrc'),
}),
);
expect(result.status).toBe(0);
expect(result.stderr).toBe('');
});
});