@astryxdesign/cli 0.6.3-canary.8492dde → 0.6.3-canary.89c4819
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 +2 -1
- package/api/docs/_adapter.d.mts +37 -24
- package/api/docs/_adapter.mjs +169 -83
- package/api/docs/compiled-topics.test.mjs +78 -0
- package/api/docs/detail/detail.mjs +14 -63
- package/api/docs/detail/section/section.d.mts +1 -1
- package/api/docs/detail/section/section.mjs +44 -20
- package/api/docs/detail/section/section.test.mjs +41 -0
- package/api/docs/docs.d.mts +7 -2
- package/api/docs/docs.doc.mjs +27 -10
- package/api/docs/docs.mjs +16 -9
- package/api/docs/docs.test.mjs +6 -0
- package/api/docs/docs.type.d.mts +37 -0
- package/api/docs/docs.type.mjs +28 -0
- package/api/docs/index/index.d.mts +18 -0
- package/api/docs/index/index.mjs +32 -0
- package/api/docs/index/index.test.mjs +62 -0
- package/api/docs/integrationDocs.test.mjs +106 -0
- package/api/doctor/doctor.d.mts +48 -0
- package/api/doctor/doctor.mjs +232 -0
- package/api/doctor/doctor.test.mjs +196 -0
- package/api/hook/list/list.d.mts +1 -1
- package/api/integration/integration-authoring.type.d.mts +1 -1
- package/api/search/search.d.mts +1 -1
- package/api/search/search.mjs +5 -5
- package/api/search/search.type.d.mts +1 -1
- package/api/template/template.d.mts +1 -1
- package/api/template/template.type.d.mts +1 -1
- package/api/upgrade/_adapter.mjs +71 -5
- package/api/upgrade/project-context.test.mjs +272 -0
- package/api/upgrade/upgrade.doc.mjs +4 -3
- package/api/upgrade/upgrade.type.d.mts +1 -1
- package/api/upgrade/upgrade.type.mjs +1 -1
- package/assets/codemods/transforms/v0.3.0/__tests__/unwrap-authoring-factories.test.mjs +27 -5
- package/assets/codemods/transforms/v0.3.0/unwrap-authoring-factories.mjs +20 -5
- package/assets/docs/README.md +9 -0
- package/assets/docs/authoring.doc.mjs +14 -0
- package/assets/docs/cli-integrations.doc.mjs +77 -15
- package/assets/templates/blocks/components/Timer/TimerFormats.doc.mjs +14 -0
- package/assets/templates/blocks/components/Timer/TimerFormats.tsx +34 -0
- package/assets/templates/blocks/components/Timer/TimerInline.doc.mjs +14 -0
- package/assets/templates/blocks/components/Timer/TimerInline.tsx +14 -0
- package/assets/templates/blocks/components/Timer/TimerShowcase.doc.mjs +13 -0
- package/assets/templates/blocks/components/Timer/TimerShowcase.tsx +47 -0
- package/assets/templates/blocks/components/Timer/TimerTypography.doc.mjs +14 -0
- package/assets/templates/blocks/components/Timer/TimerTypography.tsx +31 -0
- package/assets/templates/blocks/components/Toolbar/ToolbarTableFilter.doc.mjs +19 -3
- package/assets/templates/blocks/components/Toolbar/ToolbarTableFilter.tsx +383 -65
- package/authoring/_shared/contract.ts +22 -0
- package/authoring/codemod/codemod.doc.mjs +6 -1
- package/authoring/codemod/parse.d.mts +8 -8
- package/authoring/codemod/parse.mjs +8 -6
- package/authoring/config/parse.d.mts +13 -13
- package/authoring/config/parse.mjs +8 -8
- package/authoring/config/type.ts +3 -3
- package/authoring/debug/parse.d.mts +5 -5
- package/authoring/debug/parse.mjs +3 -3
- package/authoring/doctypes/_schema.d.mts +788 -23
- package/authoring/doctypes/_schema.mjs +492 -39
- package/authoring/doctypes/base/graph-fields.doc.d.mts +9 -0
- package/authoring/doctypes/base/graph-fields.doc.mjs +62 -0
- package/authoring/doctypes/base/type.ts +40 -0
- package/authoring/doctypes/command/command.doc.mjs +3 -2
- package/authoring/doctypes/command/parse.d.mts +2 -2
- package/authoring/doctypes/command/parse.mjs +1 -1
- package/authoring/doctypes/command/type.ts +3 -2
- package/authoring/doctypes/component/component.doc.mjs +6 -3
- package/authoring/doctypes/component/parse.d.mts +2 -2
- package/authoring/doctypes/component/parse.mjs +1 -1
- package/authoring/doctypes/component/type.ts +4 -3
- package/authoring/doctypes/enum/parse.d.mts +2 -2
- package/authoring/doctypes/enum/parse.mjs +1 -1
- package/authoring/doctypes/enum/type.ts +3 -1
- package/authoring/doctypes/function/function.doc.mjs +4 -0
- package/authoring/doctypes/function/parse.d.mts +2 -2
- package/authoring/doctypes/function/parse.mjs +1 -1
- package/authoring/doctypes/function/type.ts +6 -2
- package/authoring/doctypes/hook/hook.doc.mjs +4 -0
- package/authoring/doctypes/hook/parse.d.mts +2 -2
- package/authoring/doctypes/hook/parse.mjs +1 -1
- package/authoring/doctypes/hook/type.ts +3 -2
- package/authoring/doctypes/legacy.d.mts +8 -6
- package/authoring/doctypes/legacy.mjs +5 -4
- package/authoring/doctypes/load-contract.test.mjs +207 -0
- package/authoring/doctypes/namespace/namespace.doc.d.mts +9 -0
- package/authoring/doctypes/namespace/namespace.doc.mjs +132 -0
- package/authoring/doctypes/namespace/parse.d.mts +12 -0
- package/authoring/doctypes/namespace/parse.mjs +25 -0
- package/authoring/doctypes/namespace/parse.test.mjs +165 -0
- package/authoring/doctypes/namespace/type.ts +71 -0
- package/authoring/doctypes/parse.d.mts +20 -18
- package/authoring/doctypes/parse.mjs +16 -10
- package/authoring/doctypes/parse.test.mjs +77 -3
- package/authoring/doctypes/reference/parse.d.mts +2 -2
- package/authoring/doctypes/reference/parse.mjs +8 -5
- package/authoring/doctypes/reference/reference.doc.mjs +17 -4
- package/authoring/doctypes/reference/type.ts +51 -5
- package/authoring/doctypes/schema/parse.d.mts +2 -2
- package/authoring/doctypes/schema/parse.mjs +1 -1
- package/authoring/doctypes/schema/type.ts +3 -2
- package/authoring/doctypes/template/parse.d.mts +92 -1
- package/authoring/doctypes/template/parse.mjs +36 -2
- package/authoring/doctypes/template/parse.test.mjs +8 -2
- package/authoring/doctypes/template/template.doc.mjs +4 -0
- package/authoring/doctypes/template/type.ts +5 -2
- package/authoring/doctypes/types.ts +10 -9
- package/authoring/gap-report/parse.d.mts +10 -10
- package/authoring/gap-report/parse.mjs +6 -6
- package/authoring/gap-report/type.ts +1 -1
- package/authoring/identity/identity.doc.d.mts +9 -0
- package/authoring/identity/identity.doc.mjs +61 -0
- package/authoring/identity/type.ts +132 -0
- package/authoring/index.d.mts +1 -0
- package/authoring/index.d.ts +49 -17
- package/authoring/index.mjs +1 -0
- package/authoring/integration/integration.doc.mjs +13 -6
- package/authoring/integration/parse.d.mts +2 -2
- package/authoring/integration/parse.mjs +1 -1
- package/authoring/integration/parse.test.mjs +10 -1
- package/authoring/integration/schema.d.mts +6 -4
- package/authoring/integration/schema.mjs +9 -3
- package/authoring/integration/type.ts +23 -6
- package/authoring/shadcn/receipt.d.mts +6 -6
- package/clients/cli/commands/docs.doc.mjs +13 -3
- package/clients/cli/commands/docs.mjs +121 -21
- package/clients/cli/commands/docs.test.mjs +88 -0
- package/clients/cli/commands/theme-palette-generate.doc.mjs +8 -4
- package/clients/cli/commands/upgrade.doc.mjs +2 -2
- package/clients/cli/formatters/index.mjs +162 -1
- package/clients/cli/formatters/index.test.mjs +91 -0
- package/clients/cli/lib/manifest.mjs +7 -2
- package/foundation/config/project.mjs +21 -6
- package/foundation/discovery/authoring-self-docs.d.mts +69 -0
- package/foundation/discovery/authoring-self-docs.mjs +214 -0
- package/foundation/discovery/authoring-self-docs.test.mjs +154 -0
- package/foundation/discovery/component-discovery.d.mts +1 -1
- package/foundation/discovery/component-discovery.mjs +2 -1
- package/foundation/discovery/docs-discovery.d.mts +11 -4
- package/foundation/discovery/docs-discovery.mjs +208 -88
- package/foundation/discovery/docs-discovery.test.mjs +279 -13
- package/foundation/discovery/docs-output-budget.d.mts +28 -0
- package/foundation/discovery/docs-output-budget.mjs +50 -0
- package/foundation/discovery/docs-section-key.d.mts +98 -0
- package/foundation/discovery/docs-section-key.mjs +221 -0
- package/foundation/discovery/docs-section-key.test.mjs +224 -0
- package/foundation/discovery/template-adapter.mjs +2 -1
- package/foundation/doc-compiler/compile.d.mts +162 -0
- package/foundation/doc-compiler/compile.mjs +262 -0
- package/foundation/doc-compiler/doc-compiler.test.mjs +687 -0
- package/foundation/doc-compiler/ir.d.mts +9 -0
- package/foundation/doc-compiler/ir.mjs +287 -0
- package/foundation/doc-compiler/lenses.d.mts +33 -0
- package/foundation/doc-compiler/lenses.mjs +127 -0
- package/foundation/identity/provider-identity.d.mts +90 -0
- package/foundation/identity/provider-identity.mjs +320 -0
- package/foundation/identity/provider-identity.test.mjs +254 -0
- package/foundation/identity/providers.d.mts +7 -0
- package/foundation/identity/providers.mjs +16 -0
- package/foundation/integrations/autolink.mjs +12 -5
- package/foundation/integrations/integration-warnings.mjs +6 -0
- package/foundation/integrations/integrations.d.mts +46 -2
- package/foundation/integrations/integrations.mjs +167 -8
- package/foundation/integrations/integrations.test.mjs +384 -1
- package/foundation/integrations/provider-conflicts.test.mjs +125 -0
- package/foundation/integrations/validate-contributions.d.mts +2 -0
- package/foundation/integrations/validate-contributions.mjs +10 -0
- package/foundation/response/json-contract.test.mjs +46 -17
- package/foundation/response/response-types.doc.mjs +6 -1
- package/package.json +9 -9
package/README.md
CHANGED
|
@@ -403,7 +403,8 @@ Every response has a `type` discriminant. The full set is below (generated from
|
|
|
403
403
|
| `component.detail.blocks` | One component's example blocks, as {component, showcase, examples, related} of BlockEntry. |
|
|
404
404
|
| `docs.list` | All reference-doc topics as DocsListEntry[] ({topic, description}), in discovery order. |
|
|
405
405
|
| `docs.detail` | One topic's full ReferenceDoc, with token-ref blocks inlined. |
|
|
406
|
-
| `docs.
|
|
406
|
+
| `docs.index` | One topic's section index (--index): each section's key, title, and one-line summary. |
|
|
407
|
+
| `docs.detail.section` | One ReferenceSection of a topic, found by key or title, with token-ref blocks inlined. |
|
|
407
408
|
| `blog.list` | The feed URL plus every post parsed from the RSS feed, each with slug, title, description, date, type, authors, link, and plaintext URL. |
|
|
408
409
|
| `blog.detail` | One post's metadata plus the feed URL and the post's full plaintext body. |
|
|
409
410
|
| `discover.list` | The configured external packages (name, category, components, version, description); when empty it carries meta.configured to tell "nothing configured" from "nothing discovered". |
|
package/api/docs/_adapter.d.mts
CHANGED
|
@@ -16,34 +16,43 @@
|
|
|
16
16
|
*/
|
|
17
17
|
export function loadDocsCatalog(cwd?: string): Promise<DocsCatalog>;
|
|
18
18
|
/**
|
|
19
|
-
*
|
|
20
|
-
* @param {
|
|
21
|
-
* @returns {
|
|
19
|
+
* The overlay languages a topic ships for its own file or any extension.
|
|
20
|
+
* @param {import('../../foundation/discovery/docs-discovery.mjs').DocsTopicEntry} entry
|
|
21
|
+
* @returns {string[]}
|
|
22
22
|
*/
|
|
23
|
-
export function
|
|
24
|
-
lang?: string | null;
|
|
25
|
-
}): Promise<import("./docs.type.mjs").DocsDetailResponse["data"]>;
|
|
23
|
+
export function overlayLanguages(entry: import("../../foundation/discovery/docs-discovery.mjs").DocsTopicEntry): string[];
|
|
26
24
|
/**
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
25
|
+
* One topic, lowered for `lang`: overlaid, extensions merged, keys stamped.
|
|
26
|
+
* Memoized per catalog, so a read that references a topic twice loads it once.
|
|
27
|
+
* Every read of the catalog shares the memoized node, so it is frozen; the
|
|
28
|
+
* lenses hand readers copies.
|
|
29
|
+
* @param {DocsCatalog} catalog
|
|
30
|
+
* @param {import('../../foundation/discovery/docs-discovery.mjs').DocsTopicEntry} entry
|
|
31
|
+
* @param {string | null} [lang]
|
|
32
|
+
* @returns {Promise<import('../../foundation/doc-compiler/compile.mjs').CompiledReferenceNode>}
|
|
33
|
+
*/
|
|
34
|
+
export function lowerTopic(catalog: DocsCatalog, entry: import("../../foundation/discovery/docs-discovery.mjs").DocsTopicEntry, lang?: string | null): Promise<import("../../foundation/doc-compiler/compile.mjs").CompiledReferenceNode>;
|
|
35
|
+
/**
|
|
36
|
+
* How a token reference finds its target: the topic it names in `catalog`,
|
|
37
|
+
* lowered for the same language.
|
|
38
|
+
* @param {DocsCatalog} catalog
|
|
39
|
+
* @param {string | null} lang
|
|
40
|
+
* @returns {(topic: string) => Promise<import('../../foundation/doc-compiler/compile.mjs').CompiledReferenceNode | null>}
|
|
41
|
+
*/
|
|
42
|
+
export function referenceTargets(catalog: DocsCatalog, lang: string | null): (topic: string) => Promise<import("../../foundation/doc-compiler/compile.mjs").CompiledReferenceNode | null>;
|
|
43
|
+
/**
|
|
44
|
+
* One topic, compiled for `lang`: lowered, then every token reference linked.
|
|
45
|
+
* @param {DocsCatalog} catalog
|
|
35
46
|
* @param {import('../../foundation/discovery/docs-discovery.mjs').DocsTopicEntry} entry
|
|
36
|
-
* @param {
|
|
37
|
-
* @returns {Promise<import('
|
|
47
|
+
* @param {string | null} [lang]
|
|
48
|
+
* @returns {Promise<import('../../foundation/doc-compiler/compile.mjs').CompiledReferenceNode>}
|
|
38
49
|
*/
|
|
39
|
-
export function
|
|
40
|
-
lang?: string | null;
|
|
41
|
-
}): Promise<import("./docs.type.mjs").DocsDetailResponse["data"]>;
|
|
50
|
+
export function compileTopic(catalog: DocsCatalog, entry: import("../../foundation/discovery/docs-discovery.mjs").DocsTopicEntry, lang?: string | null): Promise<import("../../foundation/doc-compiler/compile.mjs").CompiledReferenceNode>;
|
|
42
51
|
/**
|
|
43
52
|
* Resolve `topic` against the project's catalog (throwing `ERR_UNKNOWN_TOPIC`
|
|
44
|
-
* when unmatched)
|
|
45
|
-
* integration extension applied. Shared by the
|
|
46
|
-
*
|
|
53
|
+
* when unmatched) and lower it with any --dense/--zh overlay and any
|
|
54
|
+
* integration extension applied. Shared by the leaves so topic normalization
|
|
55
|
+
* and unknown-topic handling live in exactly one place.
|
|
47
56
|
*
|
|
48
57
|
* @param {string} topic
|
|
49
58
|
* @param {object} [options]
|
|
@@ -53,7 +62,8 @@ export function loadTopicDoc(entry: import("../../foundation/discovery/docs-disc
|
|
|
53
62
|
* @param {string} [options.cwd]
|
|
54
63
|
* @returns {Promise<{
|
|
55
64
|
* catalog: DocsCatalog,
|
|
56
|
-
*
|
|
65
|
+
* node: import('../../foundation/doc-compiler/compile.mjs').CompiledReferenceNode,
|
|
66
|
+
* lang: string | null,
|
|
57
67
|
* }>}
|
|
58
68
|
*/
|
|
59
69
|
export function resolveTopicDocs(topic: string, options?: {
|
|
@@ -63,6 +73,9 @@ export function resolveTopicDocs(topic: string, options?: {
|
|
|
63
73
|
cwd?: string | undefined;
|
|
64
74
|
}): Promise<{
|
|
65
75
|
catalog: DocsCatalog;
|
|
66
|
-
|
|
76
|
+
node: import("../../foundation/doc-compiler/compile.mjs").CompiledReferenceNode;
|
|
77
|
+
lang: string | null;
|
|
67
78
|
}>;
|
|
79
|
+
/** The localized overlays a docs read can apply. */
|
|
80
|
+
export const OVERLAY_LANGUAGES: string[];
|
|
68
81
|
import { DocsCatalog } from '../../foundation/discovery/docs-discovery.mjs';
|
package/api/docs/_adapter.mjs
CHANGED
|
@@ -7,25 +7,27 @@
|
|
|
7
7
|
* packages/cli/assets/docs/{topic}.doc.mjs plus every topic the configured
|
|
8
8
|
* integrations contribute — and, when a --dense/--zh overlay is requested,
|
|
9
9
|
* the sibling {topic}.doc.dense.mjs / {topic}.doc.zh.mjs.
|
|
10
|
-
* @output Catalog access,
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* @position Sits beside docs.mjs (api/docs/).
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
10
|
+
* @output Catalog access, the compiler input for a topic, and the compiled
|
|
11
|
+
* node for it: lowered (overlaid, extensions merged, keys stamped) or linked
|
|
12
|
+
* (token references resolved too), memoized per catalog.
|
|
13
|
+
* @position Sits beside docs.mjs (api/docs/). Loads authored files and hands
|
|
14
|
+
* them to foundation/doc-compiler, so no leaf, doctor check or search loads,
|
|
15
|
+
* merges, or resolves docs on its own. Discovery itself lives in
|
|
16
|
+
* foundation/discovery/docs-discovery, which the catalog comes from.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
import * as fs from 'node:fs';
|
|
20
20
|
import * as path from 'node:path';
|
|
21
21
|
import {pathToFileURL} from 'node:url';
|
|
22
22
|
import {Project} from '../../foundation/config/project.mjs';
|
|
23
|
+
import {DocsCatalog} from '../../foundation/discovery/docs-discovery.mjs';
|
|
23
24
|
import {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
} from '../../foundation/
|
|
25
|
+
linkReferenceTopic,
|
|
26
|
+
lowerReferenceTopic,
|
|
27
|
+
} from '../../foundation/doc-compiler/compile.mjs';
|
|
27
28
|
import {AstryxError} from '../error.mjs';
|
|
28
29
|
import {ERROR_CODES} from '../../foundation/response/error-codes.mjs';
|
|
30
|
+
import {parseDoc} from '../../authoring/doctypes/parse.mjs';
|
|
29
31
|
|
|
30
32
|
/**
|
|
31
33
|
* The project's topics: the built-in ones plus whatever the configured
|
|
@@ -49,93 +51,176 @@ export async function loadDocsCatalog(cwd = process.cwd()) {
|
|
|
49
51
|
}
|
|
50
52
|
}
|
|
51
53
|
|
|
54
|
+
/** The localized overlays a docs read can apply. */
|
|
55
|
+
export const OVERLAY_LANGUAGES = ['zh', 'dense'];
|
|
56
|
+
|
|
52
57
|
/**
|
|
58
|
+
* Where the `lang` overlay of a doc file lives: `{topic}.doc.{lang}.mjs`.
|
|
53
59
|
* @param {string} docPath
|
|
54
|
-
* @param {
|
|
55
|
-
* @returns {
|
|
60
|
+
* @param {string} lang
|
|
61
|
+
* @returns {string}
|
|
62
|
+
*/
|
|
63
|
+
function overlayPath(docPath, lang) {
|
|
64
|
+
return path.join(
|
|
65
|
+
path.dirname(docPath),
|
|
66
|
+
`${path.basename(docPath, '.doc.mjs')}.doc.${lang}.mjs`,
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* The overlay languages a topic ships for its own file or any extension.
|
|
72
|
+
* @param {import('../../foundation/discovery/docs-discovery.mjs').DocsTopicEntry} entry
|
|
73
|
+
* @returns {string[]}
|
|
56
74
|
*/
|
|
57
|
-
export
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
75
|
+
export function overlayLanguages(entry) {
|
|
76
|
+
const files = [entry.path, ...entry.extensions.map(ext => ext.path)];
|
|
77
|
+
return OVERLAY_LANGUAGES.filter(lang =>
|
|
78
|
+
files.some(file => fs.existsSync(overlayPath(file, lang))),
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* The overlay a read applies: none for the authored language.
|
|
84
|
+
* @param {string | null | undefined} lang
|
|
85
|
+
* @returns {string | null}
|
|
86
|
+
*/
|
|
87
|
+
function overlayLanguage(lang) {
|
|
88
|
+
return lang && lang !== 'en' ? lang : null;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Load one authored file and the overlay for `lang`. A failure is recorded on
|
|
93
|
+
* the result, not thrown, so the compiler reports it in reading order.
|
|
94
|
+
* @param {string} docPath
|
|
95
|
+
* @param {string | null} lang
|
|
96
|
+
* @returns {Promise<import('../../foundation/doc-compiler/compile.mjs').AuthoredFile>}
|
|
97
|
+
*/
|
|
98
|
+
async function loadAuthoredFile(docPath, lang) {
|
|
99
|
+
const file = path.basename(docPath);
|
|
100
|
+
let doc;
|
|
101
|
+
try {
|
|
102
|
+
const mod = await import(pathToFileURL(docPath).href);
|
|
103
|
+
doc = parseDoc(mod.docs ?? mod.default, file);
|
|
104
|
+
} catch (error) {
|
|
105
|
+
return {file, error};
|
|
106
|
+
}
|
|
107
|
+
if (!lang) return {file, doc};
|
|
108
|
+
const translationPath = overlayPath(docPath, lang);
|
|
109
|
+
if (!fs.existsSync(translationPath)) return {file, doc};
|
|
110
|
+
try {
|
|
111
|
+
const translationMod = await import(pathToFileURL(translationPath).href);
|
|
112
|
+
return {
|
|
113
|
+
file,
|
|
114
|
+
doc,
|
|
115
|
+
overlay: translationMod.docsZh || translationMod.docsDense || null,
|
|
116
|
+
};
|
|
117
|
+
} catch (overlayError) {
|
|
118
|
+
return {file, doc, overlayError};
|
|
83
119
|
}
|
|
120
|
+
}
|
|
84
121
|
|
|
122
|
+
/**
|
|
123
|
+
* Everything the compiler needs for one topic, read from disk.
|
|
124
|
+
* @param {import('../../foundation/discovery/docs-discovery.mjs').DocsTopicEntry} entry
|
|
125
|
+
* @param {string | null} lang
|
|
126
|
+
* @returns {Promise<import('../../foundation/doc-compiler/compile.mjs').ReferenceTopicInput>}
|
|
127
|
+
*/
|
|
128
|
+
async function loadCompilerInput(entry, lang) {
|
|
129
|
+
const extensions = [];
|
|
130
|
+
for (const extension of entry.extensions) {
|
|
131
|
+
extensions.push({
|
|
132
|
+
...(await loadAuthoredFile(extension.path, lang)),
|
|
133
|
+
provider: extension.package,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
85
136
|
return {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
return {
|
|
93
|
-
...section,
|
|
94
|
-
title: ts.title || section.title,
|
|
95
|
-
content: section.content.map(
|
|
96
|
-
(
|
|
97
|
-
/** @type {import('@astryxdesign/cli/authoring').ReferenceContentBlock} */ block,
|
|
98
|
-
/** @type {number} */ bi,
|
|
99
|
-
) => {
|
|
100
|
-
const tb = ts.content?.[bi];
|
|
101
|
-
if (!tb) return block;
|
|
102
|
-
if (tb.type === 'prose' && block.type === 'prose') return {...block, text: tb.text};
|
|
103
|
-
if (tb.type === 'list' && block.type === 'list') return {...block, items: tb.items};
|
|
104
|
-
return block;
|
|
105
|
-
},
|
|
106
|
-
),
|
|
107
|
-
};
|
|
108
|
-
},
|
|
109
|
-
),
|
|
137
|
+
id: entry.name,
|
|
138
|
+
provider: entry.package,
|
|
139
|
+
replaces: entry.replaces ?? null,
|
|
140
|
+
lang,
|
|
141
|
+
base: await loadAuthoredFile(entry.path, lang),
|
|
142
|
+
extensions,
|
|
110
143
|
};
|
|
111
144
|
}
|
|
112
145
|
|
|
146
|
+
/** @type {WeakMap<DocsCatalog, Map<string, Promise<import('../../foundation/doc-compiler/compile.mjs').CompiledReferenceNode>>>} */
|
|
147
|
+
const loweredByCatalog = new WeakMap();
|
|
148
|
+
|
|
113
149
|
/**
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
* `--dense`/`--zh` (it replaces its own sections and leaves the rest
|
|
120
|
-
* translated) rather than being dropped.
|
|
121
|
-
*
|
|
150
|
+
* One topic, lowered for `lang`: overlaid, extensions merged, keys stamped.
|
|
151
|
+
* Memoized per catalog, so a read that references a topic twice loads it once.
|
|
152
|
+
* Every read of the catalog shares the memoized node, so it is frozen; the
|
|
153
|
+
* lenses hand readers copies.
|
|
154
|
+
* @param {DocsCatalog} catalog
|
|
122
155
|
* @param {import('../../foundation/discovery/docs-discovery.mjs').DocsTopicEntry} entry
|
|
123
|
-
* @param {
|
|
124
|
-
* @returns {Promise<import('
|
|
156
|
+
* @param {string | null} [lang]
|
|
157
|
+
* @returns {Promise<import('../../foundation/doc-compiler/compile.mjs').CompiledReferenceNode>}
|
|
125
158
|
*/
|
|
126
|
-
export
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
159
|
+
export function lowerTopic(catalog, entry, lang = null) {
|
|
160
|
+
const overlay = overlayLanguage(lang);
|
|
161
|
+
let cache = loweredByCatalog.get(catalog);
|
|
162
|
+
if (!cache) {
|
|
163
|
+
cache = new Map();
|
|
164
|
+
loweredByCatalog.set(catalog, cache);
|
|
165
|
+
}
|
|
166
|
+
const key = `${entry.name.toLowerCase()}\u0000${overlay ?? ''}`;
|
|
167
|
+
let lowered = cache.get(key);
|
|
168
|
+
if (!lowered) {
|
|
169
|
+
lowered = loadCompilerInput(entry, overlay).then(input =>
|
|
170
|
+
deepFreeze(lowerReferenceTopic(input)),
|
|
171
|
+
);
|
|
172
|
+
cache.set(key, lowered);
|
|
173
|
+
}
|
|
174
|
+
return lowered;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Freeze a value and everything in it.
|
|
179
|
+
* @template T
|
|
180
|
+
* @param {T} value
|
|
181
|
+
* @returns {T}
|
|
182
|
+
*/
|
|
183
|
+
function deepFreeze(value) {
|
|
184
|
+
if (value !== null && typeof value === 'object' && !Object.isFrozen(value)) {
|
|
185
|
+
Object.freeze(value);
|
|
186
|
+
for (const child of Object.values(value)) deepFreeze(child);
|
|
130
187
|
}
|
|
131
|
-
return
|
|
188
|
+
return value;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* How a token reference finds its target: the topic it names in `catalog`,
|
|
193
|
+
* lowered for the same language.
|
|
194
|
+
* @param {DocsCatalog} catalog
|
|
195
|
+
* @param {string | null} lang
|
|
196
|
+
* @returns {(topic: string) => Promise<import('../../foundation/doc-compiler/compile.mjs').CompiledReferenceNode | null>}
|
|
197
|
+
*/
|
|
198
|
+
export function referenceTargets(catalog, lang) {
|
|
199
|
+
return async topic => {
|
|
200
|
+
const target = catalog.resolve(topic);
|
|
201
|
+
return target ? lowerTopic(catalog, target, lang) : null;
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* One topic, compiled for `lang`: lowered, then every token reference linked.
|
|
207
|
+
* @param {DocsCatalog} catalog
|
|
208
|
+
* @param {import('../../foundation/discovery/docs-discovery.mjs').DocsTopicEntry} entry
|
|
209
|
+
* @param {string | null} [lang]
|
|
210
|
+
* @returns {Promise<import('../../foundation/doc-compiler/compile.mjs').CompiledReferenceNode>}
|
|
211
|
+
*/
|
|
212
|
+
export async function compileTopic(catalog, entry, lang = null) {
|
|
213
|
+
return linkReferenceTopic(
|
|
214
|
+
await lowerTopic(catalog, entry, lang),
|
|
215
|
+
referenceTargets(catalog, lang),
|
|
216
|
+
);
|
|
132
217
|
}
|
|
133
218
|
|
|
134
219
|
/**
|
|
135
220
|
* Resolve `topic` against the project's catalog (throwing `ERR_UNKNOWN_TOPIC`
|
|
136
|
-
* when unmatched)
|
|
137
|
-
* integration extension applied. Shared by the
|
|
138
|
-
*
|
|
221
|
+
* when unmatched) and lower it with any --dense/--zh overlay and any
|
|
222
|
+
* integration extension applied. Shared by the leaves so topic normalization
|
|
223
|
+
* and unknown-topic handling live in exactly one place.
|
|
139
224
|
*
|
|
140
225
|
* @param {string} topic
|
|
141
226
|
* @param {object} [options]
|
|
@@ -145,7 +230,8 @@ export async function loadTopicDoc(entry, {lang} = {}) {
|
|
|
145
230
|
* @param {string} [options.cwd]
|
|
146
231
|
* @returns {Promise<{
|
|
147
232
|
* catalog: DocsCatalog,
|
|
148
|
-
*
|
|
233
|
+
* node: import('../../foundation/doc-compiler/compile.mjs').CompiledReferenceNode,
|
|
234
|
+
* lang: string | null,
|
|
149
235
|
* }>}
|
|
150
236
|
*/
|
|
151
237
|
export async function resolveTopicDocs(topic, options = {}) {
|
|
@@ -165,6 +251,6 @@ export async function resolveTopicDocs(topic, options = {}) {
|
|
|
165
251
|
);
|
|
166
252
|
}
|
|
167
253
|
|
|
168
|
-
const
|
|
169
|
-
return {catalog,
|
|
254
|
+
const node = await lowerTopic(catalog, entry, effectiveLang);
|
|
255
|
+
return {catalog, node, lang: effectiveLang};
|
|
170
256
|
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file Every shipped topic compiles to a plain-JSON node that answers every
|
|
5
|
+
* docs read exactly as the live one does, and no read can change another read
|
|
6
|
+
* of the same catalog.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import {describe, expect, it} from 'vitest';
|
|
10
|
+
import {parseCompiledReferenceNode} from '../../foundation/doc-compiler/ir.mjs';
|
|
11
|
+
import {detailView, indexView} from '../../foundation/doc-compiler/lenses.mjs';
|
|
12
|
+
import {
|
|
13
|
+
compileTopic,
|
|
14
|
+
loadDocsCatalog,
|
|
15
|
+
lowerTopic,
|
|
16
|
+
overlayLanguages,
|
|
17
|
+
} from './_adapter.mjs';
|
|
18
|
+
|
|
19
|
+
const SLOW = 60_000;
|
|
20
|
+
|
|
21
|
+
describe('every shipped topic compiles to plain JSON', () => {
|
|
22
|
+
it(
|
|
23
|
+
'survives a JSON round trip with identical responses in every language',
|
|
24
|
+
async () => {
|
|
25
|
+
const catalog = await loadDocsCatalog();
|
|
26
|
+
let compiled = 0;
|
|
27
|
+
for (const entry of catalog.entries()) {
|
|
28
|
+
for (const lang of [null, ...overlayLanguages(entry)]) {
|
|
29
|
+
const lowered = await lowerTopic(catalog, entry, lang);
|
|
30
|
+
expect(parseCompiledReferenceNode(lowered)).toBe(lowered);
|
|
31
|
+
const node = await compileTopic(catalog, entry, lang);
|
|
32
|
+
expect(parseCompiledReferenceNode(node)).toBe(node);
|
|
33
|
+
const copy = parseCompiledReferenceNode(
|
|
34
|
+
JSON.parse(JSON.stringify(node)),
|
|
35
|
+
);
|
|
36
|
+
expect(JSON.stringify(detailView(copy))).toBe(
|
|
37
|
+
JSON.stringify(detailView(node)),
|
|
38
|
+
);
|
|
39
|
+
expect(JSON.stringify(indexView(copy))).toBe(
|
|
40
|
+
JSON.stringify(indexView(node)),
|
|
41
|
+
);
|
|
42
|
+
compiled += 1;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
expect(compiled).toBeGreaterThan(catalog.entries().length);
|
|
46
|
+
},
|
|
47
|
+
SLOW,
|
|
48
|
+
);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
describe('reads that share a catalog', () => {
|
|
52
|
+
it(
|
|
53
|
+
'never let one read change another',
|
|
54
|
+
async () => {
|
|
55
|
+
const catalog = await loadDocsCatalog();
|
|
56
|
+
const tokens = catalog.resolve('tokens');
|
|
57
|
+
const first = detailView(await compileTopic(catalog, tokens));
|
|
58
|
+
for (const section of first.sections) {
|
|
59
|
+
section.title = 'EDITED';
|
|
60
|
+
for (const block of section.content) {
|
|
61
|
+
if (typeof block.text === 'string') block.text = 'EDITED';
|
|
62
|
+
if (Array.isArray(block.rows)) block.rows.push(['EDITED']);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const again = detailView(await compileTopic(catalog, tokens));
|
|
66
|
+
const index = indexView(await lowerTopic(catalog, tokens));
|
|
67
|
+
const spacing = detailView(
|
|
68
|
+
await compileTopic(catalog, catalog.resolve('spacing')),
|
|
69
|
+
);
|
|
70
|
+
for (const read of [again, index, spacing]) {
|
|
71
|
+
expect(JSON.stringify(read)).not.toContain('EDITED');
|
|
72
|
+
}
|
|
73
|
+
const lowered = await lowerTopic(catalog, tokens);
|
|
74
|
+
expect(Object.isFrozen(lowered.doc.sections[0].content)).toBe(true);
|
|
75
|
+
},
|
|
76
|
+
SLOW,
|
|
77
|
+
);
|
|
78
|
+
});
|
|
@@ -3,69 +3,17 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* @file docs.detail leaf — load one topic's full reference doc.
|
|
5
5
|
*
|
|
6
|
-
* @input A topic name plus optional {lang, zh, dense}. Resolves
|
|
7
|
-
*
|
|
6
|
+
* @input A topic name plus optional {lang, zh, dense, cwd}. Resolves the topic
|
|
7
|
+
* via the shared adapter and compiles it with its token references linked.
|
|
8
8
|
* @output { type: 'docs.detail', data: ReferenceDoc } — the full doc with
|
|
9
|
-
* token-refs
|
|
10
|
-
* @position Leaf under api/docs.
|
|
11
|
-
*
|
|
9
|
+
* token-refs inlined, matching `astryx --json docs <topic>`.
|
|
10
|
+
* @position Leaf under api/docs. Reads the compiled node through the detail
|
|
11
|
+
* lens; resolution, overlays and extensions happen in the compiler.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
* Resolve token-ref blocks by inlining the referenced section's table.
|
|
18
|
-
* This allows section docs to reference token tables without duplicating data.
|
|
19
|
-
*
|
|
20
|
-
* The reference is resolved through the catalog, so a topic may point at one
|
|
21
|
-
* an integration contributed (or replaced) rather than only at a built-in.
|
|
22
|
-
* @param {import('../docs.type.mjs').DocsDetailResponse['data']} docsData
|
|
23
|
-
* @param {import('../../../foundation/discovery/docs-discovery.mjs').DocsCatalog} catalog
|
|
24
|
-
* @returns {Promise<import('../docs.type.mjs').DocsDetailResponse['data']>}
|
|
25
|
-
*/
|
|
26
|
-
async function resolveTokenRefs(docsData, catalog) {
|
|
27
|
-
const resolved = {...docsData, sections: [...docsData.sections]};
|
|
28
|
-
for (let si = 0; si < resolved.sections.length; si++) {
|
|
29
|
-
const section = resolved.sections[si];
|
|
30
|
-
/** @type {import('@astryxdesign/cli/authoring').ReferenceContentBlock[]} */
|
|
31
|
-
const newContent = [];
|
|
32
|
-
for (const block of section.content) {
|
|
33
|
-
if (block.type === 'token-ref') {
|
|
34
|
-
const refEntry = catalog.resolve(block.topic);
|
|
35
|
-
if (!refEntry) {
|
|
36
|
-
newContent.push({type: 'prose', text: `[token-ref: unknown topic "${block.topic}"]`});
|
|
37
|
-
continue;
|
|
38
|
-
}
|
|
39
|
-
const refDocs = await loadTopicDoc(refEntry);
|
|
40
|
-
const refSection = refDocs.sections.find(
|
|
41
|
-
(/** @type {import('@astryxdesign/cli/authoring').ReferenceSection} */ s) =>
|
|
42
|
-
s.title.toLowerCase() === block.section.toLowerCase(),
|
|
43
|
-
);
|
|
44
|
-
if (!refSection) {
|
|
45
|
-
newContent.push({type: 'prose', text: `[token-ref: section "${block.section}" not found in "${block.topic}"]`});
|
|
46
|
-
continue;
|
|
47
|
-
}
|
|
48
|
-
// Inline the referenced section's content blocks (tables, prose, etc.)
|
|
49
|
-
// and carry over the previewType
|
|
50
|
-
for (const refBlock of refSection.content) {
|
|
51
|
-
newContent.push(refBlock);
|
|
52
|
-
}
|
|
53
|
-
// If the referenced section has a previewType, attach it to our section
|
|
54
|
-
if (refSection.previewType && !section.previewType) {
|
|
55
|
-
resolved.sections[si] = {...section, previewType: refSection.previewType, content: newContent};
|
|
56
|
-
}
|
|
57
|
-
} else {
|
|
58
|
-
newContent.push(block);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
if (resolved.sections[si] === section) {
|
|
62
|
-
resolved.sections[si] = {...section, content: newContent};
|
|
63
|
-
} else {
|
|
64
|
-
resolved.sections[si].content = newContent;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
return resolved;
|
|
68
|
-
}
|
|
14
|
+
import {linkReferenceTopic} from '../../../foundation/doc-compiler/compile.mjs';
|
|
15
|
+
import {detailView} from '../../../foundation/doc-compiler/lenses.mjs';
|
|
16
|
+
import {referenceTargets, resolveTopicDocs} from '../_adapter.mjs';
|
|
69
17
|
|
|
70
18
|
/**
|
|
71
19
|
* @param {string} topic
|
|
@@ -77,7 +25,10 @@ async function resolveTokenRefs(docsData, catalog) {
|
|
|
77
25
|
* @returns {Promise<import('../docs.type.mjs').DocsDetailResponse>}
|
|
78
26
|
*/
|
|
79
27
|
export async function detail(topic, options = {}) {
|
|
80
|
-
const {catalog,
|
|
81
|
-
const
|
|
82
|
-
|
|
28
|
+
const {catalog, node, lang} = await resolveTopicDocs(topic, options);
|
|
29
|
+
const linked = await linkReferenceTopic(
|
|
30
|
+
node,
|
|
31
|
+
referenceTargets(catalog, lang),
|
|
32
|
+
);
|
|
33
|
+
return {type: 'docs.detail', data: detailView(linked)};
|
|
83
34
|
}
|