@astryxdesign/cli 0.3.0-canary.c857354 → 0.3.0-canary.d52d2cb
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/api/component/_adapter.mjs +3 -0
- package/api/integration/validate-integration.d.mts +2 -18
- package/api/integration/validate-integration.mjs +16 -141
- package/api/template/copy/copy.d.mts +2 -2
- package/api/template/copy/copy.mjs +2 -2
- package/api/template/list/list.d.mts +2 -2
- package/api/template/list/list.mjs +2 -2
- package/api/template/show/show.d.mts +2 -2
- package/api/template/show/show.mjs +2 -2
- package/api/template/skeleton/skeleton.d.mts +3 -3
- package/api/template/skeleton/skeleton.mjs +3 -3
- package/api/template/template.d.mts +7 -7
- package/api/template/template.mjs +7 -7
- package/api/template/template.test.mjs +12 -13
- package/assets/codemods/transforms/v0.3.0/__tests__/migrate-grid-minchildwidth-to-columns.test.mjs +82 -0
- package/assets/codemods/transforms/v0.3.0/migrate-grid-minchildwidth-to-columns.mjs +38 -2
- package/assets/docs/layout.doc.dense.mjs +1 -1
- package/assets/templates/blocks/components/AspectRatio/AspectRatioCircleImage.tsx +1 -1
- package/assets/templates/blocks/components/AspectRatio/AspectRatioImageGallery.tsx +1 -1
- package/assets/templates/blocks/components/AspectRatio/AspectRatioShowcase.tsx +3 -3
- package/assets/templates/blocks/components/AspectRatio/AspectRatioSquareImage.tsx +1 -1
- package/assets/templates/blocks/components/AspectRatio/AspectRatioWidescreen.tsx +1 -1
- package/assets/templates/blocks/components/Avatar/AvatarFallbackChain.tsx +6 -6
- package/assets/templates/blocks/components/Avatar/AvatarGroup.tsx +5 -5
- package/assets/templates/blocks/components/Avatar/AvatarInteractive.tsx +2 -2
- package/assets/templates/blocks/components/Avatar/AvatarShowcase.tsx +4 -4
- package/assets/templates/blocks/components/Avatar/AvatarTooltip.tsx +4 -4
- package/assets/templates/blocks/components/Avatar/AvatarUserCard.tsx +3 -3
- package/assets/templates/blocks/components/Avatar/AvatarWithImage.tsx +4 -4
- package/assets/templates/blocks/components/Avatar/AvatarWithStatus.tsx +3 -3
- package/assets/templates/blocks/components/ChatComposerDrawer/ChatComposerDrawerAttachments.tsx +5 -5
- package/assets/templates/blocks/components/Lightbox/LightboxGallery.tsx +4 -4
- package/assets/templates/blocks/components/Lightbox/LightboxShowcase.tsx +1 -1
- package/assets/templates/blocks/components/Lightbox/LightboxVideo.tsx +1 -1
- package/assets/templates/blocks/components/Lightbox/LightboxZoom.tsx +2 -2
- package/assets/templates/blocks/components/MediaTheme/MediaThemeImageOverlay.tsx +1 -1
- package/assets/templates/blocks/components/MediaTheme/MediaThemeLightScrim.tsx +1 -1
- package/assets/templates/blocks/components/MediaTheme/MediaThemeShowcase.tsx +1 -1
- package/assets/templates/blocks/components/Overlay/OverlayBottomStrip.tsx +1 -1
- package/assets/templates/blocks/components/Overlay/OverlayHoverReveal.tsx +1 -1
- package/assets/templates/blocks/components/Overlay/OverlayShowcase.tsx +1 -1
- package/assets/templates/blocks/components/TopNav/TopNavMegaMenu.tsx +1 -1
- package/assets/templates/pages/centered-hero/page.tsx +1 -1
- package/assets/templates/pages/classic-gallery/page.tsx +10 -10
- package/assets/templates/pages/detail-page/page.tsx +5 -5
- package/assets/templates/pages/form-two-column/page.tsx +1 -1
- package/assets/templates/pages/gallery-hero/page.tsx +3 -3
- package/assets/templates/pages/library/page.tsx +30 -30
- package/assets/templates/pages/login/page.tsx +1 -2
- package/assets/templates/pages/login-card/page.tsx +1 -2
- package/assets/templates/pages/login-split/page.tsx +5 -6
- package/assets/templates/pages/login-sso/page.tsx +2 -3
- package/assets/templates/pages/mixed-gallery/page.tsx +5 -5
- package/assets/templates/pages/payment-form/page.tsx +3 -3
- package/assets/templates/pages/product-detail/page.tsx +7 -7
- package/assets/templates/pages/product-gallery/page.tsx +6 -6
- package/assets/templates/pages/shell-top-nav/page.tsx +2 -2
- package/assets/templates/pages/side-gallery/page.tsx +9 -9
- package/assets/templates/pages/table-page-chart/page.tsx +6 -6
- package/assets/templates/pages/theme-showcase/page.tsx +6 -6
- package/authoring/_shared/errors.d.mts +21 -0
- package/authoring/codemod/codemod.doc.d.mts +11 -0
- package/authoring/codemod/parse.d.mts +48 -2
- package/authoring/config/config.doc.d.mts +10 -0
- package/authoring/config/parse.d.mts +54 -2
- package/authoring/doctypes/_schema.d.mts +248 -0
- package/authoring/doctypes/base/type.ts +6 -0
- package/authoring/doctypes/command/command.doc.d.mts +12 -0
- package/authoring/doctypes/command/parse.d.mts +11 -2
- package/authoring/doctypes/component/component.doc.d.mts +11 -0
- package/authoring/doctypes/component/parse.d.mts +11 -2
- package/authoring/doctypes/enum/enum.doc.d.mts +11 -0
- package/authoring/doctypes/enum/parse.d.mts +11 -2
- package/authoring/doctypes/function/function.doc.d.mts +11 -0
- package/authoring/doctypes/function/parse.d.mts +11 -2
- package/authoring/doctypes/function/parse.mjs +24 -4
- package/authoring/doctypes/hook/hook.doc.d.mts +10 -0
- package/authoring/doctypes/hook/parse.d.mts +11 -2
- package/authoring/doctypes/legacy.d.mts +13 -2
- package/authoring/doctypes/parse.d.mts +29 -20
- package/authoring/doctypes/reference/parse.d.mts +11 -2
- package/authoring/doctypes/reference/reference.doc.d.mts +11 -0
- package/authoring/doctypes/schema/parse.d.mts +11 -2
- package/authoring/doctypes/schema/schema.doc.d.mts +11 -0
- package/authoring/doctypes/template/parse.d.mts +12 -2
- package/authoring/doctypes/template/template.doc.d.mts +11 -0
- package/authoring/index.d.mts +16 -0
- package/authoring/integration/integration.doc.d.mts +10 -0
- package/authoring/integration/parse.d.mts +30 -2
- package/clients/cli/commands/hook.doc.mjs +1 -1
- package/clients/cli/lib/manifest.mjs +1 -1
- package/foundation/agent-docs/agent-docs.d.mts +197 -0
- package/foundation/agent-docs/agent-docs.mjs +3 -4
- package/foundation/agent-docs/agent-docs.test.mjs +8 -0
- package/foundation/config/config-cache.d.mts +53 -0
- package/foundation/config/project.d.mts +154 -0
- package/foundation/config/project.mjs +3 -3
- package/foundation/discovery/component-discovery.d.mts +140 -0
- package/foundation/discovery/component-loader.d.mts +50 -0
- package/foundation/discovery/hook-discovery.d.mts +28 -0
- package/{api/template/_adapter.d.mts → foundation/discovery/template-adapter.d.mts} +1 -1
- package/{api/template/_adapter.mjs → foundation/discovery/template-adapter.mjs} +28 -19
- package/foundation/env/node-version.d.mts +52 -0
- package/foundation/env/package-manager.d.mts +84 -0
- package/foundation/env/semver.d.mts +56 -0
- package/foundation/fs/module-loader.d.mts +36 -0
- package/foundation/fs/path-safety.d.mts +74 -0
- package/foundation/fs/paths.d.mts +35 -0
- package/foundation/integrations/integration-warnings.d.mts +17 -0
- package/foundation/integrations/integration-warnings.mjs +1 -1
- package/foundation/integrations/integrations.d.mts +80 -0
- package/foundation/integrations/validate-contributions.d.mts +22 -0
- package/foundation/integrations/validate-contributions.mjs +162 -0
- package/foundation/response/error-codes.d.mts +103 -0
- package/foundation/response/error-codes.doc.d.mts +11 -0
- package/foundation/response/json.d.mts +75 -0
- package/foundation/response/response-types.doc.d.mts +12 -0
- package/foundation/response/response.doc.d.mts +11 -0
- package/foundation/text/levenshtein.d.mts +21 -0
- package/foundation/text/string-utils.d.mts +43 -0
- package/foundation/xle/browser.d.mts +89 -0
- package/foundation/xle/expand.d.mts +23 -0
- package/foundation/xle/parse.d.mts +72 -0
- package/foundation/xle/print.d.mts +7 -0
- package/foundation/xle/registry-core.d.mts +168 -0
- package/foundation/xle/registry.d.mts +19 -0
- package/foundation/xle/splice.d.mts +42 -0
- package/foundation/xle/validate.d.mts +94 -0
- package/package.json +9 -9
|
@@ -270,6 +270,9 @@ export async function resolveUnscopedDoc(dirName, {coreDir, cwd, name}) {
|
|
|
270
270
|
let resolvedName = dirName;
|
|
271
271
|
// Track the resolving owner so the detail payload can carry ownership info.
|
|
272
272
|
// Defaults to core; the legacy-external fallback below may reassign it.
|
|
273
|
+
// Annotated because CORE_PACKAGE's generated declaration carries the literal
|
|
274
|
+
// type, which (unlike a fresh literal) does not widen on assignment.
|
|
275
|
+
/** @type {string} */
|
|
273
276
|
let resolvedOwnerPackage = CORE_PACKAGE;
|
|
274
277
|
let resolvedSourcePath = readmePath ? findComponentSource(coreDir, dirName) : null;
|
|
275
278
|
|
|
@@ -1,24 +1,6 @@
|
|
|
1
1
|
// @generated by scripts/sync-api-types.mjs from the JSDoc in api/**/*.mjs.
|
|
2
2
|
// DO NOT EDIT — run `pnpm sync:api-types` to regenerate.
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* Validate an already-LOADED integration (as produced by
|
|
6
|
-
* `loadIntegrations` in lib/integrations.mjs — absolute contribution roots
|
|
7
|
-
* plus identity) and return its issues. This is the reuse seam for everyday
|
|
8
|
-
* commands that have already loaded the configured integrations and want the
|
|
9
|
-
* SAME validators that `validate-integration` runs, without re-resolving the
|
|
10
|
-
* manifest from disk.
|
|
11
|
-
*
|
|
12
|
-
* The manifest schema is intentionally NOT re-validated here: `loadIntegrations`
|
|
13
|
-
* already validated it (and throws otherwise), so by the time a command holds a
|
|
14
|
-
* loaded integration the manifest is known-good. We re-run the on-disk
|
|
15
|
-
* contribution checks (roots + codemods/templates/components) because those can
|
|
16
|
-
* regress independently of the manifest (a deleted directory, a broken template).
|
|
17
|
-
*
|
|
18
|
-
* @param {import('./validate-integration.type.mjs').LoadedIntegration} loaded loaded-integration-shaped object
|
|
19
|
-
* @returns {Promise<Issue[]>}
|
|
20
|
-
*/
|
|
21
|
-
export function validateLoadedIntegration(loaded: import("./validate-integration.type.mjs").LoadedIntegration): Promise<Issue[]>;
|
|
22
4
|
/**
|
|
23
5
|
* Validate the LOCAL integration package rooted at `cwd`: nearest package.json
|
|
24
6
|
* + a single sibling astryx.integration.{ts,mjs,js}. A missing manifest yields
|
|
@@ -59,6 +41,7 @@ export function summarizeIssues(issues: Issue[]): {
|
|
|
59
41
|
errors: number;
|
|
60
42
|
warnings: number;
|
|
61
43
|
};
|
|
44
|
+
export { validateLoadedIntegration };
|
|
62
45
|
export type Issue = import("../../foundation/integrations/issue").AstryxIntegrationIssue;
|
|
63
46
|
export type ValidateResult = {
|
|
64
47
|
/**
|
|
@@ -79,3 +62,4 @@ export type ValidateResult = {
|
|
|
79
62
|
manifestFile?: string | undefined;
|
|
80
63
|
issues: Issue[];
|
|
81
64
|
};
|
|
65
|
+
import { validateLoadedIntegration } from '../../foundation/integrations/validate-contributions.mjs';
|
|
@@ -17,6 +17,14 @@
|
|
|
17
17
|
* is false only for the no-manifest local case, which is guidance (not an
|
|
18
18
|
* error) so `validate-integration` can stay exit-0 in a non-integration dir.
|
|
19
19
|
*
|
|
20
|
+
* The on-disk contribution validators themselves (roots + codemods/templates/
|
|
21
|
+
* components, behind `validateLoadedIntegration`) live in
|
|
22
|
+
* `foundation/integrations/validate-contributions.mjs`, because foundation also
|
|
23
|
+
* runs them: `Project` collects integration issues and `integration-warnings`
|
|
24
|
+
* nudges about them on ordinary commands. This file re-exports
|
|
25
|
+
* `validateLoadedIntegration` so existing importers are unaffected, and keeps
|
|
26
|
+
* the command-level entry points that resolve a manifest from disk.
|
|
27
|
+
*
|
|
20
28
|
* Validators are intentionally small and independent so more checks can be
|
|
21
29
|
* appended without reshaping the result. Issue `code`s are stable public
|
|
22
30
|
* strings.
|
|
@@ -30,9 +38,14 @@ import {
|
|
|
30
38
|
loadManifestObject,
|
|
31
39
|
resolvePackageDir,
|
|
32
40
|
} from '../../foundation/integrations/integrations.mjs';
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
import
|
|
41
|
+
// The on-disk contribution validators live in foundation: Project and
|
|
42
|
+
// integration-warnings need them too, and foundation must not depend on api.
|
|
43
|
+
import {
|
|
44
|
+
validateLoadedIntegration,
|
|
45
|
+
issueError as error,
|
|
46
|
+
} from '../../foundation/integrations/validate-contributions.mjs';
|
|
47
|
+
|
|
48
|
+
export {validateLoadedIntegration};
|
|
36
49
|
|
|
37
50
|
/**
|
|
38
51
|
* @typedef {import('../../foundation/integrations/issue').AstryxIntegrationIssue} Issue
|
|
@@ -63,144 +76,6 @@ function findNearestPackageJson(cwd) {
|
|
|
63
76
|
}
|
|
64
77
|
}
|
|
65
78
|
|
|
66
|
-
/** @param {string} code @param {string} message @returns {Issue} */
|
|
67
|
-
function error(code, message) {
|
|
68
|
-
return {code, severity: 'error', message};
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Verify each declared contribution root exists on disk. A declared-but-missing
|
|
73
|
-
* root is a `missing_root` error.
|
|
74
|
-
* @param {{components?: string, templates?: string, codemods?: string}} resolved
|
|
75
|
-
* absolute resolved roots (undefined when not declared)
|
|
76
|
-
* @param {Issue[]} issues
|
|
77
|
-
*/
|
|
78
|
-
function checkRoots(resolved, issues) {
|
|
79
|
-
const kinds = /** @type {const} */ (['components', 'templates', 'codemods']);
|
|
80
|
-
for (const kind of kinds) {
|
|
81
|
-
const root = resolved[kind];
|
|
82
|
-
if (root == null) continue;
|
|
83
|
-
if (!fs.existsSync(root)) {
|
|
84
|
-
issues.push(
|
|
85
|
-
error(
|
|
86
|
-
'missing_root',
|
|
87
|
-
`Declared ${kind} root does not exist on disk: ${root}`,
|
|
88
|
-
),
|
|
89
|
-
);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Validate the integration's codemods via the landed discovery. Discovery is
|
|
96
|
-
* strict (throws on bad export / duplicate id); we convert any throw into an
|
|
97
|
-
* `invalid_codemod` error.
|
|
98
|
-
* @param {import('./validate-integration.type.mjs').LoadedIntegration} integration loaded-integration-shaped object
|
|
99
|
-
* @param {Issue[]} issues
|
|
100
|
-
*/
|
|
101
|
-
async function checkCodemods(integration, issues) {
|
|
102
|
-
if (!integration.codemods || !fs.existsSync(integration.codemods)) return;
|
|
103
|
-
try {
|
|
104
|
-
await discoverIntegrationCodemods([integration]);
|
|
105
|
-
} catch (err) {
|
|
106
|
-
issues.push(error('invalid_codemod', /** @type {any} */ (err).message));
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Validate the integration's templates via the landed discovery. Per-template
|
|
112
|
-
* problems are reported as `invalid_template` errors.
|
|
113
|
-
* @param {import('./validate-integration.type.mjs').LoadedIntegration} integration loaded-integration-shaped object
|
|
114
|
-
* @param {Issue[]} issues
|
|
115
|
-
*/
|
|
116
|
-
async function checkTemplates(integration, issues) {
|
|
117
|
-
if (!integration.templates || !fs.existsSync(integration.templates)) return;
|
|
118
|
-
try {
|
|
119
|
-
const {errors} = await discoverIntegrationTemplatesForOne(integration);
|
|
120
|
-
for (const e of errors) {
|
|
121
|
-
issues.push(error('invalid_template', e.message));
|
|
122
|
-
}
|
|
123
|
-
} catch (err) {
|
|
124
|
-
issues.push(error('invalid_template', /** @type {any} */ (err).message));
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Validate the integration's components via the landed ownership discovery.
|
|
130
|
-
* Feature-detected: if the component-ownership export isn't present in this
|
|
131
|
-
* build (sibling PR not yet merged), component validation is skipped rather
|
|
132
|
-
* than hard-failing.
|
|
133
|
-
*
|
|
134
|
-
* `discoverIntegrationComponents` returns ownership records and does not throw
|
|
135
|
-
* on a missing same-stem source — it records `sourcePath: null`. We surface
|
|
136
|
-
* each such record as an `invalid_component` error.
|
|
137
|
-
* @param {import('./validate-integration.type.mjs').LoadedIntegration} integration loaded-integration-shaped object
|
|
138
|
-
* @param {Issue[]} issues
|
|
139
|
-
*/
|
|
140
|
-
async function checkComponents(integration, issues) {
|
|
141
|
-
if (!integration.components || !fs.existsSync(integration.components)) return;
|
|
142
|
-
const discover = componentDiscovery.discoverIntegrationComponents;
|
|
143
|
-
if (typeof discover !== 'function') return; // feature not present yet
|
|
144
|
-
try {
|
|
145
|
-
const records = (await discover(integration)) ?? [];
|
|
146
|
-
for (const record of records) {
|
|
147
|
-
if (record?.sourcePath == null) {
|
|
148
|
-
issues.push(
|
|
149
|
-
error(
|
|
150
|
-
'invalid_component',
|
|
151
|
-
`Component "${record?.name}" is missing its same-stem source file ${record?.name}.tsx.`,
|
|
152
|
-
),
|
|
153
|
-
);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
} catch (err) {
|
|
157
|
-
issues.push(error('invalid_component', /** @type {any} */ (err).message));
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Run every contribution validator against a loaded-integration-shaped object.
|
|
163
|
-
* @param {import('./validate-integration.type.mjs').LoadedIntegration} integration
|
|
164
|
-
* @param {Issue[]} issues
|
|
165
|
-
*/
|
|
166
|
-
async function runContributionChecks(integration, issues) {
|
|
167
|
-
await checkCodemods(integration, issues);
|
|
168
|
-
await checkTemplates(integration, issues);
|
|
169
|
-
await checkComponents(integration, issues);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Validate an already-LOADED integration (as produced by
|
|
174
|
-
* `loadIntegrations` in lib/integrations.mjs — absolute contribution roots
|
|
175
|
-
* plus identity) and return its issues. This is the reuse seam for everyday
|
|
176
|
-
* commands that have already loaded the configured integrations and want the
|
|
177
|
-
* SAME validators that `validate-integration` runs, without re-resolving the
|
|
178
|
-
* manifest from disk.
|
|
179
|
-
*
|
|
180
|
-
* The manifest schema is intentionally NOT re-validated here: `loadIntegrations`
|
|
181
|
-
* already validated it (and throws otherwise), so by the time a command holds a
|
|
182
|
-
* loaded integration the manifest is known-good. We re-run the on-disk
|
|
183
|
-
* contribution checks (roots + codemods/templates/components) because those can
|
|
184
|
-
* regress independently of the manifest (a deleted directory, a broken template).
|
|
185
|
-
*
|
|
186
|
-
* @param {import('./validate-integration.type.mjs').LoadedIntegration} loaded loaded-integration-shaped object
|
|
187
|
-
* @returns {Promise<Issue[]>}
|
|
188
|
-
*/
|
|
189
|
-
export async function validateLoadedIntegration(loaded) {
|
|
190
|
-
/** @type {Issue[]} */
|
|
191
|
-
const issues = [];
|
|
192
|
-
if (!loaded || typeof loaded !== 'object') return issues;
|
|
193
|
-
checkRoots(
|
|
194
|
-
{
|
|
195
|
-
components: loaded.components,
|
|
196
|
-
templates: loaded.templates,
|
|
197
|
-
codemods: loaded.codemods,
|
|
198
|
-
},
|
|
199
|
-
issues,
|
|
200
|
-
);
|
|
201
|
-
await runContributionChecks(loaded, issues);
|
|
202
|
-
return issues;
|
|
203
|
-
}
|
|
204
79
|
|
|
205
80
|
/**
|
|
206
81
|
* Validate a single integration given its package directory and identity.
|
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
/**
|
|
5
5
|
* Scaffold an already-resolved template to `targetPath` (relative to `cwd`) and
|
|
6
6
|
* return the `template.copy` receipt.
|
|
7
|
-
* @param {import('
|
|
7
|
+
* @param {import('../../../foundation/discovery/template-adapter.mjs').DiscoveredTemplate} match
|
|
8
8
|
* @param {{targetPath: string, cwd: string, overwrite?: boolean}} ctx
|
|
9
9
|
* @returns {import('../template.type.mjs').TemplateCopyResponse}
|
|
10
10
|
*/
|
|
11
|
-
export function templateCopy(match: import("
|
|
11
|
+
export function templateCopy(match: import("../../../foundation/discovery/template-adapter.mjs").DiscoveredTemplate, { targetPath, cwd, overwrite }: {
|
|
12
12
|
targetPath: string;
|
|
13
13
|
cwd: string;
|
|
14
14
|
overwrite?: boolean;
|
|
@@ -18,12 +18,12 @@ import {
|
|
|
18
18
|
} from '../../../foundation/fs/path-safety.mjs';
|
|
19
19
|
import {AstryxError} from '../../error.mjs';
|
|
20
20
|
import {ERROR_CODES} from '../../../foundation/response/error-codes.mjs';
|
|
21
|
-
import {stripTemplateAssetRefs} from '
|
|
21
|
+
import {stripTemplateAssetRefs} from '../../../foundation/discovery/template-adapter.mjs';
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
* Scaffold an already-resolved template to `targetPath` (relative to `cwd`) and
|
|
25
25
|
* return the `template.copy` receipt.
|
|
26
|
-
* @param {import('
|
|
26
|
+
* @param {import('../../../foundation/discovery/template-adapter.mjs').DiscoveredTemplate} match
|
|
27
27
|
* @param {{targetPath: string, cwd: string, overwrite?: boolean}} ctx
|
|
28
28
|
* @returns {import('../template.type.mjs').TemplateCopyResponse}
|
|
29
29
|
*/
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Project a discovered template set into the `template.list` envelope.
|
|
6
|
-
* @param {import('
|
|
6
|
+
* @param {import('../../../foundation/discovery/template-adapter.mjs').DiscoveredTemplate[]} templates
|
|
7
7
|
* @param {{type?: 'page' | 'block', package?: string}} [options]
|
|
8
8
|
* @returns {import('../template.type.mjs').TemplateListResponse}
|
|
9
9
|
*/
|
|
10
|
-
export function templateList(templates: import("
|
|
10
|
+
export function templateList(templates: import("../../../foundation/discovery/template-adapter.mjs").DiscoveredTemplate[], options?: {
|
|
11
11
|
type?: "page" | "block";
|
|
12
12
|
package?: string;
|
|
13
13
|
}): import("../template.type.mjs").TemplateListResponse;
|
|
@@ -9,11 +9,11 @@
|
|
|
9
9
|
* no-skeleton default) here.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import {pkgOf} from '
|
|
12
|
+
import {pkgOf} from '../../../foundation/discovery/template-adapter.mjs';
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Project a discovered template set into the `template.list` envelope.
|
|
16
|
-
* @param {import('
|
|
16
|
+
* @param {import('../../../foundation/discovery/template-adapter.mjs').DiscoveredTemplate[]} templates
|
|
17
17
|
* @param {{type?: 'page' | 'block', package?: string}} [options]
|
|
18
18
|
* @returns {import('../template.type.mjs').TemplateListResponse}
|
|
19
19
|
*/
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Build the `template.show` envelope for an already-resolved template.
|
|
6
|
-
* @param {import('
|
|
6
|
+
* @param {import('../../../foundation/discovery/template-adapter.mjs').DiscoveredTemplate} match
|
|
7
7
|
* @returns {import('../template.type.mjs').TemplateShowResponse}
|
|
8
8
|
*/
|
|
9
|
-
export function templateShow(match: import("
|
|
9
|
+
export function templateShow(match: import("../../../foundation/discovery/template-adapter.mjs").DiscoveredTemplate): import("../template.type.mjs").TemplateShowResponse;
|
|
@@ -11,11 +11,11 @@
|
|
|
11
11
|
import * as fs from 'node:fs';
|
|
12
12
|
import {AstryxError} from '../../error.mjs';
|
|
13
13
|
import {ERROR_CODES} from '../../../foundation/response/error-codes.mjs';
|
|
14
|
-
import {extractComponents} from '
|
|
14
|
+
import {extractComponents} from '../../../foundation/discovery/template-adapter.mjs';
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* Build the `template.show` envelope for an already-resolved template.
|
|
18
|
-
* @param {import('
|
|
18
|
+
* @param {import('../../../foundation/discovery/template-adapter.mjs').DiscoveredTemplate} match
|
|
19
19
|
* @returns {import('../template.type.mjs').TemplateShowResponse}
|
|
20
20
|
*/
|
|
21
21
|
export function templateShow(match) {
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* Build the `template.skeleton` envelope for an already-resolved template.
|
|
6
6
|
* `match` may be undefined when `--skeleton` is run without a name — the same
|
|
7
7
|
* "specify a template name" error the dispatcher's resolution would surface.
|
|
8
|
-
* @param {import('
|
|
9
|
-
* @param {import('
|
|
8
|
+
* @param {import('../../../foundation/discovery/template-adapter.mjs').DiscoveredTemplate | undefined} match
|
|
9
|
+
* @param {import('../../../foundation/discovery/template-adapter.mjs').DiscoveredTemplate[]} templates
|
|
10
10
|
* @returns {import('../template.type.mjs').TemplateSkeletonResponse}
|
|
11
11
|
*/
|
|
12
|
-
export function templateSkeleton(match: import("
|
|
12
|
+
export function templateSkeleton(match: import("../../../foundation/discovery/template-adapter.mjs").DiscoveredTemplate | undefined, templates: import("../../../foundation/discovery/template-adapter.mjs").DiscoveredTemplate[]): import("../template.type.mjs").TemplateSkeletonResponse;
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
import * as fs from 'node:fs';
|
|
12
12
|
import {AstryxError} from '../../error.mjs';
|
|
13
13
|
import {ERROR_CODES} from '../../../foundation/response/error-codes.mjs';
|
|
14
|
-
import {extractComponents} from '
|
|
14
|
+
import {extractComponents} from '../../../foundation/discovery/template-adapter.mjs';
|
|
15
15
|
|
|
16
16
|
const STRUCTURAL = new Set([
|
|
17
17
|
'AppShell',
|
|
@@ -223,8 +223,8 @@ function extractSkeleton(source) {
|
|
|
223
223
|
* Build the `template.skeleton` envelope for an already-resolved template.
|
|
224
224
|
* `match` may be undefined when `--skeleton` is run without a name — the same
|
|
225
225
|
* "specify a template name" error the dispatcher's resolution would surface.
|
|
226
|
-
* @param {import('
|
|
227
|
-
* @param {import('
|
|
226
|
+
* @param {import('../../../foundation/discovery/template-adapter.mjs').DiscoveredTemplate | undefined} match
|
|
227
|
+
* @param {import('../../../foundation/discovery/template-adapter.mjs').DiscoveredTemplate[]} templates
|
|
228
228
|
* @returns {import('../template.type.mjs').TemplateSkeletonResponse}
|
|
229
229
|
*/
|
|
230
230
|
export function templateSkeleton(match, templates) {
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
// DO NOT EDIT — run `pnpm sync:api-types` to regenerate.
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* @typedef {import('
|
|
5
|
+
* @typedef {import('../../foundation/discovery/template-adapter.mjs').DiscoveredTemplate} DiscoveredTemplate
|
|
6
6
|
*/
|
|
7
7
|
/**
|
|
8
|
-
* @typedef {import('
|
|
8
|
+
* @typedef {import('../../foundation/discovery/template-adapter.mjs').TemplateDiscoveryError} TemplateDiscoveryError
|
|
9
9
|
*/
|
|
10
10
|
/**
|
|
11
|
-
* @typedef {import('
|
|
11
|
+
* @typedef {import('../../foundation/discovery/template-adapter.mjs').TemplateDocModule} TemplateDocModule
|
|
12
12
|
*/
|
|
13
13
|
/**
|
|
14
14
|
* @param {string} [name]
|
|
@@ -36,7 +36,7 @@ export function template(name?: string, options?: {
|
|
|
36
36
|
type: string;
|
|
37
37
|
data: unknown;
|
|
38
38
|
}>;
|
|
39
|
-
export type DiscoveredTemplate = import("
|
|
40
|
-
export type TemplateDiscoveryError = import("
|
|
41
|
-
export type TemplateDocModule = import("
|
|
42
|
-
export { discoverAll, discoverAll as discoverTemplates, discoverAllWithErrors, discoverIntegrationTemplatesForOne, stripTemplateAssetRefs, listTemplates, findRelatedBlocks, findShowcase, extractComponents } from "
|
|
39
|
+
export type DiscoveredTemplate = import("../../foundation/discovery/template-adapter.mjs").DiscoveredTemplate;
|
|
40
|
+
export type TemplateDiscoveryError = import("../../foundation/discovery/template-adapter.mjs").TemplateDiscoveryError;
|
|
41
|
+
export type TemplateDocModule = import("../../foundation/discovery/template-adapter.mjs").TemplateDocModule;
|
|
42
|
+
export { discoverAll, discoverAll as discoverTemplates, discoverAllWithErrors, discoverIntegrationTemplatesForOne, stripTemplateAssetRefs, listTemplates, findRelatedBlocks, findShowcase, extractComponents } from "../../foundation/discovery/template-adapter.mjs";
|
|
@@ -6,16 +6,16 @@
|
|
|
6
6
|
* This module is BOTH the template dispatcher and the stable import surface for
|
|
7
7
|
* the template family. `template()` discovers the available templates, resolves
|
|
8
8
|
* the requested one, and routes to a leaf (list/show/skeleton/copy). The shared
|
|
9
|
-
* discovery/IO + cross-command helpers live in
|
|
9
|
+
* discovery/IO + cross-command helpers live in `foundation/discovery/template-adapter.mjs` and are
|
|
10
10
|
* RE-EXPORTED here so external import paths (`api/template/template.mjs`) —
|
|
11
11
|
* used by component, layout, search, init, discover, validate-integration, and
|
|
12
12
|
* lib/project — keep resolving unchanged.
|
|
13
13
|
*
|
|
14
14
|
* @position api/template — the template dispatcher + barrel; leaves live under
|
|
15
|
-
* ./list, ./show, ./skeleton, ./copy and shared discovery
|
|
15
|
+
* ./list, ./show, ./skeleton, ./copy and shared discovery in foundation/discovery.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
import {discoverAll, pkgOf} from '
|
|
18
|
+
import {discoverAll, pkgOf} from '../../foundation/discovery/template-adapter.mjs';
|
|
19
19
|
import {AstryxError} from '../error.mjs';
|
|
20
20
|
import {ERROR_CODES} from '../../foundation/response/error-codes.mjs';
|
|
21
21
|
import {templateList} from './list/list.mjs';
|
|
@@ -37,16 +37,16 @@ export {
|
|
|
37
37
|
findRelatedBlocks,
|
|
38
38
|
findShowcase,
|
|
39
39
|
extractComponents,
|
|
40
|
-
} from '
|
|
40
|
+
} from '../../foundation/discovery/template-adapter.mjs';
|
|
41
41
|
|
|
42
42
|
/**
|
|
43
|
-
* @typedef {import('
|
|
43
|
+
* @typedef {import('../../foundation/discovery/template-adapter.mjs').DiscoveredTemplate} DiscoveredTemplate
|
|
44
44
|
*/
|
|
45
45
|
/**
|
|
46
|
-
* @typedef {import('
|
|
46
|
+
* @typedef {import('../../foundation/discovery/template-adapter.mjs').TemplateDiscoveryError} TemplateDiscoveryError
|
|
47
47
|
*/
|
|
48
48
|
/**
|
|
49
|
-
* @typedef {import('
|
|
49
|
+
* @typedef {import('../../foundation/discovery/template-adapter.mjs').TemplateDocModule} TemplateDocModule
|
|
50
50
|
*/
|
|
51
51
|
|
|
52
52
|
/**
|
|
@@ -4,36 +4,35 @@ import {describe, it, expect} from 'vitest';
|
|
|
4
4
|
import {stripTemplateAssetRefs, template} from './template.mjs';
|
|
5
5
|
|
|
6
6
|
describe('stripTemplateAssetRefs', () => {
|
|
7
|
-
it('replaces a
|
|
7
|
+
it('replaces a /template-assets image path with an inline data URI', () => {
|
|
8
8
|
const src =
|
|
9
|
-
"const hero = '
|
|
9
|
+
"const hero = '/template-assets/colorful-home-horizontal-1.png';";
|
|
10
10
|
const out = stripTemplateAssetRefs(src);
|
|
11
|
-
expect(out).not.toContain('
|
|
11
|
+
expect(out).not.toContain('/template-assets/');
|
|
12
12
|
expect(out).toContain('data:image/svg+xml,');
|
|
13
13
|
});
|
|
14
14
|
|
|
15
|
-
it('replaces a
|
|
16
|
-
const src =
|
|
17
|
-
'src="https://lookaside.facebook.com/assets/astryx/avatar-profile-05.jpg"';
|
|
15
|
+
it('replaces a /template-assets block-avatar image path', () => {
|
|
16
|
+
const src = 'src="/template-assets/avatar-profile-05.jpg"';
|
|
18
17
|
const out = stripTemplateAssetRefs(src);
|
|
19
|
-
expect(out).not.toContain('
|
|
18
|
+
expect(out).not.toContain('/template-assets/');
|
|
20
19
|
expect(out).toContain('data:image/svg+xml,');
|
|
21
20
|
});
|
|
22
21
|
|
|
23
|
-
it('replaces every
|
|
22
|
+
it('replaces every /template-assets reference, not just the first', () => {
|
|
24
23
|
const src = [
|
|
25
|
-
"'
|
|
26
|
-
"'
|
|
27
|
-
"'
|
|
24
|
+
"'/template-assets/colorful-home-horizontal-1.png'",
|
|
25
|
+
"'/template-assets/illustrative-horizontal-3.png'",
|
|
26
|
+
"'/template-assets/moody-scene-horizontal-1.png'",
|
|
28
27
|
].join('\n');
|
|
29
28
|
const out = stripTemplateAssetRefs(src);
|
|
30
|
-
expect(out).not.toContain('
|
|
29
|
+
expect(out).not.toContain('/template-assets/');
|
|
31
30
|
expect(out.match(/data:image\/svg\+xml,/g)).toHaveLength(3);
|
|
32
31
|
});
|
|
33
32
|
|
|
34
33
|
it('preserves surrounding source structure', () => {
|
|
35
34
|
const src =
|
|
36
|
-
"const data = [{src: '
|
|
35
|
+
"const data = [{src: '/template-assets/x.png', alt: 'X'}];";
|
|
37
36
|
const out = stripTemplateAssetRefs(src);
|
|
38
37
|
expect(out).toContain("alt: 'X'");
|
|
39
38
|
expect(out).toContain('const data = [{src:');
|
package/assets/codemods/transforms/v0.3.0/__tests__/migrate-grid-minchildwidth-to-columns.test.mjs
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
import {describe, it, expect} from 'vitest';
|
|
4
|
+
|
|
5
|
+
async function applyTransform(source) {
|
|
6
|
+
const {default: transform} =
|
|
7
|
+
await import('../migrate-grid-minchildwidth-to-columns.mjs');
|
|
8
|
+
const jscodeshift = (await import('jscodeshift')).default;
|
|
9
|
+
const j = jscodeshift.withParser('tsx');
|
|
10
|
+
const api = {jscodeshift: j, stats: () => {}, report: () => {}};
|
|
11
|
+
const file = {source, path: 'test.tsx'};
|
|
12
|
+
const result = transform(file, api);
|
|
13
|
+
return result ?? source;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** Collapse whitespace (and space padding inside braces) so formatting of
|
|
17
|
+
* pretty-printed multiline objects does not matter for assertions. */
|
|
18
|
+
function normalize(str) {
|
|
19
|
+
return str
|
|
20
|
+
.replace(/\s+/g, ' ')
|
|
21
|
+
.replace(/\{\s+/g, '{')
|
|
22
|
+
.replace(/\s+\}/g, '}')
|
|
23
|
+
.trim();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
describe('migrate-grid-minchildwidth-to-columns', () => {
|
|
27
|
+
it('migrates minChildWidth only to columns={{minWidth, repeat: "fit"}}', async () => {
|
|
28
|
+
const input = `import {Grid} from '@astryxdesign/core';
|
|
29
|
+
const t = <Grid minChildWidth={280}><Item /></Grid>;`;
|
|
30
|
+
const output = await applyTransform(input);
|
|
31
|
+
expect(output).not.toContain('minChildWidth');
|
|
32
|
+
expect(normalize(output)).toContain(
|
|
33
|
+
normalize("columns={{minWidth: 280, repeat: 'fit'}}"),
|
|
34
|
+
);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('migrates columns={n} + minChildWidth to columns={{minWidth, max, repeat: "fit"}}', async () => {
|
|
38
|
+
const input = `import {Grid} from '@astryxdesign/core';
|
|
39
|
+
const t = <Grid columns={3} minChildWidth={280}><Item /></Grid>;`;
|
|
40
|
+
const output = await applyTransform(input);
|
|
41
|
+
expect(output).not.toContain('minChildWidth');
|
|
42
|
+
expect(normalize(output)).toContain(
|
|
43
|
+
normalize("columns={{minWidth: 280, max: 3, repeat: 'fit'}}"),
|
|
44
|
+
);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('preserves other attributes (gap) when migrating the combo', async () => {
|
|
48
|
+
const input = `import {Grid} from '@astryxdesign/core';
|
|
49
|
+
const t = <Grid columns={5} gap={5} minChildWidth={140}><Item /></Grid>;`;
|
|
50
|
+
const output = await applyTransform(input);
|
|
51
|
+
expect(output).not.toContain('minChildWidth');
|
|
52
|
+
expect(normalize(output)).toContain(
|
|
53
|
+
normalize("columns={{minWidth: 140, max: 5, repeat: 'fit'}}"),
|
|
54
|
+
);
|
|
55
|
+
expect(output).toContain('gap={5}');
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('bails when columns is already an object (ambiguous)', async () => {
|
|
59
|
+
const input = `import {Grid} from '@astryxdesign/core';
|
|
60
|
+
const t = <Grid columns={{minWidth: 100}} minChildWidth={280}><Item /></Grid>;`;
|
|
61
|
+
const output = await applyTransform(input);
|
|
62
|
+
// Unchanged: object columns is ambiguous, so it is left as-is.
|
|
63
|
+
expect(output).toBe(input);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('bails when columns is a non-numeric/dynamic expression', async () => {
|
|
67
|
+
const input = `import {Grid} from '@astryxdesign/core';
|
|
68
|
+
const t = <Grid columns={cols} minChildWidth={280}><Item /></Grid>;`;
|
|
69
|
+
const output = await applyTransform(input);
|
|
70
|
+
expect(output).toBe(input);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('is alias-aware and supports the subpath import source', async () => {
|
|
74
|
+
const input = `import {Grid as G} from '@astryxdesign/core/Grid';
|
|
75
|
+
const t = <G columns={4} minChildWidth={200}><Item /></G>;`;
|
|
76
|
+
const output = await applyTransform(input);
|
|
77
|
+
expect(output).not.toContain('minChildWidth');
|
|
78
|
+
expect(normalize(output)).toContain(
|
|
79
|
+
normalize("columns={{minWidth: 200, max: 4, repeat: 'fit'}}"),
|
|
80
|
+
);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
@@ -49,11 +49,10 @@ export default function transformer(file, api) {
|
|
|
49
49
|
a.type === 'JSXAttribute' && a.name?.name === 'minChildWidth',
|
|
50
50
|
);
|
|
51
51
|
if (!minAttr) return;
|
|
52
|
-
const
|
|
52
|
+
const columnsAttr = attrs.find(
|
|
53
53
|
(/** @type {any} */ a) =>
|
|
54
54
|
a.type === 'JSXAttribute' && a.name?.name === 'columns',
|
|
55
55
|
);
|
|
56
|
-
if (hasColumns) return;
|
|
57
56
|
|
|
58
57
|
let minWidthExpr;
|
|
59
58
|
if (
|
|
@@ -67,6 +66,43 @@ export default function transformer(file, api) {
|
|
|
67
66
|
return;
|
|
68
67
|
}
|
|
69
68
|
|
|
69
|
+
if (columnsAttr) {
|
|
70
|
+
// Both `columns` and `minChildWidth` are present. This is only safely
|
|
71
|
+
// migratable when `columns` is a numeric literal (e.g. `columns={3}`).
|
|
72
|
+
//
|
|
73
|
+
// In the old (0.2.0) Grid runtime, when both props were set and
|
|
74
|
+
// `columns` was a number, `minChildWidth` dominated and the numeric
|
|
75
|
+
// `columns` became a *max column cap* with `auto-fit`:
|
|
76
|
+
// repeat(auto-fit, minmax(minChildWidth, 1fr)) capped at `columns`.
|
|
77
|
+
// The 0.3.0 `columns` object models this exactly as
|
|
78
|
+
// {minWidth, max, repeat: 'fit'}.
|
|
79
|
+
// So the lossless rewrite is:
|
|
80
|
+
// <Grid columns={3} minChildWidth={280}>
|
|
81
|
+
// -> <Grid columns={{minWidth: 280, max: 3, repeat: 'fit'}}>
|
|
82
|
+
//
|
|
83
|
+
// If `columns` is already an object or a non-numeric/dynamic
|
|
84
|
+
// expression, the combined behavior is genuinely ambiguous, so we
|
|
85
|
+
// bail and leave it unmigrated (it surfaces separately).
|
|
86
|
+
const columnsValue = columnsAttr.value;
|
|
87
|
+
if (columnsValue?.type !== 'JSXExpressionContainer') return;
|
|
88
|
+
const columnsExpr = columnsValue.expression;
|
|
89
|
+
const isNumericLiteral =
|
|
90
|
+
(columnsExpr?.type === 'NumericLiteral' ||
|
|
91
|
+
columnsExpr?.type === 'Literal') &&
|
|
92
|
+
typeof columnsExpr.value === 'number';
|
|
93
|
+
if (!isNumericLiteral) return;
|
|
94
|
+
|
|
95
|
+
const columnsObject = j.objectExpression([
|
|
96
|
+
j.property('init', j.identifier('minWidth'), minWidthExpr),
|
|
97
|
+
j.property('init', j.identifier('max'), j.literal(columnsExpr.value)),
|
|
98
|
+
j.property('init', j.identifier('repeat'), j.literal('fit')),
|
|
99
|
+
]);
|
|
100
|
+
columnsAttr.value = j.jsxExpressionContainer(columnsObject);
|
|
101
|
+
attrs.splice(attrs.indexOf(minAttr), 1);
|
|
102
|
+
hasChanges = true;
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
70
106
|
const columnsObject = j.objectExpression([
|
|
71
107
|
j.property('init', j.identifier('minWidth'), minWidthExpr),
|
|
72
108
|
j.property('init', j.identifier('repeat'), j.literal('fit')),
|
|
@@ -64,7 +64,7 @@ export const docsDense = {
|
|
|
64
64
|
'no Card-wrapped list items (card soup)',
|
|
65
65
|
'no stacked full-width Cards as page structure',
|
|
66
66
|
'no Cards in Cards',
|
|
67
|
-
'no decorative Badge
|
|
67
|
+
'no decorative Badge: counts/enums only; StatusDot/Token for status',
|
|
68
68
|
],
|
|
69
69
|
},
|
|
70
70
|
],
|
|
@@ -10,7 +10,7 @@ export default function AspectRatioCircleImage() {
|
|
|
10
10
|
<Center width={300}>
|
|
11
11
|
<AspectRatio ratio={1} shape="ellipse" fit="cover">
|
|
12
12
|
<img
|
|
13
|
-
src="
|
|
13
|
+
src="/template-assets/light-home-square-1.png"
|
|
14
14
|
alt="Circular image"
|
|
15
15
|
/>
|
|
16
16
|
</AspectRatio>
|
|
@@ -27,7 +27,7 @@ export default function AspectRatioImageGallery() {
|
|
|
27
27
|
{images.map(({id, alt}) => (
|
|
28
28
|
<AspectRatio key={id} ratio={4 / 3} fit="cover">
|
|
29
29
|
<img
|
|
30
|
-
src="
|
|
30
|
+
src="/template-assets/illustrative-horizontal-1.png"
|
|
31
31
|
alt={alt}
|
|
32
32
|
style={{borderRadius: 8}}
|
|
33
33
|
/>
|