@astryxdesign/cli 0.7.2 → 0.7.3-canary.0bf23bd

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 (337) hide show
  1. package/README.md +104 -71
  2. package/api/build/_adapter.d.mts +58 -0
  3. package/api/build/_adapter.mjs +115 -3
  4. package/api/build/blocks/blocks.d.mts +42 -0
  5. package/api/build/blocks/blocks.mjs +169 -0
  6. package/api/build/blocks/blocks.test.mjs +108 -0
  7. package/api/build/blocks/blocks.weights.json +1 -0
  8. package/api/build/build.mjs +25 -6
  9. package/api/build/kit/answer.d.mts +14 -0
  10. package/api/build/kit/answer.mjs +85 -0
  11. package/api/build/kit/answer.test.mjs +38 -0
  12. package/api/build/kit/kind.d.mts +25 -0
  13. package/api/build/kit/kind.mjs +170 -0
  14. package/api/build/kit/kit.d.mts +2 -4
  15. package/api/build/kit/kit.mjs +8 -398
  16. package/api/build/kit/rank.d.mts +3 -32
  17. package/api/build/kit/rank.mjs +25 -342
  18. package/api/build/kit/rank.test.mjs +2 -1
  19. package/api/build/kit/signals.d.mts +60 -0
  20. package/api/build/kit/signals.mjs +284 -0
  21. package/api/build/kit/start.d.mts +32 -0
  22. package/api/build/kit/start.mjs +163 -0
  23. package/api/build/kit/words.d.mts +72 -0
  24. package/api/build/kit/words.mjs +202 -0
  25. package/api/build/tree.d.mts +20 -0
  26. package/api/build/tree.mjs +52 -0
  27. package/api/build/tree.test.mjs +177 -0
  28. package/api/build/tree.weights.json +1 -0
  29. package/api/component/component.mjs +17 -3
  30. package/api/component/component.test.mjs +15 -0
  31. package/api/component/doc-links.test.mjs +2 -2
  32. package/api/discover/_adapter.mjs +36 -9
  33. package/api/discover/_adapter.test.mjs +42 -0
  34. package/api/docs/_adapter.d.mts +2 -2
  35. package/api/docs/_adapter.mjs +78 -23
  36. package/api/docs/docs-homes.test.mjs +127 -0
  37. package/api/docs/docs.doc.mjs +3 -3
  38. package/api/docs/docs.test.mjs +35 -19
  39. package/api/docs/integration-tree.test.mjs +20 -20
  40. package/api/docs/integrationDocs.test.mjs +1 -1
  41. package/api/docs/namespace-section.test.mjs +6 -6
  42. package/api/docs/reference-blocks.test.mjs +2 -2
  43. package/api/doctor/doctor.mjs +102 -24
  44. package/api/doctor/doctor.test.mjs +37 -12
  45. package/api/hook/hook.mjs +1 -1
  46. package/api/init/init.doc.mjs +20 -6
  47. package/api/init/init.test.mjs +18 -2
  48. package/api/init/init.type.d.mts +3 -3
  49. package/api/init/init.type.mjs +3 -3
  50. package/api/init/remove/remove.mjs +17 -4
  51. package/api/init/remove/remove.test.mjs +114 -2
  52. package/api/init/run/run.mjs +69 -6
  53. package/api/integration/_adapter.d.mts +8 -0
  54. package/api/integration/_adapter.mjs +21 -1
  55. package/api/integration/authoring-checks.mjs +83 -9
  56. package/api/integration/authoring-checks.test.mjs +220 -0
  57. package/api/integration/pack-check.mjs +123 -4
  58. package/api/integration/pack-check.test.mjs +87 -0
  59. package/api/integration/validate-integration-case-disk.test.mjs +111 -0
  60. package/api/integration/validate-integration-gaps.test.mjs +1964 -0
  61. package/api/integration/validate-integration.d.mts +11 -2
  62. package/api/integration/validate-integration.mjs +250 -32
  63. package/api/integration/validate-integration.type.d.mts +59 -1
  64. package/api/integration/validate-integration.type.mjs +46 -2
  65. package/api/integration/validateIntegration.doc.mjs +1 -1
  66. package/api/search/ORDERING.md +28 -0
  67. package/api/search/_adapter.d.mts +82 -2
  68. package/api/search/_adapter.mjs +157 -10
  69. package/api/search/_adapter.test.mjs +173 -0
  70. package/api/search/_candidate-score.d.mts +40 -0
  71. package/api/search/_candidate-score.mjs +238 -0
  72. package/api/search/_cards.json +6098 -0
  73. package/api/search/_compound.d.mts +50 -0
  74. package/api/search/_compound.mjs +170 -0
  75. package/api/search/_doc-searcher.d.mts +4 -0
  76. package/api/search/_doc-searcher.mjs +23 -0
  77. package/api/search/_doc-searcher.test.mjs +36 -0
  78. package/api/search/_doc-searcher.weights.json +1 -0
  79. package/api/search/_doc-text.d.mts +30 -0
  80. package/api/search/_doc-text.mjs +87 -0
  81. package/api/search/_entries.d.mts +52 -0
  82. package/api/search/_entries.mjs +214 -0
  83. package/api/search/_features.d.mts +35 -0
  84. package/api/search/_features.mjs +155 -0
  85. package/api/search/_gather-components.d.mts +26 -0
  86. package/api/search/_gather-components.mjs +284 -0
  87. package/api/search/_gather-docs.d.mts +20 -0
  88. package/api/search/_gather-docs.mjs +254 -0
  89. package/api/search/_gather-hooks.d.mts +12 -0
  90. package/api/search/_gather-hooks.mjs +52 -0
  91. package/api/search/_gather-templates.d.mts +25 -0
  92. package/api/search/_gather-templates.mjs +107 -0
  93. package/api/search/_lexical.d.mts +135 -0
  94. package/api/search/_lexical.mjs +351 -0
  95. package/api/search/_main-searcher.d.mts +19 -0
  96. package/api/search/_main-searcher.mjs +115 -0
  97. package/api/search/_main-searcher.test.mjs +106 -0
  98. package/api/search/_main-searcher.weights.json +1 -0
  99. package/api/search/_module-doc.d.mts +32 -0
  100. package/api/search/_module-doc.mjs +78 -0
  101. package/api/search/_order.d.mts +32 -0
  102. package/api/search/_order.mjs +162 -0
  103. package/api/search/_order.test.mjs +72 -0
  104. package/api/search/_priority.d.mts +50 -0
  105. package/api/search/_priority.mjs +139 -0
  106. package/api/search/_query-words.d.mts +25 -0
  107. package/api/search/_query-words.mjs +92 -0
  108. package/api/search/_query.d.mts +65 -0
  109. package/api/search/_query.mjs +176 -0
  110. package/api/search/_result.d.mts +97 -0
  111. package/api/search/_result.mjs +150 -0
  112. package/api/search/_score.d.mts +60 -0
  113. package/api/search/_score.mjs +283 -0
  114. package/api/search/_synonyms.d.mts +21 -0
  115. package/api/search/_synonyms.mjs +67 -0
  116. package/api/search/_template-searcher.d.mts +4 -0
  117. package/api/search/_template-searcher.mjs +23 -0
  118. package/api/search/_template-searcher.test.mjs +40 -0
  119. package/api/search/_template-searcher.weights.json +1 -0
  120. package/api/search/_titles.d.mts +33 -0
  121. package/api/search/_titles.mjs +65 -0
  122. package/api/search/_words.d.mts +64 -0
  123. package/api/search/_words.mjs +157 -0
  124. package/api/search/search.d.mts +22 -305
  125. package/api/search/search.doc.mjs +8 -6
  126. package/api/search/search.mjs +56 -2482
  127. package/api/search/search.test.mjs +14 -14
  128. package/api/search/search.type.d.mts +6 -1
  129. package/api/search/search.type.mjs +6 -1
  130. package/api/search/tree.d.mts +15 -0
  131. package/api/search/tree.mjs +40 -0
  132. package/api/search/tree.test.mjs +66 -0
  133. package/api/search/tree.weights.json +1 -0
  134. package/api/theme/build/build.packed-old-core.test.mjs +1 -0
  135. package/api/upgrade/_adapter.d.mts +57 -9
  136. package/api/upgrade/_adapter.mjs +198 -28
  137. package/api/upgrade/registry/registry.d.mts +10 -4
  138. package/api/upgrade/registry/registry.mjs +33 -16
  139. package/api/upgrade/registry/registry.test.mjs +85 -0
  140. package/api/upgrade/run/run.d.mts +4 -2
  141. package/api/upgrade/run/run.mjs +13 -2
  142. package/api/upgrade/run/run.test.mjs +417 -3
  143. package/api/upgrade/upgrade.doc.mjs +10 -5
  144. package/api/upgrade/upgrade.mjs +13 -2
  145. package/api/upgrade/upgrade.test.mjs +194 -0
  146. package/api/upgrade/upgrade.type.d.mts +5 -3
  147. package/api/upgrade/upgrade.type.mjs +8 -6
  148. package/assets/codemods/transforms/v0.7.0/__tests__/validate-data-token-ownership.test.mjs +11 -0
  149. package/assets/codemods/transforms/v0.7.0/validate-data-token-ownership.mjs +3 -3
  150. package/assets/docs/author-a-theme.doc.mjs +2 -2
  151. package/assets/docs/is-my-code-good.doc.mjs +287 -0
  152. package/assets/docs/tree/add-a-component.doc.mjs +1 -1
  153. package/assets/docs/tree/add-a-theme.doc.mjs +1 -1
  154. package/assets/docs/tree/add-a-topic.doc.mjs +2 -2
  155. package/assets/docs/tree/agent-guidance.doc.mjs +1 -1
  156. package/assets/docs/tree/api.doc.mjs +6 -0
  157. package/assets/docs/tree/{integrations.doc.mjs → authoring.doc.mjs} +15 -6
  158. package/assets/docs/tree/block-template.doc.mjs +1 -1
  159. package/assets/docs/tree/build-the-template.doc.mjs +1 -1
  160. package/assets/docs/tree/building-blocks.doc.mjs +2 -2
  161. package/assets/docs/tree/check-the-props.doc.mjs +1 -1
  162. package/assets/docs/tree/check-your-docs.doc.mjs +2 -2
  163. package/assets/docs/tree/checks.doc.mjs +2 -2
  164. package/assets/docs/tree/cli-command.doc.mjs +1 -1
  165. package/assets/docs/tree/cli.doc.mjs +1 -1
  166. package/assets/docs/tree/codemods.doc.mjs +1 -1
  167. package/assets/docs/tree/component-family.doc.mjs +1 -1
  168. package/assets/docs/tree/component-imports.doc.mjs +1 -1
  169. package/assets/docs/tree/components.doc.mjs +1 -1
  170. package/assets/docs/tree/configuration.doc.mjs +1 -1
  171. package/assets/docs/tree/debug-and-gap-reports.doc.mjs +1 -1
  172. package/assets/docs/tree/define-the-theme.doc.mjs +1 -1
  173. package/assets/docs/tree/describe-the-component.doc.mjs +1 -1
  174. package/assets/docs/tree/docs.doc.mjs +1 -1
  175. package/assets/docs/tree/document-the-template.doc.mjs +1 -1
  176. package/assets/docs/tree/document-the-theme.doc.mjs +1 -1
  177. package/assets/docs/tree/export-template-assets.doc.mjs +1 -1
  178. package/assets/docs/tree/extend-or-replace.doc.mjs +1 -1
  179. package/assets/docs/{authoring.doc.mjs → tree/field-reference.doc.mjs} +4 -3
  180. package/assets/docs/tree/fonts-and-assets.doc.mjs +1 -1
  181. package/assets/docs/tree/generate-a-palette.doc.mjs +1 -1
  182. package/assets/docs/tree/global-integrations.doc.mjs +2 -2
  183. package/assets/docs/tree/grade-template-with-agent.doc.mjs +4 -4
  184. package/assets/docs/tree/help.doc.mjs +2 -2
  185. package/assets/docs/tree/host-entry.doc.mjs +128 -0
  186. package/assets/docs/tree/links.doc.mjs +1 -1
  187. package/assets/docs/tree/package-and-test.doc.mjs +1 -1
  188. package/assets/docs/tree/page-template.doc.mjs +1 -1
  189. package/assets/docs/tree/publishing.doc.mjs +1 -1
  190. package/assets/docs/tree/quick-start.doc.mjs +1 -1
  191. package/assets/docs/tree/replace-a-core-component.doc.mjs +1 -1
  192. package/assets/docs/tree/replace-a-core-template.doc.mjs +1 -1
  193. package/assets/docs/tree/sections-and-placement.doc.mjs +1 -1
  194. package/assets/docs/tree/see-it-in-an-app.doc.mjs +1 -1
  195. package/assets/docs/tree/ship.doc.mjs +2 -2
  196. package/assets/docs/tree/short-and-findable.doc.mjs +1 -1
  197. package/assets/docs/tree/single-component.doc.mjs +1 -1
  198. package/assets/docs/tree/start-a-template.doc.mjs +1 -1
  199. package/assets/docs/tree/subcomponent.doc.mjs +1 -1
  200. package/assets/docs/tree/template-assets.doc.mjs +1 -1
  201. package/assets/docs/tree/template-doc-overview.doc.mjs +2 -2
  202. package/assets/docs/tree/template-fonts.doc.mjs +1 -1
  203. package/assets/docs/tree/template-grading-rubric.doc.mjs +17 -38
  204. package/assets/docs/tree/template-icons.doc.mjs +1 -1
  205. package/assets/docs/tree/template-images-media.doc.mjs +1 -1
  206. package/assets/docs/tree/template-styles.doc.mjs +1 -1
  207. package/assets/docs/tree/templates.doc.mjs +1 -1
  208. package/assets/docs/tree/test-in-an-app.doc.mjs +1 -1
  209. package/assets/docs/tree/test-template-in-app.doc.mjs +1 -1
  210. package/assets/docs/tree/themes.doc.mjs +1 -1
  211. package/assets/docs/tree/tokens-data.doc.mjs +2 -2
  212. package/assets/docs/tree/troubleshooting.doc.mjs +1 -1
  213. package/assets/docs/tree/upgrading.doc.mjs +1 -1
  214. package/assets/docs/tree/use-a-theme-in-an-app.doc.mjs +1 -1
  215. package/assets/docs/tree/verify-packed-template.doc.mjs +1 -1
  216. package/assets/docs/tree/versioning.doc.mjs +1 -1
  217. package/assets/docs/tree/write-good-templates.doc.mjs +1 -1
  218. package/assets/docs/tree/write-the-template-file.doc.mjs +1 -1
  219. package/assets/docs/use-integrations.doc.mjs +120 -0
  220. package/assets/docs/working-with-ai.doc.mjs +6 -2
  221. package/assets/templates/themes/butter/butterTheme.ts +4 -2
  222. package/assets/templates/themes/stone/stoneTheme.ts +4 -2
  223. package/assets/templates/themes/y2k/y2kTheme.ts +4 -2
  224. package/authoring/debug/parse.d.mts +1 -1
  225. package/authoring/doctypes/schema/schema.doc.mjs +1 -1
  226. package/authoring/integration/integration.doc.mjs +1 -1
  227. package/authoring/integration/type.ts +1 -1
  228. package/clients/cli/bin/astryx.mjs +7 -78
  229. package/clients/cli/command-result-coverage.test.mjs +6 -5
  230. package/clients/cli/commands/build-theme.color-scheme.test.mjs +1 -1
  231. package/clients/cli/commands/{component/index.mjs → component.mjs} +37 -37
  232. package/clients/cli/commands/component.test.mjs +6 -6
  233. package/clients/cli/commands/docs.doc.mjs +2 -2
  234. package/clients/cli/commands/docs.mjs +1 -1
  235. package/clients/cli/commands/docs.test.mjs +14 -14
  236. package/clients/cli/commands/doctor.mjs +30 -0
  237. package/clients/cli/commands/doctor.test.mjs +65 -0
  238. package/clients/cli/commands/{hook/index.mjs → hook.mjs} +22 -22
  239. package/clients/cli/commands/import-hint-correctness.test.mjs +1 -1
  240. package/clients/cli/commands/init.behavior.test.mjs +230 -1
  241. package/clients/cli/commands/init.doc.mjs +28 -9
  242. package/clients/cli/commands/init.flag-help.test.mjs +1 -0
  243. package/clients/cli/commands/init.mjs +2 -2
  244. package/clients/cli/commands/integration-check.test.mjs +48 -0
  245. package/clients/cli/commands/integration.doc.mjs +1 -1
  246. package/clients/cli/commands/manifest.doc.mjs +1 -1
  247. package/clients/cli/commands/manifest.mjs +67 -0
  248. package/clients/cli/commands/outside-project.test.mjs +2 -1
  249. package/clients/cli/commands/postinstall.doc.mjs +23 -0
  250. package/clients/cli/commands/postinstall.mjs +31 -0
  251. package/clients/cli/commands/setup-nudge.test.mjs +61 -0
  252. package/clients/cli/commands/{build-theme.mjs → theme.mjs} +1 -1
  253. package/clients/cli/commands/upgrade.doc.mjs +4 -2
  254. package/clients/cli/commands/upgrade.mjs +9 -2
  255. package/clients/cli/commands/upgrade.subfolder-path.test.mjs +97 -0
  256. package/clients/cli/index.mjs +29 -86
  257. package/clients/cli/lib/component-format.mjs +1 -1
  258. package/clients/cli/lib/define-command.mjs +12 -7
  259. package/clients/cli/lib/exit-codes.test.mjs +5 -0
  260. package/clients/cli/lib/manifest.test.mjs +12 -0
  261. package/clients/cli/lib/welcome-box.mjs +50 -0
  262. package/clients/cli/run.mjs +108 -0
  263. package/foundation/agent-docs/agent-doc-state.d.mts +20 -7
  264. package/foundation/agent-docs/agent-doc-state.mjs +35 -8
  265. package/foundation/agent-docs/agent-docs.d.mts +100 -12
  266. package/foundation/agent-docs/agent-docs.mjs +1012 -100
  267. package/foundation/agent-docs/agent-docs.path-safety.test.mjs +1239 -17
  268. package/foundation/agent-docs/agent-docs.test.mjs +683 -39
  269. package/foundation/config/project.mjs +20 -22
  270. package/foundation/config/project.test.mjs +56 -0
  271. package/foundation/discovery/authoring-self-docs.d.mts +7 -0
  272. package/foundation/discovery/authoring-self-docs.mjs +16 -4
  273. package/foundation/discovery/authoring-self-docs.test.mjs +15 -3
  274. package/foundation/discovery/authoring-surface.d.mts +1 -1
  275. package/foundation/discovery/authoring-surface.mjs +2 -2
  276. package/foundation/discovery/authoring-surface.test.mjs +1 -1
  277. package/foundation/discovery/cli-self-docs.d.mts +2 -1
  278. package/foundation/discovery/cli-self-docs.mjs +4 -3
  279. package/foundation/discovery/cli-self-docs.test.mjs +2 -2
  280. package/foundation/discovery/component-discovery.d.mts +37 -0
  281. package/foundation/discovery/component-discovery.mjs +80 -5
  282. package/foundation/discovery/component-loader.d.mts +1 -1
  283. package/foundation/discovery/docs-discovery.mjs +14 -1
  284. package/foundation/discovery/module-exports.d.mts +41 -0
  285. package/foundation/discovery/module-exports.mjs +253 -0
  286. package/foundation/discovery/runner-allowlist.d.mts +2 -4
  287. package/foundation/discovery/runner-allowlist.mjs +2 -4
  288. package/foundation/discovery/runner-commands.d.mts +77 -0
  289. package/foundation/discovery/runner-commands.mjs +294 -0
  290. package/foundation/discovery/runner-commands.test.mjs +128 -0
  291. package/foundation/discovery/stray-pointers.test.mjs +1 -1
  292. package/foundation/discovery/template-adapter.mjs +18 -1
  293. package/foundation/discovery/template-needs.mjs +1 -44
  294. package/foundation/discovery/theme-discovery.mjs +147 -3
  295. package/foundation/doc-compiler/doc-loads.test.mjs +33 -9
  296. package/foundation/doc-compiler/read.mjs +59 -1
  297. package/foundation/doc-compiler/read.test.mjs +11 -2
  298. package/foundation/doc-compiler/split-topic-keywords.test.mjs +3 -2
  299. package/foundation/doc-compiler/tree.d.mts +32 -6
  300. package/foundation/doc-compiler/tree.mjs +77 -43
  301. package/foundation/doc-compiler/tree.test.mjs +7 -7
  302. package/foundation/fs/paths.d.mts +70 -8
  303. package/foundation/fs/paths.mjs +556 -38
  304. package/foundation/fs/paths.test.mjs +430 -54
  305. package/foundation/fs/read-record.d.mts +18 -0
  306. package/foundation/fs/read-record.mjs +131 -0
  307. package/foundation/fs/read-record.test.mjs +77 -0
  308. package/foundation/integrations/autolink.d.mts +2 -1
  309. package/foundation/integrations/autolink.mjs +4 -13
  310. package/foundation/integrations/computer-integrations.d.mts +6 -3
  311. package/foundation/integrations/computer-integrations.mjs +38 -9
  312. package/foundation/integrations/contribution-inventory.d.mts +15 -20
  313. package/foundation/integrations/contribution-inventory.mjs +41 -5
  314. package/foundation/integrations/integrations.d.mts +27 -1
  315. package/foundation/integrations/integrations.mjs +61 -2
  316. package/foundation/integrations/validate-contributions.d.mts +115 -0
  317. package/foundation/integrations/validate-contributions.mjs +1168 -13
  318. package/foundation/release/handoff.d.mts +23 -4
  319. package/foundation/release/handoff.mjs +175 -8
  320. package/foundation/release/run-context.mjs +14 -0
  321. package/foundation/response/response-types.doc.mjs +1 -1
  322. package/foundation/route/route.d.mts +285 -0
  323. package/foundation/route/route.mjs +324 -0
  324. package/foundation/route/route.test.mjs +153 -0
  325. package/foundation/runtime/hosted-runtime.test.mjs +403 -0
  326. package/foundation/runtime/locked-versions.d.mts +32 -0
  327. package/foundation/runtime/locked-versions.mjs +65 -0
  328. package/foundation/runtime/package-root.d.mts +91 -0
  329. package/foundation/runtime/package-root.mjs +174 -0
  330. package/foundation/runtime/package-set.d.mts +62 -0
  331. package/foundation/runtime/package-set.mjs +130 -0
  332. package/foundation/runtime/package-set.test.mjs +432 -0
  333. package/host/door-conformance.test.mjs +274 -0
  334. package/host/index.d.ts +116 -0
  335. package/host/index.mjs +295 -0
  336. package/host/index.test.mjs +302 -0
  337. package/package.json +14 -9
