@astryxdesign/cli 0.7.2-canary.e2909cf → 0.7.2-canary.e4bdd70
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/integration-export-name.test.mjs +644 -0
- 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/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 +51 -97
- 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 +93 -18
- package/api/search/search.integration-check.test.mjs +24 -0
- package/api/search/search.mjs +133 -22
- package/api/swizzle/copy/copy.mjs +28 -14
- package/api/theme/build/build.family.test.mjs +54 -6
- package/api/theme/build/build.mjs +114 -17
- package/api/theme/themeBuild.doc.mjs +4 -4
- 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/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/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/command/command.doc.mjs +14 -12
- package/authoring/doctypes/component/component.doc.mjs +29 -26
- 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 +155 -21
- 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/text-json-parity.test.mjs +5 -0
- package/clients/cli/commands/theme-build.doc.mjs +2 -2
- package/clients/cli/index.mjs +1 -0
- package/foundation/config/project.mjs +82 -0
- package/foundation/discovery/authoring-self-docs.mjs +2 -1
- package/foundation/discovery/component-discovery.d.mts +178 -10
- package/foundation/discovery/component-discovery.export-names.test.mjs +760 -0
- package/foundation/discovery/component-discovery.mjs +659 -62
- 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/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 +6 -0
- 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/package.json +9 -9
|
@@ -3,18 +3,22 @@
|
|
|
3
3
|
/** @file CLI bindings for integration authoring and package verification. */
|
|
4
4
|
|
|
5
5
|
import {integrationAdd} from '../../../api/integration/add-contribution.mjs';
|
|
6
|
+
import {integrationCheck} from '../../../api/integration/check/check.mjs';
|
|
6
7
|
import {integrationPackCheck} from '../../../api/integration/pack-check.mjs';
|
|
7
8
|
import {jsonOut} from '../../../foundation/response/json.mjs';
|
|
8
9
|
import {ERROR_CODES} from '../../../foundation/response/error-codes.mjs';
|
|
9
10
|
import {NO_RESULT_SET} from '../../../foundation/debug/index.mjs';
|
|
10
|
-
import {emit, list, section, text} from '../formatters/index.mjs';
|
|
11
|
+
import {emit, list, records, section, text} from '../formatters/index.mjs';
|
|
11
12
|
import {cliError} from '../lib/cli-error.mjs';
|
|
12
13
|
import {defineCommand} from '../lib/define-command.mjs';
|
|
13
14
|
import {doc as integrationGroup} from './integration.doc.mjs';
|
|
14
15
|
import {doc as integrationAddCommand} from './integration-add.doc.mjs';
|
|
16
|
+
import {doc as integrationCheckCommand} from './integration-check.doc.mjs';
|
|
15
17
|
import {doc as integrationVerifyCommand} from './integration-verify.doc.mjs';
|
|
16
18
|
import {doc as integrationPackCommand} from './integration-pack.doc.mjs';
|
|
17
19
|
import {doc as integrationAddFn} from '../../../api/integration/integrationAdd.doc.mjs';
|
|
20
|
+
import {doc as integrationCheckFn} from '../../../api/integration/integrationCheck.doc.mjs';
|
|
21
|
+
import {printIntegrationCheckResponse} from './doctor.mjs';
|
|
18
22
|
import {doc as integrationPackCheckFn} from '../../../api/integration/integrationPackCheck.doc.mjs';
|
|
19
23
|
|
|
20
24
|
/**
|
|
@@ -88,6 +92,102 @@ async function verifyPackage(program) {
|
|
|
88
92
|
return NO_RESULT_SET;
|
|
89
93
|
}
|
|
90
94
|
|
|
95
|
+
/**
|
|
96
|
+
* Run `integration check` and print each check as its own subcommand prints
|
|
97
|
+
* it, then one summary: each check's errors, warnings and skipped work, and
|
|
98
|
+
* what decided the exit code.
|
|
99
|
+
* @param {import('commander').Command} program
|
|
100
|
+
* @param {{strict?: boolean}} options
|
|
101
|
+
*/
|
|
102
|
+
async function checkPackage(program, options) {
|
|
103
|
+
const result = await integrationCheck({strict: options.strict === true});
|
|
104
|
+
if (program.opts().json) {
|
|
105
|
+
jsonOut(result);
|
|
106
|
+
} else {
|
|
107
|
+
const {data} = result;
|
|
108
|
+
const noPackage = data.checks[0]?.response.data.issues.some(
|
|
109
|
+
issue => issue.code === 'no_package',
|
|
110
|
+
);
|
|
111
|
+
if (noPackage) {
|
|
112
|
+
emit(
|
|
113
|
+
text(
|
|
114
|
+
'Nothing was checked: no package.json found. Run this command inside a package directory.',
|
|
115
|
+
),
|
|
116
|
+
);
|
|
117
|
+
} else if (!data.validated) {
|
|
118
|
+
emit(
|
|
119
|
+
text(
|
|
120
|
+
'Nothing was checked: no astryx.integration.* found next to package.json. ' +
|
|
121
|
+
"Run this command in an integration package's folder.",
|
|
122
|
+
),
|
|
123
|
+
);
|
|
124
|
+
} else {
|
|
125
|
+
data.checks.forEach((check, index) => {
|
|
126
|
+
// A blank line keeps each check's output apart from the next.
|
|
127
|
+
if (index > 0) emit(text(''));
|
|
128
|
+
printIntegrationCheckResponse(check.response);
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
const plural = (/** @type {number} */ n, /** @type {string} */ word) =>
|
|
132
|
+
`${n} ${word}${n === 1 ? '' : 's'}`;
|
|
133
|
+
const counts =
|
|
134
|
+
`${plural(data.errors, 'error')}, ${plural(data.warnings, 'warning')}, ` +
|
|
135
|
+
`${data.skipped.length} skipped`;
|
|
136
|
+
const notCompared =
|
|
137
|
+
data.unchecked > 0
|
|
138
|
+
? ` ${plural(data.unchecked, 'item')} could not be compared; the checks above list them.`
|
|
139
|
+
: '';
|
|
140
|
+
const closing = noPackage
|
|
141
|
+
? `[fail] ${counts}. No package.json was found here, so nothing was checked.`
|
|
142
|
+
: data.checks.some(check => check.failed)
|
|
143
|
+
? `[fail] ${counts}. Address the items marked [fail] above.`
|
|
144
|
+
: data.failed
|
|
145
|
+
? `[fail] ${counts}. --strict fails on every warning and on skipped work; fix them, or drop --strict to fail only on errors.`
|
|
146
|
+
: data.warnings > 0 || data.skipped.length > 0
|
|
147
|
+
? `[ok] ${counts}. No check failed; review the warnings and skipped work above (--strict fails on them).${notCompared}`
|
|
148
|
+
: notCompared
|
|
149
|
+
? `[ok] ${counts}. No check failed.${notCompared}`
|
|
150
|
+
: `[ok] ${counts}. Every check passed.`;
|
|
151
|
+
const identity = noPackage
|
|
152
|
+
? '(no package.json)'
|
|
153
|
+
: data.version != null
|
|
154
|
+
? `${data.name}@${data.version}`
|
|
155
|
+
: data.name;
|
|
156
|
+
emit(
|
|
157
|
+
// --strict lists each warning and each skipped check again, as the
|
|
158
|
+
// error it now is, in the issue format the checks use.
|
|
159
|
+
...(data.failures.length > 0
|
|
160
|
+
? [
|
|
161
|
+
section('Failing under --strict'),
|
|
162
|
+
records(data.failures, {
|
|
163
|
+
fields: [
|
|
164
|
+
'severity',
|
|
165
|
+
'check',
|
|
166
|
+
'code',
|
|
167
|
+
'component',
|
|
168
|
+
'prop',
|
|
169
|
+
'message',
|
|
170
|
+
'fix',
|
|
171
|
+
'file',
|
|
172
|
+
'line',
|
|
173
|
+
],
|
|
174
|
+
format: {severity: () => '[fail]'},
|
|
175
|
+
}),
|
|
176
|
+
]
|
|
177
|
+
: []),
|
|
178
|
+
section(
|
|
179
|
+
`Integration check: ${identity ?? '(local package)'}${data.strict ? ' (strict)' : ''}`,
|
|
180
|
+
),
|
|
181
|
+
records(data.checks, {
|
|
182
|
+
fields: ['check', 'failed', 'errors', 'warnings', 'skipped'],
|
|
183
|
+
}),
|
|
184
|
+
text(closing),
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
if (result.data.failed) process.exitCode = 1;
|
|
188
|
+
return NO_RESULT_SET;
|
|
189
|
+
}
|
|
190
|
+
|
|
91
191
|
/** @param {import('commander').Command} program */
|
|
92
192
|
export function registerIntegration(program) {
|
|
93
193
|
/** @type {import('commander').Command} */
|
|
@@ -159,6 +259,12 @@ export function registerIntegration(program) {
|
|
|
159
259
|
});
|
|
160
260
|
addCmd.allowExcessArguments(false);
|
|
161
261
|
|
|
262
|
+
// It takes no package name, so a name passed by mistake is an error, not a
|
|
263
|
+
// silent check of the current folder.
|
|
264
|
+
defineCommand(integration, integrationCheckCommand, {
|
|
265
|
+
fn: integrationCheckFn,
|
|
266
|
+
action: async options => checkPackage(program, options),
|
|
267
|
+
}).allowExcessArguments(false);
|
|
162
268
|
defineCommand(integration, integrationVerifyCommand, {
|
|
163
269
|
fn: integrationPackCheckFn,
|
|
164
270
|
action: async () => verifyPackage(program),
|
|
@@ -341,6 +341,11 @@ const CASES = [
|
|
|
341
341
|
args: ['doctor', 'integration', 'validate'],
|
|
342
342
|
skipFieldChecks: true,
|
|
343
343
|
},
|
|
344
|
+
{
|
|
345
|
+
name: 'integration check',
|
|
346
|
+
args: ['integration', 'check'],
|
|
347
|
+
skipFieldChecks: true,
|
|
348
|
+
},
|
|
344
349
|
{
|
|
345
350
|
name: 'doctor integration components',
|
|
346
351
|
args: ['doctor', 'integration', 'components'],
|
|
@@ -30,7 +30,7 @@ export const doc = {
|
|
|
30
30
|
{
|
|
31
31
|
flag: '--family',
|
|
32
32
|
description:
|
|
33
|
-
'Build the selected extension family into one keyed CSS, JS, and declaration set, written beside the family root theme file, which must be inside the working directory (ERR_PATH_TRAVERSAL). Requires --family-key; refused with --out or --watch (ERR_THEME_INVALID)',
|
|
33
|
+
'Build the selected extension family into one keyed CSS, JS, and declaration set, written beside the family root theme file, which must be inside the working directory to build (ERR_PATH_TRAVERSAL); --check only reads, so it compares outputs anywhere. Requires --family-key; refused with --out or --watch (ERR_THEME_INVALID)',
|
|
34
34
|
},
|
|
35
35
|
{
|
|
36
36
|
flag: '--family-key <key>',
|
|
@@ -41,7 +41,7 @@ export const doc = {
|
|
|
41
41
|
flag: '-o, --out <path>',
|
|
42
42
|
param: 'options.out',
|
|
43
43
|
description:
|
|
44
|
-
'Output CSS file path, relative or absolute; the .js and .d.ts are written beside it (default: <theme name>.css next to the source).
|
|
44
|
+
'Output CSS file path, relative or absolute; the .js and .d.ts are written beside it (default: <theme name>.css next to the source). A build writes only inside the working directory, the defaults beside the source too (ERR_PATH_TRAVERSAL); --check writes nothing, so it compares outputs anywhere and refuses only a relative path that escapes the working directory. Single theme only: refused with more than one file or with --family (ERR_THEME_INVALID)',
|
|
45
45
|
},
|
|
46
46
|
{
|
|
47
47
|
flag: '--icons-specifier <specifier>',
|
package/clients/cli/index.mjs
CHANGED
|
@@ -60,6 +60,7 @@ import {
|
|
|
60
60
|
applyTemplateReplacements,
|
|
61
61
|
effectiveTemplateDiscovery,
|
|
62
62
|
discoverAllUnresolved as discoverTemplates,
|
|
63
|
+
discoverCoreTemplates,
|
|
63
64
|
discoverIntegrationTemplatesForOne,
|
|
64
65
|
} from '../discovery/template-adapter.mjs';
|
|
65
66
|
import {
|
|
@@ -821,6 +822,85 @@ export class Project {
|
|
|
821
822
|
});
|
|
822
823
|
}
|
|
823
824
|
|
|
825
|
+
/**
|
|
826
|
+
* The components and templates this project reads, as links name them: by
|
|
827
|
+
* owner provider id, kind, and name (a template by its id).
|
|
828
|
+
* @returns {Promise<import('../discovery/docs-discovery.mjs').LinkableContributions>}
|
|
829
|
+
*/
|
|
830
|
+
async #linkableContributions() {
|
|
831
|
+
/** @type {Map<string, string>} */
|
|
832
|
+
const providers = new Map([[CORE_PACKAGE, CORE_PACKAGE]]);
|
|
833
|
+
for (const integration of this.#loadedIntegrations) {
|
|
834
|
+
if (integration?.name) {
|
|
835
|
+
providers.set(
|
|
836
|
+
integration.name,
|
|
837
|
+
integration.providerId ?? integration.name,
|
|
838
|
+
);
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
const providerOf = (/** @type {string | undefined} */ pkg) =>
|
|
842
|
+
providers.get(pkg ?? CORE_PACKAGE) ?? pkg ?? CORE_PACKAGE;
|
|
843
|
+
// An active replacement answers to the Core name it replaces, so a link
|
|
844
|
+
// to that Core component has to select Core (spec:AST-035 FR11).
|
|
845
|
+
/** @type {Map<string, string>} */
|
|
846
|
+
const replacing = new Map();
|
|
847
|
+
if (this.#loadedIntegrations.length > 0) {
|
|
848
|
+
const {active} = await resolveComponentReplacements(
|
|
849
|
+
findCoreDir(this.#cwd),
|
|
850
|
+
this.#loadedIntegrations,
|
|
851
|
+
);
|
|
852
|
+
for (const each of active) {
|
|
853
|
+
replacing.set(`${each.package}\0${each.name}`, each.target);
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
const components = (await this.components()).map(record => {
|
|
857
|
+
const replaces = replacing.get(`${record.package}\0${record.name}`);
|
|
858
|
+
return {
|
|
859
|
+
providerId: providerOf(record.package),
|
|
860
|
+
package: record.package,
|
|
861
|
+
name: record.name,
|
|
862
|
+
docPath: record.docPath,
|
|
863
|
+
...(replaces == null ? {} : {replaces}),
|
|
864
|
+
};
|
|
865
|
+
});
|
|
866
|
+
/** @param {any} template @param {string} pkg */
|
|
867
|
+
const linkable = (template, pkg) => ({
|
|
868
|
+
providerId: providerOf(pkg),
|
|
869
|
+
package: pkg,
|
|
870
|
+
type: template.type,
|
|
871
|
+
id: template.dirName,
|
|
872
|
+
name: template.name,
|
|
873
|
+
...(template.displayName == null
|
|
874
|
+
? {}
|
|
875
|
+
: {displayName: template.displayName}),
|
|
876
|
+
...(template.description == null
|
|
877
|
+
? {}
|
|
878
|
+
: {description: template.description}),
|
|
879
|
+
...(typeof template.replaces === 'string'
|
|
880
|
+
? {replaces: template.replaces}
|
|
881
|
+
: {}),
|
|
882
|
+
});
|
|
883
|
+
/** @param {any} template */
|
|
884
|
+
const isPageOrBlock = template =>
|
|
885
|
+
template.type === 'page' || template.type === 'block';
|
|
886
|
+
// Every Core template, a replaced one too, since `--package
|
|
887
|
+
// @astryxdesign/core` still opens it; everyone else's as unqualified
|
|
888
|
+
// lookups see them, an active replacement with the id it takes over.
|
|
889
|
+
const templates = [
|
|
890
|
+
...(await discoverCoreTemplates())
|
|
891
|
+
.filter(isPageOrBlock)
|
|
892
|
+
.map(template => linkable(template, CORE_PACKAGE)),
|
|
893
|
+
.../** @type {any[]} */ (await this.templates())
|
|
894
|
+
.filter(
|
|
895
|
+
template =>
|
|
896
|
+
isPageOrBlock(template) &&
|
|
897
|
+
(template.package ?? CORE_PACKAGE) !== CORE_PACKAGE,
|
|
898
|
+
)
|
|
899
|
+
.map(template => linkable(template, template.package)),
|
|
900
|
+
];
|
|
901
|
+
return {components, templates};
|
|
902
|
+
}
|
|
903
|
+
|
|
824
904
|
/**
|
|
825
905
|
* The CLI's own doc topics plus the ones the configured integrations
|
|
826
906
|
* contribute, resolved into one catalog: additions, replacements (with the
|
|
@@ -838,6 +918,8 @@ export class Project {
|
|
|
838
918
|
async docs() {
|
|
839
919
|
return this.#memo('docs', async () => {
|
|
840
920
|
const catalog = DocsCatalog.fromBuiltins();
|
|
921
|
+
// Links name component, page, and block docs too (spec:AST-047 FR9).
|
|
922
|
+
catalog.setContributions(() => this.#linkableContributions());
|
|
841
923
|
let rank = 0;
|
|
842
924
|
|
|
843
925
|
for (const integration of this.#loadedIntegrations) {
|
|
@@ -46,6 +46,7 @@ export const AUTHORING_SELF_DOCS = [
|
|
|
46
46
|
'doctypes/reference/reference.doc.mjs',
|
|
47
47
|
'doctypes/schema/schema.doc.mjs',
|
|
48
48
|
'doctypes/template/template.doc.mjs',
|
|
49
|
+
'doctypes/template/integration-template.doc.mjs',
|
|
49
50
|
'doctypes/theme/theme.doc.mjs',
|
|
50
51
|
];
|
|
51
52
|
|
|
@@ -192,7 +193,7 @@ export function buildAuthoringReferenceDoc(docs) {
|
|
|
192
193
|
title: 'Authoring Reference',
|
|
193
194
|
category: 'guide',
|
|
194
195
|
description:
|
|
195
|
-
'Every file an integration author writes, field by field: the integration manifest, astryx.config, codemods, identity, and each doc type.',
|
|
196
|
+
'Every file an integration author writes, field by field: the integration manifest, astryx.config, codemods, identity, and each doc type. The step-by-step guides are under `astryx docs cli/integrations`.',
|
|
196
197
|
sections: docs.map(selfDocSection),
|
|
197
198
|
});
|
|
198
199
|
}
|
|
@@ -115,19 +115,99 @@ export function discoverExternalComponentsGrouped(docsDir: string): Record<strin
|
|
|
115
115
|
* @returns {string | null}
|
|
116
116
|
*/
|
|
117
117
|
export function findExternalComponentDoc(docsDir: string, name: string): string | null;
|
|
118
|
+
/** @param {string} docPath */
|
|
119
|
+
export function docStem(docPath: string): string;
|
|
120
|
+
/**
|
|
121
|
+
* The `.tsx` file in `folder`, or below it, that declares `name`, taking files
|
|
122
|
+
* in path order: the source of a member whose import never reaches a `.tsx`
|
|
123
|
+
* file, as when the import names built output.
|
|
124
|
+
*
|
|
125
|
+
* @param {string} folder
|
|
126
|
+
* @param {string} name
|
|
127
|
+
* @returns {string | null}
|
|
128
|
+
*/
|
|
129
|
+
export function folderSourceFor(folder: string, name: string): string | null;
|
|
130
|
+
/**
|
|
131
|
+
* Each family doc under an integration's components root that names an
|
|
132
|
+
* import, with the file the import resolves to: null when it resolves to none,
|
|
133
|
+
* such as build output that does not exist yet.
|
|
134
|
+
*
|
|
135
|
+
* @param {{name: string, components?: string, issuesUrl?: string, __packageDir?: string, __packageExports?: Record<string, unknown>|null}} integration
|
|
136
|
+
* @returns {Array<{docPath: string, module: string | null}>}
|
|
137
|
+
*/
|
|
138
|
+
export function familyImports(integration: {
|
|
139
|
+
name: string;
|
|
140
|
+
components?: string;
|
|
141
|
+
issuesUrl?: string;
|
|
142
|
+
__packageDir?: string;
|
|
143
|
+
__packageExports?: Record<string, unknown> | null;
|
|
144
|
+
}): Array<{
|
|
145
|
+
docPath: string;
|
|
146
|
+
module: string | null;
|
|
147
|
+
}>;
|
|
148
|
+
/**
|
|
149
|
+
* Whether a discovered integration record is a member its family doc lists,
|
|
150
|
+
* decided from the files, not from whether the doc loads.
|
|
151
|
+
*
|
|
152
|
+
* @param {{name: string, docPath: string|null}} record
|
|
153
|
+
* @returns {boolean}
|
|
154
|
+
*/
|
|
155
|
+
export function isIntegrationMember(record: {
|
|
156
|
+
name: string;
|
|
157
|
+
docPath: string | null;
|
|
158
|
+
}): boolean;
|
|
159
|
+
/**
|
|
160
|
+
* The entry a family doc gives a member that discovery lists under its own
|
|
161
|
+
* name, or null when the record is the doc's own component or the loaded doc
|
|
162
|
+
* has no entry for it.
|
|
163
|
+
*
|
|
164
|
+
* @param {any} doc the doc loaded from `record.docPath`
|
|
165
|
+
* @param {{name: string, docPath: string|null}} record
|
|
166
|
+
* @returns {any}
|
|
167
|
+
*/
|
|
168
|
+
export function integrationMemberEntry(doc: any, record: {
|
|
169
|
+
name: string;
|
|
170
|
+
docPath: string | null;
|
|
171
|
+
}): any;
|
|
172
|
+
/**
|
|
173
|
+
* Visit every component doc under an integration's components root, hidden
|
|
174
|
+
* ones included, in discovery order, with its stem.
|
|
175
|
+
* @param {string | undefined} componentsDir
|
|
176
|
+
* @param {(docPath: string, stem: string) => void} visit
|
|
177
|
+
*/
|
|
178
|
+
export function forEachIntegrationDoc(componentsDir: string | undefined, visit: (docPath: string, stem: string) => void): void;
|
|
179
|
+
/**
|
|
180
|
+
* Given an integration component doc path, return the sibling component source
|
|
181
|
+
* (`{Name}.tsx`) if one exists, else null.
|
|
182
|
+
*
|
|
183
|
+
* @param {string} docPath absolute path to a `{Name}.doc.{ts,mjs,js}` file
|
|
184
|
+
* @returns {string|null}
|
|
185
|
+
*/
|
|
186
|
+
export function integrationSourceForDoc(docPath: string): string | null;
|
|
118
187
|
/**
|
|
119
188
|
* Discover ownership records for the components contributed by a single loaded
|
|
120
189
|
* integration. Scans the integration's resolved `components` dir for same-stem
|
|
121
|
-
* doc files and records each with owner package + issuesUrl + sourcePath.
|
|
190
|
+
* doc files and records each with owner package + issuesUrl + sourcePath. A doc
|
|
191
|
+
* that names a differently named export of its file is recorded under that
|
|
192
|
+
* export, and each family member it lists, under the member's name, unless the
|
|
193
|
+
* name is taken: every doc's file name (a hidden doc's too), a Core name a doc
|
|
194
|
+
* in the package replaces, and a name an earlier doc records.
|
|
122
195
|
*
|
|
123
|
-
* @param {{name: string, components?: string, issuesUrl?: string}} integration
|
|
196
|
+
* @param {{name: string, components?: string, issuesUrl?: string, __packageDir?: string, __packageExports?: Record<string, unknown>|null}} integration
|
|
124
197
|
* a single entry from `loadedIntegrations` (lib/integrations.mjs)
|
|
198
|
+
* @param {{documentedNames?: boolean}} [options] `documentedNames: false`
|
|
199
|
+
* records each doc under its file name alone, without reading the names
|
|
200
|
+
* docs document: for a caller that needs only what each doc says
|
|
125
201
|
* @returns {Array<{name: string, package: string, docPath: string, sourcePath: string|null, issuesUrl: string|undefined, group: string|null}>}
|
|
126
202
|
*/
|
|
127
203
|
export function discoverIntegrationComponents(integration: {
|
|
128
204
|
name: string;
|
|
129
205
|
components?: string;
|
|
130
206
|
issuesUrl?: string;
|
|
207
|
+
__packageDir?: string;
|
|
208
|
+
__packageExports?: Record<string, unknown> | null;
|
|
209
|
+
}, { documentedNames }?: {
|
|
210
|
+
documentedNames?: boolean;
|
|
131
211
|
}): Array<{
|
|
132
212
|
name: string;
|
|
133
213
|
package: string;
|
|
@@ -141,11 +221,16 @@ export function discoverIntegrationComponents(integration: {
|
|
|
141
221
|
* Invalid metadata or a missing same-stem source removes only that component;
|
|
142
222
|
* callers can report the returned errors while retaining valid siblings. A
|
|
143
223
|
* component whose doc sets `replaces` carries the value as written; the
|
|
144
|
-
* component replacement resolver decides what it means.
|
|
224
|
+
* component replacement resolver decides what it means. A family member is
|
|
225
|
+
* read through its family's doc: it never carries the family's `replaces`, and
|
|
226
|
+
* a family doc that fails to load is reported once. A doc that fails to load
|
|
227
|
+
* is reported under its file name: what it says cannot be trusted.
|
|
145
228
|
*
|
|
146
229
|
* @param {{name: string, components?: string, issuesUrl?: string}} integration
|
|
230
|
+
* @param {{documentedNames?: boolean}} [options] as for
|
|
231
|
+
* {@link discoverIntegrationComponents}
|
|
147
232
|
* @returns {Promise<{
|
|
148
|
-
* components: Array<{name: string, package: string, docPath: string, sourcePath: string, issuesUrl: string|undefined, group: string|null, replaces?: unknown}>,
|
|
233
|
+
* components: Array<{name: string, package: string, docPath: string, sourcePath: string|null, issuesUrl: string|undefined, group: string|null, replaces?: unknown}>,
|
|
149
234
|
* discovered: Array<{name: string, package: string, docPath: string, sourcePath: string|null, issuesUrl: string|undefined, group: string|null}>,
|
|
150
235
|
* errors: Array<{name: string, message: string}>,
|
|
151
236
|
* }>}
|
|
@@ -154,12 +239,14 @@ export function discoverValidIntegrationComponents(integration: {
|
|
|
154
239
|
name: string;
|
|
155
240
|
components?: string;
|
|
156
241
|
issuesUrl?: string;
|
|
242
|
+
}, options?: {
|
|
243
|
+
documentedNames?: boolean;
|
|
157
244
|
}): Promise<{
|
|
158
245
|
components: Array<{
|
|
159
246
|
name: string;
|
|
160
247
|
package: string;
|
|
161
248
|
docPath: string;
|
|
162
|
-
sourcePath: string;
|
|
249
|
+
sourcePath: string | null;
|
|
163
250
|
issuesUrl: string | undefined;
|
|
164
251
|
group: string | null;
|
|
165
252
|
replaces?: unknown;
|
|
@@ -177,30 +264,103 @@ export function discoverValidIntegrationComponents(integration: {
|
|
|
177
264
|
message: string;
|
|
178
265
|
}>;
|
|
179
266
|
}>;
|
|
267
|
+
/**
|
|
268
|
+
* How an owner holds a component name, which the owner rule
|
|
269
|
+
* ({@link unscopedComponentOwners}) reads: `core` when Core documents it;
|
|
270
|
+
* `file` when an integration doc named after its file is recorded under it;
|
|
271
|
+
* `doc` when only a doc records it: an export name, a member, or the file name
|
|
272
|
+
* of a doc recorded under another export.
|
|
273
|
+
* @typedef {'core' | 'file' | 'doc'} NameHold
|
|
274
|
+
*/
|
|
275
|
+
/**
|
|
276
|
+
* How a discovered integration record holds its name.
|
|
277
|
+
* @param {{name: string, docPath: string|null}} record
|
|
278
|
+
* @returns {'file' | 'doc'}
|
|
279
|
+
*/
|
|
280
|
+
export function integrationRecordHold(record: {
|
|
281
|
+
name: string;
|
|
282
|
+
docPath: string | null;
|
|
283
|
+
}): "file" | "doc";
|
|
284
|
+
/**
|
|
285
|
+
* The integration component a name finds, as discovery records it, and its
|
|
286
|
+
* hold: the same-stem doc first, then a doc that records the name as an export
|
|
287
|
+
* or a member.
|
|
288
|
+
*
|
|
289
|
+
* @param {{name?: string, components?: string, __packageDir?: string, __packageExports?: Record<string, unknown>|null}} integration
|
|
290
|
+
* @param {string} name
|
|
291
|
+
* @returns {{docPath: string, sourcePath: string|null, hold: 'file' | 'doc'} | null}
|
|
292
|
+
*/
|
|
293
|
+
export function findIntegrationComponent(integration: {
|
|
294
|
+
name?: string;
|
|
295
|
+
components?: string;
|
|
296
|
+
__packageDir?: string;
|
|
297
|
+
__packageExports?: Record<string, unknown> | null;
|
|
298
|
+
}, name: string): {
|
|
299
|
+
docPath: string;
|
|
300
|
+
sourcePath: string | null;
|
|
301
|
+
hold: "file" | "doc";
|
|
302
|
+
} | null;
|
|
303
|
+
/**
|
|
304
|
+
* The name discovery records a component doc under: the export its `name`
|
|
305
|
+
* documents when the doc is recorded under it, else the doc's file name.
|
|
306
|
+
*
|
|
307
|
+
* @param {{name?: string, components?: string, __packageDir?: string, __packageExports?: Record<string, unknown>|null}} integration
|
|
308
|
+
* @param {string} docPath
|
|
309
|
+
* @returns {string}
|
|
310
|
+
*/
|
|
311
|
+
export function recordedDocName(integration: {
|
|
312
|
+
name?: string;
|
|
313
|
+
components?: string;
|
|
314
|
+
__packageDir?: string;
|
|
315
|
+
__packageExports?: Record<string, unknown> | null;
|
|
316
|
+
}, docPath: string): string;
|
|
180
317
|
/**
|
|
181
318
|
* Find an integration component's doc file by name within a loaded
|
|
182
319
|
* integration's resolved `components` dir. Honors the same-stem convention
|
|
183
|
-
* (`{Name}.doc.{ts,mjs,js}`), preferring `.ts` → `.mjs` → `.js
|
|
320
|
+
* (`{Name}.doc.{ts,mjs,js}`), preferring `.ts` → `.mjs` → `.js`, and finds a
|
|
321
|
+
* doc that records the component under another name: a differently named
|
|
322
|
+
* export of its file, or a member its family doc lists.
|
|
184
323
|
*
|
|
185
|
-
* @param {{components?: string}} integration
|
|
324
|
+
* @param {{name?: string, components?: string, __packageDir?: string, __packageExports?: Record<string, unknown>|null}} integration
|
|
186
325
|
* @param {string} name bare component name (no `XDS`/`Astryx` prefix)
|
|
187
326
|
* @returns {string|null}
|
|
188
327
|
*/
|
|
189
328
|
export function findIntegrationComponentDoc(integration: {
|
|
329
|
+
name?: string;
|
|
190
330
|
components?: string;
|
|
331
|
+
__packageDir?: string;
|
|
332
|
+
__packageExports?: Record<string, unknown> | null;
|
|
191
333
|
}, name: string): string | null;
|
|
192
334
|
/**
|
|
193
|
-
* Find an integration component's swizzleable source file
|
|
194
|
-
*
|
|
335
|
+
* Find an integration component's swizzleable source file by name within a
|
|
336
|
+
* loaded integration's resolved `components` dir: the same-stem `{Name}.tsx`
|
|
337
|
+
* of its doc, or, for a family member, the file that declares it. Returns null
|
|
195
338
|
* when the integration ships docs without source.
|
|
196
339
|
*
|
|
197
|
-
* @param {{components?: string}} integration
|
|
340
|
+
* @param {{name?: string, components?: string, __packageDir?: string, __packageExports?: Record<string, unknown>|null}} integration
|
|
198
341
|
* @param {string} name bare component name
|
|
199
342
|
* @returns {string|null}
|
|
200
343
|
*/
|
|
201
344
|
export function findIntegrationComponentSource(integration: {
|
|
345
|
+
name?: string;
|
|
202
346
|
components?: string;
|
|
347
|
+
__packageDir?: string;
|
|
348
|
+
__packageExports?: Record<string, unknown> | null;
|
|
203
349
|
}, name: string): string | null;
|
|
350
|
+
/**
|
|
351
|
+
* The owner rule: an owner that holds a name only because a doc records it
|
|
352
|
+
* (`hold: 'doc'`) yields to Core and to every file-named owner; `--package`
|
|
353
|
+
* still reaches it. Surfaces resolve a replacement first, then this rule, then
|
|
354
|
+
* which docs load.
|
|
355
|
+
*
|
|
356
|
+
* @template {{hold?: string}} T
|
|
357
|
+
* @param {T[]} owners each with its {@link NameHold}; an owner without one
|
|
358
|
+
* counts as Core's or file-named
|
|
359
|
+
* @returns {T[]}
|
|
360
|
+
*/
|
|
361
|
+
export function unscopedComponentOwners<T extends {
|
|
362
|
+
hold?: string;
|
|
363
|
+
}>(owners: T[]): T[];
|
|
204
364
|
/**
|
|
205
365
|
* Build a flat list of ownership records for ALL discoverable components —
|
|
206
366
|
* core (built-in) plus every loaded integration. This is the authoritative
|
|
@@ -229,3 +389,11 @@ export function discoverOwnedComponents(coreDir: string, loadedIntegrations?: Ar
|
|
|
229
389
|
}>;
|
|
230
390
|
/** The owner package name for built-in (core) components. */
|
|
231
391
|
export const CORE_PACKAGE: import("../../authoring/index.js").ProviderId;
|
|
392
|
+
/**
|
|
393
|
+
* How an owner holds a component name, which the owner rule
|
|
394
|
+
* ({@link unscopedComponentOwners}) reads: `core` when Core documents it;
|
|
395
|
+
* `file` when an integration doc named after its file is recorded under it;
|
|
396
|
+
* `doc` when only a doc records it: an export name, a member, or the file name
|
|
397
|
+
* of a doc recorded under another export.
|
|
398
|
+
*/
|
|
399
|
+
export type NameHold = "core" | "file" | "doc";
|