@astryxdesign/cli 0.6.3-canary.f22695a → 0.6.3
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 -2
- package/api/build/build.type.d.mts +2 -2
- package/api/build/build.type.mjs +2 -2
- package/api/component/component.type.d.mts +6 -6
- package/api/component/component.type.mjs +19 -19
- package/api/discover/discover.type.d.mts +4 -4
- package/api/discover/discover.type.mjs +10 -10
- package/api/docs/_adapter.d.mts +24 -37
- package/api/docs/_adapter.mjs +83 -169
- package/api/docs/detail/detail.mjs +63 -14
- package/api/docs/detail/section/section.d.mts +1 -1
- package/api/docs/detail/section/section.mjs +20 -44
- package/api/docs/detail/section/section.test.mjs +0 -41
- package/api/docs/docs.d.mts +2 -7
- package/api/docs/docs.doc.mjs +10 -27
- package/api/docs/docs.mjs +9 -16
- package/api/docs/docs.test.mjs +0 -6
- package/api/docs/docs.type.d.mts +3 -40
- package/api/docs/docs.type.mjs +8 -36
- package/api/docs/integrationDocs.test.mjs +0 -106
- package/api/doctor/doctor.d.mts +0 -48
- package/api/doctor/doctor.mjs +0 -232
- package/api/doctor/doctor.test.mjs +0 -196
- package/api/hook/hook.type.d.mts +3 -3
- package/api/hook/hook.type.mjs +11 -11
- package/api/hook/list/list.d.mts +1 -1
- package/api/integration/add-contribution.mjs +3 -5
- package/api/integration/add-contribution.test.mjs +4 -4
- package/api/integration/integration-authoring.type.d.mts +1 -1
- package/api/integration/pack-check.mjs +7 -49
- package/api/integration/pack-check.test.mjs +0 -249
- package/api/search/search.d.mts +1 -1
- package/api/search/search.mjs +5 -5
- package/api/search/search.type.d.mts +2 -2
- package/api/search/search.type.mjs +1 -1
- package/api/swizzle/swizzle.type.d.mts +2 -2
- package/api/swizzle/swizzle.type.mjs +2 -2
- package/api/template/template.d.mts +1 -1
- package/api/template/template.type.d.mts +6 -6
- package/api/template/template.type.mjs +12 -12
- package/api/theme/build/build.mjs +6 -20
- package/api/theme/build/build.test.mjs +0 -127
- package/api/theme/palette/generate/generate.mjs +1 -1
- package/api/theme/palette/generate/generator.d.mts +13 -10
- package/api/theme/palette/generate/generator.mjs +3 -7
- package/api/theme/theme.type.d.mts +11 -170
- package/api/theme/theme.type.mjs +27 -94
- package/api/upgrade/_adapter.mjs +5 -71
- package/api/upgrade/upgrade.doc.mjs +3 -4
- package/api/upgrade/upgrade.type.d.mts +5 -5
- package/api/upgrade/upgrade.type.mjs +11 -11
- package/assets/codemods/integration-discovery.mjs +2 -40
- package/assets/codemods/integration-discovery.test.mjs +0 -58
- package/assets/codemods/transforms/v0.3.0/__tests__/unwrap-authoring-factories.test.mjs +5 -27
- package/assets/codemods/transforms/v0.3.0/unwrap-authoring-factories.mjs +5 -20
- package/assets/docs/README.md +0 -9
- package/assets/docs/cli-integrations.doc.mjs +15 -86
- package/assets/docs/styling-libraries.doc.mjs +1 -1
- package/assets/docs/working-with-ai.doc.mjs +1 -1
- package/assets/templates/blocks/components/Toolbar/ToolbarTableFilter.doc.mjs +3 -19
- package/assets/templates/blocks/components/Toolbar/ToolbarTableFilter.tsx +65 -383
- package/authoring/_shared/contract.ts +0 -22
- package/authoring/codemod/codemod.doc.mjs +1 -6
- package/authoring/codemod/parse.d.mts +8 -8
- package/authoring/codemod/parse.mjs +6 -8
- package/authoring/config/parse.d.mts +13 -13
- package/authoring/config/parse.mjs +8 -8
- package/authoring/config/type.ts +3 -3
- package/authoring/debug/parse.d.mts +5 -5
- package/authoring/debug/parse.mjs +3 -3
- package/authoring/doctypes/_schema.d.mts +23 -788
- package/authoring/doctypes/_schema.mjs +39 -492
- package/authoring/doctypes/base/type.ts +0 -40
- package/authoring/doctypes/command/command.doc.mjs +2 -3
- package/authoring/doctypes/command/parse.d.mts +2 -2
- package/authoring/doctypes/command/parse.mjs +1 -1
- package/authoring/doctypes/command/type.ts +2 -3
- package/authoring/doctypes/component/component.doc.mjs +3 -6
- package/authoring/doctypes/component/parse.d.mts +2 -2
- package/authoring/doctypes/component/parse.mjs +1 -1
- package/authoring/doctypes/component/type.ts +3 -4
- package/authoring/doctypes/enum/parse.d.mts +2 -2
- package/authoring/doctypes/enum/parse.mjs +1 -1
- package/authoring/doctypes/enum/type.ts +1 -3
- package/authoring/doctypes/function/function.doc.mjs +0 -4
- package/authoring/doctypes/function/parse.d.mts +2 -2
- package/authoring/doctypes/function/parse.mjs +1 -1
- package/authoring/doctypes/function/type.ts +2 -6
- package/authoring/doctypes/hook/hook.doc.mjs +0 -4
- package/authoring/doctypes/hook/parse.d.mts +2 -2
- package/authoring/doctypes/hook/parse.mjs +1 -1
- package/authoring/doctypes/hook/type.ts +2 -3
- package/authoring/doctypes/legacy.d.mts +6 -8
- package/authoring/doctypes/legacy.mjs +4 -5
- package/authoring/doctypes/parse.d.mts +18 -20
- package/authoring/doctypes/parse.mjs +10 -16
- package/authoring/doctypes/parse.test.mjs +3 -77
- package/authoring/doctypes/reference/parse.d.mts +2 -2
- package/authoring/doctypes/reference/parse.mjs +5 -8
- package/authoring/doctypes/reference/reference.doc.mjs +4 -17
- package/authoring/doctypes/reference/type.ts +5 -51
- package/authoring/doctypes/schema/parse.d.mts +2 -2
- package/authoring/doctypes/schema/parse.mjs +1 -1
- package/authoring/doctypes/schema/type.ts +2 -3
- package/authoring/doctypes/template/parse.d.mts +1 -92
- package/authoring/doctypes/template/parse.mjs +2 -36
- package/authoring/doctypes/template/parse.test.mjs +2 -8
- package/authoring/doctypes/template/template.doc.mjs +0 -4
- package/authoring/doctypes/template/type.ts +2 -5
- package/authoring/doctypes/types.ts +9 -10
- package/authoring/gap-report/parse.d.mts +10 -10
- package/authoring/gap-report/parse.mjs +6 -6
- package/authoring/gap-report/type.ts +1 -1
- package/authoring/index.d.mts +0 -1
- package/authoring/index.d.ts +17 -49
- package/authoring/index.mjs +0 -1
- package/authoring/integration/integration.doc.mjs +6 -13
- package/authoring/integration/parse.d.mts +2 -2
- package/authoring/integration/parse.mjs +1 -1
- package/authoring/integration/parse.test.mjs +1 -10
- package/authoring/integration/schema.d.mts +4 -6
- package/authoring/integration/schema.mjs +3 -9
- package/authoring/integration/type.ts +6 -23
- package/authoring/shadcn/receipt.d.mts +6 -6
- package/clients/cli/commands/docs.doc.mjs +3 -13
- package/clients/cli/commands/docs.mjs +21 -121
- package/clients/cli/commands/docs.test.mjs +0 -88
- package/clients/cli/commands/integration-authoring.test.mjs +9 -13
- package/clients/cli/commands/theme-palette-generate.doc.mjs +4 -8
- package/clients/cli/commands/upgrade.doc.mjs +2 -2
- package/clients/cli/formatters/index.mjs +1 -162
- package/clients/cli/formatters/index.test.mjs +0 -91
- package/clients/cli/lib/manifest.mjs +2 -7
- package/foundation/config/project.mjs +6 -21
- package/foundation/discovery/component-discovery.d.mts +1 -1
- package/foundation/discovery/component-discovery.mjs +1 -2
- package/foundation/discovery/docs-discovery.d.mts +4 -11
- package/foundation/discovery/docs-discovery.mjs +88 -208
- package/foundation/discovery/docs-discovery.test.mjs +13 -279
- package/foundation/discovery/template-adapter.mjs +1 -2
- package/foundation/integrations/autolink.mjs +5 -12
- package/foundation/integrations/integration-warnings.mjs +0 -6
- package/foundation/integrations/integrations.d.mts +2 -46
- package/foundation/integrations/integrations.mjs +8 -167
- package/foundation/integrations/integrations.test.mjs +1 -384
- package/foundation/integrations/validate-contributions.d.mts +0 -2
- package/foundation/integrations/validate-contributions.mjs +0 -10
- package/foundation/response/json-contract.test.mjs +17 -46
- package/foundation/response/response-types.doc.mjs +1 -6
- package/package.json +11 -9
- package/api/docs/compiled-topics.test.mjs +0 -78
- package/api/docs/index/index.d.mts +0 -18
- package/api/docs/index/index.mjs +0 -32
- package/api/docs/index/index.test.mjs +0 -62
- package/api/upgrade/project-context.test.mjs +0 -272
- package/assets/docs/authoring.doc.mjs +0 -14
- package/assets/templates/blocks/components/Timer/TimerFormats.doc.mjs +0 -14
- package/assets/templates/blocks/components/Timer/TimerFormats.tsx +0 -34
- package/assets/templates/blocks/components/Timer/TimerInline.doc.mjs +0 -14
- package/assets/templates/blocks/components/Timer/TimerInline.tsx +0 -14
- package/assets/templates/blocks/components/Timer/TimerShowcase.doc.mjs +0 -13
- package/assets/templates/blocks/components/Timer/TimerShowcase.tsx +0 -47
- package/assets/templates/blocks/components/Timer/TimerTypography.doc.mjs +0 -14
- package/assets/templates/blocks/components/Timer/TimerTypography.tsx +0 -31
- package/authoring/doctypes/base/graph-fields.doc.d.mts +0 -9
- package/authoring/doctypes/base/graph-fields.doc.mjs +0 -62
- package/authoring/doctypes/load-contract.test.mjs +0 -207
- package/authoring/doctypes/namespace/namespace.doc.d.mts +0 -9
- package/authoring/doctypes/namespace/namespace.doc.mjs +0 -132
- package/authoring/doctypes/namespace/parse.d.mts +0 -12
- package/authoring/doctypes/namespace/parse.mjs +0 -25
- package/authoring/doctypes/namespace/parse.test.mjs +0 -165
- package/authoring/doctypes/namespace/type.ts +0 -71
- package/authoring/identity/identity.doc.d.mts +0 -9
- package/authoring/identity/identity.doc.mjs +0 -61
- package/authoring/identity/type.ts +0 -132
- package/foundation/discovery/authoring-self-docs.d.mts +0 -69
- package/foundation/discovery/authoring-self-docs.mjs +0 -214
- package/foundation/discovery/authoring-self-docs.test.mjs +0 -154
- package/foundation/discovery/docs-output-budget.d.mts +0 -28
- package/foundation/discovery/docs-output-budget.mjs +0 -50
- package/foundation/discovery/docs-section-key.d.mts +0 -98
- package/foundation/discovery/docs-section-key.mjs +0 -221
- package/foundation/discovery/docs-section-key.test.mjs +0 -224
- package/foundation/doc-compiler/compile.d.mts +0 -162
- package/foundation/doc-compiler/compile.mjs +0 -262
- package/foundation/doc-compiler/doc-compiler.test.mjs +0 -687
- package/foundation/doc-compiler/ir.d.mts +0 -9
- package/foundation/doc-compiler/ir.mjs +0 -287
- package/foundation/doc-compiler/lenses.d.mts +0 -33
- package/foundation/doc-compiler/lenses.mjs +0 -127
- package/foundation/identity/provider-identity.d.mts +0 -90
- package/foundation/identity/provider-identity.mjs +0 -320
- package/foundation/identity/provider-identity.test.mjs +0 -254
- package/foundation/identity/providers.d.mts +0 -7
- package/foundation/identity/providers.mjs +0 -16
- package/foundation/integrations/provider-conflicts.test.mjs +0 -125
|
@@ -1,320 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @file Canonical provider, artifact, and immutable-instance identity helpers.
|
|
5
|
-
*
|
|
6
|
-
* IDs use versioned, RFC 3986-escaped path segments. Provider package names are
|
|
7
|
-
* case-insensitive and normalize to lowercase. Artifact names preserve case and
|
|
8
|
-
* normalize Unicode to NFC.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
/** @typedef {import('../../authoring/identity/type').ArtifactId} ArtifactId */
|
|
12
|
-
/** @typedef {import('../../authoring/identity/type').ArtifactIdentity} ArtifactIdentity */
|
|
13
|
-
/** @typedef {import('../../authoring/identity/type').AuthoredDoc} AuthoredDoc */
|
|
14
|
-
/** @typedef {import('../../authoring/identity/type').AuthoredDocEntry} AuthoredDocEntry */
|
|
15
|
-
/** @typedef {import('../../authoring/doctypes/base/type').AuthoredDocKind} AuthoredDocKind */
|
|
16
|
-
/** @typedef {import('../../authoring/identity/type').ContentDigest} ContentDigest */
|
|
17
|
-
/** @typedef {import('../../authoring/identity/type').ContributionKind} ContributionKind */
|
|
18
|
-
/** @typedef {import('../../authoring/identity/type').DocId} DocId */
|
|
19
|
-
/** @typedef {import('../../authoring/identity/type').ProviderId} ProviderId */
|
|
20
|
-
/** @typedef {import('../../authoring/identity/type').ProviderInstance} ProviderInstance */
|
|
21
|
-
/** @typedef {import('../../authoring/identity/type').ProviderInstanceId} ProviderInstanceId */
|
|
22
|
-
|
|
23
|
-
const ARTIFACT_PREFIX = 'astryx:artifact:v1/';
|
|
24
|
-
const PROVIDER_INSTANCE_PREFIX = 'astryx:provider-instance:v1/';
|
|
25
|
-
const PACKAGE_NAME_RE =
|
|
26
|
-
/^(?:@[a-z0-9][a-z0-9._~!*'()-]*\/)?[a-z0-9][a-z0-9._~!*'()-]*$/u;
|
|
27
|
-
const SHA256_RE = /^sha256:[0-9a-f]{64}$/u;
|
|
28
|
-
|
|
29
|
-
/** @type {ReadonlySet<ContributionKind>} */
|
|
30
|
-
const CONTRIBUTION_KINDS = new Set([
|
|
31
|
-
'component',
|
|
32
|
-
'function',
|
|
33
|
-
'generic',
|
|
34
|
-
'page',
|
|
35
|
-
'block',
|
|
36
|
-
'schema',
|
|
37
|
-
'command',
|
|
38
|
-
'enum',
|
|
39
|
-
'namespace',
|
|
40
|
-
'theme',
|
|
41
|
-
'codemod',
|
|
42
|
-
'agent-doc',
|
|
43
|
-
]);
|
|
44
|
-
|
|
45
|
-
/** @type {ReadonlySet<AuthoredDocKind>} */
|
|
46
|
-
const DOC_KINDS = new Set([
|
|
47
|
-
'component',
|
|
48
|
-
'function',
|
|
49
|
-
'generic',
|
|
50
|
-
'page',
|
|
51
|
-
'block',
|
|
52
|
-
'schema',
|
|
53
|
-
'command',
|
|
54
|
-
'enum',
|
|
55
|
-
'namespace',
|
|
56
|
-
]);
|
|
57
|
-
|
|
58
|
-
/** RFC 3986 path-segment encoding with uppercase escapes. */
|
|
59
|
-
/** @param {string} value @returns {string} */
|
|
60
|
-
function encodeSegment(value) {
|
|
61
|
-
return encodeURIComponent(value).replace(
|
|
62
|
-
/[!'()*]/gu,
|
|
63
|
-
character => `%${character.charCodeAt(0).toString(16).toUpperCase()}`,
|
|
64
|
-
);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/** Decode one identity segment or throw a stable, readable error. */
|
|
68
|
-
/** @param {string} value @param {string} label @returns {string} */
|
|
69
|
-
function decodeSegment(value, label) {
|
|
70
|
-
try {
|
|
71
|
-
return decodeURIComponent(value);
|
|
72
|
-
} catch {
|
|
73
|
-
throw new Error(`${label} contains invalid percent escaping.`);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/** Normalize a required identity string without changing meaningful case. */
|
|
78
|
-
/** @param {unknown} value @param {string} label @returns {string} */
|
|
79
|
-
function normalizeName(value, label) {
|
|
80
|
-
if (typeof value !== 'string' || value.trim() === '') {
|
|
81
|
-
throw new Error(`${label} must be a non-empty string.`);
|
|
82
|
-
}
|
|
83
|
-
return value.trim().normalize('NFC');
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Normalize an npm package name into a ProviderId.
|
|
88
|
-
* @param {string} packageName
|
|
89
|
-
* @returns {ProviderId}
|
|
90
|
-
*/
|
|
91
|
-
export function normalizeProviderId(packageName) {
|
|
92
|
-
const normalized = normalizeName(packageName, 'Provider ID').toLowerCase();
|
|
93
|
-
if (!PACKAGE_NAME_RE.test(normalized)) {
|
|
94
|
-
throw new Error(
|
|
95
|
-
`Provider ID "${packageName}" must be a bare npm package name.`,
|
|
96
|
-
);
|
|
97
|
-
}
|
|
98
|
-
return /** @type {ProviderId} */ (normalized);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Normalize a SHA-256 digest.
|
|
103
|
-
* @param {string} digest
|
|
104
|
-
* @returns {ContentDigest}
|
|
105
|
-
*/
|
|
106
|
-
export function normalizeContentDigest(digest) {
|
|
107
|
-
const normalized = normalizeName(digest, 'Content digest').toLowerCase();
|
|
108
|
-
if (!SHA256_RE.test(normalized)) {
|
|
109
|
-
throw new Error(
|
|
110
|
-
'Content digest must use sha256:<64 lowercase hex characters>.',
|
|
111
|
-
);
|
|
112
|
-
}
|
|
113
|
-
return /** @type {ContentDigest} */ (normalized);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Build a stable provider + contribution kind + artifact-name ID.
|
|
118
|
-
* @param {string} provider
|
|
119
|
-
* @param {ContributionKind} kind
|
|
120
|
-
* @param {string} name
|
|
121
|
-
* @returns {ArtifactId}
|
|
122
|
-
*/
|
|
123
|
-
export function createArtifactId(provider, kind, name) {
|
|
124
|
-
const providerId = normalizeProviderId(provider);
|
|
125
|
-
if (!CONTRIBUTION_KINDS.has(kind)) {
|
|
126
|
-
throw new Error(`Unknown contribution kind "${String(kind)}".`);
|
|
127
|
-
}
|
|
128
|
-
const stableName = normalizeName(name, 'Artifact name');
|
|
129
|
-
return /** @type {ArtifactId} */ (
|
|
130
|
-
`${ARTIFACT_PREFIX}${encodeSegment(providerId)}/${kind}/${encodeSegment(stableName)}`
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Build a stable document ID from provider + authored kind + stable name.
|
|
136
|
-
* @param {string} provider
|
|
137
|
-
* @param {AuthoredDocKind} kind
|
|
138
|
-
* @param {string} name
|
|
139
|
-
* @returns {DocId}
|
|
140
|
-
*/
|
|
141
|
-
export function createDocId(provider, kind, name) {
|
|
142
|
-
if (!DOC_KINDS.has(kind)) {
|
|
143
|
-
throw new Error(`Unknown authored doc kind "${String(kind)}".`);
|
|
144
|
-
}
|
|
145
|
-
return /** @type {DocId} */ (createArtifactId(provider, kind, name));
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* Build a normalized logical artifact record.
|
|
150
|
-
* @param {string} provider
|
|
151
|
-
* @param {ContributionKind} kind
|
|
152
|
-
* @param {string} name
|
|
153
|
-
* @returns {ArtifactIdentity}
|
|
154
|
-
*/
|
|
155
|
-
export function createArtifactIdentity(provider, kind, name) {
|
|
156
|
-
const providerId = normalizeProviderId(provider);
|
|
157
|
-
const stableName = normalizeName(name, 'Artifact name');
|
|
158
|
-
return Object.freeze({
|
|
159
|
-
id: createArtifactId(providerId, kind, stableName),
|
|
160
|
-
providerId,
|
|
161
|
-
kind,
|
|
162
|
-
name: stableName,
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Parse and canonicalize an ArtifactId.
|
|
168
|
-
* @param {string} value
|
|
169
|
-
* @returns {ArtifactIdentity}
|
|
170
|
-
*/
|
|
171
|
-
export function parseArtifactId(value) {
|
|
172
|
-
if (typeof value !== 'string' || !value.startsWith(ARTIFACT_PREFIX)) {
|
|
173
|
-
throw new Error(`Artifact ID must start with "${ARTIFACT_PREFIX}".`);
|
|
174
|
-
}
|
|
175
|
-
const segments = value.slice(ARTIFACT_PREFIX.length).split('/');
|
|
176
|
-
if (segments.length !== 3) {
|
|
177
|
-
throw new Error(
|
|
178
|
-
'Artifact ID must contain provider, kind, and name segments.',
|
|
179
|
-
);
|
|
180
|
-
}
|
|
181
|
-
const provider = decodeSegment(segments[0], 'Artifact provider');
|
|
182
|
-
const kind = decodeSegment(segments[1], 'Artifact kind');
|
|
183
|
-
const name = decodeSegment(segments[2], 'Artifact name');
|
|
184
|
-
if (!CONTRIBUTION_KINDS.has(/** @type {ContributionKind} */ (kind))) {
|
|
185
|
-
throw new Error(`Unknown contribution kind "${kind}".`);
|
|
186
|
-
}
|
|
187
|
-
const identity = createArtifactIdentity(
|
|
188
|
-
provider,
|
|
189
|
-
/** @type {ContributionKind} */ (kind),
|
|
190
|
-
name,
|
|
191
|
-
);
|
|
192
|
-
if (identity.id !== value) {
|
|
193
|
-
throw new Error('Artifact ID is not in canonical serialized form.');
|
|
194
|
-
}
|
|
195
|
-
return identity;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* Build one immutable provider instance.
|
|
200
|
-
* @param {{providerId: string, packageName: string, packageVersion: string, sourceDigest: string}} input
|
|
201
|
-
* @returns {ProviderInstance}
|
|
202
|
-
*/
|
|
203
|
-
export function createProviderInstance(input) {
|
|
204
|
-
const providerId = normalizeProviderId(input.providerId);
|
|
205
|
-
const packageName = normalizeProviderId(input.packageName);
|
|
206
|
-
const packageVersion = normalizeName(input.packageVersion, 'Package version');
|
|
207
|
-
const sourceDigest = normalizeContentDigest(input.sourceDigest);
|
|
208
|
-
const id = /** @type {ProviderInstanceId} */ (
|
|
209
|
-
`${PROVIDER_INSTANCE_PREFIX}${encodeSegment(providerId)}/${encodeSegment(packageName)}/${encodeSegment(packageVersion)}/${encodeSegment(sourceDigest)}`
|
|
210
|
-
);
|
|
211
|
-
return Object.freeze({
|
|
212
|
-
id,
|
|
213
|
-
providerId,
|
|
214
|
-
packageName,
|
|
215
|
-
packageVersion,
|
|
216
|
-
sourceDigest,
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
/** Normalize a package-relative source path to forward slashes. */
|
|
221
|
-
/** @param {unknown} value @returns {string} */
|
|
222
|
-
function normalizeSourcePath(value) {
|
|
223
|
-
const normalized = normalizeName(value, 'Source path').replaceAll('\\', '/');
|
|
224
|
-
const segments = normalized.split('/');
|
|
225
|
-
if (
|
|
226
|
-
normalized.startsWith('/') ||
|
|
227
|
-
/^[A-Za-z]:\//u.test(normalized) ||
|
|
228
|
-
segments.some(
|
|
229
|
-
segment => segment === '' || segment === '.' || segment === '..',
|
|
230
|
-
)
|
|
231
|
-
) {
|
|
232
|
-
throw new Error('Source path must be a normalized package-relative path.');
|
|
233
|
-
}
|
|
234
|
-
return normalized;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
/** Infer an unstamped legacy document's kind from its required shape. */
|
|
238
|
-
/** @param {AuthoredDoc} authored @returns {AuthoredDocKind} */
|
|
239
|
-
function authoredKindOf(authored) {
|
|
240
|
-
if (authored.type != null) return authored.type;
|
|
241
|
-
if ('params' in authored && 'returns' in authored) return 'function';
|
|
242
|
-
if (
|
|
243
|
-
'props' in authored ||
|
|
244
|
-
'components' in authored ||
|
|
245
|
-
'subComponentOf' in authored
|
|
246
|
-
) {
|
|
247
|
-
return 'component';
|
|
248
|
-
}
|
|
249
|
-
if ('sections' in authored && 'title' in authored) return 'generic';
|
|
250
|
-
throw new Error('Cannot infer the kind of an unstamped authored document.');
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
/** Clone and recursively freeze plain authored data. */
|
|
254
|
-
/** @template T @param {T} value @returns {T} */
|
|
255
|
-
function frozenClone(value) {
|
|
256
|
-
const clone = structuredClone(value);
|
|
257
|
-
const seen = new WeakSet();
|
|
258
|
-
/** @param {unknown} current */
|
|
259
|
-
const freeze = current => {
|
|
260
|
-
if (
|
|
261
|
-
current == null ||
|
|
262
|
-
typeof current !== 'object' ||
|
|
263
|
-
Object.isFrozen(current) ||
|
|
264
|
-
seen.has(current)
|
|
265
|
-
) {
|
|
266
|
-
return;
|
|
267
|
-
}
|
|
268
|
-
seen.add(current);
|
|
269
|
-
for (const nested of Object.values(current)) freeze(nested);
|
|
270
|
-
Object.freeze(current);
|
|
271
|
-
};
|
|
272
|
-
freeze(clone);
|
|
273
|
-
return clone;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
/**
|
|
277
|
-
* Bind one validated authored document to immutable provider and source
|
|
278
|
-
* provenance. Runtime lifecycle state is intentionally absent.
|
|
279
|
-
* @param {{
|
|
280
|
-
* provider: ProviderInstance,
|
|
281
|
-
* kind: AuthoredDocKind,
|
|
282
|
-
* stableName: string,
|
|
283
|
-
* source: {group: string, path: string, digest: string},
|
|
284
|
-
* authored: AuthoredDoc,
|
|
285
|
-
* }} input
|
|
286
|
-
* @returns {AuthoredDocEntry}
|
|
287
|
-
*/
|
|
288
|
-
export function createAuthoredDocEntry(input) {
|
|
289
|
-
const stableName = normalizeName(input.stableName, 'Stable document name');
|
|
290
|
-
const group = normalizeName(input.source.group, 'Source group');
|
|
291
|
-
const sourcePath = normalizeSourcePath(input.source.path);
|
|
292
|
-
const digest = normalizeContentDigest(input.source.digest);
|
|
293
|
-
const authoredKind = authoredKindOf(input.authored);
|
|
294
|
-
if (authoredKind !== input.kind) {
|
|
295
|
-
throw new Error(
|
|
296
|
-
`Document kind "${input.kind}" does not match authored type "${authoredKind}".`,
|
|
297
|
-
);
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
const provider = createProviderInstance({
|
|
301
|
-
providerId: input.provider.providerId,
|
|
302
|
-
packageName: input.provider.packageName,
|
|
303
|
-
packageVersion: input.provider.packageVersion,
|
|
304
|
-
sourceDigest: input.provider.sourceDigest,
|
|
305
|
-
});
|
|
306
|
-
if (provider.id !== input.provider.id) {
|
|
307
|
-
throw new Error(
|
|
308
|
-
'Provider instance ID does not match its immutable fields.',
|
|
309
|
-
);
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
return Object.freeze({
|
|
313
|
-
id: createDocId(provider.providerId, input.kind, stableName),
|
|
314
|
-
provider,
|
|
315
|
-
kind: input.kind,
|
|
316
|
-
stableName,
|
|
317
|
-
source: Object.freeze({group, path: sourcePath, digest}),
|
|
318
|
-
authored: frozenClone(input.authored),
|
|
319
|
-
});
|
|
320
|
-
}
|
|
@@ -1,254 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
-
|
|
3
|
-
import {describe, expect, it} from 'vitest';
|
|
4
|
-
import {
|
|
5
|
-
createArtifactId,
|
|
6
|
-
createArtifactIdentity,
|
|
7
|
-
createAuthoredDocEntry,
|
|
8
|
-
createDocId,
|
|
9
|
-
createProviderInstance,
|
|
10
|
-
normalizeContentDigest,
|
|
11
|
-
normalizeProviderId,
|
|
12
|
-
parseArtifactId,
|
|
13
|
-
} from './provider-identity.mjs';
|
|
14
|
-
import {CLI_PROVIDER_ID, CORE_PROVIDER_ID} from './providers.mjs';
|
|
15
|
-
|
|
16
|
-
const DIGEST_A = `sha256:${'a'.repeat(64)}`;
|
|
17
|
-
const DIGEST_B = `sha256:${'b'.repeat(64)}`;
|
|
18
|
-
|
|
19
|
-
describe('provider identity', () => {
|
|
20
|
-
it('uses the same canonical model for built-in providers', () => {
|
|
21
|
-
expect(CORE_PROVIDER_ID).toBe('@astryxdesign/core');
|
|
22
|
-
expect(CLI_PROVIDER_ID).toBe('@astryxdesign/cli');
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('normalizes npm package identity once', () => {
|
|
26
|
-
expect(normalizeProviderId(' @AstryxDesign/CLI ')).toBe(
|
|
27
|
-
'@astryxdesign/cli',
|
|
28
|
-
);
|
|
29
|
-
expect(() => normalizeProviderId('../cli')).toThrow(
|
|
30
|
-
/bare npm package name/u,
|
|
31
|
-
);
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it('normalizes content digests', () => {
|
|
35
|
-
expect(normalizeContentDigest(DIGEST_A.toUpperCase())).toBe(DIGEST_A);
|
|
36
|
-
expect(() => normalizeContentDigest('sha256:nope')).toThrow(/sha256/u);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it('keeps provider, kind, and case-sensitive artifact name in the ID', () => {
|
|
40
|
-
const component = createArtifactId('@acme/ui', 'component', 'Button');
|
|
41
|
-
expect(component).not.toBe(
|
|
42
|
-
createArtifactId('@acme/ui', 'component', 'button'),
|
|
43
|
-
);
|
|
44
|
-
expect(component).not.toBe(
|
|
45
|
-
createArtifactId('@acme/ui', 'schema', 'Button'),
|
|
46
|
-
);
|
|
47
|
-
expect(component).not.toBe(
|
|
48
|
-
createArtifactId('@other/ui', 'component', 'Button'),
|
|
49
|
-
);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
it('escapes segments canonically and round-trips without collisions', () => {
|
|
53
|
-
const identity = createArtifactIdentity(
|
|
54
|
-
'@acme/ui',
|
|
55
|
-
'generic',
|
|
56
|
-
'Deploy / 100%',
|
|
57
|
-
);
|
|
58
|
-
expect(identity.id).toContain('Deploy%20%2F%20100%25');
|
|
59
|
-
expect(parseArtifactId(identity.id)).toEqual(identity);
|
|
60
|
-
expect(() => parseArtifactId(identity.id.replace('%2F', '%2f'))).toThrow(
|
|
61
|
-
/canonical/u,
|
|
62
|
-
);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it('uses the same stable ID across immutable provider instances', () => {
|
|
66
|
-
const docId = createDocId('@acme/ui', 'schema', 'integration');
|
|
67
|
-
const first = createProviderInstance({
|
|
68
|
-
providerId: '@acme/ui',
|
|
69
|
-
packageName: '@acme/ui',
|
|
70
|
-
packageVersion: '1.0.0',
|
|
71
|
-
sourceDigest: DIGEST_A,
|
|
72
|
-
});
|
|
73
|
-
const second = createProviderInstance({
|
|
74
|
-
providerId: '@acme/ui',
|
|
75
|
-
packageName: '@acme/ui',
|
|
76
|
-
packageVersion: '1.0.1',
|
|
77
|
-
sourceDigest: DIGEST_B,
|
|
78
|
-
});
|
|
79
|
-
expect(first.id).not.toBe(second.id);
|
|
80
|
-
expect(createDocId(first.providerId, 'schema', 'integration')).toBe(docId);
|
|
81
|
-
expect(createDocId(second.providerId, 'schema', 'integration')).toBe(docId);
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
it('supports an explicit stable provider ID across a package rename', () => {
|
|
85
|
-
const instance = createProviderInstance({
|
|
86
|
-
providerId: '@acme/ui',
|
|
87
|
-
packageName: '@acme/design-system',
|
|
88
|
-
packageVersion: '2.0.0',
|
|
89
|
-
sourceDigest: DIGEST_A,
|
|
90
|
-
});
|
|
91
|
-
expect(instance.providerId).toBe('@acme/ui');
|
|
92
|
-
expect(instance.packageName).toBe('@acme/design-system');
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
it('binds a doc to stable identity and immutable source provenance', () => {
|
|
96
|
-
const provider = createProviderInstance({
|
|
97
|
-
providerId: '@acme/ui',
|
|
98
|
-
packageName: '@acme/ui',
|
|
99
|
-
packageVersion: '1.0.0',
|
|
100
|
-
sourceDigest: DIGEST_A,
|
|
101
|
-
});
|
|
102
|
-
const authored = {
|
|
103
|
-
type: 'schema',
|
|
104
|
-
name: 'integration',
|
|
105
|
-
displayName: 'Integration',
|
|
106
|
-
description: 'The integration manifest.',
|
|
107
|
-
fields: [],
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
const entry = createAuthoredDocEntry({
|
|
111
|
-
provider,
|
|
112
|
-
kind: 'schema',
|
|
113
|
-
stableName: 'integration',
|
|
114
|
-
source: {
|
|
115
|
-
group: 'cli-api',
|
|
116
|
-
path: 'authoring/integration/integration.doc.mjs',
|
|
117
|
-
digest: DIGEST_B,
|
|
118
|
-
},
|
|
119
|
-
authored,
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
expect(entry.id).toBe(createDocId('@acme/ui', 'schema', 'integration'));
|
|
123
|
-
expect(entry.provider).toEqual(provider);
|
|
124
|
-
expect(entry.stableName).toBe('integration');
|
|
125
|
-
expect(entry.source.digest).toBe(DIGEST_B);
|
|
126
|
-
expect(Object.isFrozen(entry)).toBe(true);
|
|
127
|
-
expect(Object.isFrozen(entry.provider)).toBe(true);
|
|
128
|
-
expect(Object.isFrozen(entry.source)).toBe(true);
|
|
129
|
-
expect(Object.isFrozen(entry.authored)).toBe(true);
|
|
130
|
-
|
|
131
|
-
authored.name = 'mutated';
|
|
132
|
-
expect(entry.authored.name).toBe('integration');
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
it('uses a discovery-owned stable name when authored display names collide', () => {
|
|
136
|
-
const provider = createProviderInstance({
|
|
137
|
-
providerId: '@astryxdesign/core',
|
|
138
|
-
packageName: '@astryxdesign/core',
|
|
139
|
-
packageVersion: '1.0.0',
|
|
140
|
-
sourceDigest: DIGEST_A,
|
|
141
|
-
});
|
|
142
|
-
const authored = {
|
|
143
|
-
type: 'block',
|
|
144
|
-
name: 'Banner — Statuses',
|
|
145
|
-
description: 'A template.',
|
|
146
|
-
};
|
|
147
|
-
const makeEntry = stableName =>
|
|
148
|
-
createAuthoredDocEntry({
|
|
149
|
-
provider,
|
|
150
|
-
kind: 'block',
|
|
151
|
-
stableName,
|
|
152
|
-
source: {
|
|
153
|
-
group: 'templates',
|
|
154
|
-
path: `templates/${stableName}.doc.mjs`,
|
|
155
|
-
digest: DIGEST_B,
|
|
156
|
-
},
|
|
157
|
-
authored,
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
expect(makeEntry('BannerShowcase').id).not.toBe(
|
|
161
|
-
makeEntry('BannerStatuses').id,
|
|
162
|
-
);
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
it('correlates an unstamped legacy reference doc with generic identity', () => {
|
|
166
|
-
const provider = createProviderInstance({
|
|
167
|
-
providerId: '@acme/ui',
|
|
168
|
-
packageName: '@acme/ui',
|
|
169
|
-
packageVersion: '1.0.0',
|
|
170
|
-
sourceDigest: DIGEST_A,
|
|
171
|
-
});
|
|
172
|
-
const entry = createAuthoredDocEntry({
|
|
173
|
-
provider,
|
|
174
|
-
kind: 'generic',
|
|
175
|
-
stableName: 'theming',
|
|
176
|
-
source: {group: 'guides', path: 'docs/theming.doc.mjs', digest: DIGEST_B},
|
|
177
|
-
authored: {
|
|
178
|
-
name: 'theming',
|
|
179
|
-
title: 'Theming',
|
|
180
|
-
description: 'How theming works.',
|
|
181
|
-
sections: [],
|
|
182
|
-
},
|
|
183
|
-
});
|
|
184
|
-
expect(entry.kind).toBe('generic');
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
it('rejects doc-entry identity that disagrees with stamped or legacy content', () => {
|
|
188
|
-
const provider = createProviderInstance({
|
|
189
|
-
providerId: '@acme/ui',
|
|
190
|
-
packageName: '@acme/ui',
|
|
191
|
-
packageVersion: '1.0.0',
|
|
192
|
-
sourceDigest: DIGEST_A,
|
|
193
|
-
});
|
|
194
|
-
const source = {
|
|
195
|
-
group: 'cli-api',
|
|
196
|
-
path: 'integration.doc.mjs',
|
|
197
|
-
digest: DIGEST_B,
|
|
198
|
-
};
|
|
199
|
-
|
|
200
|
-
expect(() =>
|
|
201
|
-
createAuthoredDocEntry({
|
|
202
|
-
provider,
|
|
203
|
-
kind: 'command',
|
|
204
|
-
stableName: 'integration',
|
|
205
|
-
source,
|
|
206
|
-
authored: {
|
|
207
|
-
type: 'schema',
|
|
208
|
-
name: 'integration',
|
|
209
|
-
displayName: 'Integration',
|
|
210
|
-
description: 'The integration manifest.',
|
|
211
|
-
fields: [],
|
|
212
|
-
},
|
|
213
|
-
}),
|
|
214
|
-
).toThrow(/does not match authored type/u);
|
|
215
|
-
|
|
216
|
-
expect(() =>
|
|
217
|
-
createAuthoredDocEntry({
|
|
218
|
-
provider,
|
|
219
|
-
kind: 'enum',
|
|
220
|
-
stableName: 'Button',
|
|
221
|
-
source,
|
|
222
|
-
authored: {name: 'Button', props: []},
|
|
223
|
-
}),
|
|
224
|
-
).toThrow(/does not match authored type "component"/u);
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
it('rejects source paths that escape the provider package', () => {
|
|
228
|
-
const provider = createProviderInstance({
|
|
229
|
-
providerId: '@acme/ui',
|
|
230
|
-
packageName: '@acme/ui',
|
|
231
|
-
packageVersion: '1.0.0',
|
|
232
|
-
sourceDigest: DIGEST_A,
|
|
233
|
-
});
|
|
234
|
-
expect(() =>
|
|
235
|
-
createAuthoredDocEntry({
|
|
236
|
-
provider,
|
|
237
|
-
kind: 'schema',
|
|
238
|
-
stableName: 'integration',
|
|
239
|
-
source: {
|
|
240
|
-
group: 'cli-api',
|
|
241
|
-
path: '../outside.doc.mjs',
|
|
242
|
-
digest: DIGEST_B,
|
|
243
|
-
},
|
|
244
|
-
authored: {
|
|
245
|
-
type: 'schema',
|
|
246
|
-
name: 'integration',
|
|
247
|
-
displayName: 'Integration',
|
|
248
|
-
description: 'The integration manifest.',
|
|
249
|
-
fields: [],
|
|
250
|
-
},
|
|
251
|
-
}),
|
|
252
|
-
).toThrow(/package-relative path/u);
|
|
253
|
-
});
|
|
254
|
-
});
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
// @generated by scripts/sync-api-types.mjs from the JSDoc in foundation/**/*.mjs.
|
|
2
|
-
// DO NOT EDIT — run `pnpm sync:api-types` to regenerate.
|
|
3
|
-
|
|
4
|
-
/** Core owns built-in components and templates. */
|
|
5
|
-
export const CORE_PROVIDER_ID: import("../../authoring/index.js").ProviderId;
|
|
6
|
-
/** The CLI owns built-in topic docs and CLI-authored contributions. */
|
|
7
|
-
export const CLI_PROVIDER_ID: import("../../authoring/index.js").ProviderId;
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @file Canonical identities for Astryx's built-in providers.
|
|
5
|
-
* @input Stable npm package names owned by Astryx.
|
|
6
|
-
* @output Branded ProviderId values shared by discovery and compilation.
|
|
7
|
-
* @position foundation/identity — built-in provider identity boundary.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import {normalizeProviderId} from './provider-identity.mjs';
|
|
11
|
-
|
|
12
|
-
/** Core owns built-in components and templates. */
|
|
13
|
-
export const CORE_PROVIDER_ID = normalizeProviderId('@astryxdesign/core');
|
|
14
|
-
|
|
15
|
-
/** The CLI owns built-in topic docs and CLI-authored contributions. */
|
|
16
|
-
export const CLI_PROVIDER_ID = normalizeProviderId('@astryxdesign/cli');
|