@@ -10,7 +10,8 @@
10
10
  */
11
11
  export function validateLocalIntegration(cwd?: string): Promise<ValidateResult>;
12
12
  /**
13
- * Validate an INSTALLED integration package resolved from `cwd`/node_modules.
13
+ * Validate an INSTALLED integration package: the nearest `node_modules/<spec>`
14
+ * at or above `cwd`, resolved the way the project loads it.
14
15
  * @param {string} spec package name
15
16
  * @param {string} [cwd]
16
17
  * @returns {Promise<ValidateResult>}
@@ -43,7 +44,6 @@ export function summarizeIssues(issues: Issue[]): {
43
44
  errors: number;
44
45
  warnings: number;
45
46
  };
46
- export { validateLoadedIntegration };
47
47
  export type Issue = import("../../foundation/integrations/issue").AstryxIntegrationIssue;
48
48
  export type ValidateResult = {
49
49
  /**
@@ -75,6 +75,15 @@ export type ValidateResult = {
75
75
  code: string;
76
76
  message: string;
77
77
  }[] | undefined;
78
+ /**
79
+ * Layout findings added after the last minor
80
+ * release: validate lists them as notes, which count nowhere, since they
81
+ * may not fail `--strict` until the next (architecture:cli-surface INV35);
82
+ * `integration verify` still fails on a package.json npm cannot pack.
83
+ */
84
+ listed?: import("../../foundation/integrations/issue").AstryxIntegrationIssue[] | undefined;
78
85
  integration?: import("../../foundation/integrations/integrations.mjs").LoadedIntegration | undefined;
