@astryxdesign/cli 0.7.2-canary.f16dc9f → 0.7.2-canary.f2b60a0
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 +15 -14
- package/api/build/help/help.mjs +1 -1
- package/api/component/_adapter.d.mts +41 -1
- package/api/component/_adapter.mjs +93 -7
- package/api/component/component.mjs +22 -5
- package/api/component/component.test.mjs +420 -167
- package/api/component/integration-export-name.test.mjs +644 -0
- package/api/component/list/list.mjs +42 -4
- package/api/docs/_adapter.d.mts +11 -0
- package/api/docs/_adapter.mjs +244 -1
- package/api/docs/integrationDocs.test.mjs +124 -0
- package/api/doctor/doctor.mjs +27 -3
- package/api/doctor/doctor.test.mjs +43 -0
- package/api/doctor/theme-checks.mjs +1 -1
- package/api/gap-report/gap-report.mjs +67 -4
- package/api/index.d.mts +2 -0
- package/api/index.mjs +2 -0
- package/api/init/run/run.mjs +2 -2
- package/api/integration/_adapter.d.mts +12 -0
- package/api/integration/_adapter.mjs +54 -0
- package/api/integration/add-contribution.component-names.test.mjs +66 -0
- package/api/integration/add-contribution.mjs +8 -4
- package/api/integration/add-contribution.test.mjs +4 -2
- package/api/integration/authoring-checks.mjs +11 -2
- package/api/integration/authoring-checks.test.mjs +39 -0
- package/api/integration/authoring-checks.type.d.mts +9 -0
- package/api/integration/authoring-checks.type.mjs +14 -1
- package/api/integration/check/check.d.mts +96 -0
- package/api/integration/check/check.mjs +357 -0
- package/api/integration/check/check.test.mjs +489 -0
- package/api/integration/integration-check.type.d.mts +118 -0
- package/api/integration/integration-check.type.mjs +84 -0
- package/api/integration/integrationCheck.doc.d.mts +10 -0
- package/api/integration/integrationCheck.doc.mjs +73 -0
- package/api/integration/integrationComponentConflicts.doc.mjs +36 -5
- package/api/integration/pack-check.mjs +61 -107
- package/api/integration/pack-check.test.mjs +359 -0
- package/api/integration/validate-integration.mjs +8 -0
- package/api/integration/validate-integration.test.mjs +11 -0
- package/api/integration/validate-integration.type.d.mts +8 -0
- package/api/integration/validate-integration.type.mjs +12 -1
- package/api/integration/validateIntegration.doc.mjs +17 -3
- package/api/search/search.d.mts +22 -6
- package/api/search/search.domain-priority.test.mjs +108 -18
- package/api/search/search.integration-check.test.mjs +24 -0
- package/api/search/search.mjs +141 -25
- package/api/search/search.test.mjs +36 -0
- package/api/swizzle/copy/copy.mjs +28 -14
- package/api/template/template.test.mjs +120 -3
- package/api/theme/build/build.family.test.mjs +64 -0
- package/api/theme/build/build.mjs +180 -24
- package/api/theme/themeBuild.doc.mjs +4 -4
- package/assets/codemods/transforms/next/__tests__/migrate-list-edge-compensation-to-edge.test.mjs +120 -0
- package/assets/codemods/transforms/next/index.mjs +11 -1
- package/assets/codemods/transforms/next/migrate-list-edge-compensation-to-edge.mjs +198 -0
- package/assets/docs/README.md +10 -0
- package/assets/docs/author-a-theme.doc.mjs +1 -1
- package/assets/docs/getting-started.doc.mjs +3 -3
- package/assets/docs/styling-overview.doc.mjs +1 -1
- package/assets/docs/theme.doc.dense.mjs +1 -1
- package/assets/docs/theme.doc.mjs +1 -1
- package/assets/docs/theme.doc.zh.mjs +1 -1
- package/assets/docs/tree/add-a-component.doc.mjs +11 -1
- package/assets/docs/tree/add-a-theme.doc.mjs +1 -1
- package/assets/docs/tree/add-a-topic.doc.mjs +10 -7
- package/assets/docs/tree/agent-guidance.doc.mjs +2 -2
- package/assets/docs/tree/block-template.doc.mjs +8 -20
- package/assets/docs/tree/build-the-template.doc.mjs +1 -1
- package/assets/docs/tree/check-the-props.doc.mjs +196 -0
- package/assets/docs/tree/check-your-docs.doc.mjs +51 -5
- package/assets/docs/tree/checks.doc.mjs +24 -16
- package/assets/docs/tree/codemods.doc.mjs +4 -4
- package/assets/docs/tree/component-family.doc.mjs +8 -6
- package/assets/docs/tree/component-imports.doc.mjs +10 -2
- package/assets/docs/tree/components.doc.mjs +1 -1
- package/assets/docs/tree/debug-and-gap-reports.doc.mjs +7 -18
- package/assets/docs/tree/define-the-theme.doc.mjs +6 -5
- package/assets/docs/tree/describe-the-component.doc.mjs +2 -2
- package/assets/docs/tree/docs.doc.mjs +3 -3
- package/assets/docs/tree/document-the-template.doc.mjs +1 -1
- package/assets/docs/tree/document-the-theme.doc.mjs +1 -1
- package/assets/docs/tree/export-template-assets.doc.mjs +1 -1
- package/assets/docs/tree/extend-or-replace.doc.mjs +6 -6
- package/assets/docs/tree/fonts-and-assets.doc.mjs +2 -2
- package/assets/docs/tree/generate-a-palette.doc.mjs +5 -3
- package/assets/docs/tree/grade-template-with-agent.doc.mjs +1 -1
- package/assets/docs/tree/integrations.doc.mjs +8 -0
- package/assets/docs/tree/links.doc.mjs +6 -5
- package/assets/docs/tree/migration-setup.doc.mjs +1 -0
- package/assets/docs/tree/migration-verification.doc.mjs +0 -1
- package/assets/docs/tree/migration.doc.mjs +0 -1
- package/assets/docs/tree/package-and-test.doc.mjs +1 -1
- package/assets/docs/tree/page-template.doc.mjs +4 -8
- package/assets/docs/tree/publishing.doc.mjs +1 -1
- package/assets/docs/tree/quick-start.doc.mjs +37 -21
- package/assets/docs/tree/replace-a-core-component.doc.mjs +4 -6
- package/assets/docs/tree/replace-a-core-template.doc.mjs +6 -8
- package/assets/docs/tree/sections-and-placement.doc.mjs +4 -6
- package/assets/docs/tree/see-it-in-an-app.doc.mjs +4 -2
- package/assets/docs/tree/short-and-findable.doc.mjs +6 -5
- package/assets/docs/tree/single-component.doc.mjs +15 -6
- package/assets/docs/tree/start-a-template.doc.mjs +3 -3
- package/assets/docs/tree/subcomponent.doc.mjs +6 -6
- package/assets/docs/tree/template-assets.doc.mjs +2 -2
- package/assets/docs/tree/template-doc-overview.doc.mjs +4 -15
- package/assets/docs/tree/template-fonts.doc.mjs +1 -1
- package/assets/docs/tree/template-icons.doc.mjs +1 -1
- package/assets/docs/tree/template-images-media.doc.mjs +1 -1
- package/assets/docs/tree/template-styles.doc.mjs +2 -2
- package/assets/docs/tree/templates.doc.mjs +1 -1
- package/assets/docs/tree/test-in-an-app.doc.mjs +3 -3
- package/assets/docs/tree/test-template-in-app.doc.mjs +1 -1
- package/assets/docs/tree/tokens-and-setup.doc.mjs +19 -15
- package/assets/docs/tree/troubleshooting.doc.mjs +13 -5
- package/assets/docs/tree/type-scale.doc.mjs +3 -3
- package/assets/docs/tree/upgrading.doc.mjs +3 -3
- package/assets/docs/tree/use-a-theme-in-an-app.doc.mjs +3 -1
- package/assets/docs/tree/verify-packed-template.doc.mjs +1 -1
- package/assets/docs/tree/versioning.doc.mjs +7 -6
- package/assets/docs/tree/write-the-template-file.doc.mjs +4 -3
- package/assets/docs/use-a-theme.doc.mjs +2 -2
- package/assets/docs/working-with-ai.doc.mjs +43 -4
- package/assets/templates/blocks/components/Drawer/DrawerForm.doc.mjs +24 -0
- package/assets/templates/blocks/components/Drawer/DrawerForm.tsx +62 -0
- package/assets/templates/blocks/components/Drawer/DrawerScrim.doc.mjs +22 -0
- package/assets/templates/blocks/components/Drawer/DrawerScrim.tsx +68 -0
- package/assets/templates/blocks/components/Drawer/DrawerShowcase.doc.mjs +22 -0
- package/assets/templates/blocks/components/Drawer/DrawerShowcase.tsx +41 -0
- package/assets/templates/blocks/components/Drawer/DrawerStart.doc.mjs +21 -0
- package/assets/templates/blocks/components/Drawer/DrawerStart.tsx +41 -0
- package/assets/templates/blocks/components/Drawer/DrawerWidths.doc.mjs +22 -0
- package/assets/templates/blocks/components/Drawer/DrawerWidths.tsx +54 -0
- package/assets/templates/blocks/components/DrawerHeader/DrawerHeaderShowcase.doc.mjs +15 -0
- package/assets/templates/blocks/components/DrawerHeader/DrawerHeaderShowcase.tsx +73 -0
- package/assets/templates/blocks/components/DrawerHeader/DrawerHeaderSubtitleEndContent.doc.mjs +22 -0
- package/assets/templates/blocks/components/DrawerHeader/DrawerHeaderSubtitleEndContent.tsx +49 -0
- package/assets/templates/blocks/components/DrawerHeader/DrawerHeaderWithCloseButton.doc.mjs +21 -0
- package/assets/templates/blocks/components/DrawerHeader/DrawerHeaderWithCloseButton.tsx +42 -0
- package/assets/templates/pages/detail-page/page.tsx +3 -3
- package/assets/templates/pages/table-inbox/page.tsx +10 -8
- package/assets/theme.template.ts +1 -1
- package/authoring/codemod/codemod.doc.mjs +7 -3
- package/authoring/config/config.doc.mjs +9 -6
- package/authoring/config/type.ts +4 -2
- package/authoring/discover/discover.doc.mjs +1 -1
- package/authoring/doctypes/base/graph-fields.doc.mjs +6 -4
- package/authoring/doctypes/base/type.ts +6 -0
- package/authoring/doctypes/command/command.doc.mjs +14 -12
- package/authoring/doctypes/component/component.doc.mjs +31 -28
- package/authoring/doctypes/component/type.ts +13 -8
- package/authoring/doctypes/enum/enum.doc.mjs +7 -4
- package/authoring/doctypes/function/function.doc.mjs +9 -8
- package/authoring/doctypes/hook/hook.doc.mjs +5 -4
- package/authoring/doctypes/namespace/namespace.doc.mjs +7 -6
- package/authoring/doctypes/reference/reference.doc.mjs +11 -10
- package/authoring/doctypes/schema/schema.doc.mjs +9 -9
- package/authoring/doctypes/template/integration-template.doc.d.mts +11 -0
- package/authoring/doctypes/template/integration-template.doc.mjs +49 -0
- package/authoring/doctypes/template/parse.d.mts +6 -2
- package/authoring/doctypes/template/parse.mjs +3 -1
- package/authoring/doctypes/template/template.doc.mjs +3 -3
- package/authoring/doctypes/template/type.ts +22 -0
- package/authoring/doctypes/theme/theme.doc.mjs +2 -2
- package/authoring/gap-report/gap-report.doc.mjs +2 -2
- package/authoring/identity/identity.doc.mjs +3 -3
- package/authoring/index.d.ts +1 -0
- package/authoring/integration/integration.doc.mjs +12 -4
- package/authoring/integration/parse.test.mjs +10 -0
- package/authoring/integration/schema.d.mts +2 -0
- package/authoring/integration/schema.mjs +1 -0
- package/authoring/integration/type.ts +4 -0
- package/clients/cli/commands/build-theme.batch-report.test.mjs +3 -1
- package/clients/cli/commands/build-theme.mjs +1 -1
- package/clients/cli/commands/build-theme.path-safety.test.mjs +224 -6
- package/clients/cli/commands/build-theme.registry.test.mjs +5 -2
- package/clients/cli/commands/cli-postinstall.test.mjs +49 -1
- package/clients/cli/commands/doctor-integration-components.doc.mjs +15 -4
- package/clients/cli/commands/doctor-integration-validate.doc.mjs +11 -2
- package/clients/cli/commands/doctor-integration.test.mjs +837 -0
- package/clients/cli/commands/doctor.mjs +190 -0
- package/clients/cli/commands/integration-check.doc.mjs +85 -0
- package/clients/cli/commands/integration-check.test.mjs +267 -0
- package/clients/cli/commands/integration.doc.mjs +6 -2
- package/clients/cli/commands/integration.mjs +107 -1
- package/clients/cli/commands/setup-nudge.test.mjs +79 -1
- package/clients/cli/commands/swizzle.mjs +5 -3
- package/clients/cli/commands/swizzle.routing.test.mjs +18 -1
- package/clients/cli/commands/text-json-parity.test.mjs +5 -0
- package/clients/cli/commands/theme-build.doc.mjs +2 -2
- package/clients/cli/index.mjs +30 -5
- package/clients/cli/lib/component-format.mjs +5 -1
- package/foundation/agent-docs/agent-doc-state.d.mts +14 -0
- package/foundation/agent-docs/agent-doc-state.mjs +38 -0
- package/foundation/agent-docs/agent-docs.d.mts +2 -1
- package/foundation/agent-docs/agent-docs.mjs +8 -6
- package/foundation/config/project.mjs +82 -0
- package/foundation/discovery/authoring-self-docs.mjs +2 -1
- package/foundation/discovery/component-discovery.d.mts +190 -10
- package/foundation/discovery/component-discovery.export-names.test.mjs +760 -0
- package/foundation/discovery/component-discovery.mjs +864 -56
- package/foundation/discovery/component-discovery.test.mjs +96 -0
- package/foundation/discovery/component-replacement.mjs +18 -0
- package/foundation/discovery/component-replacement.test.mjs +40 -0
- package/foundation/discovery/doc-types.d.mts +157 -0
- package/foundation/discovery/doc-types.mjs +1224 -0
- package/foundation/discovery/doc-types.test.mjs +652 -0
- package/foundation/discovery/docs-discovery.d.mts +81 -0
- package/foundation/discovery/docs-discovery.mjs +57 -0
- package/foundation/discovery/integration-doc-files.d.mts +22 -0
- package/foundation/discovery/integration-doc-files.mjs +231 -0
- package/foundation/discovery/integration-doc-files.test.mjs +246 -0
- package/foundation/discovery/module-exports.d.mts +27 -0
- package/foundation/discovery/module-exports.mjs +356 -31
- package/foundation/discovery/module-exports.test.mjs +172 -0
- package/foundation/discovery/package-tsconfig.d.mts +14 -0
- package/foundation/discovery/package-tsconfig.mjs +228 -0
- package/foundation/discovery/package-tsconfig.test.mjs +210 -0
- package/foundation/discovery/project-typescript.d.mts +23 -0
- package/foundation/discovery/project-typescript.mjs +61 -0
- package/foundation/discovery/prop-drift.d.mts +278 -0
- package/foundation/discovery/prop-drift.mjs +2263 -0
- package/foundation/discovery/prop-drift.test.mjs +2219 -0
- package/foundation/discovery/template-adapter.mjs +74 -5
- package/foundation/discovery/type-match.d.mts +53 -0
- package/foundation/discovery/type-match.mjs +660 -0
- package/foundation/discovery/type-match.test.mjs +169 -0
- package/foundation/discovery/type-text.d.mts +68 -0
- package/foundation/discovery/type-text.mjs +658 -0
- package/foundation/discovery/type-text.test.mjs +196 -0
- package/foundation/discovery/unresolved-references.d.mts +62 -0
- package/foundation/discovery/unresolved-references.mjs +790 -0
- package/foundation/discovery/unresolved-references.test.mjs +567 -0
- package/foundation/doc-compiler/doc-loads.test.mjs +11 -1
- package/foundation/doc-compiler/inputs.mjs +23 -0
- package/foundation/doc-compiler/inputs.test.mjs +0 -1
- package/foundation/doc-compiler/links.d.mts +9 -5
- package/foundation/doc-compiler/links.mjs +4 -2
- package/foundation/integrations/contribution-inventory.mjs +6 -1
- package/foundation/response/response-types.doc.mjs +7 -2
- package/foundation/xle/registry.mjs +4 -0
- package/foundation/xle/registry.test.mjs +28 -0
- package/package.json +10 -10
- package/scripts/postinstall.mjs +3 -3
|
@@ -98,6 +98,85 @@ function issueBlocks(issues) {
|
|
|
98
98
|
];
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
+
/**
|
|
102
|
+
* The docs checked against the authoring types: a visible line when it was
|
|
103
|
+
* skipped, the findings (all warnings), the files it could not check, or an
|
|
104
|
+
* [ok] (never after a failed check).
|
|
105
|
+
* @param {import('../../../api/integration/validate-integration.type.mjs').DocTypesReport | undefined} report
|
|
106
|
+
* @param {boolean} failed
|
|
107
|
+
*/
|
|
108
|
+
function docTypesBlocks(report, failed) {
|
|
109
|
+
if (!report) return [];
|
|
110
|
+
if (
|
|
111
|
+
report.status === 'checked' &&
|
|
112
|
+
report.docs === 0 &&
|
|
113
|
+
report.findings.length === 0 &&
|
|
114
|
+
report.unchecked.length === 0
|
|
115
|
+
) {
|
|
116
|
+
return [
|
|
117
|
+
text('[info] No doc files to type-check.'),
|
|
118
|
+
...(report.fixtures
|
|
119
|
+
? [text(`[info] ${report.fixtures} test fixture doc(s) not checked.`)]
|
|
120
|
+
: []),
|
|
121
|
+
];
|
|
122
|
+
}
|
|
123
|
+
if (report.status === 'skipped') {
|
|
124
|
+
return [text(`[skip] Docs not type-checked: ${report.reason}`)];
|
|
125
|
+
}
|
|
126
|
+
const blocks = [
|
|
127
|
+
section(
|
|
128
|
+
`Checking ${report.docs} doc(s) against the authoring types${report.typescript ? ` (TypeScript ${report.typescript})` : ''}`,
|
|
129
|
+
),
|
|
130
|
+
];
|
|
131
|
+
if (report.findings.length > 0) {
|
|
132
|
+
const files = new Set(report.findings.map(f => f.doc)).size;
|
|
133
|
+
blocks.push(
|
|
134
|
+
records(report.findings, {
|
|
135
|
+
fields: [
|
|
136
|
+
'severity',
|
|
137
|
+
'doc',
|
|
138
|
+
'line',
|
|
139
|
+
'export',
|
|
140
|
+
'type',
|
|
141
|
+
'field',
|
|
142
|
+
'problem',
|
|
143
|
+
'message',
|
|
144
|
+
'fix',
|
|
145
|
+
],
|
|
146
|
+
format: {severity: statusToken},
|
|
147
|
+
}),
|
|
148
|
+
text(
|
|
149
|
+
`${report.findings.length} doc field(s) in ${files} file(s) do not match the authoring types. ` +
|
|
150
|
+
'These are warnings; `astryx docs authoring` lists every field.',
|
|
151
|
+
),
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
if (report.unchecked.length > 0) {
|
|
155
|
+
blocks.push(
|
|
156
|
+
text(`[info] Not type-checked: ${report.unchecked.length} doc file(s):`),
|
|
157
|
+
records(report.unchecked, {fields: ['doc', 'reason']}),
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
if (report.fixtures) {
|
|
161
|
+
blocks.push(
|
|
162
|
+
text(`[info] ${report.fixtures} test fixture doc(s) not checked.`),
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
if (report.findings.length === 0 && report.docs > 0) {
|
|
166
|
+
// After a failed check an [ok] reads as a pass, but the result still shows.
|
|
167
|
+
blocks.push(
|
|
168
|
+
text(
|
|
169
|
+
failed
|
|
170
|
+
? `[info] No doc field differs from its authoring type (${report.docs} checked).`
|
|
171
|
+
: report.unchecked.length > 0
|
|
172
|
+
? `[ok] Every doc that was checked matches its authoring type (${report.docs} checked).`
|
|
173
|
+
: `[ok] Every doc matches its authoring type (${report.docs} checked).`,
|
|
174
|
+
),
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
return blocks;
|
|
178
|
+
}
|
|
179
|
+
|
|
101
180
|
/**
|
|
102
181
|
* @param {import('../../../api/integration/validate-integration.type.mjs').ValidateIntegrationResponse['data']} data
|
|
103
182
|
*/
|
|
@@ -119,6 +198,7 @@ function printIntegrationValidation(data) {
|
|
|
119
198
|
`Summary: ${errors} error${errors === 1 ? '' : 's'}, ` +
|
|
120
199
|
`${warnings} warning${warnings === 1 ? '' : 's'}`,
|
|
121
200
|
),
|
|
201
|
+
...docTypesBlocks(data.docTypes, errors > 0),
|
|
122
202
|
);
|
|
123
203
|
}
|
|
124
204
|
|
|
@@ -173,6 +253,98 @@ function printTemplateConflicts(data) {
|
|
|
173
253
|
emit(...output);
|
|
174
254
|
}
|
|
175
255
|
|
|
256
|
+
/**
|
|
257
|
+
* The documented-props comparison, with every field its JSON carries: a
|
|
258
|
+
* visible line when it was skipped, the findings (all warnings), the
|
|
259
|
+
* components it could not read, and how many were compared with which
|
|
260
|
+
* TypeScript, as an [ok] when nothing differs (never after a failed check).
|
|
261
|
+
* Then how many documented prop types were judged and which were not.
|
|
262
|
+
* @param {import('../../../api/integration/authoring-checks.type.mjs').PropDriftReport | undefined} report
|
|
263
|
+
* @param {boolean} failed
|
|
264
|
+
*/
|
|
265
|
+
function propDriftBlocks(report, failed) {
|
|
266
|
+
if (!report) return [];
|
|
267
|
+
if (report.status === 'skipped') {
|
|
268
|
+
return [text(`[skip] Props not compared: ${report.reason}`)];
|
|
269
|
+
}
|
|
270
|
+
const blocks = [];
|
|
271
|
+
if (report.findings.length > 0) {
|
|
272
|
+
// Two docs of one name are two components.
|
|
273
|
+
const components = new Set(
|
|
274
|
+
report.findings.map(f => `${f.doc}\0${f.component}`),
|
|
275
|
+
).size;
|
|
276
|
+
blocks.push(
|
|
277
|
+
records(report.findings, {
|
|
278
|
+
fields: [
|
|
279
|
+
'severity',
|
|
280
|
+
'component',
|
|
281
|
+
'prop',
|
|
282
|
+
'kind',
|
|
283
|
+
'message',
|
|
284
|
+
'doc',
|
|
285
|
+
'source',
|
|
286
|
+
'docType',
|
|
287
|
+
'codeType',
|
|
288
|
+
'docRequired',
|
|
289
|
+
'codeRequired',
|
|
290
|
+
],
|
|
291
|
+
format: {severity: statusToken},
|
|
292
|
+
}),
|
|
293
|
+
text(
|
|
294
|
+
`${report.findings.length} prop(s) differ between the docs and the code in ${components} of ${report.components} component(s) compared (TypeScript ${report.typescript}). ` +
|
|
295
|
+
'These are warnings: update the doc, or the code if the doc is right.',
|
|
296
|
+
),
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
if (report.unchecked.length > 0) {
|
|
300
|
+
blocks.push(
|
|
301
|
+
text(
|
|
302
|
+
`[info] Props not compared for ${report.unchecked.length} documented component(s):`,
|
|
303
|
+
),
|
|
304
|
+
records(report.unchecked, {fields: ['component', 'doc', 'reason']}),
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
const notChecked = report.propsNotChecked ?? [];
|
|
308
|
+
if (notChecked.length > 0) {
|
|
309
|
+
blocks.push(
|
|
310
|
+
text(
|
|
311
|
+
`[info] Props not checked for a doc entry in ${notChecked.length} component(s):`,
|
|
312
|
+
),
|
|
313
|
+
records(notChecked, {fields: ['component', 'doc', 'reason', 'props']}),
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
if (report.findings.length === 0) {
|
|
317
|
+
const apart =
|
|
318
|
+
notChecked.length > 0 ? ', apart from the props not checked' : '';
|
|
319
|
+
blocks.push(
|
|
320
|
+
text(
|
|
321
|
+
!failed && report.components > 0
|
|
322
|
+
? `[ok] Documented prop names and required flags match the code in ${report.components} component(s)${apart} (TypeScript ${report.typescript}).`
|
|
323
|
+
: `[info] Props compared in ${report.components} component(s) (TypeScript ${report.typescript}).`,
|
|
324
|
+
),
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
if (report.typesSkipped) {
|
|
328
|
+
blocks.push(text(`[skip] Prop types not judged: ${report.typesSkipped}.`));
|
|
329
|
+
return blocks;
|
|
330
|
+
}
|
|
331
|
+
const notCompared = report.typesNotCompared.flatMap(entry => entry.props);
|
|
332
|
+
blocks.push(
|
|
333
|
+
text(
|
|
334
|
+
`[info] Documented prop types judged: ${report.typesCompared}; not compared: ${notCompared.length}. ` +
|
|
335
|
+
'A type is judged when the doc writes it the same as the source (exactly, if it contains `readonly`), or when both are primitives, literals, arrays and unions of those, or names for them.',
|
|
336
|
+
),
|
|
337
|
+
);
|
|
338
|
+
if (notCompared.length > 0) {
|
|
339
|
+
blocks.push(
|
|
340
|
+
records(report.typesNotCompared, {
|
|
341
|
+
fields: ['component', 'doc', 'reason', 'props'],
|
|
342
|
+
}),
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
return blocks;
|
|
346
|
+
}
|
|
347
|
+
|
|
176
348
|
/**
|
|
177
349
|
* @param {import('../../../api/integration/authoring-checks.type.mjs').IntegrationComponentConflictResponse['data']} data
|
|
178
350
|
*/
|
|
@@ -205,6 +377,7 @@ function printComponentConflicts(data) {
|
|
|
205
377
|
),
|
|
206
378
|
);
|
|
207
379
|
}
|
|
380
|
+
output.push(...propDriftBlocks(data.propDrift, failed));
|
|
208
381
|
emit(...output);
|
|
209
382
|
}
|
|
210
383
|
|
|
@@ -242,6 +415,23 @@ function printDocConflicts(data) {
|
|
|
242
415
|
emit(...output);
|
|
243
416
|
}
|
|
244
417
|
|
|
418
|
+
/**
|
|
419
|
+
* Print one `doctor integration` check's result as its own subcommand prints
|
|
420
|
+
* it. `astryx integration check` prints each check it runs through this.
|
|
421
|
+
* @param {import('../../../api/integration/integration-check.type.mjs').IntegrationCheckResponse} response
|
|
422
|
+
*/
|
|
423
|
+
export function printIntegrationCheckResponse(response) {
|
|
424
|
+
if (response.type === 'integration.validate') {
|
|
425
|
+
printIntegrationValidation(response.data);
|
|
426
|
+
} else if (response.type === 'integration.component-conflicts') {
|
|
427
|
+
printComponentConflicts(response.data);
|
|
428
|
+
} else if (response.type === 'integration.template-conflicts') {
|
|
429
|
+
printTemplateConflicts(response.data);
|
|
430
|
+
} else {
|
|
431
|
+
printDocConflicts(response.data);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
245
435
|
/** @param {import('commander').Command} program */
|
|
246
436
|
async function runProjectDoctor(program) {
|
|
247
437
|
const report = await runChecks();
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file CommandDoc for `astryx integration check`.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** @type {import('@astryxdesign/cli/authoring').CommandDoc} */
|
|
8
|
+
export const doc = {
|
|
9
|
+
type: 'command',
|
|
10
|
+
name: 'integration check',
|
|
11
|
+
displayName: 'astryx integration check',
|
|
12
|
+
namespace: 'cli/commands',
|
|
13
|
+
summary:
|
|
14
|
+
"The CI check for an integration package's own build: every source check, run in continuous integration or a typecheck script, against the package in the current folder",
|
|
15
|
+
description:
|
|
16
|
+
'Takes no package argument: it runs the four `doctor integration` checks, ' +
|
|
17
|
+
'`validate`, `components`, `templates`, and `docs`, against the integration ' +
|
|
18
|
+
'package in the current folder, which is where its own build runs it. It prints ' +
|
|
19
|
+
'each result as that check ' +
|
|
20
|
+
'prints it, then a summary with the errors, warnings, and skipped work of each, ' +
|
|
21
|
+
'and exits 1 when any of the four would exit 1 on its own. With `--strict` it ' +
|
|
22
|
+
'also exits 1 on any warning and on any check, or comparison within a check, ' +
|
|
23
|
+
'that did not run, such as a package with no `astryx.integration.*` or a ' +
|
|
24
|
+
'comparison skipped because the project has no TypeScript, or prop types not ' +
|
|
25
|
+
'judged because its TypeScript is older than 4.8: it adds no check, ' +
|
|
26
|
+
'and lists each of those again as an error, after the checks, in their own ' +
|
|
27
|
+
'issue format. That is the line ' +
|
|
28
|
+
"for the package's own build, so its docs, types, and links stay in sync: run " +
|
|
29
|
+
'it as a `ci` step, or add ' +
|
|
30
|
+
'`"typecheck": "tsc --noEmit && astryx integration check --strict"` to the ' +
|
|
31
|
+
'scripts in package.json. Its exit codes and JSON are a contract for the builds ' +
|
|
32
|
+
'that run it: a new check, or a new failure code, joins only in a minor release ' +
|
|
33
|
+
'that names it in the release notes. A patch can still ship a Core component, ' +
|
|
34
|
+
'template, or CLI topic whose name conflicts with one of yours. Run ' +
|
|
35
|
+
'`integration check` on every build; run ' +
|
|
36
|
+
'`integration verify` before you publish, to check that the packed package ' +
|
|
37
|
+
'works in an app. To check an installed integration by name, run the ' +
|
|
38
|
+
'`doctor integration` subcommands with its package name.',
|
|
39
|
+
fn: 'integrationCheck',
|
|
40
|
+
options: [
|
|
41
|
+
{
|
|
42
|
+
flag: '--strict',
|
|
43
|
+
param: 'options.strict',
|
|
44
|
+
description:
|
|
45
|
+
'Also exit 1 on any warning and on any check that did not run. A new check or failure code joins only in a minor release, named in the release notes.',
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
examples: [
|
|
49
|
+
{
|
|
50
|
+
label:
|
|
51
|
+
'In CI, as the typecheck script: add "typecheck": "tsc --noEmit && astryx integration check --strict" to package.json',
|
|
52
|
+
cli: 'integration check --strict',
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
label: 'Errors only, while you fix the warnings a package already has',
|
|
56
|
+
cli: 'integration check',
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
label: 'Read the result as JSON',
|
|
60
|
+
cli: 'integration check --strict --json',
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
label:
|
|
64
|
+
'Before you publish: check that the packed package works in an app',
|
|
65
|
+
cli: 'integration verify',
|
|
66
|
+
},
|
|
67
|
+
],
|
|
68
|
+
exitCodes: [
|
|
69
|
+
{
|
|
70
|
+
code: 0,
|
|
71
|
+
when: 'no check fails on its own; with --strict, also no warning, and every check ran',
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
code: 1,
|
|
75
|
+
when: 'a check fails on its own (an error); with --strict, also any warning, or a check that did not run',
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
related: [
|
|
79
|
+
'integration verify',
|
|
80
|
+
'doctor integration validate',
|
|
81
|
+
'doctor integration components',
|
|
82
|
+
'doctor integration templates',
|
|
83
|
+
'doctor integration docs',
|
|
84
|
+
],
|
|
85
|
+
};
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file `astryx integration check`: every source check in one command, the
|
|
5
|
+
* summary, exit codes with and without `--strict`, and the `--strict`
|
|
6
|
+
* failures, in text and JSON alike.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import {afterEach, beforeEach, describe, expect, it} from 'vitest';
|
|
10
|
+
import * as fs from 'node:fs';
|
|
11
|
+
import * as os from 'node:os';
|
|
12
|
+
import * as path from 'node:path';
|
|
13
|
+
import {runCli} from '../../../test-utils/run-cli.mjs';
|
|
14
|
+
import {discoverCoreTemplates} from '../../../foundation/discovery/template-adapter.mjs';
|
|
15
|
+
|
|
16
|
+
/** @type {string} */
|
|
17
|
+
let tmpDir;
|
|
18
|
+
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
// Under the repository, so the components check resolves Core.
|
|
21
|
+
tmpDir = fs.mkdtempSync(
|
|
22
|
+
path.join(process.cwd(), '.astryx-integration-check-cli-'),
|
|
23
|
+
);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
afterEach(() => {
|
|
27
|
+
fs.rmSync(tmpDir, {recursive: true, force: true});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* A package whose one page template takes a Core template's id: one warning
|
|
32
|
+
* (`templates` conflict). The doc matches TemplateDoc, so no other check
|
|
33
|
+
* warns about it.
|
|
34
|
+
* @param {{id: string, replaces?: string, extraManifest?: string, dir?: string}} options
|
|
35
|
+
*/
|
|
36
|
+
function writePackage({id, replaces, extraManifest = '', dir = tmpDir}) {
|
|
37
|
+
fs.writeFileSync(
|
|
38
|
+
path.join(dir, 'package.json'),
|
|
39
|
+
JSON.stringify({name: '@acme/widgets', version: '1.2.3'}),
|
|
40
|
+
);
|
|
41
|
+
fs.writeFileSync(
|
|
42
|
+
path.join(dir, 'astryx.integration.mjs'),
|
|
43
|
+
`export default {templates: './templates'${extraManifest}};\n`,
|
|
44
|
+
);
|
|
45
|
+
fs.mkdirSync(path.join(dir, 'templates'), {recursive: true});
|
|
46
|
+
fs.writeFileSync(
|
|
47
|
+
path.join(dir, 'templates', `${id}.doc.mjs`),
|
|
48
|
+
`export default {type: 'page', name: 'Integration template', displayName: 'Integration template', description: 'fixture'${replaces == null ? '' : `, replaces: ${JSON.stringify(replaces)}`}};\n`,
|
|
49
|
+
);
|
|
50
|
+
fs.writeFileSync(
|
|
51
|
+
path.join(dir, 'templates', `${id}.tsx`),
|
|
52
|
+
'export default function Fixture() { return null; }\n',
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function coreTemplateId() {
|
|
57
|
+
const core = (await discoverCoreTemplates()).find(
|
|
58
|
+
template => template.type === 'page',
|
|
59
|
+
);
|
|
60
|
+
expect(core).toBeDefined();
|
|
61
|
+
return /** @type {{dirName: string}} */ (core).dirName;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
describe('astryx integration check', () => {
|
|
65
|
+
it('runs validate, components, templates, and docs in order, then a summary, and exits 0 on a warning', async () => {
|
|
66
|
+
writePackage({id: await coreTemplateId()});
|
|
67
|
+
|
|
68
|
+
const run = await runCli(['integration', 'check'], tmpDir);
|
|
69
|
+
|
|
70
|
+
const order = [
|
|
71
|
+
'Validating integration: @acme/widgets@1.2.3',
|
|
72
|
+
'Checking integration components: @acme/widgets@1.2.3',
|
|
73
|
+
'Checking integration templates: @acme/widgets@1.2.3',
|
|
74
|
+
'Checking integration docs: @acme/widgets@1.2.3',
|
|
75
|
+
'Integration check: @acme/widgets@1.2.3',
|
|
76
|
+
].map(line => run.stdout.indexOf(line));
|
|
77
|
+
expect(order.every(index => index >= 0)).toBe(true);
|
|
78
|
+
expect([...order].sort((a, b) => a - b)).toEqual(order);
|
|
79
|
+
expect(run.stdout).toContain('Consider renaming');
|
|
80
|
+
expect(run.stdout).not.toContain('Failing under --strict');
|
|
81
|
+
expect(run.stdout).toContain(
|
|
82
|
+
'[ok] 0 errors, 1 warning, 0 skipped. No check failed;',
|
|
83
|
+
);
|
|
84
|
+
// Each check's output stands apart from the next.
|
|
85
|
+
const lines = run.stdout.split('\n');
|
|
86
|
+
for (const header of [
|
|
87
|
+
'Checking integration components:',
|
|
88
|
+
'Checking integration templates:',
|
|
89
|
+
'Checking integration docs:',
|
|
90
|
+
]) {
|
|
91
|
+
expect(lines[lines.findIndex(line => line.includes(header)) - 1]).toBe(
|
|
92
|
+
'',
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
expect(run.status).toBe(0);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('--strict lists the warning again as an error, after the checks, and exits 1', async () => {
|
|
99
|
+
const id = await coreTemplateId();
|
|
100
|
+
writePackage({id});
|
|
101
|
+
|
|
102
|
+
const run = await runCli(['integration', 'check', '--strict'], tmpDir);
|
|
103
|
+
|
|
104
|
+
expect(run.stdout).toContain(
|
|
105
|
+
'Integration check: @acme/widgets@1.2.3 (strict)',
|
|
106
|
+
);
|
|
107
|
+
const block = run.stdout.indexOf('Failing under --strict');
|
|
108
|
+
expect(block).toBeGreaterThan(
|
|
109
|
+
run.stdout.indexOf('Checking integration docs:'),
|
|
110
|
+
);
|
|
111
|
+
expect(run.stdout.slice(block)).toMatch(
|
|
112
|
+
/severity: \[fail\]\ncheck: +templates\ncode: +template_id_conflict\n/,
|
|
113
|
+
);
|
|
114
|
+
expect(run.stdout).toContain(
|
|
115
|
+
'[fail] 0 errors, 1 warning, 0 skipped. --strict fails on every warning and on skipped work;',
|
|
116
|
+
);
|
|
117
|
+
expect(run.status).toBe(1);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('--json carries each check with its own envelope, the --strict failures, and exits as the text does', async () => {
|
|
121
|
+
const id = await coreTemplateId();
|
|
122
|
+
writePackage({id});
|
|
123
|
+
|
|
124
|
+
const run = await runCli(
|
|
125
|
+
['integration', 'check', '--strict', '--json'],
|
|
126
|
+
tmpDir,
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
const parsed = JSON.parse(run.stdout.trim());
|
|
130
|
+
expect(parsed.type).toBe('integration.check');
|
|
131
|
+
expect(parsed.data).toMatchObject({
|
|
132
|
+
validated: true,
|
|
133
|
+
name: '@acme/widgets',
|
|
134
|
+
version: '1.2.3',
|
|
135
|
+
strict: true,
|
|
136
|
+
errors: 0,
|
|
137
|
+
warnings: 1,
|
|
138
|
+
skipped: [],
|
|
139
|
+
failed: true,
|
|
140
|
+
});
|
|
141
|
+
expect(parsed.data.checks.map(check => check.check)).toEqual([
|
|
142
|
+
'validate',
|
|
143
|
+
'components',
|
|
144
|
+
'templates',
|
|
145
|
+
'docs',
|
|
146
|
+
]);
|
|
147
|
+
const templates = parsed.data.checks[2];
|
|
148
|
+
expect(templates).toMatchObject({
|
|
149
|
+
check: 'templates',
|
|
150
|
+
errors: 0,
|
|
151
|
+
warnings: 1,
|
|
152
|
+
skipped: [],
|
|
153
|
+
failed: false,
|
|
154
|
+
response: {
|
|
155
|
+
type: 'integration.template-conflicts',
|
|
156
|
+
data: {conflicts: [expect.objectContaining({id, severity: 'warning'})]},
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
expect(parsed.data.failures).toEqual([
|
|
160
|
+
{
|
|
161
|
+
check: 'templates',
|
|
162
|
+
severity: 'error',
|
|
163
|
+
code: 'template_id_conflict',
|
|
164
|
+
message: templates.response.data.conflicts[0].message,
|
|
165
|
+
},
|
|
166
|
+
]);
|
|
167
|
+
expect(run.status).toBe(1);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it('exits 1 without --strict when one check fails on its own, and lists no failures', async () => {
|
|
171
|
+
writePackage({id: 'acme-app-shell', replaces: 'missing-core-shell'});
|
|
172
|
+
|
|
173
|
+
const text = await runCli(['integration', 'check'], tmpDir);
|
|
174
|
+
const json = await runCli(['integration', 'check', '--json'], tmpDir);
|
|
175
|
+
|
|
176
|
+
expect(text.stdout).toContain('missing_template_replacement_target');
|
|
177
|
+
expect(text.stdout).toMatch(
|
|
178
|
+
/\[fail\] [1-9]\d* errors?, .*Address the items marked \[fail\] above\./,
|
|
179
|
+
);
|
|
180
|
+
expect(text.stdout).not.toContain('Failing under --strict');
|
|
181
|
+
expect(JSON.parse(json.stdout.trim()).data).toMatchObject({
|
|
182
|
+
strict: false,
|
|
183
|
+
failures: [],
|
|
184
|
+
failed: true,
|
|
185
|
+
});
|
|
186
|
+
expect(text.status).toBe(1);
|
|
187
|
+
expect(json.status).toBe(1);
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it('counts a package with no manifest as skipped work: exit 0, and 1 with --strict', async () => {
|
|
191
|
+
fs.writeFileSync(
|
|
192
|
+
path.join(tmpDir, 'package.json'),
|
|
193
|
+
JSON.stringify({name: '@acme/plain', version: '1.0.0'}),
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
const loose = await runCli(['integration', 'check'], tmpDir);
|
|
197
|
+
expect(loose.stdout).toContain(
|
|
198
|
+
"Nothing was checked: no astryx.integration.* found next to package.json. Run this command in an integration package's folder.",
|
|
199
|
+
);
|
|
200
|
+
// One cause, however many checks it stops: counted once.
|
|
201
|
+
expect(loose.stdout).toContain('[ok] 0 errors, 0 warnings, 1 skipped.');
|
|
202
|
+
expect(loose.status).toBe(0);
|
|
203
|
+
|
|
204
|
+
const strict = await runCli(
|
|
205
|
+
['integration', 'check', '--strict', '--json'],
|
|
206
|
+
tmpDir,
|
|
207
|
+
);
|
|
208
|
+
const {data} = JSON.parse(strict.stdout.trim());
|
|
209
|
+
expect(data).toMatchObject({validated: false, errors: 0, failed: true});
|
|
210
|
+
// One cause, however many checks it stops: listed once.
|
|
211
|
+
expect(data.failures).toEqual([
|
|
212
|
+
{
|
|
213
|
+
check: 'validate',
|
|
214
|
+
severity: 'error',
|
|
215
|
+
code: 'missing_manifest',
|
|
216
|
+
message:
|
|
217
|
+
'No astryx.integration.* found next to package.json, so nothing was checked.',
|
|
218
|
+
},
|
|
219
|
+
]);
|
|
220
|
+
expect(strict.status).toBe(1);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it('exits 1 for no package.json, as validate does', async () => {
|
|
224
|
+
const empty = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-no-pkg-'));
|
|
225
|
+
try {
|
|
226
|
+
const run = await runCli(['integration', 'check'], empty);
|
|
227
|
+
expect(run.stdout).toContain(
|
|
228
|
+
'Nothing was checked: no package.json found.',
|
|
229
|
+
);
|
|
230
|
+
expect(run.stdout).toContain('Integration check: (no package.json)');
|
|
231
|
+
expect(run.stdout).toContain(
|
|
232
|
+
'[fail] 1 error, 0 warnings, 0 skipped. No package.json was found here, so nothing was checked.',
|
|
233
|
+
);
|
|
234
|
+
expect(run.stdout).not.toContain('marked [fail] above');
|
|
235
|
+
expect(run.status).toBe(1);
|
|
236
|
+
} finally {
|
|
237
|
+
fs.rmSync(empty, {recursive: true, force: true});
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it('states in its help that it is the CI check, the line to add, and what --strict promises', async () => {
|
|
242
|
+
const run = await runCli(['integration', 'check', '--help'], tmpDir);
|
|
243
|
+
|
|
244
|
+
expect(run.stdout).toContain(
|
|
245
|
+
"The CI check for an integration package's own build",
|
|
246
|
+
);
|
|
247
|
+
expect(run.stdout).toContain(
|
|
248
|
+
'"typecheck": "tsc --noEmit && astryx integration check --strict"',
|
|
249
|
+
);
|
|
250
|
+
expect(run.stdout).toContain(
|
|
251
|
+
'A new check or failure code joins only in a minor release, named in the release notes.',
|
|
252
|
+
);
|
|
253
|
+
expect(run.stdout).toContain('integration verify');
|
|
254
|
+
expect(run.stdout).toContain('against the package in the current folder');
|
|
255
|
+
expect(run.stdout).not.toContain('[package]');
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
it('takes no package name: one passed is an error, not a check of the current folder', async () => {
|
|
259
|
+
writePackage({id: 'acme-page'});
|
|
260
|
+
|
|
261
|
+
const run = await runCli(['integration', 'check', '@acme/widgets'], tmpDir);
|
|
262
|
+
|
|
263
|
+
expect(run.stderr).toContain('too many arguments');
|
|
264
|
+
expect(run.stdout).not.toContain('Integration check:');
|
|
265
|
+
expect(run.status).toBe(1);
|
|
266
|
+
});
|
|
267
|
+
});
|
|
@@ -8,13 +8,17 @@ export const doc = {
|
|
|
8
8
|
namespace: 'cli/commands',
|
|
9
9
|
summary: 'Author and verify an Astryx integration package',
|
|
10
10
|
description:
|
|
11
|
-
'Add contributions to your package, then check the packed package the way an app receives it. The guides start at {@link namespace:integrations}.',
|
|
12
|
-
subcommands: ['add', 'verify', 'pack'],
|
|
11
|
+
'Add contributions to your package, check them on every build with `integration check --strict`, then check the packed package the way an app receives it. The guides start at {@link namespace:integrations}.',
|
|
12
|
+
subcommands: ['add', 'check', 'verify', 'pack'],
|
|
13
13
|
examples: [
|
|
14
14
|
{
|
|
15
15
|
label: 'Add a component',
|
|
16
16
|
cli: 'astryx integration add component AcmeWidget',
|
|
17
17
|
},
|
|
18
|
+
{
|
|
19
|
+
label: 'Check the package in CI, as part of its build',
|
|
20
|
+
cli: 'astryx integration check --strict',
|
|
21
|
+
},
|
|
18
22
|
{
|
|
19
23
|
label: 'Check the package before publishing',
|
|
20
24
|
cli: 'astryx integration verify',
|