mirror of
https://github.com/hanzoai/frames.git
synced 2026-09-24 00:08:03 +00:00
fix(core): publish runtime inline artifact (#1787)
This commit is contained in:
@@ -79,9 +79,12 @@ jobs:
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
with:
|
||||
node-version: 22
|
||||
- run: corepack enable
|
||||
- run: corepack prepare [email protected] --activate
|
||||
- uses: ./.github/actions/prepare-ffmpeg-bin
|
||||
- run: bun install --frozen-lockfile
|
||||
- run: bun run build
|
||||
- run: bun run verify:packed-manifests
|
||||
|
||||
lint:
|
||||
name: Lint
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@
|
||||
"player:perf": "bun run --filter @hyperframes/player perf",
|
||||
"format:check": "oxfmt --check .",
|
||||
"knip": "knip",
|
||||
"test:scripts": "node --import tsx --test scripts/validate-release-channel.test.mjs scripts/draft-changelog.test.ts scripts/set-version.test.ts scripts/release-prepare.test.ts scripts/cli-options.test.ts scripts/changelog-weekly.test.ts scripts/claude-plugin-compression.test.ts",
|
||||
"test:scripts": "node --import tsx --test scripts/validate-release-channel.test.mjs scripts/draft-changelog.test.ts scripts/set-version.test.ts scripts/release-prepare.test.ts scripts/cli-options.test.ts scripts/changelog-weekly.test.ts scripts/claude-plugin-compression.test.ts scripts/verify-packed-manifests.test.mjs",
|
||||
"test:skills": "node --test 'skills/**/*.test.mjs'",
|
||||
"generate:previews": "tsx scripts/generate-template-previews.ts",
|
||||
"generate:catalog-previews": "tsx scripts/generate-catalog-previews.ts",
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
"dist/**/*.d.ts.map",
|
||||
"dist/**/*.js.map",
|
||||
"!dist/hyperframe.runtime.mjs",
|
||||
"!dist/generated/runtime-inline.js",
|
||||
"docs",
|
||||
"schemas",
|
||||
"README.md"
|
||||
|
||||
@@ -2,13 +2,15 @@
|
||||
|
||||
import { execFileSync } from "node:child_process";
|
||||
import { existsSync, mkdtempSync, readdirSync, readFileSync, rmSync } from "node:fs";
|
||||
import { extname, join } from "node:path";
|
||||
import { extname, join, posix } from "node:path";
|
||||
import { tmpdir } from "node:os";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const ROOT = join(import.meta.dirname, "..");
|
||||
const PACKAGES_DIR = join(ROOT, "packages");
|
||||
const DEP_FIELDS = ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"];
|
||||
const RUNTIME_IMPORT_EXTENSIONS = new Set([".js", ".mjs", ".cjs", ".json", ".wasm", ".node"]);
|
||||
const PACKED_JAVASCRIPT_FILE_PATTERN = /\.(?:js|mjs|cjs)$/;
|
||||
|
||||
function listWorkspacePackageDirs() {
|
||||
return readdirSync(PACKAGES_DIR)
|
||||
@@ -129,7 +131,9 @@ function hasExplicitRuntimeExtension(specifier) {
|
||||
function listRelativeImportSpecifiers(source) {
|
||||
const patterns = [
|
||||
/^\s*import\s+["'](\.\.?\/[^"']+)["']/gm,
|
||||
/^\s*(?:import|export)\s+[^;]*?\s+from\s+["'](\.\.?\/[^"']+)["']/gm,
|
||||
/^\s*(?:import|export)\b(?:(?!;)[\s\S])*?\s+from\s+["'](\.\.?\/[^"']+)["']/gm,
|
||||
/\bimport\s*\(\s*["'](\.\.?\/[^"']+)["']\s*\)/gm,
|
||||
/\brequire\s*\(\s*["'](\.\.?\/[^"']+)["']\s*\)/gm,
|
||||
];
|
||||
const specifiers = [];
|
||||
|
||||
@@ -177,17 +181,28 @@ function verifyPackedEntrypoints(workspace, packedPackage, packedFiles) {
|
||||
}
|
||||
}
|
||||
|
||||
function listJavaScriptImportIssues(filename, file) {
|
||||
const source = readPackedFile(filename, file);
|
||||
return listRelativeImportSpecifiers(source)
|
||||
.filter(({ specifier }) => !hasExplicitRuntimeExtension(specifier))
|
||||
.map(({ index, specifier }) => `${file}:${lineNumberAt(source, index)} imports ${specifier}`);
|
||||
function resolvePackedRelativeImport(fromFile, specifier) {
|
||||
return posix.normalize(posix.join(posix.dirname(fromFile), stripSpecifierQuery(specifier)));
|
||||
}
|
||||
|
||||
function listPackedJavaScriptImportIssues(filename, packedFiles) {
|
||||
export function listPackedJavaScriptImportIssues(filename, packedFiles) {
|
||||
return [...packedFiles]
|
||||
.filter((file) => file.endsWith(".js"))
|
||||
.flatMap((file) => listJavaScriptImportIssues(filename, file));
|
||||
.filter((file) => PACKED_JAVASCRIPT_FILE_PATTERN.test(file))
|
||||
.flatMap((file) => {
|
||||
const source = readPackedFile(filename, file);
|
||||
return listRelativeImportSpecifiers(source).flatMap(({ index, specifier }) => {
|
||||
if (!hasExplicitRuntimeExtension(specifier)) {
|
||||
return [`${file}:${lineNumberAt(source, index)} imports ${specifier}`];
|
||||
}
|
||||
|
||||
const target = resolvePackedRelativeImport(file, specifier);
|
||||
if (!packedFiles.has(target)) {
|
||||
return [`${file}:${lineNumberAt(source, index)} imports missing ${specifier}`];
|
||||
}
|
||||
|
||||
return [];
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function verifyPackedJavaScriptImports(workspace, filename, packedFiles) {
|
||||
@@ -276,4 +291,6 @@ function main() {
|
||||
listWorkspacePackageDirs().forEach(verifyWorkspace);
|
||||
}
|
||||
|
||||
main();
|
||||
if (process.argv[1] === fileURLToPath(import.meta.url)) {
|
||||
main();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { execFileSync } from "node:child_process";
|
||||
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { dirname, join } from "node:path";
|
||||
import { describe, it } from "node:test";
|
||||
import { listPackedJavaScriptImportIssues } from "./verify-packed-manifests.mjs";
|
||||
|
||||
describe("packed manifest verifier", () => {
|
||||
function withPackedFiles(files, packedFiles, callback) {
|
||||
const dir = mkdtempSync(join(tmpdir(), "hyperframes-pack-test-"));
|
||||
try {
|
||||
const packageDir = join(dir, "package");
|
||||
mkdirSync(packageDir, { recursive: true });
|
||||
for (const [file, source] of Object.entries(files)) {
|
||||
mkdirSync(dirname(join(packageDir, file)), { recursive: true });
|
||||
writeFileSync(join(packageDir, file), source, "utf8");
|
||||
}
|
||||
|
||||
const tarball = join(dir, "package.tgz");
|
||||
execFileSync("tar", ["-czf", tarball, "-C", dir, "package"]);
|
||||
callback(tarball, new Set(packedFiles));
|
||||
} finally {
|
||||
rmSync(dir, { recursive: true, force: true });
|
||||
}
|
||||
}
|
||||
|
||||
it("passes explicit relative JavaScript imports whose target is packed", () => {
|
||||
withPackedFiles(
|
||||
{
|
||||
"dist/index.js": 'import { runtime } from "./generated/runtime-inline.js";\n',
|
||||
"dist/generated/runtime-inline.js": "export const runtime = 'ok';\n",
|
||||
},
|
||||
["dist/index.js", "dist/generated/runtime-inline.js"],
|
||||
(tarball, packedFiles) => {
|
||||
assert.deepEqual(listPackedJavaScriptImportIssues(tarball, packedFiles), []);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it("reports explicit relative JavaScript imports whose target is missing from the tarball", () => {
|
||||
withPackedFiles(
|
||||
{
|
||||
"dist/index.js": 'import { runtime } from "./generated/runtime-inline.js";\n',
|
||||
},
|
||||
["dist/index.js"],
|
||||
(tarball, packedFiles) => {
|
||||
assert.deepEqual(listPackedJavaScriptImportIssues(tarball, packedFiles), [
|
||||
"dist/index.js:1 imports missing ./generated/runtime-inline.js",
|
||||
]);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it("checks export-from, dynamic import, require, and mjs/cjs files", () => {
|
||||
withPackedFiles(
|
||||
{
|
||||
"dist/index.js": 'export * from "./generated/exports.js";\n',
|
||||
"dist/dynamic.mjs": 'await import("./generated/dynamic.js");\n',
|
||||
"dist/require.cjs": 'require("./generated/require.js");\n',
|
||||
},
|
||||
["dist/index.js", "dist/dynamic.mjs", "dist/require.cjs"],
|
||||
(tarball, packedFiles) => {
|
||||
assert.deepEqual(listPackedJavaScriptImportIssues(tarball, packedFiles), [
|
||||
"dist/index.js:1 imports missing ./generated/exports.js",
|
||||
"dist/dynamic.mjs:1 imports missing ./generated/dynamic.js",
|
||||
"dist/require.cjs:1 imports missing ./generated/require.js",
|
||||
]);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it("reports extensionless relative imports", () => {
|
||||
withPackedFiles(
|
||||
{
|
||||
"dist/index.js": 'export {\n runtime\n} from "./generated/runtime-inline";\n',
|
||||
},
|
||||
["dist/index.js"],
|
||||
(tarball, packedFiles) => {
|
||||
assert.deepEqual(listPackedJavaScriptImportIssues(tarball, packedFiles), [
|
||||
"dist/index.js:1 imports ./generated/runtime-inline",
|
||||
]);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it("reports side-effect imports whose target is missing from the tarball", () => {
|
||||
withPackedFiles(
|
||||
{
|
||||
"index.js": 'import "./missing.js";\n',
|
||||
},
|
||||
["index.js"],
|
||||
(tarball, packedFiles) => {
|
||||
assert.deepEqual(listPackedJavaScriptImportIssues(tarball, packedFiles), [
|
||||
"index.js:1 imports missing ./missing.js",
|
||||
]);
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user