79
86
  };
80
87
  import { validateLoadedIntegration } from '../../foundation/integrations/validate-contributions.mjs';
88
+ import { isListedIssue } from '../../foundation/integrations/validate-contributions.mjs';
89
+ export { validateLoadedIntegration, isListedIssue };
@@ -12,7 +12,7 @@
12
12
  * - validateLocalIntegration(cwd) — the package rooted at `cwd` (nearest
13
13
  * package.json + sibling astryx.integration.{ts,mjs,js}).
14
14
  * - validateInstalledIntegration(spec, cwd) — an installed package resolved
15
- * from `cwd`/node_modules.
15
+ * from the node_modules chain at or above `cwd`.
16
16
  *
17
17
  * Both return a { found, name, version, manifestFile, issues } result. `found`
18
18
  * is false only for the no-manifest local case, which is guidance (not an
@@ -34,8 +34,10 @@
34
34
  import * as fs from 'node:fs';
35
35
  import * as path from 'node:path';
36
36
  import {assertWithin} from '../../foundation/fs/path-safety.mjs';
37
+ import {normalizeProviderId} from '../../foundation/identity/provider-identity.mjs';
37
38
  import {integrationDocTypes} from '../docs/_adapter.mjs';
38
39
  import {integrationDocConsistency} from '../../foundation/discovery/doc-consistency.mjs';
40
+ import {integrationRunnerCommands} from './_adapter.mjs';
39
41
  import {
40
42
  THEME_SLUG_RE,
41
43
  unreadThemeFolders,
@@ -51,20 +53,25 @@ import {
51
53
  import {
52
54
  findManifestPaths,
53
55
  loadManifest,
54
- resolvePackageDir,
56
+ resolveInstalledIntegrationDir,
55
57
  } from '../../foundation/integrations/integrations.mjs';
56
58
  // The on-disk contribution validators live in foundation: Project and
57
59
  // integration-warnings need them too, and foundation must not depend on api.
58
60
  import {
61
+ blockComponentsCheck,
62
+ componentDocNamesCheck,
59
63
  INVALID_CLI_COMMAND,
64
+ isListedIssue,
65
+ issueListed as listed,
60
66
  validateLoadedIntegration,
67
+ validateLoadedIntegrationListed,
61
68
  issueError as error,
62
69
  issueWarning as warning,
63
70
  rootProblem,
64
71
  } from '../../foundation/integrations/validate-contributions.mjs';
65
72
  import {formatCliCommand} from '../../foundation/env/package-manager.mjs';
66
73
 
67
- export {validateLoadedIntegration};
74
+ export {validateLoadedIntegration, isListedIssue};
68
75
 
69
76
  /**
70
77
  * @typedef {import('../../foundation/integrations/issue').AstryxIntegrationIssue} Issue
@@ -80,6 +87,10 @@ export {validateLoadedIntegration};
80
87
  * @property {Issue[]} issues
81
88
  * @property {Array<{code: string, message: string}>} [notes] Information that
82
89
  * fails nothing, such as `invalid_cli_command` (a malformed `cliCommand`).
90
+ * @property {Issue[]} [listed] Layout findings added after the last minor
91
+ * release: validate lists them as notes, which count nowhere, since they
92
+ * may not fail `--strict` until the next (architecture:cli-surface INV35);
93
+ * `integration verify` still fails on a package.json npm cannot pack.
83
94
  * @property {import('../../foundation/integrations/integrations.mjs').LoadedIntegration} [integration]
84
95
  */
85
96
 
@@ -99,6 +110,14 @@ function findNearestPackageJson(cwd) {
99
110
  }
100
111
  }
101
112
 
113
+ const ROOT_KINDS = /** @type {const} */ ([
114
+ 'components',
115
+ 'templates',
116
+ 'codemods',
117
+ 'docs',
118
+ 'themes',
119
+ ]);
120
+
102
121
  const UNREACHABLE_SCAN_LIMIT = 5_000;
103
122
  const UNREACHABLE_SKIP_DIRS = new Set([
104
123
  'node_modules',
@@ -148,27 +167,51 @@ function unreadThemeFolderIssues(packageDir, loaded) {
148
167
  *
149
168
  * @param {string} packageDir
150
169
  * @param {import('../../foundation/integrations/integrations.mjs').LoadedIntegration} loaded
170
+ * @param {string[]} [reported] folders whose files another issue already covers
151
171
  * @returns {Promise<Issue[]>}
152
172
  */
153
- async function findUnreachableContributionIssues(packageDir, loaded) {
173
+ async function findUnreachableContributionIssues(
174
+ packageDir,
175
+ loaded,
176
+ reported = [],
177
+ ) {
178
+ // A root that is not a readable folder holds nothing: a fix must never
179
+ // send a file into it.
180
+ const usable = {...loaded};
181
+ for (const kind of ROOT_KINDS) {
182
+ const root = usable[kind];
183
+ if (root != null && rootProblem(root)) usable[kind] = undefined;
184
+ }
185
+ // Every declared root is skipped, readable or not: one that cannot be read
186
+ // has its own issue.
154
187
  const roots = /** @type {string[]} */ (
155
- [
156
- loaded.components,
157
- loaded.templates,
158
- loaded.codemods,
159
- loaded.docs,
160
- loaded.themes,
161
- ].filter(Boolean)
188
+ ROOT_KINDS.map(kind => loaded[kind]).filter(Boolean)
162
189
  );
190
+ // A folder a symlinked root points at is read through that root.
191
+ const realRoots = roots.map(root => {
192
+ try {
193
+ return fs.realpathSync(root);
194
+ } catch {
195
+ return root;
196
+ }
197
+ });
163
198
  /** @type {Issue[]} */
164
199
  const issues = [];
165
- const context = createFixContext(packageDir, loaded);
200
+ const context = createFixContext(packageDir, usable);
166
201
  let scanned = 0;
167
202
  let truncated = false;
168
203
 
169
204
  /** @param {string} dir */
170
205
  async function walk(dir) {
171
206
  if (roots.some(root => pathIsInside(dir, root))) return;
207
+ if (reported.some(folder => pathIsInside(dir, folder))) return;
208
+ let realDir = dir;
209
+ try {
210
+ realDir = fs.realpathSync(dir);
211
+ } catch {
212
+ // Unreadable: reported below.
213
+ }
214
+ if (realRoots.some(root => pathIsInside(realDir, root))) return;
172
215
  let entries;
173
216
  try {
174
217
  entries = fs
@@ -286,12 +329,14 @@ async function validateAtPackageDir(
286
329
  let manifest;
287
330
  /** @type {string[]} */
288
331
  let unknownKeys;
332
+ /** @type {string[]} */
333
+ let declaredKeys;
289
334
  /** @type {string | undefined} */
290
335
  let agentDocsError;
291
336
  /** @type {string | undefined} */
292
337
  let cliCommandError;
293
338
  try {
294
- ({manifest, unknownKeys, agentDocsError, cliCommandError} =
339
+ ({manifest, unknownKeys, declaredKeys, agentDocsError, cliCommandError} =
295
340
  await loadManifest(
296
341
  manifestFile,
297
342
  `Integration manifest (${path.basename(manifestFile)})`,
@@ -301,9 +346,36 @@ async function validateAtPackageDir(
301
346
  return result;
302
347
  }
303
348
 
304
- /** @param {string | null | undefined} value */
305
- const resolveRoot = (value, kind = 'contribution root') => {
349
+ /** @type {string[]} absolute roots inside the package */
350
+ const absoluteRoots = [];
351
+ /**
352
+ * @param {string | null | undefined} value
353
+ * @param {string} key the manifest key that declares it
354
+ */
355
+ const resolveRoot = (value, key, kind = 'contribution root') => {
306
356
  if (value == null) return undefined;
357
+ if (path.isAbsolute(value)) {
358
+ // An absolute root names this machine's disk, which no install shares,
359
+ // even when it happens to point inside the package.
360
+ const inside = path.relative(packageDir, value);
361
+ const relative =
362
+ inside === '' || (!inside.startsWith('..') && !path.isAbsolute(inside))
363
+ ? `./${inside.split(path.sep).join('/')}`.replace(/\/$/u, '')
364
+ : null;
365
+ // The code an absolute root has always carried, reworded.
366
+ result.issues.push(
367
+ error(
368
+ 'root_outside_package',
369
+ `The ${key} root "${value}" is an absolute path, so Astryx reads nothing from it: a root is relative to the package, so it resolves the same wherever the package is installed.` +
370
+ (relative
371
+ ? ` Fix: set \`${key}: '${relative === './' ? '.' : relative}'\` in ${path.basename(manifestFile)}.`
372
+ : ` It also points outside the package. Fix: move the files into the package and set \`${key}\` to their folder relative to package.json, such as './${key}'.`),
373
+ ),
374
+ );
375
+ // Its files are reported through this issue, not one by one.
376
+ if (relative) absoluteRoots.push(path.resolve(value));
377
+ return undefined;
378
+ }
307
379
  try {
308
380
  return assertWithin(value, packageDir, {label: kind});
309
381
  } catch {
@@ -320,18 +392,20 @@ async function validateAtPackageDir(
320
392
  const loaded = {
321
393
  name: identity.name,
322
394
  version: identity.version,
323
- components: resolveRoot(manifest.components),
324
- templates: resolveRoot(manifest.templates),
325
- codemods: resolveRoot(manifest.codemods),
326
- docs: resolveRoot(manifest.docs),
327
- themes: resolveRoot(manifest.themes),
395
+ components: resolveRoot(manifest.components, 'components'),
396
+ templates: resolveRoot(manifest.templates, 'templates'),
397
+ codemods: resolveRoot(manifest.codemods, 'codemods'),
398
+ docs: resolveRoot(manifest.docs, 'docs'),
399
+ themes: resolveRoot(manifest.themes, 'themes'),
328
400
  issuesUrl: manifest.issuesUrl,
329
401
  agentDocs: manifest.agentDocs,
330
402
  cliCommand: manifest.cliCommand,
331
403
  __cliCommandError: cliCommandError,
332
404
  __agentDocsError: agentDocsError,
333
405
  __unknownKeys: unknownKeys,
406
+ __declaredKeys: declaredKeys,
334
407
  __spec: identity.name,
408
+ __declaredProviderId: manifest.providerId,
335
409
  __packageDir: packageDir,
336
410
  __manifestFile: manifestFile,
337
411
  };
@@ -343,7 +417,9 @@ async function validateAtPackageDir(
343
417
  // `integration check --strict` fails on any warning, and a new failure code
344
418
  // joins only in a minor release (architecture:cli-surface INV35). Doctor's
345
419
  // project check still warns about it.
346
- for (const issue of await validateLoadedIntegration(loaded)) {
420
+ const contribution = await validateLoadedIntegrationListed(loaded);
421
+ (result.listed ??= []).push(...contribution.listed);
422
+ for (const issue of contribution.issues) {
347
423
  if (issue.code === INVALID_CLI_COMMAND) {
348
424
  (result.notes ??= []).push({code: issue.code, message: issue.message});
349
425
  } else {
@@ -370,7 +446,11 @@ async function validateAtPackageDir(
370
446
  );
371
447
  if (scanUnreachable) {
372
448
  issues.push(
373
- ...(await findUnreachableContributionIssues(packageDir, loaded)),
449
+ ...(await findUnreachableContributionIssues(
450
+ packageDir,
451
+ loaded,
452
+ absoluteRoots,
453
+ )),
374
454
  );
375
455
  }
376
456
 
@@ -397,7 +477,7 @@ export async function validateLocalIntegration(cwd = process.cwd()) {
397
477
  return {found: false, issues: []};
398
478
  }
399
479
 
400
- /** @type {{name?: string, version?: string}} */
480
+ /** @type {{name?: string, version?: string, private?: boolean}} */
401
481
  let pkg;
402
482
  try {
403
483
  pkg = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'));
@@ -416,31 +496,121 @@ export async function validateLocalIntegration(cwd = process.cwd()) {
416
496
  };
417
497
  }
418
498
 
419
- return validateAtPackageDir(
499
+ // npm publishes nothing without a name and a version, and the name is the
500
+ // provider ID every reader keys the package's contributions on.
501
+ // A package without one is still checked, under a placeholder name.
502
+ const fields = packageJsonFieldIssues(pkg, pkgJsonPath);
503
+ const name =
504
+ typeof pkg.name === 'string' && pkg.name !== ''
505
+ ? pkg.name
506
+ : '(local package)';
507
+ const result = await validateAtPackageDir(
420
508
  packageDir,
421
- {
422
- name: pkg.name ?? '(local package)',
423
- version: pkg.version,
424
- },
509
+ {name, version: pkg.version},
425
510
  {scanUnreachable: true},
426
511
  );
512
+ (result.listed ??= []).unshift(
513
+ ...fields,
514
+ // Only a manifest that loaded says whether it declares a providerId; one
515
+ // that did not is reported as invalid_manifest.
516
+ ...(result.integration
517
+ ? providerIdIssues(
518
+ pkg.name,
519
+ result.integration.__declaredProviderId,
520
+ result.integration.__manifestFile,
521
+ )
522
+ : []),
523
+ );
524
+ return result;
525
+ }
526
+
527
+ /**
528
+ * Whether `name` is a bare npm package name, the form a provider ID takes.
529
+ * @param {string} name
530
+ */
531
+ function isPackageName(name) {
532
+ try {
533
+ normalizeProviderId(name);
534
+ return true;
535
+ } catch {
536
+ return false;
537
+ }
427
538
  }
428
539
 
429
540
  /**
430
- * Validate an INSTALLED integration package resolved from `cwd`/node_modules.
541
+ * A warning when no provider ID can be derived for the package: its
542
+ * package.json `name` is not a bare package name and its manifest declares
543
+ * no `providerId` that is one. Readers key the package's contributions on
544
+ * that ID; a missing name is its own warning.
545
+ * @param {unknown} name package.json `name`
546
+ * @param {unknown} declared the manifest's `providerId`
547
+ * @param {string} manifestFile
548
+ * @returns {Issue[]}
549
+ */
550
+ function providerIdIssues(name, declared, manifestFile) {
551
+ if (typeof name !== 'string' || name === '') return [];
552
+ if (isPackageName(name)) return [];
553
+ if (typeof declared === 'string' && isPackageName(declared)) return [];
554
+ const manifest = path.basename(manifestFile);
555
+ return [
556
+ listed(
557
+ 'no_provider_id',
558
+ `No provider ID can be derived for this package: package.json "name" ${JSON.stringify(name)} is not a bare package name (an optional @scope/ and a name, each starting with a lowercase letter or digit and holding only lowercase letters, digits, "-", ".", "_" and "~"), and ${manifest} declares no providerId that is one. Astryx files the package's components, templates and docs under that ID, so links to them and selecting the package cannot work. Fix: rename the package, such as "@your-scope/your-package", or set \`providerId: '@your-scope/your-package'\` in ${manifest}.`,
559
+ ),
560
+ ];
561
+ }
562
+
563
+ /**
564
+ * A warning for each field npm needs that package.json lacks.
565
+ * @param {{name?: unknown, version?: unknown, private?: unknown}} pkg
566
+ * @param {string} pkgJsonPath
567
+ * @returns {Issue[]}
568
+ */
569
+ function packageJsonFieldIssues(pkg, pkgJsonPath) {
570
+ /** @type {Issue[]} */
571
+ const issues = [];
572
+ const shown = path.basename(pkgJsonPath);
573
+ // Listed, so validate and `--strict` keep the result they had for these
574
+ // packages; `integration verify`, which packs, reports them as errors.
575
+ if (typeof pkg.name !== 'string' || pkg.name === '') {
576
+ issues.push(
577
+ listed(
578
+ 'invalid_package_json',
579
+ `${shown} has no "name", so npm cannot pack or publish the package, and a project that installs it has no name to select it by. Fix: add "name": "@your-scope/your-package" to ${shown}.`,
580
+ ),
581
+ );
582
+ }
583
+ // A private package is never published, so it needs no version.
584
+ if (
585
+ pkg.private !== true &&
586
+ (typeof pkg.version !== 'string' || pkg.version === '')
587
+ ) {
588
+ issues.push(
589
+ listed(
590
+ 'invalid_package_json',
591
+ `${shown} has no "version", so npm cannot pack or publish the package. Fix: add "version": "0.1.0" to ${shown}.`,
592
+ ),
593
+ );
594
+ }
595
+ return issues;
596
+ }
597
+
598
+ /**
599
+ * Validate an INSTALLED integration package: the nearest `node_modules/<spec>`
600
+ * at or above `cwd`, resolved the way the project loads it.
431
601
  * @param {string} spec package name
432
602
  * @param {string} [cwd]
433
603
  * @returns {Promise<ValidateResult>}
434
604
  */
435
605
  export async function validateInstalledIntegration(spec, cwd = process.cwd()) {
436
- // resolvePackageDir throws (path-safety guard) on a spec with path segments,
606
+ // The resolver throws (path-safety guard) on a spec with path segments,
437
607
  // `..`, or an absolute path. Every other malformed input to this command
438
608
  // degrades into a diagnostic — so catch it here and return an issue instead
439
609
  // of letting the throw escape to a raw stack (human) / generic ERR_UNKNOWN
440
610
  // (--json).
441
611
  let packageDir;
442
612
  try {
443
- packageDir = resolvePackageDir(spec, cwd);
613
+ packageDir = resolveInstalledIntegrationDir(spec, cwd);
444
614
  } catch (err) {
445
615
  return {
446
616
  found: true,
@@ -478,6 +648,24 @@ export async function validateInstalledIntegration(spec, cwd = process.cwd()) {
478
648
  });
479
649
  }
480
650
 
651
+ /**
652
+ * The runner-command notes for a package's topics: each Astryx command a topic
653
+ * writes with a package runner, where the doc file is, and the bare command to
654
+ * write.
655
+ * @param {any} integration a loaded integration
656
+ * @returns {Promise<Array<{code: string, message: string}>>}
657
+ */
658
+ async function runnerCommandNotes(integration) {
659
+ const packageDir = integration.__packageDir;
660
+ return (await integrationRunnerCommands(integration)).map(each => ({
661
+ code: 'runner_command',
662
+ message:
663
+ typeof packageDir === 'string'
664
+ ? `${path.relative(packageDir, each.file).split(path.sep).join('/')}: ${each.message}`
665
+ : each.message,
666
+ }));
667
+ }
668
+
481
669
  /**
482
670
  * Unified entry: validate the LOCAL integration (no `pkg`) or an INSTALLED one
483
671
  * (`pkg` given) and return the `integration.validate` envelope. The no-manifest
@@ -504,7 +692,35 @@ export async function validateIntegration(pkg, options = {}) {
504
692
  const docTypes = integration
505
693
  ? await integrationDocTypes(integration, cwd)
506
694
  : undefined;
507
- const notes = result.found ? (result.notes ?? []) : [];
695
+ // The component names docs and blocks give: those that cannot be judged
696
+ // are listed in their reports, and those judged wrong are notes.
697
+ const names = integration
698
+ ? [
699
+ await componentDocNamesCheck(integration),
700
+ await blockComponentsCheck(integration),
701
+ ]
702
+ : undefined;
703
+ const docNames = names?.[0].report;
704
+ const blockComponents = names?.[1].report;
705
+ // Notes fail nothing: a malformed `cliCommand`, and the findings added
706
+ // after the last minor release, each with its fix in the message, which
707
+ // may not fail `--strict` until the next (architecture:cli-surface INV35):
708
+ // the layout findings and the component names judged wrong.
709
+ const notes = result.found
710
+ ? [
711
+ ...(result.notes ?? []),
712
+ ...(result.listed ?? []).map(issue => ({
713
+ code: issue.code,
714
+ message: issue.message,
715
+ })),
716
+ ...(names ?? []).flatMap(each => each.notes),
717
+ ]
718
+ : [];
719
+ // Each Astryx command a topic writes with a package runner, as a
720
+ // `runner_command` note with its fix, the same way.
721
+ if (integration?.docs) {
722
+ notes.push(...(await runnerCommandNotes(integration)));
723
+ }
508
724
  return {
509
725
  type: 'integration.validate',
510
726
  data: {
@@ -526,6 +742,8 @@ export async function validateIntegration(pkg, options = {}) {
526
742
  : result.issues,
527
743
  ...(notes.length > 0 ? {notes} : {}),
528
744
  ...(docTypes ? {docTypes} : {}),
745
+ ...(docNames ? {docNames} : {}),
746
+ ...(blockComponents ? {blockComponents} : {}),
529
747
  },
530
748
  };
531
749
  }
@@ -14,6 +14,7 @@ export type LoadedIntegration = {
14
14
  codemods?: string | undefined;
15
15
  docs?: string | undefined;
16
16
  issuesUrl?: string | undefined;
17
+ __declaredKeys?: string[] | undefined;
17
18
  __unknownKeys?: string[] | undefined;
18
19
  __spec: string;
19
20
  __packageDir: string;
@@ -36,7 +37,18 @@ export type ValidateIntegrationResponse = {
36
37
  type: "integration.validate";
37
38
  /**
38
39
  * `notes`: information beside the issues that fails nothing, such as
39
- * `invalid_cli_command`, a `cliCommand` that was ignored as malformed
40
+ * `invalid_cli_command`, a `cliCommand` that was ignored as malformed, and
41
+ * the package layout findings added after the last minor release, each with
42
+ * its fix in the message: two docs for one component
43
+ * (`duplicate_component_doc`), a root reached through a symlink
44
+ * (`symlinked_root`), a contribution file that cannot be read
45
+ * (`unreadable_file`), a package.json without `name` or `version`
46
+ * (`invalid_package_json`), no provider ID (`no_provider_id`), and a doc
47
+ * whose file name differs from its source only in letter case where the two
48
+ * still pair (`source_without_component_doc`); and `doc_name_mismatch` and
49
+ * `unknown_block_component` (see `docNames` and `blockComponents`); they
50
+ * become warnings in the next minor release; and `runner_command`, an
51
+ * Astryx command a topic writes with a package runner
40
52
  */
41
53
  data: {
42
54
  validated: boolean;
@@ -48,6 +60,8 @@ export type ValidateIntegrationResponse = {
48
60
  message: string;
49
61
  }>;
50
62
  docTypes?: DocTypesReport;
63
+ docNames?: DocNamesReport;
64
+ blockComponents?: BlockComponentsReport;
51
65
  };
52
66
  };
53
67
  /**
@@ -57,3 +71,47 @@ export type ValidateIntegrationResponse = {
57
71
  export type DocTypesReport = import("../../foundation/discovery/doc-types.mjs").DocTypesReport & {
58
72
  fixtures?: number;
59
73
  };
74
+ /**
75
+ * Each component doc whose `name` differs from the name it is listed under,
76
+ * judged against its source. Present when the manifest loads. A name the
77
+ * module its printed import names provably does not export is a
78
+ * `doc_name_mismatch` note beside the issues, with its fix in the message
79
+ * (it becomes a warning in the next minor release), so `findings` is always
80
+ * empty; `unchecked` lists each doc whose source's
81
+ * exports could not all be read (a re-export from another package, `export
82
+ * =`, a destructured binding, a namespace): `file` (the doc, package-relative),
83
+ * `name` (what the doc says), and `reason`.
84
+ */
85
+ export type DocNamesReport = {
86
+ status: "checked";
87
+ findings: [];
88
+ unchecked: Array<{
89
+ file: string;
90
+ name: string;
91
+ reason: string;
92
+ }>;
93
+ };
94
+ /**
95
+ * Each component name a template gives in `exampleFor` or `componentsUsed`
96
+ * that could not be judged. Present when the manifest loads. A name neither
97
+ * the package nor Core has, and the template does not import, is an
98
+ * `unknown_block_component` note beside the issues, with its fix in the
99
+ * message (it becomes a warning in the next minor release), so `findings` is
100
+ * always empty;
101
+ * `unchecked` lists each name that cannot be judged: one the template may
102
+ * reach through anything other than named imports and re-exports from
103
+ * Core, React, StyleX, local helpers or the package's own entry (an import from another
104
+ * package, a default or namespace import, an alias of or member read off an imported
105
+ * binding, require(), a dynamic import(), a local module this check cannot
106
+ * read), or, without Core installed, any name Core would have to resolve: `file` (the template doc, package-relative),
107
+ * `name`, and `reason`.
108
+ */
109
+ export type BlockComponentsReport = {
110
+ status: "checked";
111
+ findings: [];
112
+ unchecked: Array<{
113
+ file: string;
114
+ name: string;
115
+ reason: string;
116
+ }>;
117
+ };
@@ -18,6 +18,7 @@
18
18
  * @property {string} [codemods]
19
19
  * @property {string} [docs]
20
20
  * @property {string} [issuesUrl]
21
+ * @property {string[]} [__declaredKeys]
21
22
  * @property {string[]} [__unknownKeys]
22
23
  * @property {string} __spec
23
24
  * @property {string} __packageDir
@@ -38,9 +39,20 @@
38
39
  * "healthy" — the two are otherwise byte-identical.
39
40
  * @typedef {object} ValidateIntegrationResponse
40
41
  * @property {'integration.validate'} type
41
- * @property {{validated: boolean, name: string | null, version: string | null, issues: import('../../foundation/integrations/issue').AstryxIntegrationIssue[], notes?: Array<{code: string, message: string}>, docTypes?: DocTypesReport}} data
42
+ * @property {{validated: boolean, name: string | null, version: string | null, issues: import('../../foundation/integrations/issue').AstryxIntegrationIssue[], notes?: Array<{code: string, message: string}>, docTypes?: DocTypesReport, docNames?: DocNamesReport, blockComponents?: BlockComponentsReport}} data
42
43
  * `notes`: information beside the issues that fails nothing, such as
43
- * `invalid_cli_command`, a `cliCommand` that was ignored as malformed
44
+ * `invalid_cli_command`, a `cliCommand` that was ignored as malformed, and
45
+ * the package layout findings added after the last minor release, each with
46
+ * its fix in the message: two docs for one component
47
+ * (`duplicate_component_doc`), a root reached through a symlink
48
+ * (`symlinked_root`), a contribution file that cannot be read
49
+ * (`unreadable_file`), a package.json without `name` or `version`
50
+ * (`invalid_package_json`), no provider ID (`no_provider_id`), and a doc
51
+ * whose file name differs from its source only in letter case where the two
52
+ * still pair (`source_without_component_doc`); and `doc_name_mismatch` and
53
+ * `unknown_block_component` (see `docNames` and `blockComponents`); they
54
+ * become warnings in the next minor release; and `runner_command`, an
55
+ * Astryx command a topic writes with a package runner
44
56
  */
45
57
 
46
58
  /**
@@ -54,4 +66,36 @@
54
66
  * components or docs root, which those readers skip) were not checked
55
67
  */
56
68
 
69
+ /**
70
+ * Each component doc whose `name` differs from the name it is listed under,
71
+ * judged against its source. Present when the manifest loads. A name the
72
+ * module its printed import names provably does not export is a
73
+ * `doc_name_mismatch` note beside the issues, with its fix in the message
74
+ * (it becomes a warning in the next minor release), so `findings` is always
75
+ * empty; `unchecked` lists each doc whose source's
76
+ * exports could not all be read (a re-export from another package, `export
77
+ * =`, a destructured binding, a namespace): `file` (the doc, package-relative),
78
+ * `name` (what the doc says), and `reason`.
79
+ *
80
+ * @typedef {{status: 'checked', findings: [], unchecked: Array<{file: string, name: string, reason: string}>}} DocNamesReport
81
+ */
82
+
83
+ /**
84
+ * Each component name a template gives in `exampleFor` or `componentsUsed`
85
+ * that could not be judged. Present when the manifest loads. A name neither
86
+ * the package nor Core has, and the template does not import, is an
87
+ * `unknown_block_component` note beside the issues, with its fix in the
88
+ * message (it becomes a warning in the next minor release), so `findings` is
89
+ * always empty;
90
+ * `unchecked` lists each name that cannot be judged: one the template may
91
+ * reach through anything other than named imports and re-exports from
92
+ * Core, React, StyleX, local helpers or the package's own entry (an import from another
93
+ * package, a default or namespace import, an alias of or member read off an imported
94
+ * binding, require(), a dynamic import(), a local module this check cannot
95
+ * read), or, without Core installed, any name Core would have to resolve: `file` (the template doc, package-relative),
96
+ * `name`, and `reason`.
97
+ *
98
+ * @typedef {{status: 'checked', findings: [], unchecked: Array<{file: string, name: string, reason: string}>}} BlockComponentsReport
99
+ */
100
+
57
101
  export {};
@@ -62,7 +62,7 @@ export const doc = {
62
62
  {
63
63
  type: 'integration.validate',
64
64
  description:
65
- 'The result envelope: `data.validated`, false when nothing was validated — with no `package.json` at all, `data.issues` carries one `no_package` error-severity issue so the command exits 1; with a `package.json` but no integration manifest, `data.issues` is empty, which means "not looked at", not "healthy"; `data.name` and `data.version` of the validated package (both null when `data.validated` is false; `data.name` is `(local package)` when the local package.json has no readable name), plus `data.issues`, an AstryxIntegrationIssue[] of {code, severity: `warning` | `error`, message, fix?, file?, line?}: `fix` is the change that resolves the issue, and `file` and `line` where it is, relative to the package, when the check knows them; and `data.notes` when there are any: {code, message} information that fails nothing, such as `invalid_cli_command` for a `cliCommand` that was ignored as malformed. When the manifest loads, `data.docTypes` holds the doc type check: `status` (`checked` | `skipped`), `reason` when skipped, `typescript`, `docs` (doc values checked), `findings` ({doc, line, export, type, field, problem: `unknown_field` | `missing_field` | `wrong_type`, severity: `warning`, message, fix}), `unchecked` ({doc, reason}: a doc that could not be fully checked, or a root its reader cannot read), and `fixtures` when the components or docs root holds test fixture docs under `__tests__`: how many, none of them checked.',
65
+ 'The result envelope: `data.validated`, false when nothing was validated — with no `package.json` at all, `data.issues` carries one `no_package` error-severity issue so the command exits 1; with a `package.json` but no integration manifest, `data.issues` is empty, which means "not looked at", not "healthy"; `data.name` and `data.version` of the validated package (both null when `data.validated` is false; `data.name` is `(local package)` when the local package.json has no readable name), plus `data.issues`, an AstryxIntegrationIssue[] of {code, severity: `warning` | `error`, message, fix?, file?, line?}: `fix` is the change that resolves the issue, and `file` and `line` where it is, relative to the package, when the check knows them; and `data.notes` when there are any: {code, message} information that fails nothing, such as `invalid_cli_command` for a `cliCommand` that was ignored as malformed, and the package layout findings added after the last minor release, each with its fix in the message: `duplicate_component_doc`, `symlinked_root`, `unreadable_file`, `invalid_package_json` (no `name` or `version`), `no_provider_id`, and `source_without_component_doc` for a doc whose file name differs from its source only in letter case where the two still pair; and `doc_name_mismatch` and `unknown_block_component` (see `docNames` and `blockComponents`); they become warnings in the next minor release. A `runner_command` note lists each Astryx command a topic writes with a package runner, with its file, line and the bare command to write. When the manifest loads, `data.docTypes` holds the doc type check: `status` (`checked` | `skipped`), `reason` when skipped, `typescript`, `docs` (doc values checked), `findings` ({doc, line, export, type, field, problem: `unknown_field` | `missing_field` | `wrong_type`, severity: `warning`, message, fix}), `unchecked` ({doc, reason}: a doc that could not be fully checked, or a root its reader cannot read), and `fixtures` when the components or docs root holds test fixture docs under `__tests__`: how many, none of them checked. When the manifest loads, `data.docNames` lists the component doc names it could not judge: `status` (`checked`), `findings` (always empty; a doc name the module its import names provably does not export is a `doc_name_mismatch` note, with its fix in the message) and `unchecked` ({file, name, reason}: a doc whose `name` differs from the name it is listed under and whose source exports cannot all be read, such as a re-export from another package). When the manifest loads, `data.blockComponents` lists the component names templates give in `exampleFor` or `componentsUsed` that could not be judged: `status` (`checked`), `findings` (always empty; a name neither the package nor Core has, and the template does not import, is an `unknown_block_component` note, with its fix in the message) and `unchecked` ({file, name, reason}: a name the template may reach through anything other than named imports and re-exports from Core, React, StyleX, local helpers or the entry of the package itself, such as an import from another package, a default or namespace import, an alias of or member read off an imported binding, require() or a dynamic import(), or a local module that cannot be read, or any name Core would have to resolve when Core is not installed).',
66
66
  },
67
67
  ],
68
68
  examples: [