@astryxdesign/cli 0.7.2-canary.fbc03f7 → 0.7.2-canary.fdd384f

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.
Files changed (139) hide show
  1. package/README.md +9 -8
  2. package/api/build/help/help.mjs +1 -1
  3. package/api/component/_adapter.d.mts +41 -1
  4. package/api/component/_adapter.mjs +93 -7
  5. package/api/component/component.mjs +22 -5
  6. package/api/component/integration-export-name.test.mjs +644 -0
  7. package/api/docs/_adapter.d.mts +11 -0
  8. package/api/docs/_adapter.mjs +244 -1
  9. package/api/docs/integrationDocs.test.mjs +124 -0
  10. package/api/doctor/theme-checks.mjs +1 -1
  11. package/api/gap-report/gap-report.mjs +67 -4
  12. package/api/index.d.mts +2 -0
  13. package/api/index.mjs +2 -0
  14. package/api/init/run/run.mjs +2 -2
  15. package/api/integration/_adapter.d.mts +12 -0
  16. package/api/integration/_adapter.mjs +54 -0
  17. package/api/integration/add-contribution.component-names.test.mjs +66 -0
  18. package/api/integration/add-contribution.mjs +8 -4
  19. package/api/integration/add-contribution.test.mjs +4 -2
  20. package/api/integration/authoring-checks.mjs +11 -2
  21. package/api/integration/authoring-checks.test.mjs +39 -0
  22. package/api/integration/authoring-checks.type.d.mts +9 -0
  23. package/api/integration/authoring-checks.type.mjs +14 -1
  24. package/api/integration/check/check.d.mts +96 -0
  25. package/api/integration/check/check.mjs +357 -0
  26. package/api/integration/check/check.test.mjs +489 -0
  27. package/api/integration/integration-check.type.d.mts +118 -0
  28. package/api/integration/integration-check.type.mjs +84 -0
  29. package/api/integration/integrationCheck.doc.d.mts +10 -0
  30. package/api/integration/integrationCheck.doc.mjs +73 -0
  31. package/api/integration/integrationComponentConflicts.doc.mjs +36 -5
  32. package/api/integration/pack-check.mjs +51 -97
  33. package/api/integration/pack-check.test.mjs +359 -0
  34. package/api/integration/validate-integration.mjs +8 -0
  35. package/api/integration/validate-integration.test.mjs +11 -0
  36. package/api/integration/validate-integration.type.d.mts +8 -0
  37. package/api/integration/validate-integration.type.mjs +12 -1
  38. package/api/integration/validateIntegration.doc.mjs +17 -3
  39. package/api/search/search.d.mts +9 -0
  40. package/api/search/search.integration-check.test.mjs +24 -0
  41. package/api/search/search.mjs +100 -13
  42. package/api/swizzle/copy/copy.mjs +28 -14
  43. package/api/theme/build/build.family.test.mjs +54 -6
  44. package/api/theme/build/build.mjs +114 -17
  45. package/api/theme/themeBuild.doc.mjs +4 -4
  46. package/assets/docs/README.md +10 -0
  47. package/assets/docs/author-a-theme.doc.mjs +1 -1
  48. package/assets/docs/getting-started.doc.mjs +3 -3
  49. package/assets/docs/theme.doc.dense.mjs +1 -1
  50. package/assets/docs/theme.doc.mjs +1 -1
  51. package/assets/docs/theme.doc.zh.mjs +1 -1
  52. package/assets/docs/tree/add-a-component.doc.mjs +10 -0
  53. package/assets/docs/tree/block-template.doc.mjs +2 -2
  54. package/assets/docs/tree/check-the-props.doc.mjs +196 -0
  55. package/assets/docs/tree/check-your-docs.doc.mjs +44 -3
  56. package/assets/docs/tree/checks.doc.mjs +21 -13
  57. package/assets/docs/tree/component-family.doc.mjs +5 -1
  58. package/assets/docs/tree/component-imports.doc.mjs +8 -0
  59. package/assets/docs/tree/describe-the-component.doc.mjs +1 -1
  60. package/assets/docs/tree/links.doc.mjs +2 -2
  61. package/assets/docs/tree/page-template.doc.mjs +1 -1
  62. package/assets/docs/tree/quick-start.doc.mjs +1 -1
  63. package/assets/docs/tree/replace-a-core-template.doc.mjs +1 -1
  64. package/assets/docs/tree/single-component.doc.mjs +3 -2
  65. package/assets/docs/tree/troubleshooting.doc.mjs +9 -1
  66. package/assets/docs/tree/type-scale.doc.mjs +3 -3
  67. package/assets/docs/tree/versioning.doc.mjs +1 -0
  68. package/assets/docs/tree/write-the-template-file.doc.mjs +2 -1
  69. package/assets/docs/use-a-theme.doc.mjs +2 -2
  70. package/assets/theme.template.ts +1 -1
  71. package/authoring/doctypes/component/component.doc.mjs +2 -2
  72. package/authoring/doctypes/component/type.ts +6 -3
  73. package/authoring/doctypes/template/integration-template.doc.d.mts +11 -0
  74. package/authoring/doctypes/template/integration-template.doc.mjs +49 -0
  75. package/authoring/doctypes/template/parse.d.mts +6 -2
  76. package/authoring/doctypes/template/parse.mjs +3 -1
  77. package/authoring/doctypes/template/template.doc.mjs +1 -1
  78. package/authoring/doctypes/template/type.ts +22 -0
  79. package/authoring/index.d.ts +1 -0
  80. package/authoring/integration/integration.doc.mjs +8 -1
  81. package/authoring/integration/parse.test.mjs +10 -0
  82. package/authoring/integration/schema.d.mts +2 -0
  83. package/authoring/integration/schema.mjs +1 -0
  84. package/authoring/integration/type.ts +4 -0
  85. package/clients/cli/commands/build-theme.batch-report.test.mjs +3 -1
  86. package/clients/cli/commands/build-theme.mjs +1 -1
  87. package/clients/cli/commands/build-theme.path-safety.test.mjs +155 -21
  88. package/clients/cli/commands/doctor-integration-components.doc.mjs +15 -4
  89. package/clients/cli/commands/doctor-integration-validate.doc.mjs +11 -2
  90. package/clients/cli/commands/doctor-integration.test.mjs +837 -0
  91. package/clients/cli/commands/doctor.mjs +190 -0
  92. package/clients/cli/commands/integration-check.doc.mjs +85 -0
  93. package/clients/cli/commands/integration-check.test.mjs +267 -0
  94. package/clients/cli/commands/integration.doc.mjs +6 -2
  95. package/clients/cli/commands/integration.mjs +107 -1
  96. package/clients/cli/commands/text-json-parity.test.mjs +5 -0
  97. package/clients/cli/commands/theme-build.doc.mjs +2 -2
  98. package/clients/cli/index.mjs +1 -0
  99. package/foundation/config/project.mjs +82 -0
  100. package/foundation/discovery/authoring-self-docs.mjs +1 -0
  101. package/foundation/discovery/component-discovery.d.mts +178 -10
  102. package/foundation/discovery/component-discovery.export-names.test.mjs +760 -0
  103. package/foundation/discovery/component-discovery.mjs +659 -62
  104. package/foundation/discovery/component-replacement.mjs +18 -0
  105. package/foundation/discovery/component-replacement.test.mjs +40 -0
  106. package/foundation/discovery/doc-types.d.mts +157 -0
  107. package/foundation/discovery/doc-types.mjs +1224 -0
  108. package/foundation/discovery/doc-types.test.mjs +652 -0
  109. package/foundation/discovery/docs-discovery.d.mts +81 -0
  110. package/foundation/discovery/docs-discovery.mjs +57 -0
  111. package/foundation/discovery/integration-doc-files.d.mts +22 -0
  112. package/foundation/discovery/integration-doc-files.mjs +231 -0
  113. package/foundation/discovery/integration-doc-files.test.mjs +246 -0
  114. package/foundation/discovery/module-exports.d.mts +27 -0
  115. package/foundation/discovery/module-exports.mjs +356 -31
  116. package/foundation/discovery/module-exports.test.mjs +172 -0
  117. package/foundation/discovery/package-tsconfig.d.mts +14 -0
  118. package/foundation/discovery/package-tsconfig.mjs +228 -0
  119. package/foundation/discovery/package-tsconfig.test.mjs +210 -0
  120. package/foundation/discovery/project-typescript.d.mts +23 -0
  121. package/foundation/discovery/project-typescript.mjs +61 -0
  122. package/foundation/discovery/prop-drift.d.mts +278 -0
  123. package/foundation/discovery/prop-drift.mjs +2263 -0
  124. package/foundation/discovery/prop-drift.test.mjs +2219 -0
  125. package/foundation/discovery/type-match.d.mts +53 -0
  126. package/foundation/discovery/type-match.mjs +660 -0
  127. package/foundation/discovery/type-match.test.mjs +169 -0
  128. package/foundation/discovery/type-text.d.mts +68 -0
  129. package/foundation/discovery/type-text.mjs +658 -0
  130. package/foundation/discovery/type-text.test.mjs +196 -0
  131. package/foundation/discovery/unresolved-references.d.mts +62 -0
  132. package/foundation/discovery/unresolved-references.mjs +790 -0
  133. package/foundation/discovery/unresolved-references.test.mjs +567 -0
  134. package/foundation/doc-compiler/doc-loads.test.mjs +6 -0
  135. package/foundation/doc-compiler/links.d.mts +9 -5
  136. package/foundation/doc-compiler/links.mjs +4 -2
  137. package/foundation/integrations/contribution-inventory.mjs +6 -1
  138. package/foundation/response/response-types.doc.mjs +7 -2
  139. package/package.json +9 -9
