@ankhorage/devtools 1.12.0 → 1.13.0
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 +1 -1
- package/dist/tools/agents/index.js +13 -0
- package/dist/tools/skills/assets/ankhorage-project-structure/SKILL.md +21 -0
- package/dist/tools/skills/assets/zora-designer/SKILL.md +3 -0
- package/dist/tools/skills/assets/zora-designer/references/workflow.md +3 -0
- package/dist/tools/skills/assets/zora-designer/scripts/owner-api.ts +74 -5
- package/dist/tools/skills/zoraDesignerOwnerFixtures.d.ts +6 -0
- package/dist/tools/skills/zoraDesignerOwnerFixtures.js +144 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -188,7 +188,7 @@ The canonical workflow, VS Code, and skill files are packaged with `@ankhorage/d
|
|
|
188
188
|
|
|
189
189
|
## Managed agent instructions
|
|
190
190
|
|
|
191
|
-
`ankh devtools agents sync` owns the repository-root `AGENTS.md`. The shared instructions are intentionally small and stable. The target repository's package name and description are rendered from `package.json`; the remaining content defines the unconditional current-architecture policy
|
|
191
|
+
`ankh devtools agents sync` owns the repository-root `AGENTS.md`. The shared instructions are intentionally small and stable. The target repository's package name and description are rendered from `package.json`; the remaining content defines the unconditional current-architecture policy, directs structural work to the managed project-structure skill, and requires the canonical build, type, lint, Knip, Changeset, and formatting commands before pull request creation.
|
|
192
192
|
|
|
193
193
|
Only the current Ankhorage architecture is supported. Managed instructions reject deprecated APIs, compatibility aliases, shims, dual old/new paths, historical-state fallbacks, and migrations whose sole purpose is obsolete state. A canonical cross-package change requires affected repositories to update to the latest released public API.
|
|
194
194
|
|
|
@@ -39,6 +39,19 @@ For directory ownership, package boundaries, architectural profiles, ports and a
|
|
|
39
39
|
entrypoints, or cross-repository structural work, load and follow
|
|
40
40
|
\`.agents/skills/ankhorage-project-structure/SKILL.md\`.
|
|
41
41
|
|
|
42
|
+
## Pull requests
|
|
43
|
+
|
|
44
|
+
Before creating a pull request, run all of these commands in this order and resolve every failure:
|
|
45
|
+
|
|
46
|
+
\`\`\`sh
|
|
47
|
+
bun run build
|
|
48
|
+
bun run check-types
|
|
49
|
+
bun run lint
|
|
50
|
+
bun run knip:test
|
|
51
|
+
bun run changeset
|
|
52
|
+
bun run format
|
|
53
|
+
\`\`\`
|
|
54
|
+
|
|
42
55
|
## Skill scripts
|
|
43
56
|
|
|
44
57
|
Scripts inside an Agent Skill must always be TypeScript files with the \`.ts\` extension.
|
|
@@ -76,6 +76,7 @@ src/
|
|
|
76
76
|
utils/
|
|
77
77
|
types/
|
|
78
78
|
<topic>.ts
|
|
79
|
+
constants.ts
|
|
79
80
|
utils/
|
|
80
81
|
```
|
|
81
82
|
|
|
@@ -154,6 +155,26 @@ For example, `selectRoute.ts` can own a non-exported `SelectRouteInput` directly
|
|
|
154
155
|
Types used by several local navigation operations belong together in `src/types/navigation.ts`.
|
|
155
156
|
A navigation binding exchanged by Studio and Navigator belongs in `@ankhorage/contracts/navigator`.
|
|
156
157
|
|
|
158
|
+
## Constant ownership
|
|
159
|
+
|
|
160
|
+
Constants are static declarations, not utility implementations. Do not create one exported
|
|
161
|
+
constant per constant-named file under `utils/`.
|
|
162
|
+
|
|
163
|
+
1. **Used by one implementation module:** keep the constant private in the module that owns it.
|
|
164
|
+
2. **Reused only inside a feature:** group related constants in that feature's `constants.ts`.
|
|
165
|
+
3. **Shared across features in one package:** group related package metadata, static policy values,
|
|
166
|
+
and other constants in `src/constants.ts`.
|
|
167
|
+
|
|
168
|
+
A `constants.ts` module may export multiple related constants. Keep it cohesive by ownership and
|
|
169
|
+
purpose; it is not a package-wide catch-all. Split constants when they have different owners, not
|
|
170
|
+
merely to create one file per export.
|
|
171
|
+
|
|
172
|
+
For example, Navigator's
|
|
173
|
+
[`src/utils/NAVIGATOR_PACKAGE_METADATA.ts`](https://github.com/ankhorage/navigator/blob/main/src/utils/NAVIGATOR_PACKAGE_METADATA.ts)
|
|
174
|
+
and
|
|
175
|
+
[`src/utils/NAVIGATOR_ROUTER_POLICY.ts`](https://github.com/ankhorage/navigator/blob/main/src/utils/NAVIGATOR_ROUTER_POLICY.ts)
|
|
176
|
+
belong together in `ankhorage/navigator/src/constants.ts`.
|
|
177
|
+
|
|
157
178
|
## Utilities
|
|
158
179
|
|
|
159
180
|
`utils/` is the only utility directory name. Do not create `shared/`, `helper/`, `helpers/`,
|
|
@@ -42,6 +42,9 @@ types, ZORA elements, events, recipes, and version provenance. Never copy owner
|
|
|
42
42
|
schemas, token inventories, color algorithms, action types, or manifest implementations into this
|
|
43
43
|
skill.
|
|
44
44
|
|
|
45
|
+
The inspection composes metadata-only descriptors from every installed `@ankhorage/zora-*` plugin;
|
|
46
|
+
use those plugin elements exactly like ZORA core elements and keep their package provenance.
|
|
47
|
+
|
|
45
48
|
Compile chosen values with the same helper before composing screens. Inspect both computed modes,
|
|
46
49
|
including their resolved Surface themes and all owner diagnostics. Never hand-calculate a value the
|
|
47
50
|
owner exposes.
|
|
@@ -18,6 +18,9 @@ navigator types, ZORA elements, or events. Resolve explicit user input before pr
|
|
|
18
18
|
existing brief values, category recommendations, and global defaults. Record the origin of every
|
|
19
19
|
resolved decision.
|
|
20
20
|
|
|
21
|
+
Installed `@ankhorage/zora-*` packages contribute their metadata-only plugin descriptors to this
|
|
22
|
+
same composed element catalog; do not maintain a second plugin list in the skill.
|
|
23
|
+
|
|
21
24
|
## 2. Ask in dependency order
|
|
22
25
|
|
|
23
26
|
Advance through this sequence. Skip only a value already supplied or reliably discovered.
|
|
@@ -58,7 +58,7 @@ interface ZoraThemeApi extends Record<string, unknown> {
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
interface EventMetadata extends Record<string, unknown> {
|
|
61
|
-
description
|
|
61
|
+
description?: string;
|
|
62
62
|
eventType: string;
|
|
63
63
|
label: string;
|
|
64
64
|
payloadFields?: unknown;
|
|
@@ -84,6 +84,10 @@ interface RecipeMetadata extends Record<string, unknown> {
|
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
interface ZoraMetadataApi extends Record<string, unknown> {
|
|
87
|
+
composeZoraPluginMetadata: (plugins: readonly Record<string, unknown>[]) => {
|
|
88
|
+
componentMeta: Record<string, ComponentMetadata | undefined>;
|
|
89
|
+
};
|
|
90
|
+
ZORA_CORE_PLUGIN_METADATA: Record<string, unknown>;
|
|
87
91
|
ZORA_COMPONENT_META: Record<string, ComponentMetadata | undefined>;
|
|
88
92
|
ZORA_THEME_RECIPE_META: Record<string, RecipeMetadata | undefined>;
|
|
89
93
|
}
|
|
@@ -119,7 +123,7 @@ const OWNER_RELEASES = {
|
|
|
119
123
|
colorTheory: { packageName: '@ankhorage/color-theory', minimumVersion: '0.3.0' },
|
|
120
124
|
contracts: { packageName: '@ankhorage/contracts', minimumVersion: '10.1.0' },
|
|
121
125
|
templates: { packageName: '@ankhorage/templates', minimumVersion: '9.3.0' },
|
|
122
|
-
zora: { packageName: '@ankhorage/zora', minimumVersion: '4.
|
|
126
|
+
zora: { packageName: '@ankhorage/zora', minimumVersion: '4.3.0' },
|
|
123
127
|
};
|
|
124
128
|
|
|
125
129
|
const OWNER_REQUIREMENTS = {
|
|
@@ -155,7 +159,12 @@ const OWNER_REQUIREMENTS = {
|
|
|
155
159
|
zoraMetadata: {
|
|
156
160
|
...OWNER_RELEASES.zora,
|
|
157
161
|
specifier: '@ankhorage/zora/metadata',
|
|
158
|
-
exports: [
|
|
162
|
+
exports: [
|
|
163
|
+
'composeZoraPluginMetadata',
|
|
164
|
+
'ZORA_COMPONENT_META',
|
|
165
|
+
'ZORA_CORE_PLUGIN_METADATA',
|
|
166
|
+
'ZORA_THEME_RECIPE_META',
|
|
167
|
+
],
|
|
159
168
|
},
|
|
160
169
|
};
|
|
161
170
|
|
|
@@ -171,27 +180,81 @@ export async function loadOwnerApis(targetDirectory = process.cwd()) {
|
|
|
171
180
|
const templates = await loadOwnerModule(targetDirectory, OWNER_REQUIREMENTS.templates);
|
|
172
181
|
const zoraTheme = await loadOwnerModule(targetDirectory, OWNER_REQUIREMENTS.zoraTheme);
|
|
173
182
|
const zoraMetadata = await loadOwnerModule(targetDirectory, OWNER_REQUIREMENTS.zoraMetadata);
|
|
183
|
+
const installedPluginMetadata = await loadInstalledZoraPluginMetadata(targetDirectory);
|
|
174
184
|
assertColorTheoryApi(colorTheory.module);
|
|
175
185
|
assertContractsApi(contracts.module);
|
|
176
186
|
assertTemplatesApi(templates.module);
|
|
177
187
|
assertZoraThemeApi(zoraTheme.module);
|
|
178
188
|
assertZoraMetadataApi(zoraMetadata.module);
|
|
189
|
+
const composedZoraMetadata = zoraMetadata.module.composeZoraPluginMetadata([
|
|
190
|
+
zoraMetadata.module.ZORA_CORE_PLUGIN_METADATA,
|
|
191
|
+
...installedPluginMetadata.map((entry) => entry.metadata),
|
|
192
|
+
]);
|
|
193
|
+
assertRecord(composedZoraMetadata, 'composed ZORA plugin metadata');
|
|
194
|
+
assertRecord(composedZoraMetadata.componentMeta, 'composed ZORA component metadata');
|
|
179
195
|
|
|
180
196
|
return {
|
|
181
197
|
colorTheory: colorTheory.module,
|
|
182
198
|
contracts: contracts.module,
|
|
183
199
|
templates: templates.module,
|
|
184
200
|
zoraTheme: zoraTheme.module,
|
|
185
|
-
zoraMetadata:
|
|
201
|
+
zoraMetadata: {
|
|
202
|
+
...zoraMetadata.module,
|
|
203
|
+
ZORA_COMPONENT_META: composedZoraMetadata.componentMeta,
|
|
204
|
+
},
|
|
186
205
|
versions: {
|
|
187
206
|
colorTheory: colorTheory.version,
|
|
188
207
|
contracts: contracts.version,
|
|
189
208
|
templates: templates.version,
|
|
190
209
|
zora: zoraTheme.version,
|
|
210
|
+
plugins: Object.fromEntries(
|
|
211
|
+
installedPluginMetadata.map((entry) => [entry.packageName, entry.version]),
|
|
212
|
+
),
|
|
191
213
|
},
|
|
192
214
|
};
|
|
193
215
|
}
|
|
194
216
|
|
|
217
|
+
/*** Load metadata-only descriptors for every installed ZORA plugin declared by the target package. */
|
|
218
|
+
async function loadInstalledZoraPluginMetadata(
|
|
219
|
+
targetDirectory: string,
|
|
220
|
+
): Promise<{ metadata: Record<string, unknown>; packageName: string; version: string }[]> {
|
|
221
|
+
const targetManifestPath = join(resolve(targetDirectory), 'package.json');
|
|
222
|
+
const targetManifest: unknown = JSON.parse(await readFile(targetManifestPath, 'utf8'));
|
|
223
|
+
assertRecord(targetManifest, 'Target package manifest');
|
|
224
|
+
const packageNames = new Set<string>();
|
|
225
|
+
if (typeof targetManifest.name === 'string') packageNames.add(targetManifest.name);
|
|
226
|
+
for (const field of ['dependencies', 'devDependencies', 'peerDependencies']) {
|
|
227
|
+
const dependencies = targetManifest[field];
|
|
228
|
+
if (!isRecord(dependencies)) continue;
|
|
229
|
+
for (const packageName of Object.keys(dependencies)) packageNames.add(packageName);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const loaded: { metadata: Record<string, unknown>; packageName: string; version: string }[] = [];
|
|
233
|
+
for (const packageName of [...packageNames].filter(isZoraPluginPackage).sort()) {
|
|
234
|
+
const minimumVersion =
|
|
235
|
+
packageName === '@ankhorage/zora-chess'
|
|
236
|
+
? '0.2.0'
|
|
237
|
+
: packageName === '@ankhorage/zora-tabletop'
|
|
238
|
+
? '0.1.0'
|
|
239
|
+
: '0.0.0';
|
|
240
|
+
const requirement: OwnerRequirement = {
|
|
241
|
+
packageName,
|
|
242
|
+
minimumVersion,
|
|
243
|
+
specifier: `${packageName}/metadata`,
|
|
244
|
+
exports: ['ZORA_PLUGIN_METADATA'],
|
|
245
|
+
};
|
|
246
|
+
const plugin = await loadOwnerModule(targetDirectory, requirement);
|
|
247
|
+
const metadata = plugin.module.ZORA_PLUGIN_METADATA;
|
|
248
|
+
assertRecord(metadata, `${packageName} ZORA plugin metadata`);
|
|
249
|
+
loaded.push({ metadata, packageName, version: plugin.version });
|
|
250
|
+
}
|
|
251
|
+
return loaded;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function isZoraPluginPackage(packageName: string): boolean {
|
|
255
|
+
return packageName.startsWith('@ankhorage/zora-') && packageName !== '@ankhorage/zora';
|
|
256
|
+
}
|
|
257
|
+
|
|
195
258
|
/*** Load only Contracts for tooling that runs before another owner package has been built. */
|
|
196
259
|
export async function loadContractsApi(targetDirectory = process.cwd()): Promise<ContractsApi> {
|
|
197
260
|
const loaded = await loadOwnerModule(targetDirectory, OWNER_REQUIREMENTS.contracts);
|
|
@@ -661,6 +724,10 @@ function assertZoraThemeApi(value: Record<string, unknown>): asserts value is Zo
|
|
|
661
724
|
|
|
662
725
|
/*** Narrow released ZORA metadata into only the fields the orchestration needs. */
|
|
663
726
|
function assertZoraMetadataApi(value: Record<string, unknown>): asserts value is ZoraMetadataApi {
|
|
727
|
+
if (typeof value.composeZoraPluginMetadata !== 'function') {
|
|
728
|
+
throw new Error('composeZoraPluginMetadata must be a function.');
|
|
729
|
+
}
|
|
730
|
+
assertRecord(value.ZORA_CORE_PLUGIN_METADATA, 'ZORA_CORE_PLUGIN_METADATA');
|
|
664
731
|
assertRecord(value.ZORA_COMPONENT_META, 'ZORA_COMPONENT_META');
|
|
665
732
|
for (const [name, metadata] of Object.entries(value.ZORA_COMPONENT_META)) {
|
|
666
733
|
assertComponentMetadata(metadata, name);
|
|
@@ -696,7 +763,9 @@ function assertEventMetadata(value: unknown, name: string): asserts value is Eve
|
|
|
696
763
|
assertRecord(value, `ZORA event metadata ${name}`);
|
|
697
764
|
assertNonEmptyString(value.eventType, `ZORA event metadata ${name}.eventType`);
|
|
698
765
|
assertNonEmptyString(value.label, `ZORA event metadata ${name}.label`);
|
|
699
|
-
|
|
766
|
+
if (value.description !== undefined) {
|
|
767
|
+
assertNonEmptyString(value.description, `ZORA event metadata ${name}.description`);
|
|
768
|
+
}
|
|
700
769
|
}
|
|
701
770
|
|
|
702
771
|
/*** Validate one theme recipe metadata entry and its supported fields. */
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare function createThemeConfig(): Record<string, unknown>;
|
|
2
|
+
export declare const TEMPLATES_FIXTURE_SOURCE: string;
|
|
3
|
+
export declare const COLOR_THEORY_FIXTURE_SOURCE = "\nexport const COLOR_HARMONIES = ['monochromatic', 'complementary'];\nexport const COLOR_HARMONY_CATALOG = [\n { id: 'monochromatic', label: 'Monochromatic', description: 'One hue.' },\n { id: 'complementary', label: 'Complementary', description: 'Opposing hues.' },\n];\n";
|
|
4
|
+
export declare const CONTRACTS_FIXTURE_SOURCE = "\nexport const APP_CATEGORIES = ['business_productivity'];\nexport const NAVIGATOR_TYPES = ['stack', 'tabs', 'drawer'];\n";
|
|
5
|
+
export declare const ZORA_THEME_FIXTURE_SOURCE = "\nexport const compileZoraTheme = (themeConfig) => ({\n themeConfig,\n light: { surfaceTheme: { mode: 'light' }, diagnostics: [] },\n dark: { surfaceTheme: { mode: 'dark' }, diagnostics: [] },\n diagnostics: [],\n});\n";
|
|
6
|
+
export declare const ZORA_METADATA_FIXTURE_SOURCE = "\nexport const ZORA_COMPONENT_META = {\n View: { name: 'View', directManifestNode: true, allowedChildren: ['Text', 'Box'], props: {} },\n Box: { name: 'Box', directManifestNode: true, allowedChildren: [], props: {} },\n Text: {\n name: 'Text',\n directManifestNode: true,\n allowedChildren: [],\n props: { text: { type: 'string' } },\n events: {\n press: {\n eventType: 'text.press',\n label: 'Press',\n description: 'Text was pressed.',\n },\n },\n },\n MissingElement: {\n name: 'MissingElement',\n directManifestNode: true,\n allowedChildren: [],\n manifestPolicy: { kind: 'unresolved-element', availability: 'draft-only', releaseGate: 'blocked' },\n blueprint: { defaultProps: { requestedCapability: 'Unresolved', reason: 'No exact element.' } },\n props: {\n requestedCapability: { type: 'string' },\n reason: { type: 'string' },\n evidenceId: { type: 'string' },\n },\n },\n};\nexport const ZORA_CORE_PLUGIN_METADATA = {\n packageName: '@ankhorage/zora',\n componentMeta: ZORA_COMPONENT_META,\n extensionHosts: ['View', 'Box'],\n};\nexport const composeZoraPluginMetadata = (plugins) => {\n const componentMeta = {};\n const extensionHosts = new Set();\n for (const plugin of [...plugins].sort((left, right) => left.packageName.localeCompare(right.packageName))) {\n Object.assign(componentMeta, plugin.componentMeta);\n for (const host of plugin.extensionHosts ?? []) extensionHosts.add(host);\n }\n for (const plugin of plugins) {\n for (const placement of plugin.placements ?? []) {\n for (const parent of placement.parents) {\n if (!extensionHosts.has(parent)) throw new Error('Invalid extension host');\n componentMeta[parent] = {\n ...componentMeta[parent],\n allowedChildren: [...componentMeta[parent].allowedChildren, placement.child],\n };\n }\n }\n }\n return { componentMeta };\n};\nexport const ZORA_THEME_RECIPE_META = {\n Card: {\n name: 'Card',\n kind: 'component',\n fields: { variant: { type: 'choice', options: ['filled', 'outlined'] } },\n },\n};\n";
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
export function createThemeConfig() {
|
|
2
|
+
return {
|
|
3
|
+
id: 'evidence-theme',
|
|
4
|
+
name: 'Evidence Theme',
|
|
5
|
+
light: { primaryColor: '#2563EB', harmony: 'complementary' },
|
|
6
|
+
dark: { primaryColor: '#2563EB', harmony: 'complementary' },
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
export const TEMPLATES_FIXTURE_SOURCE = `
|
|
10
|
+
export const CATEGORY_PRESETS = {
|
|
11
|
+
business_productivity: {
|
|
12
|
+
category: 'business_productivity',
|
|
13
|
+
label: 'Business',
|
|
14
|
+
recommendedPrimaryColors: ['#2563EB'],
|
|
15
|
+
recommendedHarmonies: ['complementary'],
|
|
16
|
+
tonePairs: { light: 'jewel-on-neutral-light', dark: 'pastel-on-neutral-dark' },
|
|
17
|
+
density: 'compact',
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
export const TONE_PAIR_CATALOG = [];
|
|
21
|
+
export const resolveTonePair = () => null;
|
|
22
|
+
export const resolveCategoryDesignPreset = (category, theme = {}) => ({ category, theme });
|
|
23
|
+
const themeConfig = ${JSON.stringify(createThemeConfig())};
|
|
24
|
+
export const compileCategoryDesign = (category) => ({
|
|
25
|
+
category,
|
|
26
|
+
themeConfig,
|
|
27
|
+
diagnostics: [],
|
|
28
|
+
computedTheme: {
|
|
29
|
+
themeConfig,
|
|
30
|
+
light: { surfaceTheme: { mode: 'light' }, diagnostics: [] },
|
|
31
|
+
dark: { surfaceTheme: { mode: 'dark' }, diagnostics: [] },
|
|
32
|
+
diagnostics: [],
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
export const composeCategoryAppManifest = (input) => ({
|
|
36
|
+
manifest: {
|
|
37
|
+
metadata: {
|
|
38
|
+
name: input.name ?? 'Generated App',
|
|
39
|
+
slug: input.slug ?? 'generated-app',
|
|
40
|
+
version: input.version ?? '1.0.0',
|
|
41
|
+
category: input.category,
|
|
42
|
+
themeId: 'evidence-theme',
|
|
43
|
+
},
|
|
44
|
+
themes: [themeConfig],
|
|
45
|
+
activeThemeId: 'evidence-theme',
|
|
46
|
+
infra: { modules: input.modules ?? [] },
|
|
47
|
+
navigator: input.navigator,
|
|
48
|
+
screens: input.screens,
|
|
49
|
+
settings: { localization: { defaultLocale: 'en', locales: ['en'] } },
|
|
50
|
+
},
|
|
51
|
+
diagnostics: [],
|
|
52
|
+
status: input.authoringState === 'release' ? 'ready' : 'blocked',
|
|
53
|
+
authoringState: input.authoringState,
|
|
54
|
+
});
|
|
55
|
+
export const validateTemplateManifest = (manifest) => ({
|
|
56
|
+
manifest,
|
|
57
|
+
diagnostics: [],
|
|
58
|
+
status: 'ready',
|
|
59
|
+
authoringState: 'release',
|
|
60
|
+
});
|
|
61
|
+
export const assertTemplateManifestReady = (composition) => composition.manifest;
|
|
62
|
+
`;
|
|
63
|
+
export const COLOR_THEORY_FIXTURE_SOURCE = `
|
|
64
|
+
export const COLOR_HARMONIES = ['monochromatic', 'complementary'];
|
|
65
|
+
export const COLOR_HARMONY_CATALOG = [
|
|
66
|
+
{ id: 'monochromatic', label: 'Monochromatic', description: 'One hue.' },
|
|
67
|
+
{ id: 'complementary', label: 'Complementary', description: 'Opposing hues.' },
|
|
68
|
+
];
|
|
69
|
+
`;
|
|
70
|
+
export const CONTRACTS_FIXTURE_SOURCE = `
|
|
71
|
+
export const APP_CATEGORIES = ['business_productivity'];
|
|
72
|
+
export const NAVIGATOR_TYPES = ['stack', 'tabs', 'drawer'];
|
|
73
|
+
`;
|
|
74
|
+
export const ZORA_THEME_FIXTURE_SOURCE = `
|
|
75
|
+
export const compileZoraTheme = (themeConfig) => ({
|
|
76
|
+
themeConfig,
|
|
77
|
+
light: { surfaceTheme: { mode: 'light' }, diagnostics: [] },
|
|
78
|
+
dark: { surfaceTheme: { mode: 'dark' }, diagnostics: [] },
|
|
79
|
+
diagnostics: [],
|
|
80
|
+
});
|
|
81
|
+
`;
|
|
82
|
+
export const ZORA_METADATA_FIXTURE_SOURCE = `
|
|
83
|
+
export const ZORA_COMPONENT_META = {
|
|
84
|
+
View: { name: 'View', directManifestNode: true, allowedChildren: ['Text', 'Box'], props: {} },
|
|
85
|
+
Box: { name: 'Box', directManifestNode: true, allowedChildren: [], props: {} },
|
|
86
|
+
Text: {
|
|
87
|
+
name: 'Text',
|
|
88
|
+
directManifestNode: true,
|
|
89
|
+
allowedChildren: [],
|
|
90
|
+
props: { text: { type: 'string' } },
|
|
91
|
+
events: {
|
|
92
|
+
press: {
|
|
93
|
+
eventType: 'text.press',
|
|
94
|
+
label: 'Press',
|
|
95
|
+
description: 'Text was pressed.',
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
MissingElement: {
|
|
100
|
+
name: 'MissingElement',
|
|
101
|
+
directManifestNode: true,
|
|
102
|
+
allowedChildren: [],
|
|
103
|
+
manifestPolicy: { kind: 'unresolved-element', availability: 'draft-only', releaseGate: 'blocked' },
|
|
104
|
+
blueprint: { defaultProps: { requestedCapability: 'Unresolved', reason: 'No exact element.' } },
|
|
105
|
+
props: {
|
|
106
|
+
requestedCapability: { type: 'string' },
|
|
107
|
+
reason: { type: 'string' },
|
|
108
|
+
evidenceId: { type: 'string' },
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
export const ZORA_CORE_PLUGIN_METADATA = {
|
|
113
|
+
packageName: '@ankhorage/zora',
|
|
114
|
+
componentMeta: ZORA_COMPONENT_META,
|
|
115
|
+
extensionHosts: ['View', 'Box'],
|
|
116
|
+
};
|
|
117
|
+
export const composeZoraPluginMetadata = (plugins) => {
|
|
118
|
+
const componentMeta = {};
|
|
119
|
+
const extensionHosts = new Set();
|
|
120
|
+
for (const plugin of [...plugins].sort((left, right) => left.packageName.localeCompare(right.packageName))) {
|
|
121
|
+
Object.assign(componentMeta, plugin.componentMeta);
|
|
122
|
+
for (const host of plugin.extensionHosts ?? []) extensionHosts.add(host);
|
|
123
|
+
}
|
|
124
|
+
for (const plugin of plugins) {
|
|
125
|
+
for (const placement of plugin.placements ?? []) {
|
|
126
|
+
for (const parent of placement.parents) {
|
|
127
|
+
if (!extensionHosts.has(parent)) throw new Error('Invalid extension host');
|
|
128
|
+
componentMeta[parent] = {
|
|
129
|
+
...componentMeta[parent],
|
|
130
|
+
allowedChildren: [...componentMeta[parent].allowedChildren, placement.child],
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return { componentMeta };
|
|
136
|
+
};
|
|
137
|
+
export const ZORA_THEME_RECIPE_META = {
|
|
138
|
+
Card: {
|
|
139
|
+
name: 'Card',
|
|
140
|
+
kind: 'component',
|
|
141
|
+
fields: { variant: { type: 'choice', options: ['filled', 'outlined'] } },
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
`;
|
package/package.json
CHANGED