import assert from 'node:assert/strict'; import { mkdir, readFile, writeFile } from 'node:fs/promises'; import { createRequire } from 'node:module'; import { fileURLToPath, pathToFileURL } from 'node:url'; import { execFileSync } from 'node:child_process'; import path from 'node:path'; const root = fileURLToPath(new URL('../../', import.meta.url)); const consumer = path.join(root, 'test-results/org-chart-react/tarball-consumer'); await mkdir(consumer, { recursive: true }); for (const name of ['org-chart', 'org-chart-react']) { const destination = path.join(consumer, 'node_modules/@hm-design', name); await mkdir(destination, { recursive: true }); execFileSync('tar.exe', ['-xzf', path.join(root, `test-results/hm-design-${name}-0.1.0.tgz`), '-C', destination, '--strip-components=1']); } await writeFile(path.join(consumer, 'package.json'), JSON.stringify({ name: 'org-chart-react-tarball-consumer', private: true, type: 'module' })); const require = createRequire(path.join(consumer, 'package.json')); const module = await import(pathToFileURL(require.resolve('@hm-design/org-chart-react')).href); assert.deepEqual(Object.keys(module), ['OrgChart']); assert.equal(typeof module.OrgChart, 'function'); const manifest = JSON.parse(await readFile(path.join(consumer, 'node_modules/@hm-design/org-chart-react/package.json'), 'utf8')); assert.deepEqual(manifest.dependencies, { '@hm-design/org-chart': '0.1.0' }); assert.deepEqual(manifest.peerDependencies, { react: '^19.0.0' }); const bundle = await readFile(require.resolve('@hm-design/org-chart-react'), 'utf8'); assert.ok(bundle.startsWith('"use client";')); for (const dependency of ['react', 'react/jsx-runtime', '@hm-design/org-chart']) assert.ok(bundle.includes(`from "${dependency}"`) || bundle.includes(`from '${dependency}'`)); assert.ok(!bundle.includes('ManagedOrgChart') && !bundle.includes('validateOrgChartDataset') && !bundle.includes('JsonOrgChartDataSource')); await writeFile(path.join(consumer, 'consumer.tsx'), `import { OrgChart, type OrgChartProps, type OrgChartDataSource, type OrgChartState, type OrgChartDataset } from '@hm-design/org-chart-react'; import { JsonOrgChartDataSource } from '@hm-design/org-chart'; declare const data: OrgChartDataset; const source: OrgChartDataSource = new JsonOrgChartDataSource(data); const props: OrgChartProps = { dataSource: source, stylesheetUrls: { engine: './engine.css', core: './style.css' }, onStateChange(state: OrgChartState) { if(state.status === 'ready') void state.summary.raw.total; }, onLifecycleError(error: unknown) { void error; } }; export const consumer = ; // @ts-expect-error dataSource is a required Core source interface export const missingSource = ; // @ts-expect-error wrapper does not expose engine controls export const unsupportedZoom = ; // @ts-expect-error Core-owned container cannot be supplied through React Props export const unsupportedContainer = ; `); await writeFile(path.join(consumer, 'tsconfig.json'), JSON.stringify({ compilerOptions: { target: 'ES2022', module: 'NodeNext', moduleResolution: 'NodeNext', jsx: 'react-jsx', strict: true, noEmit: true, skipLibCheck: false, types: ['react'] }, include: ['consumer.tsx'] })); const localRequire = createRequire(import.meta.url); const typescriptManifest = localRequire.resolve('typescript/package.json'); const typescript = JSON.parse(await readFile(typescriptManifest, 'utf8')); execFileSync(process.execPath, [path.resolve(path.dirname(typescriptManifest), typescript.bin.tsc), '-p', path.join(consumer, 'tsconfig.json')], { stdio: 'inherit' }); const report = { status: 'PASS', checks: ['Actual tarball runtime/public export without DOM', 'Strict NodeNext declarations using extracted Core/Wrapper', 'Required source and unsupported Props type boundaries', 'React/Core remain external', 'ESM client boundary retained'], limitation: 'React and compiler supplied by verification environment; fresh remote-registry dependency installation and SSR/hydration are not verified.', }; await writeFile(path.join(consumer, 'report.json'), JSON.stringify(report, null, 2)); console.log(JSON.stringify(report));