@@ -86,7 +86,7 @@ export const docs = {
86
86
  type: 'code',
87
87
  lang: 'tsx',
88
88
  label: 'App root',
89
- code: `import {Theme} from '@astryxdesign/core';
89
+ code: `import {Theme} from '@astryxdesign/core/theme';
90
90
  import {themes, defaultThemeSlug} from './astryx-themes';
91
91
 
92
92
  <Theme theme={themes[defaultThemeSlug]}><App /></Theme>`,
@@ -119,14 +119,14 @@ import {themes, defaultThemeSlug} from './astryx-themes';
119
119
  content: [
120
120
  {
121
121
  type: 'prose',
122
- text: 'Components are imported from per-category subpath entrypoints. This keeps bundles small and makes intent clear.',
122
+ text: 'Import each component from its own entry, the path `astryx component <Name>` prints. This keeps bundles small and makes intent clear.',
123
123
  },
124
124
  {
125
125
  type: 'code',
126
126
  lang: 'tsx',
127
127
  label: 'app/page.tsx',
128
128
  code: `import {Button} from '@astryxdesign/core/Button';
129
- import {VStack} from '@astryxdesign/core/Layout';
129
+ import {VStack} from '@astryxdesign/core/VStack';
130
130
 
131
131
  export default function Page() {
132
132
  return (
@@ -9,7 +9,7 @@ export const docsDense = {
9
9
  section: 'Wrap your app in a theme',
10
10
  title: 'Quick start',
11
11
  content: [
12
- {type: 'prose', text: "Install a theme, wrap in `<Theme>` (`import {Theme} from '@astryxdesign/core'`). {@link generic:use-a-theme} for full guide."},
12
+ {type: 'prose', text: "Install a theme, wrap in `<Theme>` (`import {Theme} from '@astryxdesign/core/theme'`). {@link generic:use-a-theme} for full guide."},
13
13
  ],
14
14
  },
15
15
  {
@@ -23,7 +23,7 @@ export const docs = {
23
23
  type: 'code',
24
24
  lang: 'tsx',
25
25
  label: 'Wire the generated module once',
26
- code: "import {Theme} from '@astryxdesign/core';\nimport {themes, defaultThemeSlug} from './astryx-themes';\n\nfunction App() {\n return (\n <Theme theme={themes[defaultThemeSlug]}>\n <YourApp />\n </Theme>\n );\n}",
26
+ code: "import {Theme} from '@astryxdesign/core/theme';\nimport {themes, defaultThemeSlug} from './astryx-themes';\n\nfunction App() {\n return (\n <Theme theme={themes[defaultThemeSlug]}>\n <YourApp />\n </Theme>\n );\n}",
27
27
  },
28
28
  ],
29
29
  },
@@ -11,7 +11,7 @@ export const docsZh = {
11
11
  content: [
12
12
  {
13
13
  type: 'prose',
14
- text: "安装主题包,用 `<Theme>`(`import {Theme} from '@astryxdesign/core'`)包裹应用,选择浅色或深色模式。完整指南——可用主题、集成主题、深色模式、嵌套主题和生产构建——请参阅 {@link generic:use-a-theme}。",
14
+ text: "安装主题包,用 `<Theme>`(`import {Theme} from '@astryxdesign/core/theme'`)包裹应用,选择浅色或深色模式。完整指南——可用主题、集成主题、深色模式、嵌套主题和生产构建——请参阅 {@link generic:use-a-theme}。",
15
15
  },
16
16
  ],
17
17
  },
@@ -71,5 +71,15 @@ Declare component root ./components in astryx.integration.mjs.
71
71
  },
72
72
  ],
