handoff-app 2.0.0-6 → 2.0.0-8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +240 -52
- package/UPGRADE.md +218 -0
- package/config/config.template.js +1 -4
- package/config/config.template.ts +1 -2
- package/dist/app-builder/build.js +12 -6
- package/dist/app-builder/client-config.js +3 -1
- package/dist/app-builder/config-diff/strategies/pattern.js +3 -3
- package/dist/app-builder/watchers/component.js +5 -5
- package/dist/app-builder/watchers/utils.d.ts +2 -3
- package/dist/app-builder/watchers.d.ts +8 -15
- package/dist/app-builder/watchers.js +70 -61
- package/dist/cache/build-cache.js +23 -23
- package/dist/catalog/define.d.ts +6 -0
- package/dist/catalog/define.js +72 -0
- package/dist/catalog/implementation.d.ts +27 -0
- package/dist/catalog/implementation.js +133 -0
- package/dist/catalog/index.d.ts +6 -0
- package/dist/catalog/index.js +22 -0
- package/dist/catalog/normalize.d.ts +16 -0
- package/dist/catalog/normalize.js +115 -0
- package/dist/catalog/previews.d.ts +18 -0
- package/dist/catalog/previews.js +106 -0
- package/dist/catalog/renderers.d.ts +43 -0
- package/dist/catalog/renderers.js +62 -0
- package/dist/catalog/types.d.ts +63 -0
- package/dist/cli/auth/device.d.ts +6 -1
- package/dist/cli/auth/device.js +5 -2
- package/dist/cli/auth/store.d.ts +15 -6
- package/dist/cli/auth/store.js +72 -19
- package/dist/cli/make.d.ts +0 -5
- package/dist/cli/make.js +22 -67
- package/dist/cli/scaffold.js +25 -33
- package/dist/commands/checkout/index.d.ts +7 -4
- package/dist/commands/checkout/index.js +9 -6
- package/dist/commands/compat/push-args.d.ts +2 -2
- package/dist/commands/index.js +0 -2
- package/dist/commands/login/index.d.ts +5 -0
- package/dist/commands/login/index.js +18 -6
- package/dist/commands/logout/index.d.ts +5 -0
- package/dist/commands/logout/index.js +54 -15
- package/dist/commands/publish/index.d.ts +9 -6
- package/dist/commands/publish/index.js +11 -8
- package/dist/commands/pull/index.js +1 -1
- package/dist/commands/push/index.js +1 -1
- package/dist/commands/types.d.ts +2 -0
- package/dist/commands/utils.d.ts +36 -11
- package/dist/commands/utils.js +30 -16
- package/dist/config/catalog-include.d.ts +43 -0
- package/dist/config/catalog-include.js +203 -0
- package/dist/config/defaults.d.ts +3 -3
- package/dist/config/defaults.js +54 -48
- package/dist/config/env.d.ts +9 -0
- package/dist/config/env.js +43 -0
- package/dist/config/errors.d.ts +4 -0
- package/dist/config/errors.js +11 -0
- package/dist/config/from-env.d.ts +24 -0
- package/dist/config/from-env.js +7 -0
- package/dist/config/helpers.d.ts +2 -0
- package/dist/config/helpers.js +3 -1
- package/dist/config/index.d.ts +4 -3
- package/dist/config/index.js +10 -5
- package/dist/config/loader.d.ts +29 -11
- package/dist/config/loader.js +126 -45
- package/dist/config/resolve-env.d.ts +5 -0
- package/dist/config/resolve-env.js +102 -0
- package/dist/config/runtime.d.ts +7 -8
- package/dist/config/runtime.js +154 -154
- package/dist/config/validator.d.ts +2 -2
- package/dist/config/validator.js +2 -4
- package/dist/handlebars.d.ts +9 -0
- package/dist/handlebars.js +16 -0
- package/dist/index.d.ts +48 -8
- package/dist/index.js +88 -30
- package/dist/pattern.d.ts +7 -0
- package/dist/pattern.js +13 -0
- package/dist/pipeline/index.d.ts +1 -1
- package/dist/pipeline/index.js +1 -1
- package/dist/react.d.ts +43 -0
- package/dist/react.js +11 -0
- package/dist/registry/asset-storage/adapters/vercel-blob.js +1 -1
- package/dist/registry/asset-storage/define.d.ts +1 -1
- package/dist/registry/asset-storage/define.js +1 -1
- package/dist/registry/asset-storage/resolve.d.ts +2 -2
- package/dist/registry/asset-storage/resolve.js +4 -1
- package/dist/registry/checkout/index.d.ts +9 -0
- package/dist/registry/checkout/index.js +339 -153
- package/dist/registry/connection.d.ts +28 -24
- package/dist/registry/connection.js +53 -67
- package/dist/registry/db/driver.d.ts +4 -11
- package/dist/registry/db/driver.js +4 -16
- package/dist/registry/db/index.d.ts +1 -1
- package/dist/registry/db/index.js +1 -2
- package/dist/registry/db/schema.d.ts +34 -0
- package/dist/registry/db/schema.js +2 -0
- package/dist/registry/publish/index.d.ts +13 -2
- package/dist/registry/publish/index.js +113 -29
- package/dist/registry/publish/package.js +14 -1
- package/dist/registry/selection.d.ts +20 -0
- package/dist/registry/selection.js +37 -1
- package/dist/store/filesystem.d.ts +3 -3
- package/dist/store/filesystem.js +7 -7
- package/dist/store/registry.js +24 -3
- package/dist/transformers/plugins/csf-render.js +4 -2
- package/dist/transformers/plugins/ssr-render.js +14 -5
- package/dist/transformers/preview/component/api.d.ts +8 -0
- package/dist/transformers/preview/component/api.js +11 -15
- package/dist/transformers/preview/component/artifacts.d.ts +1 -1
- package/dist/transformers/preview/component/artifacts.js +11 -7
- package/dist/transformers/preview/component/builder.js +15 -18
- package/dist/transformers/preview/component/css.d.ts +2 -0
- package/dist/transformers/preview/component/css.js +8 -11
- package/dist/transformers/preview/component/html.js +18 -16
- package/dist/transformers/preview/component/javascript.js +2 -4
- package/dist/transformers/preview/pattern/builder.js +31 -18
- package/dist/transformers/preview/types.d.ts +15 -1
- package/dist/types/config.d.ts +77 -40
- package/docs/api.md +34 -0
- package/docs/cli.md +3 -3
- package/drizzle/0006_add_component_source_format.sql +3 -0
- package/drizzle/meta/0006_snapshot.json +1941 -0
- package/drizzle/meta/_journal.json +8 -1
- package/package.json +34 -1
- package/src/app/components/Component/Preview.tsx +36 -50
- package/src/app/components/Markdown/CodeHighlight.tsx +73 -70
- package/src/app/components/context/PreviewContext.tsx +5 -5
- package/src/app/components/util/index.ts +7 -15
- package/src/app/lib/mcp/shape.ts +6 -5
- package/src/app/lib/registry-api/transfer.ts +7 -5
- package/src/app/pages/account/tokens.tsx +3 -1
- package/src/app-builder/build.ts +13 -8
- package/src/app-builder/client-config.ts +5 -3
- package/src/app-builder/config-diff/strategies/pattern.ts +1 -1
- package/src/app-builder/watchers/component.ts +3 -3
- package/src/app-builder/watchers/utils.ts +2 -3
- package/src/app-builder/watchers.ts +63 -57
- package/src/cache/build-cache.ts +16 -15
- package/src/catalog/README.md +92 -0
- package/src/catalog/define.ts +79 -0
- package/src/catalog/implementation.ts +145 -0
- package/src/catalog/index.ts +31 -0
- package/src/catalog/normalize.ts +143 -0
- package/src/catalog/previews.ts +111 -0
- package/src/catalog/renderers.ts +94 -0
- package/src/catalog/types.ts +74 -0
- package/src/cli/README.md +1 -1
- package/src/cli/auth/device.ts +8 -3
- package/src/cli/auth/store.ts +75 -18
- package/src/cli/make.ts +20 -72
- package/src/cli/scaffold.ts +25 -31
- package/src/commands/README.md +1 -1
- package/src/commands/checkout/index.ts +17 -7
- package/src/commands/compat/push-args.ts +2 -2
- package/src/commands/index.ts +0 -2
- package/src/commands/login/index.ts +20 -6
- package/src/commands/logout/index.ts +74 -20
- package/src/commands/publish/index.ts +19 -9
- package/src/commands/pull/index.ts +2 -2
- package/src/commands/push/index.ts +2 -2
- package/src/commands/types.ts +2 -0
- package/src/commands/utils.ts +36 -12
- package/src/config/README.md +63 -2
- package/src/config/catalog-include.ts +227 -0
- package/src/config/defaults.ts +24 -14
- package/src/config/env.ts +41 -0
- package/src/config/errors.ts +7 -0
- package/src/config/from-env.ts +26 -0
- package/src/config/helpers.ts +4 -2
- package/src/config/index.ts +7 -4
- package/src/config/loader.ts +168 -50
- package/src/config/resolve-env.ts +94 -0
- package/src/config/runtime.ts +188 -193
- package/src/config/validator.ts +4 -6
- package/src/handlebars.ts +18 -0
- package/src/index.d.ts +2 -2
- package/src/index.ts +124 -34
- package/src/pattern.ts +14 -0
- package/src/pipeline/index.ts +1 -1
- package/src/react.ts +52 -0
- package/src/registry/asset-storage/adapters/vercel-blob.ts +1 -1
- package/src/registry/asset-storage/define.ts +1 -1
- package/src/registry/asset-storage/resolve.ts +6 -3
- package/src/registry/checkout/index.ts +421 -157
- package/src/registry/connection.ts +72 -71
- package/src/registry/db/driver.ts +6 -17
- package/src/registry/db/index.ts +0 -1
- package/src/registry/db/schema.ts +2 -0
- package/src/registry/publish/index.ts +128 -31
- package/src/registry/publish/package.ts +14 -1
- package/src/registry/selection.ts +44 -0
- package/src/store/filesystem.ts +6 -6
- package/src/store/registry.ts +13 -2
- package/src/transformers/plugins/csf-render.ts +4 -2
- package/src/transformers/plugins/ssr-render.ts +15 -5
- package/src/transformers/preview/component/api.ts +13 -1
- package/src/transformers/preview/component/artifacts.ts +8 -4
- package/src/transformers/preview/component/builder.ts +17 -4
- package/src/transformers/preview/component/css.ts +6 -10
- package/src/transformers/preview/component/html.ts +30 -19
- package/src/transformers/preview/component/javascript.ts +1 -3
- package/src/transformers/preview/pattern/builder.ts +33 -20
- package/src/transformers/preview/types.ts +15 -1
- package/src/types/config.ts +76 -40
- package/templates/default/components/button/button.react.handoff.js.tpl +19 -23
- package/templates/default/components/button/button.react.handoff.ts.tpl +22 -22
- package/templates/default/env.tpl +10 -0
- package/templates/default/gitignore.tpl +7 -0
- package/templates/default/handoff.config.js.tpl +21 -182
- package/templates/default/handoff.config.ts.tpl +21 -166
- package/templates/default/handoff.config.with-examples.js.tpl +22 -180
- package/templates/default/handoff.config.with-examples.ts.tpl +22 -164
- package/config/templates/component/template.json +0 -49
- package/config/templates/template.html +0 -7
- package/dist/commands/make/template.d.ts +0 -8
- package/dist/commands/make/template.js +0 -43
- package/dist/config/entries.d.ts +0 -47
- package/dist/config/entries.js +0 -162
- package/dist/config/normalizers/declaration.d.ts +0 -11
- package/dist/config/normalizers/declaration.js +0 -122
- package/dist/config/normalizers/pattern.d.ts +0 -8
- package/dist/config/normalizers/pattern.js +0 -41
- package/dist/declarations/helpers.d.ts +0 -6
- package/dist/declarations/helpers.js +0 -19
- package/dist/declarations/index.d.ts +0 -2
- package/dist/declarations/index.js +0 -9
- package/dist/declarations/types.d.ts +0 -60
- package/src/commands/make/template.ts +0 -46
- package/src/config/entries.ts +0 -175
- package/src/config/normalizers/declaration.ts +0 -179
- package/src/config/normalizers/pattern.ts +0 -59
- package/src/declarations/helpers.ts +0 -36
- package/src/declarations/index.ts +0 -19
- package/src/declarations/types.ts +0 -70
- /package/dist/{declarations → catalog}/types.js +0 -0
|
@@ -377,13 +377,21 @@ After migrations and deployment, open \`/install\` immediately and create the in
|
|
|
377
377
|
The installer verifies the deployment but never changes the schema. An exposed, uninstalled registry
|
|
378
378
|
can be claimed by its first visitor, so do not leave this step unattended.
|
|
379
379
|
|
|
380
|
-
Once installation completes, sign in and authorize a workspace
|
|
380
|
+
Once installation completes, sign in and authorize a workspace. Either approve the CLI in the
|
|
381
|
+
browser:
|
|
381
382
|
|
|
382
383
|
\`\`\`bash
|
|
383
384
|
handoff-app login --url https://registry.example.com
|
|
384
385
|
\`\`\`
|
|
385
386
|
|
|
386
|
-
|
|
387
|
+
or create a token under Account > Access tokens and set it in the workspace environment:
|
|
388
|
+
|
|
389
|
+
\`\`\`bash
|
|
390
|
+
HANDOFF_REGISTRY_URL=https://registry.example.com
|
|
391
|
+
HANDOFF_REGISTRY_ACCESS_TOKEN=hnd_…
|
|
392
|
+
\`\`\`
|
|
393
|
+
|
|
394
|
+
Both produce the same revocable, user-owned credential. The former
|
|
387
395
|
\`HANDOFF_REGISTRY_API_TOKEN\` fixed server secret is no longer accepted.
|
|
388
396
|
|
|
389
397
|
## Run it (self-hosting)
|
|
@@ -695,14 +703,12 @@ const watchApp = (handoff) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
695
703
|
pendingHandlers: new Map(),
|
|
696
704
|
runtimeComponentsWatcher: null,
|
|
697
705
|
runtimeConfigurationWatcher: null,
|
|
698
|
-
|
|
699
|
-
patternDirectoriesWatcher: null,
|
|
706
|
+
catalogDirectoriesWatcher: null,
|
|
700
707
|
};
|
|
701
708
|
(0, watchers_1.watchPublicDirectory)(handoff, wss, state, chokidarConfig);
|
|
702
709
|
(0, watchers_1.watchRuntimeComponents)(handoff, state, (0, watchers_1.getRuntimeComponentsPathsToWatch)(handoff));
|
|
703
710
|
(0, watchers_1.watchRuntimeConfiguration)(handoff, state);
|
|
704
|
-
(0, watchers_1.
|
|
705
|
-
(0, watchers_1.watchPatternDirectories)(handoff, state, chokidarConfig);
|
|
711
|
+
(0, watchers_1.watchCatalogDirectories)(handoff, state, chokidarConfig);
|
|
706
712
|
(0, watchers_1.watchGlobalEntries)(handoff, state, chokidarConfig);
|
|
707
713
|
(0, watchers_1.watchPages)(handoff, chokidarConfig);
|
|
708
714
|
});
|
|
@@ -95,7 +95,9 @@ const persistClientConfig = (handoff_1, ...args_1) => __awaiter(void 0, [handoff
|
|
|
95
95
|
// even when packaged from a connected project. Otherwise a workspace is connected whenever a
|
|
96
96
|
// registry URL resolves — from config/env or a saved device login — so `login` alone surfaces
|
|
97
97
|
// the publish/checkout UI without also requiring HANDOFF_REGISTRY_URL.
|
|
98
|
-
const connected = mode === 'registry'
|
|
98
|
+
const connected = mode === 'registry'
|
|
99
|
+
? false
|
|
100
|
+
: Boolean((yield (0, connection_1.resolveAuthenticatedRegistryConnection)(handoff.config, handoff.workingPath, handoff.getProfile())).url);
|
|
99
101
|
clientConfig.runtime = Object.assign(Object.assign({}, clientConfig.runtime), { mode, connected });
|
|
100
102
|
yield fs_extra_1.default.writeJson(path_1.default.resolve(appPath, 'client.config.json'), { config: clientConfig }, { spaces: 2 });
|
|
101
103
|
yield fs_extra_1.default.writeJson(path_1.default.resolve(appPath, 'runtime.server.json'), buildServerRuntimeConfig(handoff.config, options.runtimeModeOverride), { spaces: 2 });
|
|
@@ -43,12 +43,12 @@ const snapshot_1 = require("../snapshot");
|
|
|
43
43
|
* components. Outer key is component id, inner key is synthetic preview key.
|
|
44
44
|
*/
|
|
45
45
|
const snapshotPatternSynthetics = (handoff, patternId) => {
|
|
46
|
-
var _a, _b, _c
|
|
47
|
-
const components = (
|
|
46
|
+
var _a, _b, _c;
|
|
47
|
+
const components = (_b = (_a = handoff.runtimeConfig) === null || _a === void 0 ? void 0 : _a.entities.components) !== null && _b !== void 0 ? _b : {};
|
|
48
48
|
const prefix = `__pattern_${patternId}_`;
|
|
49
49
|
const result = new Map();
|
|
50
50
|
for (const [componentId, component] of Object.entries(components)) {
|
|
51
|
-
const previews = (
|
|
51
|
+
const previews = (_c = component.internalPatternPreviews) !== null && _c !== void 0 ? _c : {};
|
|
52
52
|
const entries = new Map();
|
|
53
53
|
for (const [key, preview] of Object.entries(previews)) {
|
|
54
54
|
if (key.startsWith(prefix)) {
|
|
@@ -23,11 +23,11 @@ const mapEntryTypeToSegment = (type) => {
|
|
|
23
23
|
};
|
|
24
24
|
exports.mapEntryTypeToSegment = mapEntryTypeToSegment;
|
|
25
25
|
const resolveComponentIdForChangedFile = (handoff, changedFilePath) => {
|
|
26
|
-
var _a, _b, _c
|
|
26
|
+
var _a, _b, _c;
|
|
27
27
|
const normalizedChangedPath = (0, path_2.normalizePathForCompare)(changedFilePath);
|
|
28
|
-
const runtimeComponents = (
|
|
28
|
+
const runtimeComponents = (_b = (_a = handoff.runtimeConfig) === null || _a === void 0 ? void 0 : _a.entities.components) !== null && _b !== void 0 ? _b : {};
|
|
29
29
|
for (const [componentId, componentDef] of Object.entries(runtimeComponents)) {
|
|
30
|
-
const entries = (
|
|
30
|
+
const entries = (_c = componentDef.entries) !== null && _c !== void 0 ? _c : {};
|
|
31
31
|
for (const entryPath of Object.values(entries)) {
|
|
32
32
|
if (!entryPath)
|
|
33
33
|
continue;
|
|
@@ -49,8 +49,8 @@ exports.resolveComponentIdForChangedFile = resolveComponentIdForChangedFile;
|
|
|
49
49
|
const getRuntimeComponentsPathsToWatch = (handoff) => {
|
|
50
50
|
var _a, _b, _c;
|
|
51
51
|
const result = new Map();
|
|
52
|
-
for (const runtimeComponentId of Object.keys((_b = (_a = handoff.runtimeConfig) === null || _a === void 0 ? void 0 : _a.
|
|
53
|
-
const runtimeComponent = handoff.runtimeConfig.
|
|
52
|
+
for (const runtimeComponentId of Object.keys((_b = (_a = handoff.runtimeConfig) === null || _a === void 0 ? void 0 : _a.entities.components) !== null && _b !== void 0 ? _b : {})) {
|
|
53
|
+
const runtimeComponent = handoff.runtimeConfig.entities.components[runtimeComponentId];
|
|
54
54
|
for (const [runtimeComponentEntryType, runtimeComponentEntryPath] of Object.entries((_c = runtimeComponent.entries) !== null && _c !== void 0 ? _c : {})) {
|
|
55
55
|
const normalizedComponentEntryPath = runtimeComponentEntryPath;
|
|
56
56
|
if (fs_extra_1.default.existsSync(normalizedComponentEntryPath)) {
|
|
@@ -4,9 +4,8 @@ export interface WatcherState {
|
|
|
4
4
|
pendingHandlers: Map<string, () => Promise<void>>;
|
|
5
5
|
runtimeComponentsWatcher: chokidar.FSWatcher | null;
|
|
6
6
|
runtimeConfigurationWatcher: chokidar.FSWatcher | null;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
patternDirectoriesWatcher: chokidar.FSWatcher | null;
|
|
7
|
+
/** Watches every registered catalog directory for newly created item subdirectories. */
|
|
8
|
+
catalogDirectoriesWatcher: chokidar.FSWatcher | null;
|
|
10
9
|
}
|
|
11
10
|
/**
|
|
12
11
|
* Schedules a handler for execution with mutual exclusion and per-source
|
|
@@ -36,19 +36,12 @@ export declare const watchRuntimeComponents: (handoff: Handoff, state: WatcherSt
|
|
|
36
36
|
*/
|
|
37
37
|
export declare const watchRuntimeConfiguration: (handoff: Handoff, state: WatcherState) => void;
|
|
38
38
|
/**
|
|
39
|
-
* Watches
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* reference it.
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Watches the parent pattern directories from config.entries.patterns for new
|
|
48
|
-
* patterns being added. The rebuild sequence intentionally differs from
|
|
49
|
-
* watchComponentDirectories because the dependency arrow is reversed: a new
|
|
50
|
-
* pattern references existing components, so we rebuild only the preview
|
|
51
|
-
* segment of those components (to produce the __pattern_* HTML files that
|
|
52
|
-
* injectPatternPreviews registered) before composing the pattern itself.
|
|
39
|
+
* Watches `catalog.include` directories for a new item. A single watcher covers implementations
|
|
40
|
+
* and compositions; the declaration determines which pipeline builds the item.
|
|
41
|
+
*
|
|
42
|
+
* The rebuild differs by kind, and the dependency arrow is reversed between them. A new item with
|
|
43
|
+
* an implementation builds itself, then the compositions that reference it. A new composition
|
|
44
|
+
* rebuilds the preview segment of the items it references, so the synthetic `__pattern_*` HTML
|
|
45
|
+
* exists, and only then composes itself.
|
|
53
46
|
*/
|
|
54
|
-
export declare const
|
|
47
|
+
export declare const watchCatalogDirectories: (handoff: Handoff, state: WatcherState, chokidarConfig: chokidar.WatchOptions) => void;
|
|
@@ -35,7 +35,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
35
35
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
36
36
|
};
|
|
37
37
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
-
exports.
|
|
38
|
+
exports.watchCatalogDirectories = exports.watchRuntimeConfiguration = exports.watchRuntimeComponents = exports.watchGlobalEntries = exports.watchPages = exports.watchAppSource = exports.watchPublicDirectory = exports.mapEntryTypeToSegment = exports.getRuntimeComponentsPathsToWatch = void 0;
|
|
39
39
|
const chokidar_1 = __importDefault(require("chokidar"));
|
|
40
40
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
41
41
|
const path_1 = __importDefault(require("path"));
|
|
@@ -228,9 +228,9 @@ const watchRuntimeComponents = (handoff, state, runtimeComponentPathsToWatch) =>
|
|
|
228
228
|
};
|
|
229
229
|
exports.watchRuntimeComponents = watchRuntimeComponents;
|
|
230
230
|
const rebuildPatternComponentPreviews = (handoff, patternId) => __awaiter(void 0, void 0, void 0, function* () {
|
|
231
|
-
var _a, _b
|
|
232
|
-
const pattern = (
|
|
233
|
-
if (!((
|
|
231
|
+
var _a, _b;
|
|
232
|
+
const pattern = (_a = handoff.runtimeConfig) === null || _a === void 0 ? void 0 : _a.entities.patterns[patternId];
|
|
233
|
+
if (!((_b = pattern === null || pattern === void 0 ? void 0 : pattern.components) === null || _b === void 0 ? void 0 : _b.length))
|
|
234
234
|
return;
|
|
235
235
|
for (const ref of pattern.components) {
|
|
236
236
|
yield (0, builder_1.default)(handoff, ref.id, builder_1.ComponentSegment.Previews);
|
|
@@ -264,18 +264,40 @@ const watchRuntimeConfiguration = (handoff, state) => {
|
|
|
264
264
|
const entryBefore = handoff.getConfigFileEntry(changedFile);
|
|
265
265
|
const strategy = entryBefore ? (0, config_diff_1.getStrategy)(entryBefore.kind) : undefined;
|
|
266
266
|
const handle = entryBefore && strategy ? strategy.capture(handoff, entryBefore.entityId) : undefined;
|
|
267
|
-
|
|
268
|
-
|
|
267
|
+
let reloadFailed = false;
|
|
268
|
+
try {
|
|
269
|
+
handoff.reload();
|
|
270
|
+
yield (0, client_config_1.persistClientConfig)(handoff);
|
|
271
|
+
}
|
|
272
|
+
catch (e) {
|
|
273
|
+
// A failed reload leaves the last config that loaded on the instance, so the
|
|
274
|
+
// re-arm below still names the file that just broke. Without it the file drops
|
|
275
|
+
// out of the watch set - chokidar stops tracking a watched file once it is
|
|
276
|
+
// deleted - and a later valid save is never seen.
|
|
277
|
+
reloadFailed = true;
|
|
278
|
+
logger_1.Logger.error('Error reloading runtime configuration:', e);
|
|
279
|
+
}
|
|
269
280
|
(0, exports.watchRuntimeComponents)(handoff, state, (0, component_1.getRuntimeComponentsPathsToWatch)(handoff));
|
|
270
281
|
(0, exports.watchRuntimeConfiguration)(handoff, state);
|
|
282
|
+
if (reloadFailed) {
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
271
285
|
const entryAfter = handoff.getConfigFileEntry(changedFile);
|
|
272
|
-
const
|
|
273
|
-
|
|
274
|
-
? (0, path_2.normalizePathForCompare)(handoff.getMainConfigFilePath())
|
|
275
|
-
: undefined;
|
|
276
|
-
if (normalizedMainConfig && normalizedChanged === normalizedMainConfig) {
|
|
286
|
+
const kindChanged = !!entryBefore && !!entryAfter && entryBefore.kind !== entryAfter.kind;
|
|
287
|
+
if (handoff.isMainConfigFile(changedFile)) {
|
|
277
288
|
yield (0, builder_1.default)(handoff);
|
|
278
289
|
}
|
|
290
|
+
else if (kindChanged) {
|
|
291
|
+
// The declaration switched between an implementation and a composition. A targeted
|
|
292
|
+
// rebuild would leave the previous lane's summary entry and artifacts behind, so
|
|
293
|
+
// rebuild everything and let the finalizers re-sync.
|
|
294
|
+
yield (0, builder_1.default)(handoff);
|
|
295
|
+
}
|
|
296
|
+
else if ((entryAfter === null || entryAfter === void 0 ? void 0 : entryAfter.kind) === 'unknown') {
|
|
297
|
+
// The file did not parse. It stays watched, so the next valid save rebuilds it.
|
|
298
|
+
// Guessing a lane here would rebuild the wrong entity.
|
|
299
|
+
logger_1.Logger.warn(`Declaration is not valid yet; skipping rebuild: ${changedFile}`);
|
|
300
|
+
}
|
|
279
301
|
else if (handle) {
|
|
280
302
|
yield handle.apply(handoff, entryAfter === null || entryAfter === void 0 ? void 0 : entryAfter.entityId);
|
|
281
303
|
}
|
|
@@ -319,9 +341,14 @@ const watchEntityDirectories = (handoff, state, chokidarConfig, options) => {
|
|
|
319
341
|
if (configPaths.length === 0)
|
|
320
342
|
return;
|
|
321
343
|
const dirsToWatch = [];
|
|
344
|
+
const seenDirs = new Set();
|
|
322
345
|
for (const configPath of configPaths) {
|
|
323
346
|
const resolved = path_1.default.resolve(handoff.workingPath, configPath);
|
|
347
|
+
const key = (0, path_2.normalizePathForCompare)(resolved);
|
|
348
|
+
if (seenDirs.has(key))
|
|
349
|
+
continue;
|
|
324
350
|
if (fs_extra_1.default.existsSync(resolved) && fs_extra_1.default.statSync(resolved).isDirectory()) {
|
|
351
|
+
seenDirs.add(key);
|
|
325
352
|
dirsToWatch.push(resolved);
|
|
326
353
|
}
|
|
327
354
|
}
|
|
@@ -335,13 +362,8 @@ const watchEntityDirectories = (handoff, state, chokidarConfig, options) => {
|
|
|
335
362
|
watcher.on('add', (file) => __awaiter(void 0, void 0, void 0, function* () {
|
|
336
363
|
const basename = path_1.default.basename(file);
|
|
337
364
|
const dirName = path_1.default.basename(path_1.default.dirname(file));
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
// The basename.startsWith(dirName) guard below ensures .ts here only
|
|
341
|
-
// ever matches files named after their parent directory, not arbitrary
|
|
342
|
-
// TypeScript source files.
|
|
343
|
-
const isConfigFile = basename.endsWith('.json') || basename.endsWith('.js') || basename.endsWith('.cjs') || basename.endsWith('.ts');
|
|
344
|
-
const isNewEntity = isConfigFile && basename.startsWith(dirName) && !knownIds.has(dirName);
|
|
365
|
+
const isConfigFile = /\.handoff\.(ts|js|cjs)$/.test(basename);
|
|
366
|
+
const isNewEntity = isConfigFile && !knownIds.has(dirName);
|
|
345
367
|
if (!isNewEntity)
|
|
346
368
|
return;
|
|
347
369
|
yield (0, utils_1.scheduleHandler)(state, `${scheduleKeyPrefix}:${dirName}`, () => __awaiter(void 0, void 0, void 0, function* () {
|
|
@@ -380,57 +402,44 @@ const watchEntityDirectories = (handoff, state, chokidarConfig, options) => {
|
|
|
380
402
|
}));
|
|
381
403
|
};
|
|
382
404
|
/**
|
|
383
|
-
* Watches
|
|
384
|
-
*
|
|
385
|
-
*
|
|
386
|
-
*
|
|
387
|
-
* reference it.
|
|
405
|
+
* Watches `catalog.include` directories for a new item. A single watcher covers implementations
|
|
406
|
+
* and compositions; the declaration determines which pipeline builds the item.
|
|
407
|
+
*
|
|
408
|
+
* The rebuild differs by kind, and the dependency arrow is reversed between them. A new item with
|
|
409
|
+
* an implementation builds itself, then the compositions that reference it. A new composition
|
|
410
|
+
* rebuilds the preview segment of the items it references, so the synthetic `__pattern_*` HTML
|
|
411
|
+
* exists, and only then composes itself.
|
|
388
412
|
*/
|
|
389
|
-
const
|
|
413
|
+
const watchCatalogDirectories = (handoff, state, chokidarConfig) => {
|
|
390
414
|
watchEntityDirectories(handoff, state, chokidarConfig, {
|
|
391
|
-
getConfigPaths: (h) => { var _a, _b; return (_b = (_a = h.config.
|
|
392
|
-
getKnownIds: (h) => {
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
415
|
+
getConfigPaths: (h) => { var _a, _b; return [...((_b = (_a = h.config.catalog) === null || _a === void 0 ? void 0 : _a.include) !== null && _b !== void 0 ? _b : [])]; },
|
|
416
|
+
getKnownIds: (h) => {
|
|
417
|
+
var _a, _b, _c, _d;
|
|
418
|
+
return [
|
|
419
|
+
...Object.keys((_b = (_a = h.runtimeConfig) === null || _a === void 0 ? void 0 : _a.entities.components) !== null && _b !== void 0 ? _b : {}),
|
|
420
|
+
...Object.keys((_d = (_c = h.runtimeConfig) === null || _c === void 0 ? void 0 : _c.entities.patterns) !== null && _d !== void 0 ? _d : {}),
|
|
421
|
+
];
|
|
422
|
+
},
|
|
423
|
+
getWatcher: (s) => s.catalogDirectoriesWatcher,
|
|
424
|
+
setWatcher: (s, w) => {
|
|
425
|
+
s.catalogDirectoriesWatcher = w;
|
|
426
|
+
},
|
|
427
|
+
scheduleKeyPrefix: 'newCatalogItem',
|
|
428
|
+
entityLabel: 'catalog item',
|
|
397
429
|
onDetected: (handoff_1, _a) => __awaiter(void 0, [handoff_1, _a], void 0, function* (handoff, { addedIds }) {
|
|
398
|
-
|
|
430
|
+
const addedComponentIds = addedIds.filter((id) => { var _a; return !!((_a = handoff.runtimeConfig) === null || _a === void 0 ? void 0 : _a.entities.components[id]); });
|
|
431
|
+
const addedPatternIds = addedIds.filter((id) => { var _a; return !!((_a = handoff.runtimeConfig) === null || _a === void 0 ? void 0 : _a.entities.patterns[id]); });
|
|
432
|
+
for (const componentId of addedComponentIds) {
|
|
399
433
|
yield (0, builder_1.default)(handoff, componentId);
|
|
400
434
|
yield (0, config_diff_1.runAllFinalizers)(handoff, { patternRebuildComponentIds: [componentId] });
|
|
401
435
|
}
|
|
402
|
-
|
|
403
|
-
});
|
|
404
|
-
};
|
|
405
|
-
exports.watchComponentDirectories = watchComponentDirectories;
|
|
406
|
-
/**
|
|
407
|
-
* Watches the parent pattern directories from config.entries.patterns for new
|
|
408
|
-
* patterns being added. The rebuild sequence intentionally differs from
|
|
409
|
-
* watchComponentDirectories because the dependency arrow is reversed: a new
|
|
410
|
-
* pattern references existing components, so we rebuild only the preview
|
|
411
|
-
* segment of those components (to produce the __pattern_* HTML files that
|
|
412
|
-
* injectPatternPreviews registered) before composing the pattern itself.
|
|
413
|
-
*/
|
|
414
|
-
const watchPatternDirectories = (handoff, state, chokidarConfig) => {
|
|
415
|
-
watchEntityDirectories(handoff, state, chokidarConfig, {
|
|
416
|
-
getConfigPaths: (h) => { var _a, _b; return (_b = (_a = h.config.entries) === null || _a === void 0 ? void 0 : _a.patterns) !== null && _b !== void 0 ? _b : []; },
|
|
417
|
-
getKnownIds: (h) => { var _a, _b, _c; return Object.keys((_c = (_b = (_a = h.runtimeConfig) === null || _a === void 0 ? void 0 : _a.entries) === null || _b === void 0 ? void 0 : _b.patterns) !== null && _c !== void 0 ? _c : {}); },
|
|
418
|
-
getWatcher: (s) => s.patternDirectoriesWatcher,
|
|
419
|
-
setWatcher: (s, w) => { s.patternDirectoriesWatcher = w; },
|
|
420
|
-
scheduleKeyPrefix: 'newPattern',
|
|
421
|
-
entityLabel: 'pattern',
|
|
422
|
-
onDetected: (handoff_1, _a) => __awaiter(void 0, [handoff_1, _a], void 0, function* (handoff, { addedIds }) {
|
|
423
|
-
// Rebuild only the previews segment for each component the new pattern
|
|
424
|
-
// references. Their JS/CSS/structure are unchanged — only the new
|
|
425
|
-
// synthetic preview HTML files need to be generated so that buildPatterns
|
|
426
|
-
// can assemble the pattern from them.
|
|
427
|
-
for (const patternId of addedIds) {
|
|
436
|
+
for (const patternId of addedPatternIds) {
|
|
428
437
|
yield rebuildPatternComponentPreviews(handoff, patternId);
|
|
429
438
|
}
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
439
|
+
if (addedPatternIds.length > 0) {
|
|
440
|
+
yield (0, patterns_1.buildPatterns)(handoff, { onlyPatternIds: new Set(addedPatternIds) });
|
|
441
|
+
}
|
|
433
442
|
}),
|
|
434
443
|
});
|
|
435
444
|
};
|
|
436
|
-
exports.
|
|
445
|
+
exports.watchCatalogDirectories = watchCatalogDirectories;
|
|
@@ -35,7 +35,11 @@ const CACHE_VERSION = '1.0.0';
|
|
|
35
35
|
* Gets the path to the build cache file
|
|
36
36
|
*/
|
|
37
37
|
function getCachePath(handoff) {
|
|
38
|
-
|
|
38
|
+
// Two profiles share one project id and can build different output, so the profile has to name
|
|
39
|
+
// the cache file. One shared cache would serve the other profile's components.
|
|
40
|
+
const profile = handoff.getProfile();
|
|
41
|
+
const fileName = profile ? `build-cache.${profile}.json` : 'build-cache.json';
|
|
42
|
+
return path_1.default.resolve(handoff.modulePath, '.handoff', handoff.getProjectId(), '.cache', fileName);
|
|
39
43
|
}
|
|
40
44
|
/**
|
|
41
45
|
* Loads the build cache from disk
|
|
@@ -136,14 +140,20 @@ function haveGlobalDepsChanged(cached, current) {
|
|
|
136
140
|
* Gets all file paths that should be tracked for a component
|
|
137
141
|
*/
|
|
138
142
|
function getComponentFilePaths(handoff, componentId) {
|
|
139
|
-
var _a, _b, _c, _d
|
|
140
|
-
const runtimeComponent = (
|
|
143
|
+
var _a, _b, _c, _d;
|
|
144
|
+
const runtimeComponent = (_a = handoff.runtimeConfig) === null || _a === void 0 ? void 0 : _a.entities.components[componentId];
|
|
141
145
|
if (!runtimeComponent) {
|
|
142
146
|
return { files: [] };
|
|
143
147
|
}
|
|
144
148
|
const files = [];
|
|
145
149
|
let templateDir;
|
|
146
150
|
const componentDirs = new Set();
|
|
151
|
+
// A catalog item declares its previews in the declaration file, and its implementation can sit
|
|
152
|
+
// outside the item directory. The directories derived from `entries` below can therefore miss the
|
|
153
|
+
// declaration, which would leave a preview edit uncached.
|
|
154
|
+
if (runtimeComponent.path) {
|
|
155
|
+
componentDirs.add((0, path_2.normalizePathForCompare)(runtimeComponent.path));
|
|
156
|
+
}
|
|
147
157
|
// Add entry files and infer component directories from resolved entry paths
|
|
148
158
|
const entries = runtimeComponent.entries;
|
|
149
159
|
if (entries) {
|
|
@@ -169,7 +179,7 @@ function getComponentFilePaths(handoff, componentId) {
|
|
|
169
179
|
componentDirs.add((0, path_2.normalizePathForCompare)(path_1.default.dirname(templatePath)));
|
|
170
180
|
}
|
|
171
181
|
}
|
|
172
|
-
catch (
|
|
182
|
+
catch (_e) {
|
|
173
183
|
// File doesn't exist, still add to track
|
|
174
184
|
files.push(templatePath);
|
|
175
185
|
componentDirs.add((0, path_2.normalizePathForCompare)(path_1.default.dirname(templatePath)));
|
|
@@ -178,19 +188,9 @@ function getComponentFilePaths(handoff, componentId) {
|
|
|
178
188
|
}
|
|
179
189
|
// Find the config file path for this component using exact config filename + directory matching.
|
|
180
190
|
const configPaths = handoff.getConfigFilePaths();
|
|
181
|
-
const expectedConfigFileNames = new Set([
|
|
182
|
-
`${componentId}.handoff.ts`,
|
|
183
|
-
`${componentId}.handoff.js`,
|
|
184
|
-
`${componentId}.handoff.cjs`,
|
|
185
|
-
`${componentId}.handoff.json`,
|
|
186
|
-
`${componentId}.json`,
|
|
187
|
-
`${componentId}.js`,
|
|
188
|
-
`${componentId}.cjs`,
|
|
189
|
-
]);
|
|
190
191
|
const matchingConfigPath = configPaths.find((configPath) => {
|
|
191
192
|
const configFileName = path_1.default.basename(configPath);
|
|
192
|
-
|
|
193
|
-
if (!expectedConfigFileNames.has(configFileName) && !isModernDeclaration) {
|
|
193
|
+
if (!/\.handoff\.(ts|js|cjs)$/.test(configFileName)) {
|
|
194
194
|
return false;
|
|
195
195
|
}
|
|
196
196
|
if (componentDirs.size === 0) {
|
|
@@ -208,7 +208,7 @@ function getComponentFilePaths(handoff, componentId) {
|
|
|
208
208
|
// what processComponents must render. Without tracking these files here, the
|
|
209
209
|
// cache would incorrectly consider the component unchanged and skip the preview
|
|
210
210
|
// rebuild, leaving buildPatterns unable to find the required HTML fragments.
|
|
211
|
-
const runtimePatterns = (
|
|
211
|
+
const runtimePatterns = (_c = (_b = handoff.runtimeConfig) === null || _b === void 0 ? void 0 : _b.entities.patterns) !== null && _c !== void 0 ? _c : {};
|
|
212
212
|
for (const configPath of configPaths) {
|
|
213
213
|
const entry = handoff.getConfigFileEntry(configPath);
|
|
214
214
|
if ((entry === null || entry === void 0 ? void 0 : entry.kind) !== 'pattern')
|
|
@@ -216,7 +216,7 @@ function getComponentFilePaths(handoff, componentId) {
|
|
|
216
216
|
const pattern = runtimePatterns[entry.entityId];
|
|
217
217
|
if (!pattern)
|
|
218
218
|
continue;
|
|
219
|
-
if ((
|
|
219
|
+
if ((_d = pattern.components) === null || _d === void 0 ? void 0 : _d.some((ref) => ref.id === componentId)) {
|
|
220
220
|
files.push(configPath);
|
|
221
221
|
}
|
|
222
222
|
}
|
|
@@ -280,24 +280,24 @@ function hasComponentChanged(cached, current) {
|
|
|
280
280
|
*/
|
|
281
281
|
function checkOutputExists(handoff, componentId) {
|
|
282
282
|
return __awaiter(this, void 0, void 0, function* () {
|
|
283
|
-
var _a, _b, _c, _d
|
|
283
|
+
var _a, _b, _c, _d;
|
|
284
284
|
const outputDirectory = path_1.default.resolve(handoff.workingPath, 'public/api/component');
|
|
285
285
|
const componentPath = path_1.default.resolve(outputDirectory, `${componentId}.json`);
|
|
286
286
|
if (!(yield fs_extra_1.default.pathExists(componentPath))) {
|
|
287
287
|
return false;
|
|
288
288
|
}
|
|
289
|
-
const runtimeComponent = (
|
|
289
|
+
const runtimeComponent = (_a = handoff.runtimeConfig) === null || _a === void 0 ? void 0 : _a.entities.components[componentId];
|
|
290
290
|
const previewIds = new Set([
|
|
291
|
-
...Object.keys((
|
|
292
|
-
...Object.keys((
|
|
291
|
+
...Object.keys((_b = runtimeComponent === null || runtimeComponent === void 0 ? void 0 : runtimeComponent.previews) !== null && _b !== void 0 ? _b : {}),
|
|
292
|
+
...Object.keys((_c = runtimeComponent === null || runtimeComponent === void 0 ? void 0 : runtimeComponent.internalPatternPreviews) !== null && _c !== void 0 ? _c : {}),
|
|
293
293
|
]);
|
|
294
294
|
try {
|
|
295
295
|
const component = yield fs_extra_1.default.readJson(componentPath);
|
|
296
|
-
for (const previewId of Object.keys((
|
|
296
|
+
for (const previewId of Object.keys((_d = component === null || component === void 0 ? void 0 : component.previews) !== null && _d !== void 0 ? _d : {})) {
|
|
297
297
|
previewIds.add(previewId);
|
|
298
298
|
}
|
|
299
299
|
}
|
|
300
|
-
catch (
|
|
300
|
+
catch (_e) {
|
|
301
301
|
return false;
|
|
302
302
|
}
|
|
303
303
|
for (const previewId of previewIds) {
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type RendererKind } from './renderers';
|
|
2
|
+
import type { CatalogItem, CatalogItemInput } from './types';
|
|
3
|
+
/** Keeps declarations as plain data that the loader can read without evaluating Handoff. */
|
|
4
|
+
export declare const createCatalogItem: <TArgs = Record<string, unknown>>(input: CatalogItemInput, renderer?: RendererKind) => CatalogItem<TArgs>;
|
|
5
|
+
/** Validate module declarations too, because JavaScript callers have no compile-time checks. */
|
|
6
|
+
export declare function validateCatalogItem(value: unknown): asserts value is CatalogItem;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createCatalogItem = void 0;
|
|
4
|
+
exports.validateCatalogItem = validateCatalogItem;
|
|
5
|
+
const renderers_1 = require("./renderers");
|
|
6
|
+
const MISSING_RENDERER_HELP = "An implementation needs a renderer. Import defineCatalogItem from 'handoff-app/react' or 'handoff-app/handlebars'.";
|
|
7
|
+
/** Handles the shared implementation forms here so renderer entry points only supply types and a renderer. */
|
|
8
|
+
const stampImplementation = (implementation, renderer) => {
|
|
9
|
+
if (typeof implementation === 'string') {
|
|
10
|
+
return { renderer, file: implementation };
|
|
11
|
+
}
|
|
12
|
+
const descriptor = implementation;
|
|
13
|
+
if (descriptor && typeof descriptor === 'object' && typeof descriptor.format === 'string' && typeof descriptor.file === 'string') {
|
|
14
|
+
return { renderer, format: descriptor.format, file: descriptor.file };
|
|
15
|
+
}
|
|
16
|
+
return { renderer, value: implementation };
|
|
17
|
+
};
|
|
18
|
+
/** Keeps declarations as plain data that the loader can read without evaluating Handoff. */
|
|
19
|
+
const createCatalogItem = (input, renderer) => {
|
|
20
|
+
const hasImplementation = input.implementation !== undefined && input.implementation !== null;
|
|
21
|
+
const hasComposition = Array.isArray(input.composition) && input.composition.length > 0;
|
|
22
|
+
if (hasImplementation && hasComposition) {
|
|
23
|
+
throw new Error('A catalog item declares either "implementation" or "composition", not both.');
|
|
24
|
+
}
|
|
25
|
+
if (!hasImplementation && !hasComposition) {
|
|
26
|
+
throw new Error('A catalog item must declare "implementation" or "composition".');
|
|
27
|
+
}
|
|
28
|
+
if (!hasImplementation) {
|
|
29
|
+
validateCatalogItem(input);
|
|
30
|
+
return input;
|
|
31
|
+
}
|
|
32
|
+
if (!renderer) {
|
|
33
|
+
throw new Error(MISSING_RENDERER_HELP);
|
|
34
|
+
}
|
|
35
|
+
const item = Object.assign(Object.assign({}, input), { implementation: stampImplementation(input.implementation, renderer) });
|
|
36
|
+
validateCatalogItem(item);
|
|
37
|
+
return item;
|
|
38
|
+
};
|
|
39
|
+
exports.createCatalogItem = createCatalogItem;
|
|
40
|
+
/** Validate module declarations too, because JavaScript callers have no compile-time checks. */
|
|
41
|
+
function validateCatalogItem(value) {
|
|
42
|
+
const help = ' Use defineCatalogItem. See UPGRADE.md#catalog-items.';
|
|
43
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
44
|
+
throw new Error('Invalid catalog item.' + help);
|
|
45
|
+
const item = value;
|
|
46
|
+
for (const key of ['previews', 'components', 'renderer', 'sourceFormat', 'should_do', 'should_not_do', 'title']) {
|
|
47
|
+
if (key in item)
|
|
48
|
+
throw new Error(`Catalog field "${key}" is no longer supported.` + help);
|
|
49
|
+
}
|
|
50
|
+
for (const key of ['component', 'story', 'template']) {
|
|
51
|
+
if (item.entries && key in item.entries)
|
|
52
|
+
throw new Error(`entries.${key} was removed. Use implementation.` + help);
|
|
53
|
+
}
|
|
54
|
+
if (item.composition !== undefined) {
|
|
55
|
+
if (item.implementation !== undefined || !Array.isArray(item.composition) || !item.composition.length) {
|
|
56
|
+
throw new Error('Declare either an implementation or a non-empty composition.' + help);
|
|
57
|
+
}
|
|
58
|
+
for (const ref of item.composition) {
|
|
59
|
+
if (!ref || typeof ref.ref !== 'string' || !ref.ref.trim() || 'id' in ref) {
|
|
60
|
+
throw new Error('Composition members require "ref", the catalog item id.' + help);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const source = item.implementation;
|
|
66
|
+
if (!source || !(0, renderers_1.isRendererKind)(source.renderer))
|
|
67
|
+
throw new Error('implementation must state a supported renderer.' + help);
|
|
68
|
+
if (source.format !== undefined &&
|
|
69
|
+
(!(0, renderers_1.isSourceFormat)(source.format) || !renderers_1.SOURCE_FORMATS[source.format].renderers.includes(source.renderer))) {
|
|
70
|
+
throw new Error('implementation.format is not supported by this renderer.' + help);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** A source file plus the export the implementation is bound to. */
|
|
2
|
+
export type ResolvedSource = {
|
|
3
|
+
file: string;
|
|
4
|
+
/** `default`, a named export, or `*` for a namespace import. */
|
|
5
|
+
exportName: string;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Resolves a relative module specifier to a file. Node and bundlers probe extensions and index
|
|
9
|
+
* files; `path.resolve` alone does not. A bare specifier (a package, or a tsconfig path alias) is
|
|
10
|
+
* not resolvable against the workspace, so it returns undefined.
|
|
11
|
+
*/
|
|
12
|
+
export declare const resolveModulePath: (specifier: string, fromFile: string) => string | undefined;
|
|
13
|
+
/**
|
|
14
|
+
* Resolves the value a property is bound to back to its source file.
|
|
15
|
+
*
|
|
16
|
+
* Two callers use this: `implementation:` inside a catalog declaration, and `component:` inside a
|
|
17
|
+
* CSF meta object. In both cases only the value is authored, so the file has to be recovered from
|
|
18
|
+
* the import that produced it.
|
|
19
|
+
*/
|
|
20
|
+
export declare const resolvePropertySource: (sourcePath: string, property: string) => ResolvedSource | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* Last-resort lookup when the import cannot be resolved: the single component file sitting next to
|
|
23
|
+
* the declaration. Story files and the declaration itself are excluded.
|
|
24
|
+
*/
|
|
25
|
+
export declare const findSiblingComponentFile: (directory: string, declarationPath: string) => string | undefined;
|
|
26
|
+
/** True when `file` sits inside `directory`. Publish rejects any path that escapes the entity directory. */
|
|
27
|
+
export declare const isInsideDirectory: (file: string, directory: string) => boolean;
|