mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-11-15 13:58:20 +00:00
* fix(studio): reload the preview only when a file it loaded changes * test(studio): read the owner id from the new change-owner shape * refactor(studio): drop a comment the parser name already says * fix(studio): keep reloading until the preview is built, and count what its document names * style(studio): format the reference pattern and name the kept reload * fix(studio-server): scan preview references in linear time and refresh all thumbnails on a merged reload * fix(studio): keep a waiting film change when a file the preview never loaded arrives behind it * test(studio): name the preview ownership test for what it checks * chore(ci): allow the watchIgnore removals and trim the new comments * fix(studio-server): reload the preview when a folder holding a file it loaded moves in or out * perf(studio-server): check a changed folder in one lookup and cover every reference form * fix(studio-server): record read folders for a project at the filesystem root * fix(studio-server): reload the preview when the file a symlinked asset points at changes * fix(studio-server): resolve symlinks on every preview read and key projects by their real folder * fix(studio-server): record every link a preview read passes through, resolved as the system does
77 lines
3.2 KiB
TypeScript
77 lines
3.2 KiB
TypeScript
/**
|
|
* `docs/schema/hyperframes.json` is authored by hand (sync-schemas.ts mirrors
|
|
* only the registry schemas and skips this one), sets `additionalProperties:
|
|
* false` at both levels, and is the schema every generated `hyperframes.json`
|
|
* points at. So a new config key that lands in code but not in the schema turns
|
|
* a valid, committed config into one that fails validation in any schema-aware
|
|
* editor, with nothing in CI to notice.
|
|
*
|
|
* This pins the two together by validating a config that exercises every key
|
|
* the CLI can write, nested objects included. A key-name check alone is not
|
|
* enough: `registryItems` is an array of objects with their own
|
|
* `additionalProperties: false`, so a fourth field on `RegistryItemRecord`
|
|
* would recreate the same break one level down.
|
|
*/
|
|
import { describe, expect, it } from "vitest";
|
|
import { readFileSync } from "node:fs";
|
|
import { fileURLToPath } from "node:url";
|
|
import { dirname, resolve } from "node:path";
|
|
import { Ajv2020 } from "ajv/dist/2020.js";
|
|
import {
|
|
DEFAULT_PROJECT_CONFIG,
|
|
type ProjectConfig,
|
|
type RegistryItemRecord,
|
|
} from "./projectConfig.js";
|
|
|
|
const REPO_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "../../../..");
|
|
const SCHEMA_PATH = resolve(REPO_ROOT, "docs/schema/hyperframes.json");
|
|
|
|
/**
|
|
* One record carrying every field the CLI writes. Typed, so a new field on
|
|
* `RegistryItemRecord` is a compile error here until it is listed, and then a
|
|
* validation failure until it is declared in the schema.
|
|
*/
|
|
const EVERY_RECORD_FIELD: Required<RegistryItemRecord> = {
|
|
name: "data-chart",
|
|
type: "hyperframes:block",
|
|
target: "compositions/data-chart.html",
|
|
};
|
|
|
|
/** A config exercising every key the CLI can write, at every level. */
|
|
const EVERY_WRITTEN_KEY: Required<ProjectConfig> = {
|
|
$schema: "https://hyperframes.heygen.com/schema/hyperframes.json",
|
|
registry: "https://example.test/registry",
|
|
paths: DEFAULT_PROJECT_CONFIG.paths,
|
|
media: { autoProxy: true },
|
|
authoringSkill: "product-launch-video",
|
|
registryItems: [EVERY_RECORD_FIELD],
|
|
};
|
|
|
|
describe("hyperframes.json schema", () => {
|
|
const schema = JSON.parse(readFileSync(SCHEMA_PATH, "utf-8")) as Record<string, unknown>;
|
|
const validate = new Ajv2020({ strict: false, validateFormats: false }).compile(schema);
|
|
|
|
it("accepts a config using every key the CLI can write", () => {
|
|
// Guard the guard: without a closed schema at both levels the assertion
|
|
// below would pass for an undeclared key rather than failing.
|
|
expect(schema.additionalProperties).toBe(false);
|
|
const items = (schema.properties as Record<string, { items?: Record<string, unknown> }>)
|
|
.registryItems?.items;
|
|
expect(items?.additionalProperties).toBe(false);
|
|
|
|
expect(validate(EVERY_WRITTEN_KEY), JSON.stringify(validate.errors)).toBe(true);
|
|
});
|
|
|
|
// Proves the check above can fail, rather than passing because ajv was
|
|
// handed something it never rejects.
|
|
it("rejects a key the schema does not declare, at either level", () => {
|
|
expect(validate({ ...EVERY_WRITTEN_KEY, unknownTopLevelKey: 1 })).toBe(false);
|
|
expect(
|
|
validate({
|
|
...EVERY_WRITTEN_KEY,
|
|
registryItems: [{ ...EVERY_RECORD_FIELD, unknownItemKey: 1 }],
|
|
}),
|
|
).toBe(false);
|
|
});
|
|
});
|