@astryxdesign/cli 0.6.3-canary.f839b67 → 0.6.4-canary.06c8fa3
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/CHANGELOG.md +194 -0
- package/README.md +64 -66
- package/api/component/_adapter.d.mts +25 -0
- package/api/component/_adapter.mjs +59 -5
- package/api/component/component.d.mts +6 -3
- package/api/component/component.doc.mjs +23 -10
- package/api/component/component.mjs +249 -9
- package/api/component/component.type.d.mts +25 -0
- package/api/component/component.type.mjs +44 -0
- package/api/discover/_adapter.d.mts +114 -6
- package/api/discover/_adapter.mjs +372 -17
- package/api/discover/_adapter.test.mjs +215 -0
- package/api/discover/_catalog-view.d.mts +115 -0
- package/api/discover/_catalog-view.mjs +203 -0
- package/api/discover/_catalog-view.test.mjs +128 -0
- package/api/discover/detail/detail.d.mts +18 -6
- package/api/discover/detail/detail.mjs +67 -13
- package/api/discover/detail/detail.test.mjs +85 -0
- package/api/discover/detail/item/item.d.mts +26 -0
- package/api/discover/detail/item/item.mjs +78 -0
- package/api/discover/detail/item/item.test.mjs +73 -0
- package/api/discover/discover.d.mts +3 -9
- package/api/discover/discover.doc.mjs +61 -18
- package/api/discover/discover.mjs +220 -36
- package/api/discover/discover.test.mjs +11 -2
- package/api/discover/discover.type.d.mts +147 -8
- package/api/discover/discover.type.mjs +102 -12
- package/api/discover/list/list.d.mts +20 -6
- package/api/discover/list/list.mjs +45 -12
- package/api/discover/list/list.test.mjs +46 -0
- package/api/discover/search/search.d.mts +18 -16
- package/api/discover/search/search.mjs +102 -56
- package/api/discover/search/search.test.mjs +144 -10
- package/api/docs/_adapter.d.mts +49 -7
- package/api/docs/_adapter.mjs +284 -33
- package/api/docs/docs.doc.mjs +4 -3
- package/api/docs/docs.test.mjs +2 -0
- package/api/docs/docs.type.d.mts +21 -5
- package/api/docs/docs.type.mjs +21 -5
- package/api/docs/integration-tree.test.mjs +9 -1
- package/api/docs/reference-blocks.test.mjs +406 -0
- package/api/doctor/doctor.d.mts +8 -3
- package/api/doctor/doctor.mjs +95 -10
- package/api/doctor/doctor.test.mjs +122 -10
- package/api/index.d.mts +1 -2
- package/api/index.mjs +4 -4
- package/api/integration/add-helpers.d.mts +5 -2
- package/api/integration/add-helpers.mjs +36 -9
- package/api/integration/authoring-checks.mjs +14 -1
- package/api/integration/pack-check.lifecycle-output.test.mjs +105 -0
- package/api/integration/pack-check.mjs +28 -3
- package/api/json/index.ts +0 -1
- package/api/search/search.test.mjs +18 -0
- package/api/template/table-floating-bulk-actions.test.mjs +66 -0
- package/api/template/template-integration.test.mjs +1 -65
- package/api/template/template.mjs +1 -1
- package/api/theme/add/add.mjs +17 -25
- package/api/theme/add/add.rollback.test.mjs +158 -0
- package/api/theme/add/add.staging.test.mjs +40 -23
- package/api/theme/build/build.family.test.mjs +7 -12
- package/api/theme/build/build.mjs +8 -18
- package/api/theme/build/build.rollback.test.mjs +148 -0
- package/api/upgrade/run/files-changed.test.mjs +111 -0
- package/api/upgrade/run/run.mjs +6 -4
- package/api/upgrade/upgrade.type.mjs +2 -2
- package/assets/codemods/__tests__/registry.test.mjs +1 -0
- package/assets/codemods/__tests__/runner.test.mjs +3 -1
- package/assets/codemods/file-count.test.mjs +163 -0
- package/assets/codemods/integration-runner.mjs +3 -3
- package/assets/codemods/registry.mjs +1 -0
- package/assets/codemods/runner.mjs +5 -4
- package/assets/codemods/transforms/next/index.mjs +1 -19
- package/assets/codemods/transforms/v0.6.4/index.mjs +31 -0
- package/assets/docs/internationalization.doc.mjs +7 -5
- package/assets/docs/styling-libraries.doc.mjs +1 -1
- package/assets/docs/theme.doc.mjs +1 -1
- package/assets/docs/tree/component-lookups.doc.mjs +149 -0
- package/assets/docs/tree/integrations.doc.mjs +20 -1
- package/assets/templates/blocks/components/CheckboxList/CheckboxListSelectAllPattern.doc.mjs +1 -1
- package/assets/templates/blocks/components/CheckboxList/CheckboxListSelectAllPattern.tsx +1 -3
- package/assets/templates/blocks/components/InternationalizationProvider/InternationalizationProvider01ShippedLocale.tsx +1 -1
- package/assets/templates/blocks/components/Table/TableBulkActionsTable.doc.mjs +14 -0
- package/assets/templates/blocks/components/Table/TableBulkActionsTable.tsx +71 -0
- package/assets/templates/blocks/components/Table/TableFloatingBulkActionsTable.doc.mjs +19 -0
- package/assets/templates/blocks/components/Table/TableFloatingBulkActionsTable.tsx +139 -0
- package/authoring/config/config.doc.mjs +9 -1
- package/authoring/config/parse.d.mts +2 -0
- package/authoring/config/parse.mjs +19 -0
- package/authoring/config/parse.test.mjs +8 -0
- package/authoring/config/type.ts +13 -2
- package/authoring/discover/discover.doc.d.mts +13 -0
- package/authoring/discover/discover.doc.mjs +138 -0
- package/authoring/discover/parse.d.mts +24 -0
- package/authoring/discover/parse.mjs +128 -0
- package/authoring/discover/parse.test.mjs +124 -0
- package/authoring/discover/type.ts +87 -0
- package/authoring/doctypes/_schema.d.mts +72 -0
- package/authoring/doctypes/_schema.mjs +25 -1
- package/authoring/doctypes/command/command.doc.mjs +1 -1
- package/authoring/doctypes/command/type.ts +1 -1
- package/authoring/doctypes/load-contract.test.mjs +25 -0
- package/authoring/doctypes/reference/reference.doc.mjs +31 -4
- package/authoring/doctypes/reference/type.ts +20 -5
- package/authoring/index.d.mts +1 -0
- package/authoring/index.d.ts +10 -0
- package/authoring/index.mjs +1 -0
- package/clients/cli/command-result-coverage.test.mjs +7 -7
- package/clients/cli/commands/component/index.mjs +152 -55
- package/clients/cli/commands/component-batch.test.mjs +341 -0
- package/clients/cli/commands/component-ownership.test.mjs +89 -0
- package/clients/cli/commands/component.doc.mjs +23 -6
- package/clients/cli/commands/debug-result-summary.test.mjs +2 -2
- package/clients/cli/commands/discover.doc.mjs +53 -9
- package/clients/cli/commands/discover.mjs +393 -118
- package/clients/cli/commands/discover.sources.test.mjs +267 -0
- package/clients/cli/commands/docs.mjs +2 -2
- package/clients/cli/commands/docs.test.mjs +29 -0
- package/clients/cli/commands/doctor-integration-docs.doc.mjs +1 -1
- package/clients/cli/commands/text-json-parity.test.mjs +0 -17
- package/clients/cli/index.mjs +0 -4
- package/clients/cli/lib/exit-codes.test.mjs +1 -8
- package/clients/cli/lib/json-shim.mjs +24 -14
- package/clients/cli/lib/json-shim.test.mjs +6 -20
- package/clients/cli/lib/manifest.mjs +3 -8
- package/clients/cli/lib/manifest.test.mjs +5 -2
- package/clients/cli/lib/parse-error-format.test.mjs +81 -0
- package/foundation/discovery/authoring-self-docs.d.mts +12 -0
- package/foundation/discovery/authoring-self-docs.mjs +21 -8
- package/foundation/discovery/authoring-self-docs.test.mjs +7 -2
- package/foundation/discovery/docs-discovery.d.mts +4 -1
- package/foundation/discovery/docs-discovery.mjs +40 -6
- package/foundation/discovery/docs-discovery.test.mjs +40 -0
- package/foundation/discovery/template-adapter.mjs +1 -1
- package/foundation/doc-compiler/doc-loads.test.mjs +0 -12
- package/foundation/doc-compiler/lenses.d.mts +5 -3
- package/foundation/doc-compiler/lenses.mjs +48 -3
- package/foundation/doc-compiler/links.d.mts +30 -3
- package/foundation/doc-compiler/links.mjs +46 -5
- package/foundation/doc-compiler/links.test.mjs +53 -0
- package/foundation/doc-compiler/tree.test.mjs +9 -1
- package/foundation/integrations/cli-requirement.test.mjs +17 -42
- package/foundation/integrations/integrations.d.mts +14 -1
- package/foundation/integrations/integrations.mjs +41 -1
- package/foundation/integrations/integrations.test.mjs +31 -0
- package/foundation/response/batch.type.d.mts +33 -0
- package/foundation/response/batch.type.mjs +34 -0
- package/foundation/response/response-types.doc.mjs +15 -21
- package/foundation/response/response-types.doc.test.mjs +23 -0
- package/foundation/xle/browser.d.mts +3 -3
- package/foundation/xle/browser.mjs +3 -3
- package/foundation/xle/expand.mjs +2 -2
- package/foundation/xle/parse.mjs +1 -1
- package/foundation/xle/print.mjs +2 -2
- package/foundation/xle/splice.mjs +1 -1
- package/package.json +9 -9
- package/api/layout/_adapter.d.mts +0 -34
- package/api/layout/_adapter.mjs +0 -148
- package/api/layout/check/check.d.mts +0 -16
- package/api/layout/check/check.mjs +0 -40
- package/api/layout/expand/expand.d.mts +0 -22
- package/api/layout/expand/expand.mjs +0 -155
- package/api/layout/expand/expand.path-safety.test.mjs +0 -53
- package/api/layout/grammar/grammar.d.mts +0 -13
- package/api/layout/grammar/grammar.mjs +0 -87
- package/api/layout/layout.d.mts +0 -6
- package/api/layout/layout.mjs +0 -17
- package/api/layout/layout.test.mjs +0 -297
- package/api/layout/layout.type.d.mts +0 -89
- package/api/layout/layout.type.mjs +0 -103
- package/api/layout/layoutCheck.doc.d.mts +0 -11
- package/api/layout/layoutCheck.doc.mjs +0 -85
- package/api/layout/layoutExpand.doc.d.mts +0 -11
- package/api/layout/layoutExpand.doc.mjs +0 -107
- package/api/layout/layoutGrammar.doc.d.mts +0 -11
- package/api/layout/layoutGrammar.doc.mjs +0 -57
- package/clients/cli/commands/layout-check.doc.mjs +0 -65
- package/clients/cli/commands/layout-expand.doc.mjs +0 -83
- package/clients/cli/commands/layout-grammar.doc.mjs +0 -30
- package/clients/cli/commands/layout.doc.mjs +0 -34
- package/clients/cli/commands/layout.error-codes.test.mjs +0 -66
- package/clients/cli/commands/layout.exit-parity.test.mjs +0 -41
- package/clients/cli/commands/layout.mjs +0 -275
- package/clients/cli/commands/layout.path-help.test.mjs +0 -33
- package/clients/cli/commands/layout.stdin-cap.test.mjs +0 -47
- package/clients/cli/commands/layout.text-fields.test.mjs +0 -39
- /package/assets/codemods/transforms/{next → v0.6.4}/__tests__/migrate-native-picker-to-presentation.test.mjs +0 -0
- /package/assets/codemods/transforms/{next → v0.6.4}/__tests__/migrate-theme-catalog-to-descriptors.test.mjs +0 -0
- /package/assets/codemods/transforms/{next → v0.6.4}/migrate-native-picker-to-presentation.mjs +0 -0
- /package/assets/codemods/transforms/{next → v0.6.4}/migrate-theme-catalog-to-descriptors.mjs +0 -0
|
@@ -68,6 +68,16 @@ export function requireCoreDir(cwd: string): string;
|
|
|
68
68
|
* @returns {Promise<import('../../foundation/integrations/integrations.mjs').LoadedIntegration[]>}
|
|
69
69
|
*/
|
|
70
70
|
export function loadIntegrationsSafely(cwd: string): Promise<import("../../foundation/integrations/integrations.mjs").LoadedIntegration[]>;
|
|
71
|
+
/**
|
|
72
|
+
* Read the exact installed version available to a package-qualified component
|
|
73
|
+
* selector. Legacy docs packages do not expose a reliable version here, so a
|
|
74
|
+
* version-qualified lookup never falls through to them.
|
|
75
|
+
* @param {string} coreDir
|
|
76
|
+
* @param {import('../../foundation/integrations/integrations.mjs').LoadedIntegration[]} loadedIntegrations
|
|
77
|
+
* @param {string} packageName
|
|
78
|
+
* @returns {string|null}
|
|
79
|
+
*/
|
|
80
|
+
export function installedComponentPackageVersion(coreDir: string, loadedIntegrations: import("../../foundation/integrations/integrations.mjs").LoadedIntegration[], packageName: string): string | null;
|
|
71
81
|
/**
|
|
72
82
|
* Build the set of OWNER packages that provide a component with this name
|
|
73
83
|
* across core + every loaded integration. This is what lets the CLI
|
|
@@ -180,6 +190,20 @@ export function scopeSubComponent(docs: LoadedComponentDoc, dirName: string, cor
|
|
|
180
190
|
matchingComponent: any;
|
|
181
191
|
} | null;
|
|
182
192
|
export { CORE_PACKAGE };
|
|
193
|
+
/**
|
|
194
|
+
* Internal ambiguity marker. Single-component callers still receive the same
|
|
195
|
+
* AstryxError code, message, and suggestions; batch callers can additionally
|
|
196
|
+
* project every installed candidate without parsing prose.
|
|
197
|
+
*/
|
|
198
|
+
export class ComponentAmbiguityError extends AstryxError {
|
|
199
|
+
/**
|
|
200
|
+
* @param {ComponentOwner[]} owners
|
|
201
|
+
* @param {string} dirName
|
|
202
|
+
*/
|
|
203
|
+
constructor(owners: ComponentOwner[], dirName: string);
|
|
204
|
+
/** @type {import('./component.type.mjs').ComponentBatchCandidate[]} */
|
|
205
|
+
candidates: import("./component.type.mjs").ComponentBatchCandidate[];
|
|
206
|
+
}
|
|
183
207
|
/**
|
|
184
208
|
* A loaded component doc. The shared validated loader accepts stamped and legacy
|
|
185
209
|
* component docs; this loose view captures the fields the API reads across both.
|
|
@@ -258,3 +282,4 @@ export type ResolvedUnscopedDoc = {
|
|
|
258
282
|
resolvedSourcePath: string | null;
|
|
259
283
|
};
|
|
260
284
|
import { CORE_PACKAGE } from '../../foundation/discovery/component-discovery.mjs';
|
|
285
|
+
import { AstryxError } from '../error.mjs';
|
|
@@ -18,6 +18,8 @@
|
|
|
18
18
|
* deduped, so each leaf stays a thin projection.
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
|
+
import * as fs from 'node:fs';
|
|
22
|
+
import * as path from 'node:path';
|
|
21
23
|
import {ERROR_CODES} from '../../foundation/response/error-codes.mjs';
|
|
22
24
|
import {
|
|
23
25
|
findCoreDir,
|
|
@@ -146,6 +148,34 @@ function findLoadedIntegration(loadedIntegrations, packageName) {
|
|
|
146
148
|
return loadedIntegrations.find(i => i.name === packageName) ?? null;
|
|
147
149
|
}
|
|
148
150
|
|
|
151
|
+
/**
|
|
152
|
+
* Read the exact installed version available to a package-qualified component
|
|
153
|
+
* selector. Legacy docs packages do not expose a reliable version here, so a
|
|
154
|
+
* version-qualified lookup never falls through to them.
|
|
155
|
+
* @param {string} coreDir
|
|
156
|
+
* @param {import('../../foundation/integrations/integrations.mjs').LoadedIntegration[]} loadedIntegrations
|
|
157
|
+
* @param {string} packageName
|
|
158
|
+
* @returns {string|null}
|
|
159
|
+
*/
|
|
160
|
+
export function installedComponentPackageVersion(
|
|
161
|
+
coreDir,
|
|
162
|
+
loadedIntegrations,
|
|
163
|
+
packageName,
|
|
164
|
+
) {
|
|
165
|
+
if (packageName === CORE_PACKAGE) {
|
|
166
|
+
try {
|
|
167
|
+
const pkg = JSON.parse(
|
|
168
|
+
fs.readFileSync(path.join(coreDir, 'package.json'), 'utf8'),
|
|
169
|
+
);
|
|
170
|
+
return typeof pkg.version === 'string' ? pkg.version : null;
|
|
171
|
+
} catch {
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
const integration = findLoadedIntegration(loadedIntegrations, packageName);
|
|
176
|
+
return typeof integration?.version === 'string' ? integration.version : null;
|
|
177
|
+
}
|
|
178
|
+
|
|
149
179
|
/**
|
|
150
180
|
* Resolve an external package by name from the discovered externals list.
|
|
151
181
|
* @param {string} packageName - e.g. '@acme/xds-widgets'
|
|
@@ -244,6 +274,34 @@ export function classifyScope(
|
|
|
244
274
|
return {kind: 'legacy', ext};
|
|
245
275
|
}
|
|
246
276
|
|
|
277
|
+
/**
|
|
278
|
+
* Internal ambiguity marker. Single-component callers still receive the same
|
|
279
|
+
* AstryxError code, message, and suggestions; batch callers can additionally
|
|
280
|
+
* project every installed candidate without parsing prose.
|
|
281
|
+
*/
|
|
282
|
+
export class ComponentAmbiguityError extends AstryxError {
|
|
283
|
+
/** @type {import('./component.type.mjs').ComponentBatchCandidate[]} */
|
|
284
|
+
candidates;
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* @param {ComponentOwner[]} owners
|
|
288
|
+
* @param {string} dirName
|
|
289
|
+
*/
|
|
290
|
+
constructor(owners, dirName) {
|
|
291
|
+
super(
|
|
292
|
+
`Component "${dirName}" is provided by multiple packages. Re-run with --package <pkg> to choose one.`,
|
|
293
|
+
owners.map(o => ({name: o.package, reason: 'provides this component'})),
|
|
294
|
+
ERROR_CODES.ERR_UNKNOWN_COMPONENT,
|
|
295
|
+
);
|
|
296
|
+
this.candidates = owners.map(owner => ({
|
|
297
|
+
package: owner.package,
|
|
298
|
+
component: dirName,
|
|
299
|
+
kind: 'component',
|
|
300
|
+
installed: true,
|
|
301
|
+
}));
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
247
305
|
/**
|
|
248
306
|
* Refuse to guess when the name is owned by MORE THAN ONE package (core and/or
|
|
249
307
|
* integrations) and the caller did not scope with --package. Legacy
|
|
@@ -254,11 +312,7 @@ export function classifyScope(
|
|
|
254
312
|
*/
|
|
255
313
|
export function assertUnambiguousOwners(owners, dirName) {
|
|
256
314
|
if (owners.length > 1) {
|
|
257
|
-
throw new
|
|
258
|
-
`Component "${dirName}" is provided by multiple packages. Re-run with --package <pkg> to choose one.`,
|
|
259
|
-
owners.map(o => ({name: o.package, reason: 'provides this component'})),
|
|
260
|
-
ERROR_CODES.ERR_UNKNOWN_COMPONENT,
|
|
261
|
-
);
|
|
315
|
+
throw new ComponentAmbiguityError(owners, dirName);
|
|
262
316
|
}
|
|
263
317
|
}
|
|
264
318
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// DO NOT EDIT — run `pnpm sync:api-types` to regenerate.
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* @param {string} [name]
|
|
5
|
+
* @param {string|string[]} [name]
|
|
6
6
|
* @param {object} [options]
|
|
7
7
|
* @param {string} [options.cwd]
|
|
8
8
|
* @param {boolean} [options.list]
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
* @param {boolean} [options.dense]
|
|
19
19
|
* @returns {Promise<(
|
|
20
20
|
* import('./component.type.mjs').ComponentListResponse
|
|
21
|
+
* | import('./component.type.mjs').ComponentBatchResponse
|
|
21
22
|
* | import('./component.type.mjs').ComponentDetailResponse
|
|
22
23
|
* | import('./component.type.mjs').ComponentDetailPropsResponse
|
|
23
24
|
* | import('./component.type.mjs').ComponentDetailSourceResponse
|
|
@@ -25,7 +26,7 @@
|
|
|
25
26
|
* | import('./component.type.mjs').ComponentDetailBlocksResponse
|
|
26
27
|
* )>}
|
|
27
28
|
*/
|
|
28
|
-
export function component(name?: string, options?: {
|
|
29
|
+
export function component(name?: string | string[], options?: {
|
|
29
30
|
cwd?: string | undefined;
|
|
30
31
|
list?: boolean | undefined;
|
|
31
32
|
category?: string | undefined;
|
|
@@ -38,4 +39,6 @@ export function component(name?: string, options?: {
|
|
|
38
39
|
lang?: string | undefined;
|
|
39
40
|
zh?: boolean | undefined;
|
|
40
41
|
dense?: boolean | undefined;
|
|
41
|
-
}): Promise<(import("./component.type.mjs").ComponentListResponse | import("./component.type.mjs").ComponentDetailResponse | import("./component.type.mjs").ComponentDetailPropsResponse | import("./component.type.mjs").ComponentDetailSourceResponse | import("./component.type.mjs").ComponentDetailShowcaseResponse | import("./component.type.mjs").ComponentDetailBlocksResponse)>;
|
|
42
|
+
}): Promise<(import("./component.type.mjs").ComponentListResponse | import("./component.type.mjs").ComponentBatchResponse | import("./component.type.mjs").ComponentDetailResponse | import("./component.type.mjs").ComponentDetailPropsResponse | import("./component.type.mjs").ComponentDetailSourceResponse | import("./component.type.mjs").ComponentDetailShowcaseResponse | import("./component.type.mjs").ComponentDetailBlocksResponse)>;
|
|
43
|
+
/** Maximum selectors accepted before any component resolution starts. */
|
|
44
|
+
export const COMPONENT_BATCH_SELECTOR_LIMIT: 100;
|
|
@@ -15,16 +15,16 @@ export const doc = {
|
|
|
15
15
|
namespace: 'cli/api',
|
|
16
16
|
displayName: 'component()',
|
|
17
17
|
summary:
|
|
18
|
-
'Resolve
|
|
18
|
+
'Resolve one or several components by name, or list the catalog, with optional focused slices (props, source, showcase, blocks).',
|
|
19
19
|
description:
|
|
20
|
-
'Routes on its arguments:
|
|
21
|
-
'integration packages
|
|
22
|
-
'
|
|
23
|
-
'
|
|
24
|
-
'
|
|
20
|
+
'Routes on its arguments: one string resolves that component across core and ' +
|
|
21
|
+
'integration packages; an array returns one ordered result row per selector at ' +
|
|
22
|
+
'every array length; and no name returns the catalog grouped by category. ' +
|
|
23
|
+
'Boolean flags narrow each resolved component to just its props, source, ' +
|
|
24
|
+
'showcase, or example blocks.',
|
|
25
25
|
importPath: '@astryxdesign/cli/api',
|
|
26
26
|
signature:
|
|
27
|
-
'component(name?: string, options?: ComponentOptions): Promise<ComponentListResponse | ComponentDetailResponse | ComponentDetailPropsResponse | ComponentDetailSourceResponse | ComponentDetailShowcaseResponse | ComponentDetailBlocksResponse>',
|
|
27
|
+
'component(name?: string | string[], options?: ComponentOptions): Promise<ComponentListResponse | ComponentBatchResponse | ComponentDetailResponse | ComponentDetailPropsResponse | ComponentDetailSourceResponse | ComponentDetailShowcaseResponse | ComponentDetailBlocksResponse>',
|
|
28
28
|
keywords: [
|
|
29
29
|
'component',
|
|
30
30
|
'components',
|
|
@@ -37,9 +37,9 @@ export const doc = {
|
|
|
37
37
|
params: [
|
|
38
38
|
{
|
|
39
39
|
name: 'name',
|
|
40
|
-
type: 'string',
|
|
40
|
+
type: 'string | string[]',
|
|
41
41
|
description:
|
|
42
|
-
"
|
|
42
|
+
"Pass one selector string for the existing single-result response, or an array of at most 100 selectors for an ordered component.batch response. The limit counts duplicates in every projection mode. An array always requests a batch, including [] and ['Button']. Use 'Button', 'widgets/Button', '@acme/widgets/Button', or '@acme/widgets@1.2.3/Button'. A version applies to the package and must match the installed version. Omit the argument to list the catalog.",
|
|
43
43
|
},
|
|
44
44
|
{
|
|
45
45
|
name: 'options.cwd',
|
|
@@ -112,6 +112,11 @@ export const doc = {
|
|
|
112
112
|
description:
|
|
113
113
|
"The catalog grouped by category. data.detail is the level ('names' | 'compact' | 'full') and data.components is the grouped map: names entries with name, package, and an optional canonical import for integration and legacy package components; brief entries; or full ComponentDoc entries.",
|
|
114
114
|
},
|
|
115
|
+
{
|
|
116
|
+
type: 'component.batch',
|
|
117
|
+
description:
|
|
118
|
+
'An explicit selector array returns one ordered receipt at every array length: count and one results row per selector, including duplicates. ComponentBatchResponse specializes the shared BatchResponse and BatchRow types. Each row carries selector and status (found, not_found, ambiguous, or error); found rows carry the single-selector result, ambiguous rows carry installed candidates ({package, component, kind, installed}), and failed rows carry code, error, and optional suggestions.',
|
|
119
|
+
},
|
|
115
120
|
{
|
|
116
121
|
type: 'component.detail',
|
|
117
122
|
description:
|
|
@@ -137,6 +142,10 @@ export const doc = {
|
|
|
137
142
|
},
|
|
138
143
|
],
|
|
139
144
|
throws: [
|
|
145
|
+
{
|
|
146
|
+
code: 'ERR_INVALID_ARGUMENT',
|
|
147
|
+
when: 'a selector array has more than 100 entries, a package-shaped selector has no component item, or its package conflicts with options.package',
|
|
148
|
+
},
|
|
140
149
|
{
|
|
141
150
|
code: 'ERR_INVALID_DETAIL',
|
|
142
151
|
when: "options.detail is not 'full', 'compact', or 'brief'",
|
|
@@ -159,7 +168,7 @@ export const doc = {
|
|
|
159
168
|
},
|
|
160
169
|
{
|
|
161
170
|
code: 'ERR_UNKNOWN_PACKAGE',
|
|
162
|
-
when: 'options.package names a legacy external package that cannot be found',
|
|
171
|
+
when: 'options.package names a legacy external package that cannot be found, or a package-qualified selector requests a version that is not installed',
|
|
163
172
|
},
|
|
164
173
|
{
|
|
165
174
|
code: 'ERR_NO_DOC',
|
|
@@ -179,6 +188,10 @@ export const doc = {
|
|
|
179
188
|
label: 'Look up a component',
|
|
180
189
|
code: "const r = await component('Button');",
|
|
181
190
|
},
|
|
191
|
+
{
|
|
192
|
+
label: 'Look up several components',
|
|
193
|
+
code: "await component(['Button', 'Badge']);",
|
|
194
|
+
},
|
|
182
195
|
{label: 'Props only', code: "await component('Button', {props: true});"},
|
|
183
196
|
{
|
|
184
197
|
label: 'Browse a category',
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
* @file Programmatic API for the component command — DISPATCHER + BARREL.
|
|
5
5
|
*
|
|
6
6
|
* Returns the same typed envelope { type, data } that `astryx --json component`
|
|
7
|
-
* outputs. `component(name, opts)` parses
|
|
8
|
-
* subject
|
|
9
|
-
* (list · detail · detail.props/source/showcase/blocks)
|
|
10
|
-
*
|
|
7
|
+
* outputs. `component(name, opts)` parses one selector or an ordered selector
|
|
8
|
+
* list, resolves each subject through `_adapter`, and routes to the correct leaf
|
|
9
|
+
* (list · detail · detail.props/source/showcase/blocks). The CLI command handler
|
|
10
|
+
* is a thin wrapper around this function.
|
|
11
11
|
*
|
|
12
12
|
* Every leaf is also re-exported for direct scripting use.
|
|
13
13
|
*/
|
|
@@ -26,6 +26,8 @@ import {
|
|
|
26
26
|
resolveUnscopedDoc,
|
|
27
27
|
loadComponentDoc,
|
|
28
28
|
scopeSubComponent,
|
|
29
|
+
ComponentAmbiguityError,
|
|
30
|
+
installedComponentPackageVersion,
|
|
29
31
|
} from './_adapter.mjs';
|
|
30
32
|
import {componentList} from './list/list.mjs';
|
|
31
33
|
import {componentDetail} from './detail/detail.mjs';
|
|
@@ -34,13 +36,199 @@ import {componentDetailSource} from './detail/source/source.mjs';
|
|
|
34
36
|
import {componentDetailShowcase} from './detail/showcase/showcase.mjs';
|
|
35
37
|
import {componentDetailBlocks} from './detail/blocks/blocks.mjs';
|
|
36
38
|
|
|
39
|
+
/** Maximum selectors accepted before any component resolution starts. */
|
|
40
|
+
export const COMPONENT_BATCH_SELECTOR_LIMIT = 100;
|
|
41
|
+
|
|
37
42
|
/** @type {ReadonlyArray<string>} */
|
|
38
43
|
const DETAIL_LEVELS = ['full', 'compact', 'brief'];
|
|
39
44
|
/** @type {ReadonlyArray<string>} */
|
|
40
45
|
const LANGS = ['en', 'zh', 'dense'];
|
|
46
|
+
/** @type {Set<string>} */
|
|
47
|
+
const NOT_FOUND_CODES = new Set([
|
|
48
|
+
ERROR_CODES.ERR_UNKNOWN_COMPONENT,
|
|
49
|
+
ERROR_CODES.ERR_UNKNOWN_PACKAGE,
|
|
50
|
+
ERROR_CODES.ERR_NOT_FOUND,
|
|
51
|
+
]);
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Discover-compatible package target grammar. Versions belong to the package
|
|
55
|
+
* head, never the item after the package slash.
|
|
56
|
+
* @param {string} selector
|
|
57
|
+
* @returns {{scoped: boolean, name: string, version?: string, item?: string}}
|
|
58
|
+
*/
|
|
59
|
+
function splitSelector(selector) {
|
|
60
|
+
const scoped = selector.startsWith('@');
|
|
61
|
+
const firstSlash = selector.indexOf('/');
|
|
62
|
+
let head = selector;
|
|
63
|
+
/** @type {string | undefined} */
|
|
64
|
+
let rest;
|
|
65
|
+
const split = scoped
|
|
66
|
+
? firstSlash < 0
|
|
67
|
+
? -1
|
|
68
|
+
: selector.indexOf('/', firstSlash + 1)
|
|
69
|
+
: firstSlash;
|
|
70
|
+
if (split > 0) {
|
|
71
|
+
head = selector.slice(0, split);
|
|
72
|
+
rest = selector.slice(split + 1) || undefined;
|
|
73
|
+
}
|
|
74
|
+
const at = head.indexOf('@', 1);
|
|
75
|
+
return {
|
|
76
|
+
scoped,
|
|
77
|
+
name: at > 0 ? head.slice(0, at) : head,
|
|
78
|
+
...(at > 0 && head.slice(at + 1) ? {version: head.slice(at + 1)} : {}),
|
|
79
|
+
...(rest ? {item: rest} : {}),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Resolve one component selector into the existing single-component API inputs.
|
|
85
|
+
* @param {unknown} value
|
|
86
|
+
* @param {string|undefined} packageScope
|
|
87
|
+
* @returns {{selector: string, name: string, package?: string, version?: string}}
|
|
88
|
+
*/
|
|
89
|
+
function parseComponentSelector(value, packageScope) {
|
|
90
|
+
if (typeof value !== 'string' || value.length === 0) {
|
|
91
|
+
throw new AstryxError(
|
|
92
|
+
`Invalid component selector "${String(value)}"`,
|
|
93
|
+
undefined,
|
|
94
|
+
ERROR_CODES.ERR_INVALID_ARGUMENT,
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
const target = splitSelector(value);
|
|
98
|
+
const packageShaped =
|
|
99
|
+
target.scoped || target.item != null || target.version != null;
|
|
100
|
+
if (!packageShaped) {
|
|
101
|
+
return {selector: value, name: target.name, package: packageScope};
|
|
102
|
+
}
|
|
103
|
+
if (!target.item) {
|
|
104
|
+
throw new AstryxError(
|
|
105
|
+
`Component selector "${value}" names a package but no component`,
|
|
106
|
+
undefined,
|
|
107
|
+
ERROR_CODES.ERR_INVALID_ARGUMENT,
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
if (packageScope && packageScope !== target.name) {
|
|
111
|
+
throw new AstryxError(
|
|
112
|
+
`Component selector "${value}" conflicts with --package "${packageScope}"`,
|
|
113
|
+
undefined,
|
|
114
|
+
ERROR_CODES.ERR_INVALID_ARGUMENT,
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
selector: value,
|
|
119
|
+
name: target.item,
|
|
120
|
+
package: target.name,
|
|
121
|
+
...(target.version ? {version: target.version} : {}),
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* A version-qualified selector never falls through to another installed
|
|
127
|
+
* version. Its structured suggestion points at the command that can discover
|
|
128
|
+
* the requested package release.
|
|
129
|
+
* @param {{package?: string, version?: string}} target
|
|
130
|
+
* @param {string} coreDir
|
|
131
|
+
* @param {import('../../foundation/integrations/integrations.mjs').LoadedIntegration[]} loadedIntegrations
|
|
132
|
+
* @returns {void}
|
|
133
|
+
*/
|
|
134
|
+
function requireInstalledSelectorVersion(target, coreDir, loadedIntegrations) {
|
|
135
|
+
if (!target.version) return;
|
|
136
|
+
const packageName = /** @type {string} */ (target.package);
|
|
137
|
+
const installed = installedComponentPackageVersion(
|
|
138
|
+
coreDir,
|
|
139
|
+
loadedIntegrations,
|
|
140
|
+
packageName,
|
|
141
|
+
);
|
|
142
|
+
if (installed === target.version) return;
|
|
143
|
+
const exact = `${packageName}@${target.version}`;
|
|
144
|
+
throw new AstryxError(
|
|
145
|
+
`Package "${exact}" is not installed`,
|
|
146
|
+
[
|
|
147
|
+
{
|
|
148
|
+
name: `astryx discover ${exact}`,
|
|
149
|
+
reason: 'look up this package version',
|
|
150
|
+
},
|
|
151
|
+
],
|
|
152
|
+
ERROR_CODES.ERR_UNKNOWN_PACKAGE,
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Turn a single-lookup failure into one complete batch row.
|
|
158
|
+
* @param {string} selector
|
|
159
|
+
* @param {unknown} error
|
|
160
|
+
* @returns {import('./component.type.mjs').ComponentBatchResult}
|
|
161
|
+
*/
|
|
162
|
+
function batchFailure(selector, error) {
|
|
163
|
+
const err =
|
|
164
|
+
error instanceof AstryxError
|
|
165
|
+
? error
|
|
166
|
+
: new AstryxError(
|
|
167
|
+
error instanceof Error ? error.message : String(error),
|
|
168
|
+
undefined,
|
|
169
|
+
ERROR_CODES.ERR_UNKNOWN,
|
|
170
|
+
);
|
|
171
|
+
if (err instanceof ComponentAmbiguityError) {
|
|
172
|
+
return {
|
|
173
|
+
selector,
|
|
174
|
+
status: 'ambiguous',
|
|
175
|
+
code: err.code,
|
|
176
|
+
error: err.message,
|
|
177
|
+
candidates: err.candidates,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
return {
|
|
181
|
+
selector,
|
|
182
|
+
status: NOT_FOUND_CODES.has(err.code) ? 'not_found' : 'error',
|
|
183
|
+
code: err.code,
|
|
184
|
+
error: err.message,
|
|
185
|
+
...(err.suggestions ? {suggestions: err.suggestions} : {}),
|
|
186
|
+
};
|
|
187
|
+
}
|
|
41
188
|
|
|
42
189
|
/**
|
|
43
|
-
* @param {
|
|
190
|
+
* @param {unknown[]} selectors
|
|
191
|
+
* @param {object} options
|
|
192
|
+
* @param {string} options.cwd
|
|
193
|
+
* @param {string} [options.package]
|
|
194
|
+
* @param {boolean} [options.props]
|
|
195
|
+
* @param {boolean} [options.source]
|
|
196
|
+
* @param {boolean} [options.showcase]
|
|
197
|
+
* @param {boolean} [options.blocks]
|
|
198
|
+
* @param {'full'|'compact'|'brief'} [options.detail]
|
|
199
|
+
* @param {string|null} [options.lang]
|
|
200
|
+
* @param {boolean} [options.zh]
|
|
201
|
+
* @param {boolean} [options.dense]
|
|
202
|
+
* @param {string} coreDir
|
|
203
|
+
* @returns {Promise<import('./component.type.mjs').ComponentBatchResponse>}
|
|
204
|
+
*/
|
|
205
|
+
async function componentBatch(selectors, options, coreDir) {
|
|
206
|
+
const loadedIntegrations = await loadIntegrationsSafely(options.cwd);
|
|
207
|
+
/** @type {import('./component.type.mjs').ComponentBatchResult[]} */
|
|
208
|
+
const results = [];
|
|
209
|
+
for (const value of selectors) {
|
|
210
|
+
const selector = typeof value === 'string' ? value : String(value);
|
|
211
|
+
try {
|
|
212
|
+
const target = parseComponentSelector(value, options.package);
|
|
213
|
+
requireInstalledSelectorVersion(target, coreDir, loadedIntegrations);
|
|
214
|
+
const result =
|
|
215
|
+
/** @type {import('./component.type.mjs').ComponentSingleResponse} */ (
|
|
216
|
+
await component(target.name, {
|
|
217
|
+
...options,
|
|
218
|
+
lang: options.lang ?? undefined,
|
|
219
|
+
package: target.package,
|
|
220
|
+
})
|
|
221
|
+
);
|
|
222
|
+
results.push({selector, status: 'found', result});
|
|
223
|
+
} catch (error) {
|
|
224
|
+
results.push(batchFailure(selector, error));
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return {type: 'component.batch', data: {count: results.length, results}};
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* @param {string|string[]} [name]
|
|
44
232
|
* @param {object} [options]
|
|
45
233
|
* @param {string} [options.cwd]
|
|
46
234
|
* @param {boolean} [options.list]
|
|
@@ -56,6 +244,7 @@ const LANGS = ['en', 'zh', 'dense'];
|
|
|
56
244
|
* @param {boolean} [options.dense]
|
|
57
245
|
* @returns {Promise<(
|
|
58
246
|
* import('./component.type.mjs').ComponentListResponse
|
|
247
|
+
* | import('./component.type.mjs').ComponentBatchResponse
|
|
59
248
|
* | import('./component.type.mjs').ComponentDetailResponse
|
|
60
249
|
* | import('./component.type.mjs').ComponentDetailPropsResponse
|
|
61
250
|
* | import('./component.type.mjs').ComponentDetailSourceResponse
|
|
@@ -79,11 +268,16 @@ export async function component(name, options = {}) {
|
|
|
79
268
|
dense = false,
|
|
80
269
|
} = options;
|
|
81
270
|
|
|
271
|
+
const selectorList = Array.isArray(name) ? name : null;
|
|
272
|
+
const noName = selectorList == null && !name;
|
|
273
|
+
|
|
82
274
|
// Default detail level mirrors the CLI (see commands/component/index.mjs):
|
|
83
275
|
// single-component views default to 'full', list-style views (--list,
|
|
84
276
|
// --category, or no name) default to 'brief' (scannable name lists).
|
|
85
|
-
//
|
|
86
|
-
|
|
277
|
+
// An explicit array remains a batch even when it is empty or a caller also
|
|
278
|
+
// passes a list-only option.
|
|
279
|
+
const isListView =
|
|
280
|
+
selectorList == null && (list || category != null || noName);
|
|
87
281
|
const detail = detailOption ?? (isListView ? 'brief' : 'full');
|
|
88
282
|
|
|
89
283
|
// Same accepted values and codes as the CLI's --detail and --lang, checked
|
|
@@ -103,6 +297,14 @@ export async function component(name, options = {}) {
|
|
|
103
297
|
);
|
|
104
298
|
}
|
|
105
299
|
|
|
300
|
+
if (selectorList && selectorList.length > COMPONENT_BATCH_SELECTOR_LIMIT) {
|
|
301
|
+
throw new AstryxError(
|
|
302
|
+
`Component batch accepts at most ${COMPONENT_BATCH_SELECTOR_LIMIT} selectors; received ${selectorList.length}`,
|
|
303
|
+
undefined,
|
|
304
|
+
ERROR_CODES.ERR_INVALID_ARGUMENT,
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
|
|
106
308
|
const coreDir = requireCoreDir(cwd);
|
|
107
309
|
|
|
108
310
|
// A public API caller could pass a non-string category; the list leaf does
|
|
@@ -116,11 +318,46 @@ export async function component(name, options = {}) {
|
|
|
116
318
|
);
|
|
117
319
|
}
|
|
118
320
|
|
|
321
|
+
// ── Explicit batch selector list ─────────────────────────────────
|
|
322
|
+
// Array shape owns cardinality even if a caller also supplies a list-only
|
|
323
|
+
// option. The aggregate limit above is checked before core or integrations
|
|
324
|
+
// are resolved, so an oversized request can never emit a partial receipt.
|
|
325
|
+
if (selectorList) {
|
|
326
|
+
return componentBatch(
|
|
327
|
+
selectorList,
|
|
328
|
+
{
|
|
329
|
+
cwd,
|
|
330
|
+
package: packageScope,
|
|
331
|
+
props,
|
|
332
|
+
source,
|
|
333
|
+
showcase,
|
|
334
|
+
blocks,
|
|
335
|
+
detail,
|
|
336
|
+
lang,
|
|
337
|
+
zh,
|
|
338
|
+
dense,
|
|
339
|
+
},
|
|
340
|
+
coreDir,
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
|
|
119
344
|
// ── List mode ──────────────────────────────────────────────────
|
|
120
|
-
if (category || list ||
|
|
345
|
+
if (category || list || noName) {
|
|
121
346
|
return componentList(coreDir, {cwd, category, detail, zh, dense, lang});
|
|
122
347
|
}
|
|
123
348
|
|
|
349
|
+
if (typeof name === 'string') {
|
|
350
|
+
const target = parseComponentSelector(name, packageScope);
|
|
351
|
+
if (target.version) {
|
|
352
|
+
const loadedIntegrations = await loadIntegrationsSafely(cwd);
|
|
353
|
+
requireInstalledSelectorVersion(target, coreDir, loadedIntegrations);
|
|
354
|
+
}
|
|
355
|
+
if (target.name !== name || target.package !== packageScope) {
|
|
356
|
+
return component(target.name, {...options, package: target.package});
|
|
357
|
+
}
|
|
358
|
+
name = target.name;
|
|
359
|
+
}
|
|
360
|
+
|
|
124
361
|
// ── Single component ───────────────────────────────────────────
|
|
125
362
|
if (typeof name !== 'string') {
|
|
126
363
|
throw new AstryxError(
|
|
@@ -186,7 +423,10 @@ export async function component(name, options = {}) {
|
|
|
186
423
|
if (extDocPath) {
|
|
187
424
|
// Legacy packages ship docs, never source.
|
|
188
425
|
if (source) {
|
|
189
|
-
return componentDetailSource(dirName, null, {
|
|
426
|
+
return componentDetailSource(dirName, null, {
|
|
427
|
+
name,
|
|
428
|
+
notFoundInPackage: packageScope,
|
|
429
|
+
});
|
|
190
430
|
}
|
|
191
431
|
if (blocks) {
|
|
192
432
|
return componentDetailBlocks(dirName, cwd);
|
|
@@ -28,6 +28,31 @@ export type ComponentListData = ({
|
|
|
28
28
|
detail: "full";
|
|
29
29
|
components: Record<string, import("@astryxdesign/cli/authoring").ComponentDoc[]>;
|
|
30
30
|
});
|
|
31
|
+
/**
|
|
32
|
+
* `component(string[])` always returns this type, including empty and one-item
|
|
33
|
+
* arrays. The CLI returns it for two or more positional selectors.
|
|
34
|
+
*/
|
|
35
|
+
export type ComponentBatchResponse = import("../../foundation/response/batch.type.mjs").BatchResponse<"component.batch", ComponentSingleResponse, ComponentBatchCandidate>;
|
|
36
|
+
/**
|
|
37
|
+
* One installed component that makes an unqualified selector ambiguous.
|
|
38
|
+
* Keys match a component row in `discover.search` so a caller does not learn a
|
|
39
|
+
* second candidate shape.
|
|
40
|
+
*/
|
|
41
|
+
export type ComponentBatchCandidate = {
|
|
42
|
+
package: string;
|
|
43
|
+
component: string;
|
|
44
|
+
kind: "component";
|
|
45
|
+
installed: true;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* The response a successful single selector would have returned.
|
|
49
|
+
*/
|
|
50
|
+
export type ComponentSingleResponse = (ComponentDetailResponse | ComponentDetailPropsResponse | ComponentDetailSourceResponse | ComponentDetailShowcaseResponse | ComponentDetailBlocksResponse);
|
|
51
|
+
/**
|
|
52
|
+
* One row per requested selector, in argument order. Duplicate selectors keep
|
|
53
|
+
* duplicate rows.
|
|
54
|
+
*/
|
|
55
|
+
export type ComponentBatchResult = import("../../foundation/response/batch.type.mjs").BatchRow<ComponentSingleResponse, ComponentBatchCandidate>;
|
|
31
56
|
/**
|
|
32
57
|
* A single entry in a `component.list` group at `detail: 'names'`. Pre-1.0 the
|
|
33
58
|
* list moved from bare strings to package-qualified objects so consumers can
|
|
@@ -18,6 +18,9 @@
|
|
|
18
18
|
* astryx --json component --category Form -> component.list (filtered)
|
|
19
19
|
* astryx --json component --list --detail compact -> component.list (data.detail='compact')
|
|
20
20
|
* astryx --json component --list --detail full -> component.list (data.detail='full')
|
|
21
|
+
* component([]) -> component.batch (data.count=0)
|
|
22
|
+
* component(['Button']) -> component.batch (data.count=1)
|
|
23
|
+
* astryx --json component Button Badge -> component.batch
|
|
21
24
|
* astryx --json component Button -> component.detail
|
|
22
25
|
* astryx --json component Button --props -> component.detail.props
|
|
23
26
|
* astryx --json component Button --source -> component.detail.source
|
|
@@ -49,6 +52,47 @@
|
|
|
49
52
|
* )} ComponentListData
|
|
50
53
|
*/
|
|
51
54
|
|
|
55
|
+
/**
|
|
56
|
+
* `component(string[])` always returns this type, including empty and one-item
|
|
57
|
+
* arrays. The CLI returns it for two or more positional selectors.
|
|
58
|
+
* @typedef {import('../../foundation/response/batch.type.mjs').BatchResponse<
|
|
59
|
+
* 'component.batch',
|
|
60
|
+
* ComponentSingleResponse,
|
|
61
|
+
* ComponentBatchCandidate
|
|
62
|
+
* >} ComponentBatchResponse
|
|
63
|
+
*/
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* One installed component that makes an unqualified selector ambiguous.
|
|
67
|
+
* Keys match a component row in `discover.search` so a caller does not learn a
|
|
68
|
+
* second candidate shape.
|
|
69
|
+
* @typedef {object} ComponentBatchCandidate
|
|
70
|
+
* @property {string} package
|
|
71
|
+
* @property {string} component
|
|
72
|
+
* @property {'component'} kind
|
|
73
|
+
* @property {true} installed
|
|
74
|
+
*/
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* The response a successful single selector would have returned.
|
|
78
|
+
* @typedef {(
|
|
79
|
+
* | ComponentDetailResponse
|
|
80
|
+
* | ComponentDetailPropsResponse
|
|
81
|
+
* | ComponentDetailSourceResponse
|
|
82
|
+
* | ComponentDetailShowcaseResponse
|
|
83
|
+
* | ComponentDetailBlocksResponse
|
|
84
|
+
* )} ComponentSingleResponse
|
|
85
|
+
*/
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* One row per requested selector, in argument order. Duplicate selectors keep
|
|
89
|
+
* duplicate rows.
|
|
90
|
+
* @typedef {import('../../foundation/response/batch.type.mjs').BatchRow<
|
|
91
|
+
* ComponentSingleResponse,
|
|
92
|
+
* ComponentBatchCandidate
|
|
93
|
+
* >} ComponentBatchResult
|
|
94
|
+
*/
|
|
95
|
+
|
|
52
96
|
/**
|
|
53
97
|
* A single entry in a `component.list` group at `detail: 'names'`. Pre-1.0 the
|
|
54
98
|
* list moved from bare strings to package-qualified objects so consumers can
|