73
73
  },
74
+ {
75
+ id: 'document-an-existing-component',
76
+ title: 'Document a component you already have',
77
+ content: [
78
+ {
79
+ type: 'prose',
80
+ text: "To document a component your package already has, write its doc beside the source file and name the doc after that file, such as `acme-gallery.doc.mjs` beside `acme-gallery.tsx`. Set `name` to the export apps import, such as `name: 'AcmeGallery'`, and keep both files inside the components root that `astryx.integration.mjs` declares. The file does not have to be named after the component; {@link generic:component-imports} shows how apps then find it.",
81
+ },
82
+ ],
83
+ },
74
84
  ],
75
85
  };
@@ -31,7 +31,7 @@ export const docs = {
31
31
  type: 'code',
32
32
  lang: 'javascript',
33
33
  label: 'templates/acme-stat-card.doc.mjs',
34
- code: `/** @type {import('@astryxdesign/cli/authoring').TemplateDoc} */
34
+ code: `/** @type {import('@astryxdesign/cli/authoring').IntegrationTemplateDoc} */
35
35
  export default {
36
36
  type: 'block',
37
37
  name: 'acme-stat-card',
@@ -75,7 +75,7 @@ export default {
75
75
  type: 'code',
76
76
  lang: 'javascript',
77
77
  label: 'templates/acme-status-card-showcase.doc.mjs',
78
- code: `/** @type {import('@astryxdesign/cli/authoring').TemplateDoc} */
78
+ code: `/** @type {import('@astryxdesign/cli/authoring').IntegrationTemplateDoc} */
79
79
  export default {
80
80
  type: 'block',
81
81
  name: 'acme-status-card-showcase',
@@ -0,0 +1,196 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file `astryx docs cli/integrations/building-blocks/components/describe-the-component/check-the-props`:
5
+ * compare each component doc's props table with the component's TypeScript
6
+ * props, read each finding, and fix the doc or the code.
7
+ */
8
+
9
+ /** @type {import('@astryxdesign/cli/authoring').ReferenceDoc} */
10
+ export const docs = {
11
+ type: 'generic',
12
+ name: 'check-the-props',
13
+ placement: {
14
+ parent: 'namespace:describe-the-component',
15
+ slot: 'guides',
16
+ order: 50,
17
+ },
18
+ title: 'Check the props table',
19
+ category: 'guide',
20
+ keywords: [
21
+ 'props table',
22
+ 'documented props',
23
+ 'prop drift',
24
+ 'props not compared',
25
+ ],
26
+ description:
27
+ "Compare each props table with the component's TypeScript props, then fix the doc or the code.",
28
+ sections: [
29
+ {
30
+ id: 'run-the-props-check',
31
+ title: 'Run the props check',
32
+ content: [
33
+ {
34
+ type: 'prose',
35
+ text: "`doctor integration components` compares every props table in your component docs, hidden docs and every family entry included, with the props the component's TypeScript declares. Run it in your package after you change a component or its doc.",
36
+ },
37
+ {
38
+ type: 'code',
39
+ lang: 'bash',
40
+ code: 'npx astryx doctor integration components',
41
+ },
42
+ {
43
+ type: 'code',
44
+ lang: 'text',
45
+ code: `severity: [warn]
46
+ component: AcmeCarousel
47
+ prop: loop
48
+ kind: not_in_code
49
+ message: "loop" is documented, but AcmeCarousel's props have no "loop".
50
+ doc: components/AcmeCarousel.doc.mjs
51
+ source: components/AcmeCarousel.tsx
52
+ docType: boolean
53
+
54
+ 1 prop(s) differ between the docs and the code in 1 of 1 component(s) compared (TypeScript 6.0.3). These are warnings: update the doc, or the code if the doc is right.`,
55
+ },
56
+ {
57
+ type: 'list',
58
+ style: 'unordered',
59
+ items: [
60
+ "A doc's own `props` describe the export its `name` names. In a family doc, each entry describes its own export. A hook entry documents parameters and returns, so it is not compared.",
61
+ "It reads props with the `typescript` your package installs, and reads your package's `tsconfig.json` the way `tsc -p` does. Without TypeScript it prints `[skip] Props not compared` and the reason.",
62
+ 'Every finding is a warning, so the exit code stays 0. Read them before you publish. With `--json`, they are in `data.propDrift.findings`.',
63
+ ],
64
+ },
65
+ ],
66
+ },
67
+ {
68
+ id: 'fix-each-finding',
69
+ title: 'Fix each finding',
70
+ content: [
71
+ {
72
+ type: 'prose',
73
+ text: "Each finding's `kind` says what differs. Fix the doc, or the code if the doc is right.",
74
+ },
75
+ {
76
+ type: 'table',
77
+ headers: ['Kind', 'Means', 'Fix'],
78
+ rows: [
79
+ [
80
+ '`not_in_code`',
81
+ "The doc lists a prop the component's props do not have",
82
+ 'Remove it from the doc, or add it to the code. A name an index signature takes, such as `data-*`, counts as present',
83
+ ],
84
+ [
85
+ '`not_in_doc`',
86
+ "Your package declares a prop the doc does not list, or builds one with a mapped type, such as `Partial<Record<'sm' | 'md', string>>`",
87
+ 'Document it. Props from React, the DOM, or another package are never asked for, and neither are props whose keys another package defines (`keyof CSSProperties`, behind an alias or not), `className`, `style`, `xstyle`, `data-testid`, `ref`, `key`, or a prop whose JSDoc has `@internal`. A deprecated prop is still a prop: document it until you remove it. A prop a mapped type builds from keys the check cannot trace (a template literal, say) is listed under `[info] Props not checked for a doc entry` instead',
88
+ ],
89
+ [
90
+ '`required_mismatch`',
91
+ '`required` disagrees with the code',
92
+ 'Set `required: true` exactly when every caller must pass the prop. One your `defaultProps` fills counts as optional, as it is to JSX callers, and so does one only some members of a union require, since a caller can leave it out: say in its description which variants need it. An entry that names several props (`value / onChange`) makes the same claim about each: give them separate entries when they differ',
93
+ ],
94
+ [
95
+ '`type_mismatch`',
96
+ "The documented `type` differs from the code's, where both read exactly",
97
+ 'Copy the type from the source, or fix the code. The next section says which types are judged',
98
+ ],
99
+ ],
100
+ },
101
+ ],
102
+ },
103
+ {
104
+ id: 'write-types-the-check-can-judge',
105
+ title: 'Write types the check can judge',
106
+ content: [
107
+ {
108
+ type: 'prose',
109
+ text: 'For a prop your package declares, the check also compares the documented `type`, but only where both sides read exactly. It never guesses, so a type it cannot judge is listed, not reported. It needs TypeScript 4.8 or later: with an older one it prints `[skip] Prop types not judged` and judges none.',
110
+ },
111
+ {
112
+ type: 'code',
113
+ lang: 'text',
114
+ code: `severity: [warn]
115
+ component: AcmeCarousel
116
+ prop: interval
117
+ kind: type_mismatch
118
+ message: "interval" is documented as string, but the code declares number.
119
+ doc: components/AcmeCarousel.doc.mjs
120
+ source: components/AcmeCarousel.tsx
121
+ docType: string
122
+ codeType: number`,
123
+ },
124
+ {
125
+ type: 'list',
126
+ style: 'unordered',
127
+ items: [
128
+ "Write the type as the source writes it, such as `ReactNode[]` or `(index: number) => void`. Parameter names, member order, quotes and whitespace may differ. Text that writes `readonly` must match exactly, parameter names included; only whitespace may differ. `React.X` names React's own `X` where the prop is declared, so it matches a bare `X` only where that name is React's: `React.KeyboardEvent` is not the DOM's `KeyboardEvent`.",
129
+ "Name a type as the file that declares the prop names it, so an import renamed there (`Item as BaseItem`) is written as that file writes it. A field (`cfg.level`) takes its prop's file, even when the field's own type is declared in another file.",
130
+ 'A type written another way is judged only when both sides are built from exact parts: primitives such as `string` and `number`, string, number and boolean literals, string enum members, arrays and unions of these, and type names that stand for them. Union members may come in any order, and a member another covers adds nothing, as TypeScript passes it there: `undefined` beside `void`, or `string[]` beside `(string | number)[]`.',
131
+ 'A mutable array type matches a readonly one, because callers can pass it. A readonly one documented for a mutable array is a mismatch.',
132
+ "When a prop's variants give a field different types, as `{value: string} | {value: number}` does, document every variant's type (`string | number`). The types of only some variants are listed: the prop's variants give this field different types. With more than six variant types, any other type is listed too.",
133
+ "To name an alias and show its values, write `AcmeSize = 'sm' | 'md'` or `AcmeSize ('sm' | 'md')`. Both parts must match.",
134
+ "An optional prop's `undefined` is set aside on both sides. With `exactOptionalPropertyTypes`, the doc shows `undefined` exactly when the code declares it.",
135
+ 'Anything else, such as an object, a tuple, a generic with arguments, `keyof`, an intersection, or a mapped or conditional type written another way, is not compared.',
136
+ ],
137
+ },
138
+ {
139
+ type: 'prose',
140
+ text: "The check prints how many documented types it judged, then lists the rest by reason: not a form the check judges exactly, a field the prop's variants give different types, a standard prop, or a prop declared outside the package. With `--json`, they are in `data.propDrift.typesNotCompared`.",
141
+ },
142
+ {
143
+ type: 'code',
144
+ lang: 'text',
145
+ code: '[info] Documented prop types judged: 2; not compared: 0. 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.',
146
+ },
147
+ ],
148
+ },
149
+ {
150
+ id: 'when-a-component-is-not-compared',
151
+ title: 'When a component is not compared',
152
+ content: [
153
+ {
154
+ type: 'prose',
155
+ text: "When the check cannot read a component's props exactly, it lists the component under `[info] Props not compared`, with the reason, instead of reporting findings that might be wrong.",
156
+ },
157
+ {
158
+ type: 'code',
159
+ lang: 'text',
160
+ code: `[info] Props not compared for 1 documented component(s):
161
+
162
+ component: AcmeCarousel
163
+ doc: components/AcmeCarousel.doc.mjs
164
+ reason: AcmeCarousel depends on \`@acme/motion\` (imported in AcmeCarousel.tsx), which the compiler could not resolve, usually a dependency that is not installed. Install the package's dependencies and run this check again`,
165
+ },
166
+ {
167
+ type: 'table',
168
+ headers: ['Reason', 'Fix'],
169
+ rows: [
170
+ [
171
+ 'It depends on a package or file the compiler could not resolve',
172
+ "Install the package's dependencies, then run the check again",
173
+ ],
174
+ [
175
+ "It depends on a type the compiler can't work out",
176
+ 'Make the types compile with `npx tsc --noEmit`, then run the check again',
177
+ ],
178
+ [
179
+ "The package's TypeScript config has an error",
180
+ 'Fix `tsconfig.json` until `npx tsc -p .` reads it',
181
+ ],
182
+ ['Its props are typed `any`', 'Give the component a props type'],
183
+ [
184
+ 'Some prop names come from a type parameter',
185
+ 'Nothing to fix: a component that renders an element the caller picks takes props known only where it is used',
186
+ ],
187
+ [
188
+ "The file has no export named by the doc's `name`",
189
+ 'Change `name` or the export so they agree',
190
+ ],
191
+ ],
192
+ },
193
+ ],
194
+ },
195
+ ],
196
+ };
@@ -2,8 +2,8 @@
2
2
 
3
3
  /**
4
4
  * @file `astryx docs cli/integrations/docs/check-your-docs`: what each check
5
- * proves about an integration's docs: the docs check, the read size, and the
6
- * CLI peer.
5
+ * proves about an integration's docs: the docs check, each doc's fields, the
6
+ * read size, and the CLI peer.
7
7
  */
8
8
 
9
9
  /** @type {import('@astryxdesign/cli/authoring').ReferenceDoc} */
@@ -13,7 +13,8 @@ export const docs = {
13
13
  placement: {parent: 'namespace:docs', slot: 'guides', order: 60},
14
14
  title: 'Check your docs',
15
15
  category: 'guide',
16
- description: 'Check the docs tree, links, overlaps, read size, and CLI peer.',
16
+ description:
17
+ 'Check the docs tree, links, overlaps, doc fields, read size, and CLI peer.',
17
18
  sections: [
18
19
  {
19
20
  id: 'run-the-docs-check',
@@ -80,6 +81,46 @@ export const docs = {
80
81
  },
81
82
  ],
82
83
  },
84
+ {
85
+ id: 'check-each-doc-against-its-type',
86
+ title: 'Check each doc against its type',
87
+ content: [
88
+ {
89
+ type: 'prose',
90
+ text: "`doctor integration validate` reads every doc your package ships against the type `@astryxdesign/cli/authoring` publishes for its kind, the way `tsc` would: a `hidden` doc and a second doc for one name too. Test fixtures under `__tests__` in the components or docs root, which those readers skip, are counted, not checked. It reports a field the type does not have (`unknown_field`), a missing required field (`missing_field`), and a value outside the field's type (`wrong_type`).",
91
+ },
92
+ {
93
+ type: 'code',
94
+ lang: 'bash',
95
+ code: 'npx astryx doctor integration validate',
96
+ },
97
+ {
98
+ type: 'code',
99
+ lang: 'text',
100
+ code: `Checking 1 doc(s) against the authoring types (TypeScript 6.0.3)
101
+
102
+ severity: [warn]
103
+ doc: components/AcmeCarousel.doc.mjs
104
+ line: 7
105
+ export: default
106
+ type: ComponentDoc
107
+ field: summary
108
+ problem: unknown_field
109
+ message: Object literal may only specify known properties, and 'summary' does not exist in type 'SingleComponentDoc'.
110
+ fix: Remove \`summary\`: SingleComponentDoc has no field \`summary\`.`,
111
+ },
112
+ {
113
+ type: 'list',
114
+ style: 'unordered',
115
+ items: [
116
+ "The folder decides the type: `ComponentDoc` in your components root, `IntegrationTemplateDoc` in your templates root, `ThemeDoc` in your themes root, and in your docs root the type the doc's `type` names. Keep the `@type` comment above each doc's export too, so your editor shows the same problems as you type.",
117
+ 'Every finding is a warning, so the exit code stays 0. With `--json`, they are in `data.docTypes.findings`.',
118
+ 'It uses the `typescript` your package installs. Without it, it prints `[skip] Docs not type-checked` and the reason.',
119
+ 'Every field of every doc type is in `astryx docs authoring`.',
120
+ ],
121
+ },
122
+ ],
123
+ },
83
124
  {
84
125
  id: 'check-read-size',
85
126
  title: 'Check read size',
@@ -12,7 +12,7 @@ export const docs = {
12
12
  placement: {parent: 'namespace:ship', slot: 'guides', order: 20},
13
13
  title: 'Check an integration',
14
14
  category: 'guide',
15
- keywords: ['check before publishing', 'validate an integration', 'ci'],
15
+ keywords: ['check before publishing', 'validate an integration'],
16
16
  description:
17
17
  'Pick the check for each problem, learn what fails and what only warns, and run every check in CI.',
18
18
  sections: [
@@ -22,7 +22,7 @@ export const docs = {
22
22
  content: [
23
23
  {
24
24
  type: 'prose',
25
- text: 'Run these in the package folder. The four `doctor integration` checks read your source; `integration verify` checks the package npm would publish.',
25
+ text: 'Run these in the package folder. The four `doctor integration` checks read your source, and `integration check` runs all four; `integration verify` checks the package npm would publish.',
26
26
  },
27
27
  {
28
28
  type: 'table',
@@ -30,15 +30,15 @@ export const docs = {
30
30
  rows: [
31
31
  [
32
32
  '`npx astryx doctor integration validate`',
33
- 'The manifest loads, and each root holds contributions the CLI can read',
33
+ 'The manifest loads, each root holds contributions the CLI can read, and each doc matches its authoring type',
34
34
  'A declared root is missing (`missing_root`), a contribution does not load (`invalid_doc`, `invalid_component`, `invalid_theme`), or two templates in the package replace one Core id (`ambiguous_template_replacement`)',
35
- 'The manifest has a key this CLI does not know (`unknown_manifest_key`). With no `astryx.integration.mjs` it prints a hint and exits 0',
35
+ "The manifest has a key this CLI does not know (`unknown_manifest_key`), or a doc field does not match the doc's authoring type: a field the type does not have, a missing required field, or a value outside the field's type. It checks docs with your installed `typescript`; without it, it prints `[skip] Docs not type-checked`. With no `astryx.integration.mjs` it prints a hint and exits 0",
36
36
  ],
37
37
  [
38
38
  '`npx astryx doctor integration components`',
39
- 'No component name clashes with a Core component, and each `replaces` names one Core component',
39
+ "No component name clashes with a Core component, each `replaces` names one Core component, and each component doc's props match the component's TypeScript props",
40
40
  'Core is not installed (`core_not_found`). In a package that declares the CLI range that turns replacement on, a `replaces` target is missing (`missing_component_replacement_target`) or invalid (`invalid_component_replacement`), or two components replace one Core component (`ambiguous_component_replacement`)',
41
- 'A name clashes with Core, or a component sets `replaces` in a package without that range (`inactive_component_replacement`, plus any missing, invalid, or duplicate `replaces` reported as a warning)',
41
+ 'A name clashes with Core, a component sets `replaces` in a package without that range (`inactive_component_replacement`, plus any missing, invalid, or duplicate `replaces` reported as a warning), or a documented prop differs from the code: it is missing there (`not_in_code`), the doc omits a prop the package declares (`not_in_doc`), or its `required` (`required_mismatch`) or type (`type_mismatch`) disagrees. It reads props with your installed `typescript`; without it, it prints `[skip] Props not compared`',
42
42
  ],
43
43
  [
44
44
  '`npx astryx doctor integration templates`',
@@ -52,6 +52,12 @@ export const docs = {
52
52
  'A topic takes a Core topic name without `replaces` or `extends`, a doc is invalid (`invalid_doc`), or a namespace or placement fails, which hides the doc (`invalid_doc_graph`)',
53
53
  'A link names no doc (`invalid_doc_graph`)',
54
54
  ],
55
+ [
56
+ '`npx astryx integration check`',
57
+ 'Everything the four `doctor integration` checks prove, in one command, for your build',
58
+ 'Any of the four would exit 1 on its own. With `--strict`, also any warning, and any check that did not run, such as a package with no `astryx.integration.*`',
59
+ 'Anything the four warn about, unless you pass `--strict`',
60
+ ],
55
61
  [
56
62
  '`npx astryx integration verify`',
57
63
  'The packed package holds every file, shows the same contributions, resolves every public import, and declares the CLI it needs',
@@ -62,7 +68,7 @@ export const docs = {
62
68
  },
63
69
  {
64
70
  type: 'prose',
65
- text: 'Pass a package name, such as `npx astryx doctor integration validate @acme/astryx-widgets`, to check an installed copy from an app instead.',
71
+ text: 'Pass a package name, such as `npx astryx doctor integration validate @acme/astryx-widgets`, to check an installed copy from an app instead. To fix a props finding, see {@link generic:check-the-props}.',
66
72
  },
67
73
  ],
68
74
  },
@@ -72,19 +78,21 @@ export const docs = {
72
78
  content: [
73
79
  {
74
80
  type: 'prose',
75
- text: 'Chain the five checks so the first failure stops the run. Install devDependencies first, because the components check needs Core.',
81
+ text: "Run `integration check --strict` in your package's own build, so every build keeps your docs, types, and links in sync, and run `integration verify` before you publish. Install devDependencies first, because the components check needs Core, and `tsc --noEmit` needs `typescript` and a `tsconfig.json`. In package.json:",
76
82
  },
77
83
  {
78
84
  type: 'code',
79
- lang: 'bash',
80
- code: 'npx astryx doctor integration validate && npx astryx doctor integration components && npx astryx doctor integration templates && npx astryx doctor integration docs && npx astryx integration verify',
85
+ lang: 'json',
86
+ code: '"typecheck": "tsc --noEmit && astryx integration check --strict"',
81
87
  },
82
88
  {
83
89
  type: 'list',
84
90
  style: 'unordered',
85
91
  items: [
86
- '`integration verify` runs `validate` but none of the other three: a Core name clash, a `replaces` that names no Core template, a topic that takes a Core name, or a hidden guide still passes it.',
87
- 'Warnings keep exit code 0, so read them before you publish.',
92
+ '`integration check` runs `validate`, `components`, `templates`, and `docs` in that order, prints each result, then a summary, and exits 1 when any of them would.',
93
+ '`--strict` also exits 1 on any warning and on any check that did not run. Without it, warnings keep exit code 0: use that while you fix the warnings a package already has.',
94
+ 'Its exit codes and JSON are a contract for your build: a new check, or a new failure code, joins only in a minor release that names it in the release notes. A patch can still ship a Core component, template, or CLI topic whose name conflicts with one of yours.',
95
+ '`integration verify` runs `validate` but none of the other three: a Core name clash, a `replaces` that names no Core template, a topic that takes a Core name, or a hidden guide still passes it. Run both before you publish: `npx astryx integration check --strict && npx astryx integration verify`.',
88
96
  'Bare `npx astryx doctor` in the package also warns about a doc section over 32 KB, which no check above measures.',
89
97
  ],
90
98
  },
@@ -105,7 +113,7 @@ export const docs = {
105
113
  'It runs `npm pack` the way `npm publish` would, including your `prepack` script.',
106
114
  'It checks that every contribution file is in the `.tgz` file. A root missing from `files` fails with `Add "templates" to "files" in package.json.`',
107
115
  'It lists the components, templates, themes, docs, and codemods the temporary app sees, and compares them with your source.',
108
- "It resolves each component's `import`, and each template's public import, the way Node does, and checks that the module exports the component, or a default export for a template.",
116
+ "It resolves each component's `import`, and each template's public import, the way Node does, and checks that the module exports the component under the name its doc documents, or a default export for a template. A type-only export does not count.",
109
117
  'For each theme, it rebuilds the source, compares the built module and production CSS with the authored outputs, and proves the module, CSS, and optional font CSS exports resolve from the packed package.',
110
118
  'It fails a package that needs an `@astryxdesign/cli` peer and lacks it: `>=0.6.6` for a template that sets `keywords`, and `>=0.6.4` for a template that sets `replaces`, a docs section, a placed guide, a doc section with an `id`, or a theme.',
111
119
  ],
@@ -95,7 +95,11 @@ export default {
95
95
  },
96
96
  {
97
97
  type: 'prose',
98
- text: 'The public module named by `import` must export every component or hook named by a full entry.',
98
+ text: "The public module named by `import` must export every component or hook named by a full entry. Apps then list, search and open each component in the family by its own name. A full entry the module does not export is not listed, and `integration verify` does not report it: check the family with `astryx component --list`. When `import` names output your pack lifecycle builds (such as `dist`), the members are listed once that output exists, and `integration verify` compares them as they are listed after the pack builds it.",
99
+ },
100
+ {
101
+ type: 'prose',
102
+ text: "A member's source is the `.tsx` file in the family doc's folder, or below it, that declares it: the one the family's own file or the module `import` names reaches, else the one in that folder that declares the name, as when `import` names built output. A member that only a bundle or a file outside that folder declares is still listed, with no source for `--source` or `swizzle`. A member is not listed when a doc's file or a Core name your package replaces already has its name. A member that shares a name with Core opens with `--package`.",
99
103
  },
100
104
  ],
101
105
  },
@@ -35,6 +35,14 @@ export const docs = {
35
35
  type: 'prose',
36
36
  text: 'Add writes the entry only when package.json already has an `exports` map, so start every package with `"exports": {}`.',
37
37
  },
38
+ {
39
+ type: 'prose',
40
+ text: 'A file does not have to be named after its component. When `Slides.tsx` exports `AcmeCarousel` and nothing named `Slides`, keep the doc beside it as `Slides.doc.mjs` and set its `name` to `AcmeCarousel`: apps list, search and open the component by that name, and `integration verify` checks that its import exports `AcmeCarousel`. A file that exports its own name keeps that name. A package that names its files in kebab case works the same way: `acme-gallery.doc.mjs` beside `acme-gallery.tsx` sets `name: \'AcmeGallery\'`.',
41
+ },
42
+ {
43
+ type: 'prose',
44
+ text: "The file name still opens the doc. A name that Core or another doc's file already has stays theirs, and so does a Core name your package replaces: with `Badge.doc.mjs` naming `AcmeBadge`, `astryx component Badge` opens Core's `Badge`, and `--package` with your package name reaches yours.",
45
+ },
38
46
  ],
39
47
  },
40
48
  {
@@ -37,7 +37,7 @@ export const docs = {
37
37
  items: [
38
38
  'Change the source and its `.doc.mjs` together.',
39
39
  'Update the doc whenever the public name, import, behavior, props, defaults, examples, or accessibility requirements change.',
40
- '`integration verify` checks the doc shape and packed import, but it cannot prove the prose still matches the component.',
40
+ '`integration verify` checks the doc shape and packed import, and `doctor integration components` compares each props table with the component\'s TypeScript props ({@link generic:check-the-props}). Neither can prove the prose still matches the component.',
41
41
  ],
42
42
  },
43
43
  {
@@ -36,8 +36,8 @@ export const docs = {
36
36
  type: 'list',
37
37
  style: 'unordered',
38
38
  items: [
39
- 'The kind is `generic` for a topic or guide, `namespace` for a docs section, and `command` or `function` for a CLI command or API function.',
40
- 'A link to a component or a template does not resolve. Write its name in backticks instead, such as `AcmeCarousel`.',
39
+ 'The kind is `generic` for a topic or guide, `namespace` for a docs section, `command` or `function` for a CLI command or API function, `component` for a component, and `page` or `block` for a template.',
40
+ 'Name a component by its export name and a template by its id. Its link reads as the command that opens it, such as `astryx component AcmeCarousel --package @acme/widgets`.',
41
41
  'Inside backticks or a code block, link syntax prints as written.',
42
42
  ],
43
43
  },
@@ -31,7 +31,7 @@ export const docs = {
31
31
  type: 'code',
32
32
  lang: 'javascript',
33
33
  label: 'templates/acme-dashboard.doc.mjs',
34
- code: `/** @type {import('@astryxdesign/cli/authoring').TemplateDoc} */
34
+ code: `/** @type {import('@astryxdesign/cli/authoring').IntegrationTemplateDoc} */
35
35
  export default {
36
36
  type: 'page',
37
37
  name: 'acme-dashboard',
@@ -184,7 +184,7 @@ export const docs = {
184
184
  },
185
185
  {
186
186
  type: 'prose',
187
- text: 'Peer ranges and releases are covered in {@link generic:versioning}; `files` and publishing in {@link generic:publishing}.',
187
+ text: 'Peer ranges and releases are covered in {@link generic:versioning}; `files` and publishing in {@link generic:publishing}. Add `"typecheck": "tsc --noEmit && astryx integration check --strict"` to `scripts` so each run checks your types and that your docs, props, and links still match the code. It needs `typescript` and a `tsconfig.json`; see {@link generic:checks}.',
188
188
  },
189
189
  ],
190
190
  },
@@ -54,7 +54,7 @@ export const docs = {
54
54
  type: 'code',
55
55
  lang: 'javascript',
56
56
  label: 'templates/acme-app-shell.doc.mjs',
57
- code: `/** @type {import('@astryxdesign/cli/authoring').TemplateDoc} */
57
+ code: `/** @type {import('@astryxdesign/cli/authoring').IntegrationTemplateDoc} */
58
58
  export default {
59
59
  type: 'page',
60
60
  name: 'acme-app-shell',
@@ -56,7 +56,7 @@ export default {
56
56
  style: 'unordered',
57
57
  items: [
58
58
  'Keep `props` on the top-level doc. Private implementation helpers do not need entries.',
59
- 'Keep the doc beside the source and change both in the same pull request.',
59
+ 'Name the doc after the source file beside it, such as `AcmeCarousel.doc.mjs` beside `AcmeCarousel.tsx`, and change both in the same pull request.',
60
60
  'If the module later exposes several related public exports, adapt this doc with {@link generic:component-family}.',
61
61
  ],
62
62
  },
@@ -122,6 +122,7 @@ export default {
122
122
  'Set `required: true` only when every caller must pass the prop.',
123
123
  'Write `default` exactly as the value should appear in documentation.',
124
124
  'Skip styling escape hatches such as `xstyle`, `className`, and `style`.',
125
+ '`npx astryx doctor integration components` lists a documented prop the code lacks, a public prop the doc misses, and a wrong `required`. See {@link generic:check-the-props}.',
125
126
  ],
126
127
  },
127
128
  ],
@@ -157,7 +158,7 @@ export default {
157
158
  {
158
159
  type: 'code',
159
160
  lang: 'bash',
160
- code: 'npx astryx component AcmeCarousel\nnpx astryx integration verify',
161
+ code: 'npx astryx component AcmeCarousel\nnpx astryx doctor integration components\nnpx astryx integration verify',
161
162
  },
162
163
  ],
163
164
  },
@@ -67,7 +67,7 @@ export const docs = {
67
67
  rows: [
68
68
  [
69
69
  '`component_export_missing`: `Component "AcmeCarousel" advertises import "@acme/astryx-widgets/components/AcmeCarousel", but that packed module does not export "AcmeCarousel".`',
70
- "package.json has no `exports` map, or the module does not export the name. Keep `export function AcmeCarousel`, and add the entry: `npm pkg set 'exports[./components/AcmeCarousel]=./components/AcmeCarousel.tsx'`.",
70
+ "package.json has no `exports` map, or the module does not export the name. Keep `export function AcmeCarousel`, and add the entry: `npm pkg set 'exports[./components/AcmeCarousel]=./components/AcmeCarousel.tsx'`. When the quoted name is a file name, such as `acme-carousel`, set the doc's `name` to the component the file exports. A type-only export does not count.",
71
71
  ],
72
72
  [
73
73
  '`template_export_missing`: `Template "acme-dashboard" public import "@acme/astryx-widgets/templates/acme-dashboard" does not have a default export.`',
@@ -125,6 +125,14 @@ export const docs = {
125
125
  type: 'table',
126
126
  headers: ['Symptom', 'Fix'],
127
127
  rows: [
128
+ [
129
+ '`Error: No component named "AcmeCarousel"` for a component your package documents.',
130
+ "Its doc still names its file. Set `name` to the export, such as `name: 'AcmeCarousel'` in `acme-carousel.doc.mjs`. A family member is listed only when the module its family doc imports exports it ({@link generic:component-family}).",
131
+ ],
132
+ [
133
+ '`npx astryx component Dialog` opens Core\'s `Dialog`, not yours.',
134
+ "A name that Core, a legacy docs package, or another package's file already has stays theirs. Run `npx astryx component Dialog --package @acme/astryx-widgets`, or give your component a name of its own.",
135
+ ],
128
136
  [
129
137
  '`Error: Template "dashboard" is ambiguous — narrow it with --type and/or --package.`',
130
138
  "Your template id matches a Core id. Rename it, such as `acme-dashboard`, or set `replaces: 'dashboard'` to take its place. `npx astryx doctor integration templates` warns about this before you publish.",
@@ -76,7 +76,7 @@ export const docs = {
76
76
  type: 'code',
77
77
  lang: 'tsx',
78
78
  label: 'Heading for document structure',
79
- code: `import {Heading} from '@astryxdesign/core';
79
+ code: `import {Heading} from '@astryxdesign/core/Heading';
80
80
 
81
81
  // Heading levels map to semantic tokens: level 1 → --text-heading-1-*
82
82
  <Heading level={1}>Page Title</Heading>
@@ -96,7 +96,7 @@ export const docs = {
96
96
  type: 'code',
97
97
  lang: 'tsx',
98
98
  label: 'Text for body, label, and display text',
99
- code: `import {Text} from '@astryxdesign/core';
99
+ code: `import {Text} from '@astryxdesign/core/Text';
100
100
 
101
101
  <Text type="body">Body text at the base scale.</Text>
102
102
  <Text type="large">Emphasized body text.</Text>
@@ -121,7 +121,7 @@ export const docs = {
121
121
  type: 'code',
122
122
  lang: 'tsx',
123
123
  label: 'Customizing the type scale via defineTheme',
124
- code: `import {defineTheme} from '@astryxdesign/core';
124
+ code: `import {defineTheme} from '@astryxdesign/core/theme';
125
125
 
126
126
  // Adjust the entire ramp holistically with base and ratio
127
127
  const editorialTheme = defineTheme({
@@ -140,6 +140,7 @@ export const docs = {
140
140
  'Published 0.6.3 and earlier reject a template that sets `replaces` or `keywords`, drop that template, and hide every doc topic your package ships. Published 0.6.4 and 0.6.5 still drop a template that sets `keywords`.',
141
141
  'A stable CLI before 0.6.4 cannot read a docs section, a section `id`, or a theme folder that `integration add theme` writes. It can then hide every doc topic your package ships.',
142
142
  'Stable 0.6.3 still loads your components, but 0.6.0 cannot read the component docs that `integration add component` writes: `component AcmeCarousel` fails there.',
143
+ 'An app on an older CLI lists a component whose doc names another export of its file under the file name, and lists no family members, so `component AcmeCarousel` fails there.',
143
144
  ],
144
145
  },
145
146
  {