@astryxdesign/cli 0.7.2-canary.fe2c655 → 0.7.2

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 (509) hide show
  1. package/CHANGELOG.md +119 -0
  2. package/README.md +175 -154
  3. package/api/build/_adapter.d.mts +8 -0
  4. package/api/build/_adapter.mjs +12 -1
  5. package/api/build/build.doc.mjs +4 -0
  6. package/api/build/help/help.mjs +1 -1
  7. package/api/build/kit/kit.mjs +3 -11
  8. package/api/component/_adapter.d.mts +72 -1
  9. package/api/component/_adapter.mjs +212 -18
  10. package/api/component/component.doc.mjs +6 -1
  11. package/api/component/component.mjs +82 -15
  12. package/api/component/component.test.mjs +80 -0
  13. package/api/component/doc-links.test.mjs +386 -0
  14. package/api/component/integration-export-name.test.mjs +644 -0
  15. package/api/component/list/list.mjs +42 -4
  16. package/api/discover/_adapter.d.mts +132 -12
  17. package/api/discover/_adapter.mjs +488 -27
  18. package/api/discover/_adapter.test.mjs +599 -17
  19. package/api/discover/_catalog-view.d.mts +16 -5
  20. package/api/discover/_catalog-view.mjs +32 -8
  21. package/api/discover/detail/doc/doc.mjs +9 -1
  22. package/api/discover/discover.d.mts +11 -0
  23. package/api/discover/discover.doc.mjs +9 -7
  24. package/api/discover/discover.mjs +121 -19
  25. package/api/discover/discover.type.d.mts +20 -7
  26. package/api/discover/discover.type.mjs +17 -7
  27. package/api/discover/list/list.d.mts +4 -3
  28. package/api/discover/list/list.mjs +17 -10
  29. package/api/docs/_adapter.d.mts +74 -0
  30. package/api/docs/_adapter.mjs +553 -16
  31. package/api/docs/docs.doc.mjs +2 -1
  32. package/api/docs/docs.mjs +2 -1
  33. package/api/docs/docs.test.mjs +5 -2
  34. package/api/docs/integration-tree.test.mjs +22 -0
  35. package/api/docs/integrationDocs.test.mjs +124 -0
  36. package/api/docs/list/list.mjs +12 -2
  37. package/api/docs/reference-blocks.test.mjs +1 -3
  38. package/api/doctor/_adapter.d.mts +108 -0
  39. package/api/doctor/_adapter.mjs +223 -4
  40. package/api/doctor/doctor.d.mts +199 -0
  41. package/api/doctor/doctor.doc.mjs +3 -2
  42. package/api/doctor/doctor.mjs +530 -34
  43. package/api/doctor/doctor.test.mjs +180 -14
  44. package/api/doctor/release-checks.test.mjs +156 -0
  45. package/api/doctor/theme-checks.mjs +17 -4
  46. package/api/doctor/theme-checks.test.mjs +223 -7
  47. package/api/error.d.mts +10 -0
  48. package/api/error.mjs +25 -0
  49. package/api/gap-report/gap-report.d.mts +3 -0
  50. package/api/gap-report/gap-report.doc.mjs +11 -3
  51. package/api/gap-report/gap-report.mjs +219 -52
  52. package/api/gap-report/gap-report.test.mjs +233 -0
  53. package/api/gap-report/gap-report.type.d.mts +41 -0
  54. package/api/gap-report/gap-report.type.mjs +18 -0
  55. package/api/hook/_adapter.mjs +3 -11
  56. package/api/hook/hook.doc.mjs +4 -0
  57. package/api/hook/list/list.d.mts +1 -1
  58. package/api/index.d.mts +2 -0
  59. package/api/index.mjs +2 -0
  60. package/api/init/_adapter.d.mts +22 -0
  61. package/api/init/_adapter.mjs +59 -0
  62. package/api/init/init.d.mts +7 -5
  63. package/api/init/init.doc.mjs +28 -7
  64. package/api/init/init.mjs +28 -4
  65. package/api/init/init.type.d.mts +48 -3
  66. package/api/init/init.type.mjs +37 -3
  67. package/api/init/run/run.d.mts +1 -1
  68. package/api/init/run/run.mjs +17 -6
  69. package/api/init/user/user.d.mts +14 -0
  70. package/api/init/user/user.mjs +87 -0
  71. package/api/init/user/user.test.mjs +232 -0
  72. package/api/integration/_adapter.d.mts +45 -0
  73. package/api/integration/_adapter.mjs +112 -0
  74. package/api/integration/add-contribution.component-names.test.mjs +66 -0
  75. package/api/integration/add-contribution.mjs +8 -4
  76. package/api/integration/add-contribution.test.mjs +4 -2
  77. package/api/integration/authoring-checks.mjs +110 -6
  78. package/api/integration/authoring-checks.test.mjs +808 -0
  79. package/api/integration/authoring-checks.type.d.mts +143 -0
  80. package/api/integration/authoring-checks.type.mjs +74 -2
  81. package/api/integration/check/check.d.mts +96 -0
  82. package/api/integration/check/check.mjs +357 -0
  83. package/api/integration/check/check.test.mjs +489 -0
  84. package/api/integration/integration-check.type.d.mts +118 -0
  85. package/api/integration/integration-check.type.mjs +84 -0
  86. package/api/integration/integrationCheck.doc.d.mts +10 -0
  87. package/api/integration/integrationCheck.doc.mjs +73 -0
  88. package/api/integration/integrationComponentConflicts.doc.mjs +45 -6
  89. package/api/integration/integrationDocConflicts.doc.mjs +22 -5
  90. package/api/integration/pack-check.mjs +364 -120
  91. package/api/integration/pack-check.test.mjs +730 -10
  92. package/api/integration/validate-integration-fixes.test.mjs +67 -0
  93. package/api/integration/validate-integration.d.mts +8 -0
  94. package/api/integration/validate-integration.mjs +63 -9
  95. package/api/integration/validate-integration.test.mjs +88 -8
  96. package/api/integration/validate-integration.type.d.mts +16 -0
  97. package/api/integration/validate-integration.type.mjs +14 -1
  98. package/api/integration/validate-unread-theme-folders.test.mjs +3 -2
  99. package/api/integration/validateIntegration.doc.mjs +19 -3
  100. package/api/search/_adapter.d.mts +11 -0
  101. package/api/search/_adapter.mjs +25 -0
  102. package/api/search/search.d.mts +82 -13
  103. package/api/search/search.doc.mjs +8 -3
  104. package/api/search/search.domain-priority.test.mjs +108 -18
  105. package/api/search/search.integration-check.test.mjs +24 -0
  106. package/api/search/search.mjs +645 -64
  107. package/api/search/search.test.mjs +179 -1
  108. package/api/search/search.type.d.mts +14 -1
  109. package/api/search/search.type.mjs +6 -1
  110. package/api/swizzle/_adapter.mjs +2 -2
  111. package/api/swizzle/copy/copy.mjs +29 -15
  112. package/api/template/template-integration.test.mjs +1 -1
  113. package/api/template/template.test.mjs +120 -3
  114. package/api/theme/_adapter.d.mts +16 -0
  115. package/api/theme/_adapter.mjs +32 -5
  116. package/api/theme/build/build.d.mts +2 -1
  117. package/api/theme/build/build.family.test.mjs +64 -0
  118. package/api/theme/build/build.mjs +250 -38
  119. package/api/theme/build/build.packed-old-core.test.mjs +20 -3
  120. package/api/theme/build/font-warning.mjs +5 -3
  121. package/api/theme/build/font-warning.test.mjs +2 -1
  122. package/api/theme/remove/remove.test.mjs +2 -2
  123. package/api/theme/targets/targets.mjs +3 -10
  124. package/api/theme/themeBuild.doc.mjs +4 -4
  125. package/api/theme/themeTargets.doc.mjs +4 -0
  126. package/api/theme/use/use.test.mjs +1 -1
  127. package/api/upgrade/_adapter.d.mts +40 -2
  128. package/api/upgrade/_adapter.mjs +118 -5
  129. package/api/upgrade/run/cli-behind-core.test.mjs +438 -0
  130. package/api/upgrade/run/run.mjs +35 -2
  131. package/api/upgrade/status/status.d.mts +21 -5
  132. package/api/upgrade/status/status.mjs +45 -8
  133. package/api/upgrade/upgrade.doc.mjs +6 -3
  134. package/api/upgrade/upgrade.mjs +5 -1
  135. package/api/upgrade/upgrade.type.d.mts +23 -0
  136. package/api/upgrade/upgrade.type.mjs +16 -1
  137. package/assets/codemods/__tests__/registry.test.mjs +1 -0
  138. package/assets/codemods/registry.mjs +1 -0
  139. package/assets/codemods/runner.mjs +7 -1
  140. package/assets/codemods/transforms/v0.7.2/__tests__/migrate-list-edge-compensation-to-edge.test.mjs +120 -0
  141. package/assets/codemods/transforms/v0.7.2/index.mjs +20 -0
  142. package/assets/codemods/transforms/v0.7.2/migrate-list-edge-compensation-to-edge.mjs +198 -0
  143. package/assets/discover/official-packages.json +367 -0
  144. package/assets/docs/README.md +10 -0
  145. package/assets/docs/author-a-theme.doc.mjs +3 -3
  146. package/assets/docs/browser-support.doc.mjs +1 -1
  147. package/assets/docs/getting-started.doc.mjs +26 -6
  148. package/assets/docs/styling-overview.doc.mjs +1 -1
  149. package/assets/docs/theme.doc.dense.mjs +1 -1
  150. package/assets/docs/theme.doc.mjs +2 -2
  151. package/assets/docs/theme.doc.zh.mjs +1 -1
  152. package/assets/docs/tree/add-a-component.doc.mjs +22 -2
  153. package/assets/docs/tree/add-a-theme.doc.mjs +13 -3
  154. package/assets/docs/tree/add-a-topic.doc.mjs +54 -9
  155. package/assets/docs/tree/agent-guidance.doc.mjs +19 -5
  156. package/assets/docs/tree/block-template.doc.mjs +8 -20
  157. package/assets/docs/tree/build-the-template.doc.mjs +1 -1
  158. package/assets/docs/tree/building-blocks.doc.mjs +4 -0
  159. package/assets/docs/tree/check-the-props.doc.mjs +201 -0
  160. package/assets/docs/tree/check-your-docs.doc.mjs +69 -11
  161. package/assets/docs/tree/checks.doc.mjs +32 -24
  162. package/assets/docs/tree/ci-and-containers.doc.mjs +88 -0
  163. package/assets/docs/tree/cli-command.doc.mjs +142 -0
  164. package/assets/docs/tree/cli.doc.mjs +6 -0
  165. package/assets/docs/tree/codemods.doc.mjs +17 -7
  166. package/assets/docs/tree/commands.doc.mjs +7 -1
  167. package/assets/docs/tree/component-family.doc.mjs +8 -6
  168. package/assets/docs/tree/component-imports.doc.mjs +21 -3
  169. package/assets/docs/tree/components.doc.mjs +7 -1
  170. package/assets/docs/tree/computer-agent-guide.doc.mjs +160 -0
  171. package/assets/docs/tree/computer-integrations.doc.mjs +93 -0
  172. package/assets/docs/tree/configuration.doc.mjs +7 -3
  173. package/assets/docs/tree/debug-and-gap-reports.doc.mjs +41 -22
  174. package/assets/docs/tree/define-the-theme.doc.mjs +6 -5
  175. package/assets/docs/tree/describe-the-component.doc.mjs +3 -3
  176. package/assets/docs/tree/docs.doc.mjs +9 -3
  177. package/assets/docs/tree/document-the-template.doc.mjs +1 -1
  178. package/assets/docs/tree/document-the-theme.doc.mjs +3 -3
  179. package/assets/docs/tree/export-template-assets.doc.mjs +1 -1
  180. package/assets/docs/tree/extend-or-replace.doc.mjs +19 -9
  181. package/assets/docs/tree/fonts-and-assets.doc.mjs +2 -2
  182. package/assets/docs/tree/generate-a-palette.doc.mjs +7 -5
  183. package/assets/docs/tree/global-integrations.doc.mjs +124 -0
  184. package/assets/docs/tree/global.doc.mjs +131 -0
  185. package/assets/docs/tree/grade-template-with-agent.doc.mjs +5 -5
  186. package/assets/docs/tree/install-once.doc.mjs +105 -0
  187. package/assets/docs/tree/integrations.doc.mjs +13 -1
  188. package/assets/docs/tree/layout-spacing.doc.mjs +2 -3
  189. package/assets/docs/tree/layout.doc.mjs +6 -6
  190. package/assets/docs/tree/links.doc.mjs +7 -6
  191. package/assets/docs/tree/migration-setup.doc.mjs +3 -2
  192. package/assets/docs/tree/migration-verification.doc.mjs +0 -1
  193. package/assets/docs/tree/migration.doc.mjs +0 -1
  194. package/assets/docs/tree/monorepos.doc.mjs +84 -0
  195. package/assets/docs/tree/package-and-test.doc.mjs +1 -1
  196. package/assets/docs/tree/page-template.doc.mjs +4 -8
  197. package/assets/docs/tree/problems.doc.mjs +205 -0
  198. package/assets/docs/tree/project-global-or-both.doc.mjs +131 -0
  199. package/assets/docs/tree/publishing.doc.mjs +6 -6
  200. package/assets/docs/tree/quick-start.doc.mjs +53 -27
  201. package/assets/docs/tree/reference.doc.mjs +192 -0
  202. package/assets/docs/tree/replace-a-core-component.doc.mjs +15 -7
  203. package/assets/docs/tree/replace-a-core-template.doc.mjs +10 -12
  204. package/assets/docs/tree/scaffold.doc.mjs +1 -1
  205. package/assets/docs/tree/sections-and-placement.doc.mjs +9 -11
  206. package/assets/docs/tree/see-it-in-an-app.doc.mjs +17 -5
  207. package/assets/docs/tree/short-and-findable.doc.mjs +9 -8
  208. package/assets/docs/tree/single-component.doc.mjs +15 -6
  209. package/assets/docs/tree/start-a-template.doc.mjs +18 -8
  210. package/assets/docs/tree/subcomponent.doc.mjs +6 -6
  211. package/assets/docs/tree/template-assets.doc.mjs +2 -2
  212. package/assets/docs/tree/template-doc-overview.doc.mjs +6 -17
  213. package/assets/docs/tree/template-fonts.doc.mjs +1 -1
  214. package/assets/docs/tree/template-icons.doc.mjs +1 -1
  215. package/assets/docs/tree/template-images-media.doc.mjs +1 -1
  216. package/assets/docs/tree/template-styles.doc.mjs +2 -2
  217. package/assets/docs/tree/templates.doc.mjs +7 -1
  218. package/assets/docs/tree/test-in-an-app.doc.mjs +7 -7
  219. package/assets/docs/tree/test-template-in-app.doc.mjs +5 -5
  220. package/assets/docs/tree/themes.doc.mjs +4 -0
  221. package/assets/docs/tree/tokens-and-setup.doc.mjs +19 -15
  222. package/assets/docs/tree/troubleshooting.doc.mjs +29 -13
  223. package/assets/docs/tree/type-scale.doc.mjs +3 -3
  224. package/assets/docs/tree/uninstall.doc.mjs +109 -0
  225. package/assets/docs/tree/updates.doc.mjs +92 -0
  226. package/assets/docs/tree/upgrading.doc.mjs +6 -6
  227. package/assets/docs/tree/use-a-theme-in-an-app.doc.mjs +14 -2
  228. package/assets/docs/tree/verify-packed-template.doc.mjs +3 -3
  229. package/assets/docs/tree/versioning.doc.mjs +10 -9
  230. package/assets/docs/tree/who-answers.doc.mjs +119 -0
  231. package/assets/docs/tree/write-the-template-file.doc.mjs +7 -6
  232. package/assets/docs/use-a-theme.doc.mjs +2 -2
  233. package/assets/docs/working-with-ai.doc.mjs +66 -13
  234. package/assets/theme.template.ts +1 -1
  235. package/authoring/codemod/codemod.doc.mjs +7 -3
  236. package/authoring/config/config.doc.mjs +9 -6
  237. package/authoring/config/type.ts +4 -2
  238. package/authoring/debug/parse.d.mts +5 -5
  239. package/authoring/discover/discover.doc.mjs +7 -1
  240. package/authoring/doctypes/_schema.d.mts +8 -3
  241. package/authoring/doctypes/_schema.mjs +1 -0
  242. package/authoring/doctypes/base/graph-fields.doc.mjs +6 -4
  243. package/authoring/doctypes/command/command.doc.mjs +20 -12
  244. package/authoring/doctypes/command/type.ts +14 -0
  245. package/authoring/doctypes/component/component.doc.mjs +30 -27
  246. package/authoring/doctypes/component/type.ts +21 -8
  247. package/authoring/doctypes/enum/enum.doc.mjs +7 -4
  248. package/authoring/doctypes/function/function.doc.mjs +9 -8
  249. package/authoring/doctypes/hook/hook.doc.mjs +5 -4
  250. package/authoring/doctypes/hook/type.ts +4 -0
  251. package/authoring/doctypes/namespace/namespace.doc.mjs +7 -6
  252. package/authoring/doctypes/reference/reference.doc.mjs +12 -11
  253. package/authoring/doctypes/schema/schema.doc.mjs +9 -9
  254. package/authoring/doctypes/template/integration-template.doc.d.mts +11 -0
  255. package/authoring/doctypes/template/integration-template.doc.mjs +49 -0
  256. package/authoring/doctypes/template/parse.d.mts +6 -2
  257. package/authoring/doctypes/template/parse.mjs +3 -1
  258. package/authoring/doctypes/template/template.doc.mjs +3 -3
  259. package/authoring/doctypes/template/type.ts +22 -0
  260. package/authoring/doctypes/theme/theme.doc.mjs +2 -2
  261. package/authoring/gap-report/gap-report.doc.mjs +2 -2
  262. package/authoring/identity/identity.doc.mjs +3 -3
  263. package/authoring/index.d.ts +2 -0
  264. package/authoring/integration/integration.doc.mjs +30 -6
  265. package/authoring/integration/parse.test.mjs +21 -0
  266. package/authoring/integration/schema.d.mts +16 -3
  267. package/authoring/integration/schema.mjs +34 -2
  268. package/authoring/integration/type.ts +12 -0
  269. package/clients/cli/bin/astryx.mjs +20 -3
  270. package/clients/cli/cli-command.test.mjs +166 -0
  271. package/clients/cli/commands/blog.doc.mjs +1 -0
  272. package/clients/cli/commands/build-theme.batch-report.test.mjs +17 -3
  273. package/clients/cli/commands/build-theme.font-warning.test.mjs +3 -3
  274. package/clients/cli/commands/build-theme.mjs +26 -13
  275. package/clients/cli/commands/build-theme.path-safety.test.mjs +224 -6
  276. package/clients/cli/commands/build-theme.registry.test.mjs +5 -2
  277. package/clients/cli/commands/build.doc.mjs +1 -0
  278. package/clients/cli/commands/build.exit-codes-doc.test.mjs +4 -0
  279. package/clients/cli/commands/cli-postinstall.test.mjs +49 -1
  280. package/clients/cli/commands/component.doc.mjs +1 -0
  281. package/clients/cli/commands/discover.broken-integration.test.mjs +11 -7
  282. package/clients/cli/commands/discover.doc.mjs +9 -1
  283. package/clients/cli/commands/discover.mjs +144 -93
  284. package/clients/cli/commands/discover.no-source.test.mjs +448 -33
  285. package/clients/cli/commands/discover.sources.test.mjs +20 -1
  286. package/clients/cli/commands/docs.doc.mjs +1 -0
  287. package/clients/cli/commands/docs.mjs +49 -19
  288. package/clients/cli/commands/docs.test.mjs +2 -2
  289. package/clients/cli/commands/doctor-integration-components.doc.mjs +19 -4
  290. package/clients/cli/commands/doctor-integration-docs.doc.mjs +20 -5
  291. package/clients/cli/commands/doctor-integration-templates.doc.mjs +1 -0
  292. package/clients/cli/commands/doctor-integration-validate.doc.mjs +22 -2
  293. package/clients/cli/commands/doctor-integration.test.mjs +888 -3
  294. package/clients/cli/commands/doctor.doc.mjs +12 -2
  295. package/clients/cli/commands/doctor.mjs +292 -7
  296. package/clients/cli/commands/doctor.test.mjs +10 -4
  297. package/clients/cli/commands/gap-report.doc.mjs +15 -2
  298. package/clients/cli/commands/gap-report.mjs +24 -2
  299. package/clients/cli/commands/gap-report.test.mjs +79 -0
  300. package/clients/cli/commands/hook.doc.mjs +1 -0
  301. package/clients/cli/commands/init.behavior.test.mjs +5 -0
  302. package/clients/cli/commands/init.doc.mjs +29 -3
  303. package/clients/cli/commands/integration-add.doc.mjs +7 -0
  304. package/clients/cli/commands/integration-authoring.test.mjs +49 -3
  305. package/clients/cli/commands/integration-check.doc.mjs +93 -0
  306. package/clients/cli/commands/integration-check.test.mjs +441 -0
  307. package/clients/cli/commands/integration-pack.doc.mjs +8 -1
  308. package/clients/cli/commands/integration-verify.doc.mjs +8 -1
  309. package/clients/cli/commands/integration.doc.mjs +6 -2
  310. package/clients/cli/commands/integration.mjs +119 -7
  311. package/clients/cli/commands/json-contract.test.mjs +11 -2
  312. package/clients/cli/commands/manifest.doc.mjs +1 -0
  313. package/clients/cli/commands/outside-project.test.mjs +774 -0
  314. package/clients/cli/commands/search.doc.mjs +1 -0
  315. package/clients/cli/commands/search.mjs +16 -11
  316. package/clients/cli/commands/search.test.mjs +429 -296
  317. package/clients/cli/commands/setup-nudge.test.mjs +102 -2
  318. package/clients/cli/commands/swizzle.doc.mjs +7 -0
  319. package/clients/cli/commands/swizzle.mjs +5 -3
  320. package/clients/cli/commands/swizzle.routing.test.mjs +19 -2
  321. package/clients/cli/commands/template.doc.mjs +1 -0
  322. package/clients/cli/commands/text-json-parity.test.mjs +5 -0
  323. package/clients/cli/commands/theme-add-lifecycle.test.mjs +3 -3
  324. package/clients/cli/commands/theme-add.doc.mjs +8 -1
  325. package/clients/cli/commands/theme-build.doc.mjs +3 -2
  326. package/clients/cli/commands/theme-eject.doc.mjs +1 -0
  327. package/clients/cli/commands/theme-list.behavior.test.mjs +6 -0
  328. package/clients/cli/commands/theme-list.doc.mjs +1 -0
  329. package/clients/cli/commands/theme-palette-generate.doc.mjs +1 -0
  330. package/clients/cli/commands/theme-remove.doc.mjs +7 -0
  331. package/clients/cli/commands/theme-targets.doc.mjs +1 -0
  332. package/clients/cli/commands/theme-template.doc.mjs +1 -0
  333. package/clients/cli/commands/theme-use.doc.mjs +7 -0
  334. package/clients/cli/commands/upgrade.config-ordering.test.mjs +2 -1
  335. package/clients/cli/commands/upgrade.doc.mjs +22 -1
  336. package/clients/cli/commands/upgrade.file-protection.test.mjs +3 -2
  337. package/clients/cli/commands/upgrade.hook-output.test.mjs +2 -1
  338. package/clients/cli/commands/upgrade.older-cli.test.mjs +160 -0
  339. package/clients/cli/index.mjs +112 -16
  340. package/clients/cli/lib/cli-error.mjs +4 -1
  341. package/clients/cli/lib/component-format.test.mjs +1 -1
  342. package/clients/cli/lib/define-command.mjs +2 -2
  343. package/clients/cli/lib/json-shim.mjs +3 -1
  344. package/clients/cli/lib/manifest.d.ts +9 -0
  345. package/clients/cli/lib/manifest.mjs +17 -1
  346. package/clients/cli/lib/manifest.test.mjs +25 -0
  347. package/foundation/agent-docs/agent-doc-state.d.mts +35 -6
  348. package/foundation/agent-docs/agent-doc-state.mjs +66 -6
  349. package/foundation/agent-docs/agent-docs.d.mts +4 -3
  350. package/foundation/agent-docs/agent-docs.mjs +11 -9
  351. package/foundation/agent-docs/computer-agent-text.d.mts +133 -0
  352. package/foundation/agent-docs/computer-agent-text.mjs +623 -0
  353. package/foundation/agent-docs/computer-agent-text.test.mjs +602 -0
  354. package/foundation/config/project.d.mts +35 -3
  355. package/foundation/config/project.mjs +226 -7
  356. package/foundation/config/project.test.mjs +66 -0
  357. package/foundation/config/theme-state.mjs +5 -4
  358. package/foundation/discovery/authoring-self-docs.mjs +2 -1
  359. package/foundation/discovery/cli-self-docs.mjs +20 -3
  360. package/foundation/discovery/cli-self-docs.test.mjs +3 -2
  361. package/foundation/discovery/component-discovery.d.mts +190 -10
  362. package/foundation/discovery/component-discovery.export-names.test.mjs +760 -0
  363. package/foundation/discovery/component-discovery.mjs +864 -56
  364. package/foundation/discovery/component-discovery.test.mjs +96 -0
  365. package/foundation/discovery/component-replacement.mjs +20 -1
  366. package/foundation/discovery/component-replacement.test.mjs +40 -0
  367. package/foundation/discovery/copied-passages.d.mts +216 -0
  368. package/foundation/discovery/copied-passages.mjs +720 -0
  369. package/foundation/discovery/copied-passages.test.mjs +124 -0
  370. package/foundation/discovery/doc-consistency.d.mts +34 -0
  371. package/foundation/discovery/doc-consistency.mjs +513 -0
  372. package/foundation/discovery/doc-consistency.test.mjs +347 -0
  373. package/foundation/discovery/doc-fluff.d.mts +112 -0
  374. package/foundation/discovery/doc-fluff.mjs +328 -0
  375. package/foundation/discovery/doc-fluff.test.mjs +142 -0
  376. package/foundation/discovery/doc-types.d.mts +157 -0
  377. package/foundation/discovery/doc-types.mjs +1231 -0
  378. package/foundation/discovery/doc-types.test.mjs +744 -0
  379. package/foundation/discovery/docs-discovery.d.mts +88 -0
  380. package/foundation/discovery/docs-discovery.mjs +83 -2
  381. package/foundation/discovery/integration-doc-files.d.mts +22 -0
  382. package/foundation/discovery/integration-doc-files.mjs +231 -0
  383. package/foundation/discovery/integration-doc-files.test.mjs +246 -0
  384. package/foundation/discovery/module-exports.d.mts +27 -0
  385. package/foundation/discovery/module-exports.mjs +356 -31
  386. package/foundation/discovery/module-exports.test.mjs +172 -0
  387. package/foundation/discovery/package-tsconfig.d.mts +14 -0
  388. package/foundation/discovery/package-tsconfig.mjs +228 -0
  389. package/foundation/discovery/package-tsconfig.test.mjs +210 -0
  390. package/foundation/discovery/project-typescript.d.mts +32 -0
  391. package/foundation/discovery/project-typescript.mjs +89 -0
  392. package/foundation/discovery/prop-drift.d.mts +297 -0
  393. package/foundation/discovery/prop-drift.mjs +2428 -0
  394. package/foundation/discovery/prop-drift.test.mjs +2337 -0
  395. package/foundation/discovery/runner-allowlist.d.mts +40 -0
  396. package/foundation/discovery/runner-allowlist.mjs +53 -0
  397. package/foundation/discovery/stray-pointers.d.mts +52 -0
  398. package/foundation/discovery/stray-pointers.mjs +293 -0
  399. package/foundation/discovery/stray-pointers.test.mjs +86 -0
  400. package/foundation/discovery/template-adapter.mjs +74 -5
  401. package/foundation/discovery/template-needs.mjs +5 -2
  402. package/foundation/discovery/theme-imports.mjs +8 -4
  403. package/foundation/discovery/theme-imports.test.mjs +1 -1
  404. package/foundation/discovery/type-match.d.mts +53 -0
  405. package/foundation/discovery/type-match.mjs +660 -0
  406. package/foundation/discovery/type-match.test.mjs +169 -0
  407. package/foundation/discovery/type-text.d.mts +68 -0
  408. package/foundation/discovery/type-text.mjs +658 -0
  409. package/foundation/discovery/type-text.test.mjs +196 -0
  410. package/foundation/discovery/unresolved-references.d.mts +62 -0
  411. package/foundation/discovery/unresolved-references.mjs +790 -0
  412. package/foundation/discovery/unresolved-references.test.mjs +567 -0
  413. package/foundation/doc-compiler/doc-loads.test.mjs +51 -1
  414. package/foundation/doc-compiler/inputs.mjs +27 -1
  415. package/foundation/doc-compiler/inputs.test.mjs +0 -1
  416. package/foundation/doc-compiler/links.d.mts +41 -5
  417. package/foundation/doc-compiler/links.mjs +167 -28
  418. package/foundation/doc-compiler/links.test.mjs +97 -4
  419. package/foundation/doc-compiler/read.d.mts +1 -1
  420. package/foundation/doc-compiler/tree.mjs +30 -1
  421. package/foundation/doc-compiler/tree.test.mjs +8 -1
  422. package/foundation/env/cli-command.d.mts +83 -0
  423. package/foundation/env/cli-command.mjs +152 -0
  424. package/foundation/env/cli-command.test.mjs +129 -0
  425. package/foundation/env/node-version.test.mjs +15 -3
  426. package/foundation/env/package-manager.d.mts +93 -9
  427. package/foundation/env/package-manager.global.test.mjs +66 -0
  428. package/foundation/env/package-manager.mjs +184 -13
  429. package/foundation/env/package-manager.test.mjs +341 -15
  430. package/foundation/env/project-scope.d.mts +9 -0
  431. package/foundation/env/project-scope.mjs +33 -0
  432. package/foundation/env/search-path.d.mts +42 -0
  433. package/foundation/env/search-path.mjs +205 -0
  434. package/foundation/env/search-path.test.mjs +122 -0
  435. package/foundation/env/user-dirs.d.mts +39 -0
  436. package/foundation/env/user-dirs.mjs +93 -0
  437. package/foundation/env/user-dirs.test.mjs +72 -0
  438. package/foundation/env/user-settings.d.mts +46 -0
  439. package/foundation/env/user-settings.mjs +106 -0
  440. package/foundation/env/user-settings.test.mjs +64 -0
  441. package/foundation/fs/file-protection.mjs +15 -1
  442. package/foundation/fs/module-loader.d.mts +2 -1
  443. package/foundation/fs/module-loader.mjs +60 -4
  444. package/foundation/fs/module-loader.stdout.test.mjs +3 -2
  445. package/foundation/fs/module-loader.test.mjs +194 -0
  446. package/foundation/fs/path-compare.d.mts +33 -0
  447. package/foundation/fs/path-compare.mjs +73 -0
  448. package/foundation/fs/paths.d.mts +57 -1
  449. package/foundation/fs/paths.mjs +131 -3
  450. package/foundation/fs/paths.test.mjs +10 -1
  451. package/foundation/integrations/computer-integrations.d.mts +78 -0
  452. package/foundation/integrations/computer-integrations.mjs +316 -0
  453. package/foundation/integrations/computer-integrations.test.mjs +292 -0
  454. package/foundation/integrations/contribution-inventory.d.mts +11 -0
  455. package/foundation/integrations/contribution-inventory.mjs +56 -3
  456. package/foundation/integrations/integration-warnings.mjs +3 -2
  457. package/foundation/integrations/integration-warnings.test.mjs +8 -9
  458. package/foundation/integrations/integrations.d.mts +25 -1
  459. package/foundation/integrations/integrations.mjs +46 -3
  460. package/foundation/integrations/issue.ts +6 -0
  461. package/foundation/integrations/validate-contributions.d.mts +2 -0
  462. package/foundation/integrations/validate-contributions.mjs +41 -1
  463. package/foundation/release/agent-text-worker.d.mts +4 -0
  464. package/foundation/release/agent-text-worker.mjs +52 -0
  465. package/foundation/release/cache.d.mts +310 -0
  466. package/foundation/release/cache.mjs +1216 -0
  467. package/foundation/release/cache.test.mjs +920 -0
  468. package/foundation/release/choose.d.mts +207 -0
  469. package/foundation/release/choose.mjs +677 -0
  470. package/foundation/release/choose.test.mjs +427 -0
  471. package/foundation/release/core-worker.d.mts +4 -0
  472. package/foundation/release/core-worker.mjs +38 -0
  473. package/foundation/release/global-state.d.mts +259 -0
  474. package/foundation/release/global-state.mjs +472 -0
  475. package/foundation/release/global-state.test.mjs +381 -0
  476. package/foundation/release/handoff.d.mts +60 -0
  477. package/foundation/release/handoff.e2e.test.mjs +278 -0
  478. package/foundation/release/handoff.mjs +357 -0
  479. package/foundation/release/lock-lease.d.mts +23 -0
  480. package/foundation/release/lock-lease.mjs +80 -0
  481. package/foundation/release/notices.d.mts +253 -0
  482. package/foundation/release/notices.mjs +596 -0
  483. package/foundation/release/notices.test.mjs +565 -0
  484. package/foundation/release/npm-guard.d.mts +4 -0
  485. package/foundation/release/npm-guard.mjs +126 -0
  486. package/foundation/release/project.d.mts +141 -0
  487. package/foundation/release/project.mjs +466 -0
  488. package/foundation/release/project.test.mjs +288 -0
  489. package/foundation/release/refresh-worker.d.mts +4 -0
  490. package/foundation/release/refresh-worker.mjs +27 -0
  491. package/foundation/release/run-context.d.mts +47 -0
  492. package/foundation/release/run-context.mjs +149 -0
  493. package/foundation/release/update-notice-env.d.mts +28 -0
  494. package/foundation/release/update-notice-env.mjs +39 -0
  495. package/foundation/response/base.d.ts +26 -3
  496. package/foundation/response/error-codes.d.mts +3 -1
  497. package/foundation/response/error-codes.doc.mjs +12 -0
  498. package/foundation/response/error-codes.mjs +17 -0
  499. package/foundation/response/error-codes.test.mjs +2 -0
  500. package/foundation/response/json-contract.test.mjs +7 -2
  501. package/foundation/response/json.mjs +4 -1
  502. package/foundation/response/response-types.doc.mjs +22 -11
  503. package/foundation/response/response-types.doc.test.mjs +46 -0
  504. package/foundation/response/response.doc.mjs +3 -3
  505. package/foundation/xle/browser-imports.test.mjs +74 -0
  506. package/foundation/xle/registry.mjs +4 -0
  507. package/foundation/xle/registry.test.mjs +28 -0
  508. package/package.json +11 -11
  509. package/scripts/postinstall.mjs +24 -5
@@ -0,0 +1,328 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * Fluff in docs: padding phrases that add words and no meaning, and guides
5
+ * whose prose is mostly function words. Docs are read by people and agents
6
+ * with a budget, so every word should carry something.
7
+ *
8
+ * Only prose is read (the same strings copied passages compare), and inline
9
+ * code and quoted text are set aside, so a phrase inside a command, or one
10
+ * quoted as an example, never counts.
11
+ */
12
+
13
+ import fs from 'node:fs';
14
+
15
+ import {builtinGuideFiles} from './docs-discovery.mjs';
16
+ import {
17
+ contentWords,
18
+ fileWords,
19
+ lineAtOffset,
20
+ locateWords,
21
+ loadQuietly,
22
+ proseStrings,
23
+ passageWords,
24
+ textWords,
25
+ } from './copied-passages.mjs';
26
+
27
+ /**
28
+ * Padding phrases: each can be cut, or replaced by a shorter word, without
29
+ * losing meaning. Only phrases that are padding in every use are listed;
30
+ * words such as "just", "simply" or "really", and phrases such as "whether or
31
+ * not" or "keep in mind", which carry meaning in a correct sentence ("not
32
+ * simply a wrapper", "regardless of whether"), are not.
33
+ */
34
+ export const FILLER_PHRASES = [
35
+ "it's important to note",
36
+ 'it is important to note',
37
+ 'important to note that',
38
+ "it's worth noting",
39
+ 'it is worth noting',
40
+ 'worth noting that',
41
+ 'it should be noted',
42
+ 'please note',
43
+ 'note that',
44
+ 'as mentioned above',
45
+ 'as mentioned earlier',
46
+ 'as mentioned before',
47
+ 'as noted above',
48
+ 'as you can see',
49
+ 'needless to say',
50
+ 'in order to',
51
+ 'due to the fact that',
52
+ 'for the purpose of',
53
+ 'at this point in time',
54
+ 'in other words',
55
+ 'basically',
56
+ 'essentially',
57
+ 'obviously',
58
+ ];
59
+
60
+ /** What to write instead, where a phrase is not simply cut. */
61
+ const INSTEAD = {
62
+ 'in order to': 'to',
63
+ 'due to the fact that': 'because',
64
+ 'for the purpose of': 'to or for',
65
+ 'at this point in time': 'now',
66
+ };
67
+
68
+ /** A guide shorter than this many prose words is not scored for density. */
69
+ export const DENSITY_MIN_WORDS = 80;
70
+
71
+ /**
72
+ * A guide whose share of content words is below this is mostly glue. Core's
73
+ * own guides score from about 0.51 up, with a median near 0.62.
74
+ */
75
+ export const MIN_DENSITY = 0.5;
76
+
77
+ /**
78
+ * @param {string} phrase
79
+ * @returns {RegExp}
80
+ */
81
+ function phrasePattern(phrase) {
82
+ const escaped = phrase.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
83
+ // "note that" is padding as a sentence opener ("Note that X"), not inside
84
+ // one ("a note that explains").
85
+ return phrase === 'note that'
86
+ ? new RegExp(`(?:^|[.;:!?]\\s+)${escaped}\\b`, 'gi')
87
+ : // A hyphen joins words ("non-obviously"), so it bounds no phrase.
88
+ new RegExp(`(?<![a-z'-])${escaped}(?![a-z-])`, 'gi');
89
+ }
90
+
91
+ const PATTERNS = FILLER_PHRASES.map(phrase => ({
92
+ phrase,
93
+ pattern: phrasePattern(phrase),
94
+ }));
95
+
96
+ /**
97
+ * A prose string with what is not prose blanked out, length kept: `{@link}`
98
+ * pointers, inline code, and quoted text. A quoted phrase is mentioned, not
99
+ * used ("cut 'in order to'").
100
+ *
101
+ * @param {string} text
102
+ * @returns {string}
103
+ */
104
+ export function maskProse(text) {
105
+ // A quoted phrase is mentioned, not used ("cut 'in order to'"), so quotes
106
+ // are set aside along with inline code. Each mask keeps the text's length,
107
+ // so an offset in the masked text is an offset in the text.
108
+ const blank = (/** @type {string} */ span) => ' '.repeat(span.length);
109
+ return (
110
+ text
111
+ // A pointer names a doc, and its target is no prose ("{@link
112
+ // generic:obviously-fast}").
113
+ .replace(/\{@link\s[^}]*\}/g, blank)
114
+ .replace(/`[^`]*`/g, blank)
115
+ .replace(/"[^"]*"|“[^”]*”|‘[^’]*’/g, blank)
116
+ .replace(/’/g, "'")
117
+ // A single-quoted span opens and closes beside a non-letter, so the
118
+ // apostrophe in "don't" or "it's" opens nothing.
119
+ .replace(/(?<![A-Za-z])'[^']*'(?![A-Za-z])/g, blank)
120
+ );
121
+ }
122
+
123
+ /**
124
+ * Each padding phrase in a text, outside inline code and quotes, in order,
125
+ * with its offset in the text.
126
+ *
127
+ * `thatAfter` is true when the phrase is followed by a "that" a reader cuts
128
+ * with it ("It is worth noting that the cache is shared").
129
+ *
130
+ * @param {string} text
131
+ * @returns {{phrase: string, at: number, thatAfter: boolean}[]}
132
+ */
133
+ export function fillerAt(text) {
134
+ const prose = maskProse(text);
135
+ /** @type {{phrase: string, at: number, thatAfter: boolean}[]} */
136
+ const found = [];
137
+ for (const {phrase, pattern} of PATTERNS) {
138
+ for (const match of prose.matchAll(pattern)) {
139
+ // A phrase inside a longer listed one ("note that" in "worth noting
140
+ // that") is the longer one's.
141
+ const at = match.index + match[0].toLowerCase().indexOf(phrase);
142
+ if (
143
+ !found.some(each => at >= each.at && at < each.at + each.phrase.length)
144
+ ) {
145
+ found.push({
146
+ phrase,
147
+ at,
148
+ // Only a phrase that ends in note or noting leads into a "that"
149
+ // clause the reader cuts with it; "Obviously that works" and "As
150
+ // noted above that flag" keep their "that".
151
+ thatAfter:
152
+ /\bnot(?:e|ed|ing)$/.test(phrase) &&
153
+ !phrase.endsWith('that') &&
154
+ /^\s+that\b/i.test(prose.slice(at + phrase.length)),
155
+ });
156
+ }
157
+ }
158
+ }
159
+ return found.sort((a, b) => a.at - b.at);
160
+ }
161
+
162
+ /**
163
+ * Each padding phrase in a text, outside inline code and quotes, in order.
164
+ *
165
+ * @param {string} text
166
+ * @returns {string[]}
167
+ */
168
+ export function fillerIn(text) {
169
+ return fillerAt(text).map(each => each.phrase);
170
+ }
171
+
172
+ /**
173
+ * The share of a doc's prose words that are content words.
174
+ *
175
+ * @param {{word: string}[]} words
176
+ * @returns {number}
177
+ */
178
+ export function density(words) {
179
+ if (words.length === 0) return 1;
180
+ let content = 0;
181
+ for (let i = 0; i < words.length; i++) {
182
+ if (contentWords(words, i, 1) === 1) content++;
183
+ }
184
+ return content / words.length;
185
+ }
186
+
187
+ /**
188
+ * A number rounded down to `places` decimals, so a share under the floor
189
+ * never reads as the floor.
190
+ *
191
+ * @param {number} value
192
+ * @param {number} places
193
+ * @returns {number}
194
+ */
195
+ export function floorTo(value, places) {
196
+ const scale = 10 ** places;
197
+ return Math.floor(value * scale + 1e-9) / scale;
198
+ }
199
+
200
+ /**
201
+ * A share as a percent with one decimal, rounded down ("49.5%").
202
+ *
203
+ * @param {number} share
204
+ * @returns {string}
205
+ */
206
+ export function sharePercent(share) {
207
+ return `${floorTo(share * 100, 1).toFixed(1)}%`;
208
+ }
209
+
210
+ /**
211
+ * The words a topic's density is measured on: its prose, without what the
212
+ * phrase check also leaves unread (links, inline code, quoted text).
213
+ *
214
+ * @param {unknown} doc
215
+ * @returns {{word: string}[]}
216
+ */
217
+ export function densityWords(doc) {
218
+ return proseStrings(doc).flatMap(({text}) =>
219
+ passageWords(maskProse(text)).map(word => ({word})),
220
+ );
221
+ }
222
+
223
+ /**
224
+ * The median density of Core's own guides of at least
225
+ * {@link DENSITY_MIN_WORDS} words.
226
+ *
227
+ * @returns {Promise<number>}
228
+ */
229
+ export async function coreDensityMedian() {
230
+ // Core's guides are measured the way a package's topics are.
231
+ /** @type {number[]} */
232
+ const scores = [];
233
+ for (const file of builtinGuideFiles()) {
234
+ const doc = await loadQuietly(file);
235
+ if (typeof doc?.name !== 'string') continue;
236
+ const words = densityWords(doc);
237
+ if (words.length >= DENSITY_MIN_WORDS) scores.push(density(words));
238
+ }
239
+ scores.sort((a, b) => a - b);
240
+ return scores.length === 0 ? 0 : scores[Math.floor(scores.length / 2)];
241
+ }
242
+
243
+ /**
244
+ * Fluff in a package's topics: every padding phrase, with its section and
245
+ * file line, and every topic of at least {@link DENSITY_MIN_WORDS} words
246
+ * whose density is below {@link MIN_DENSITY}.
247
+ *
248
+ * @param {{records: {name: string, path: string}[], guides?: {name: string, ref?: {topicFile?: string}}[]}} discovered
249
+ * the package's docs, as discoverIntegrationDocs returns them
250
+ * @returns {Promise<import('../../api/integration/authoring-checks.type.mjs').DocFluff[]>}
251
+ */
252
+ export async function findFluff(discovered) {
253
+ const topics = [
254
+ ...discovered.records.map(record => ({
255
+ name: record.name,
256
+ file: record.path,
257
+ })),
258
+ ...(discovered.guides ?? []).map(guide => ({
259
+ name: guide.name,
260
+ file: guide.ref?.topicFile,
261
+ })),
262
+ ];
263
+ /** @type {import('../../api/integration/authoring-checks.type.mjs').DocFluff[]} */
264
+ const found = [];
265
+ /** @type {number | null} */
266
+ let median = null;
267
+ for (const {name, file} of topics) {
268
+ const doc = file ? await loadQuietly(file) : null;
269
+ if (!doc || !file) continue;
270
+ /** @type {{word: string, line: number}[]} */
271
+ let source = [];
272
+ try {
273
+ source = fileWords(fs.readFileSync(file, 'utf8'));
274
+ } catch {
275
+ // No line numbers; each finding still names its section.
276
+ }
277
+ // Each string is found by its whole run of words, from where the last
278
+ // one was found, so two strings that open alike keep their own lines.
279
+ let cursor = 0;
280
+ for (const {text, section} of proseStrings(doc)) {
281
+ const words = textWords(text);
282
+ let index = locateWords(source, words, cursor);
283
+ if (index < 0) index = locateWords(source, words);
284
+ if (index >= 0) cursor = index + words.length;
285
+ for (const {phrase, at, thatAfter} of fillerAt(text)) {
286
+ const line = index < 0 ? null : lineAtOffset(source, index, words, at);
287
+ const where = section ? ` (section "${section}")` : '';
288
+ const instead = /** @type {Record<string, string>} */ (INSTEAD)[phrase];
289
+ found.push({
290
+ topic: name,
291
+ kind: 'phrase',
292
+ phrase,
293
+ section,
294
+ file,
295
+ line,
296
+ density: null,
297
+ message:
298
+ `"${name}"${where} pads its prose with "${phrase}"` +
299
+ `${line == null ? '' : ` (line ${line})`}. ` +
300
+ (instead
301
+ ? `Write "${instead}" instead.`
302
+ : thatAfter
303
+ ? 'Cut it and the "that" after it; the sentence says the same without them.'
304
+ : 'Cut it; the sentence says the same without it.'),
305
+ });
306
+ }
307
+ }
308
+ const words = densityWords(doc);
309
+ if (words.length < DENSITY_MIN_WORDS) continue;
310
+ const score = density(words);
311
+ if (score >= MIN_DENSITY) continue;
312
+ median ??= await coreDensityMedian();
313
+ found.push({
314
+ topic: name,
315
+ kind: 'density',
316
+ phrase: null,
317
+ section: null,
318
+ file,
319
+ line: null,
320
+ density: floorTo(score, 3),
321
+ message:
322
+ `"${name}" is mostly glue: ${sharePercent(score)} of its ${words.length} prose words carry content, ` +
323
+ `under the ${Math.round(MIN_DENSITY * 100)}% floor (Core's guides have a median of ${Math.round(median * 100)}%). ` +
324
+ 'Cut filler and restated context until each sentence states one thing.',
325
+ });
326
+ }
327
+ return found;
328
+ }
@@ -0,0 +1,142 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ import {describe, expect, it} from 'vitest';
4
+
5
+ import {
6
+ density,
7
+ densityWords,
8
+ fillerAt,
9
+ fillerIn,
10
+ floorTo,
11
+ sharePercent,
12
+ } from './doc-fluff.mjs';
13
+ import {passageWords} from './copied-passages.mjs';
14
+
15
+ const words = (/** @type {string} */ text) =>
16
+ passageWords(text).map(word => ({word}));
17
+
18
+ describe('fillerIn', () => {
19
+ it('finds padding phrases in order, the longest one only', () => {
20
+ expect(
21
+ fillerIn(
22
+ 'In order to start, it is worth noting that you basically run it. Note that it builds.',
23
+ ),
24
+ ).toEqual(['in order to', 'it is worth noting', 'basically', 'note that']);
25
+ });
26
+
27
+ it('leaves inline code, quotes, a noun "note", and ambiguous words alone', () => {
28
+ expect(
29
+ fillerIn(
30
+ 'Run `basically --in order to`. Cut "in order to" and “basically”. Add a note that explains it. Copy just this one file; it really is the source.',
31
+ ),
32
+ ).toEqual([]);
33
+ });
34
+
35
+ it('sets aside single-quoted text, but not an apostrophe', () => {
36
+ expect(
37
+ fillerIn(
38
+ "Avoid ‘basically’ and ‘obviously’. Don't write 'it is worth noting that' in a guide.",
39
+ ),
40
+ ).toEqual([]);
41
+ expect(fillerIn("Don't pad: it's important to note the order.")).toEqual([
42
+ "it's important to note",
43
+ ]);
44
+ });
45
+
46
+ it('lists no phrase that carries meaning in a correct sentence', () => {
47
+ expect(
48
+ fillerIn(
49
+ 'It is not simply a wrapper. Every app gets a theme whether or not anyone picks one. Keep in mind the order. Feel free to skip it.',
50
+ ),
51
+ ).toEqual([]);
52
+ });
53
+
54
+ it('reads a curly apostrophe like a straight one', () => {
55
+ expect(fillerIn('It’s important to note the order.')).toEqual([
56
+ "it's important to note",
57
+ ]);
58
+ });
59
+ });
60
+
61
+ describe('fillerAt', () => {
62
+ it('reads no phrase inside a link target or a hyphenated word', () => {
63
+ expect(
64
+ fillerIn(
65
+ 'Read {@link generic:obviously-fast} before you tune the build.',
66
+ ),
67
+ ).toEqual([]);
68
+ expect(fillerIn('A non-obviously slow build still passes.')).toEqual([]);
69
+ expect(fillerIn('It is obviously slow.')).toEqual(['obviously']);
70
+ });
71
+
72
+ it('marks a "that" the reader cuts with the phrase', () => {
73
+ expect(
74
+ fillerAt('It is worth noting that the cache is shared.').map(
75
+ each => each.thatAfter,
76
+ ),
77
+ ).toEqual([true]);
78
+ expect(
79
+ fillerAt('Basically, the cache is shared.').map(each => each.thatAfter),
80
+ ).toEqual([false]);
81
+ // Only a note or noting phrase leads a clause the reader cuts.
82
+ expect(
83
+ fillerAt('Obviously that works only in a browser.').map(
84
+ each => each.thatAfter,
85
+ ),
86
+ ).toEqual([false]);
87
+ expect(
88
+ fillerAt('As noted above that flag is required.').map(
89
+ each => each.thatAfter,
90
+ ),
91
+ ).toEqual([false]);
92
+ });
93
+ });
94
+
95
+ describe('densityWords', () => {
96
+ it('measures prose only, not quoted text, inline code or links', () => {
97
+ const doc = {
98
+ sections: [
99
+ {
100
+ title: 'Overview',
101
+ content: [
102
+ {
103
+ type: 'prose',
104
+ text: 'Theme tokens set colors. Write "it is in the" or `of the` as {@link generic:theme} shows.',
105
+ },
106
+ ],
107
+ },
108
+ ],
109
+ };
110
+ expect(densityWords(doc).map(each => each.word)).toEqual([
111
+ 'theme',
112
+ 'tokens',
113
+ 'set',
114
+ 'colors.',
115
+ 'write',
116
+ 'or',
117
+ 'as',
118
+ 'shows.',
119
+ ]);
120
+ });
121
+ });
122
+
123
+ describe('share rounding', () => {
124
+ it('rounds a share under the floor down, never up to it', () => {
125
+ expect(floorTo(0.4995, 3)).toBe(0.499);
126
+ expect(sharePercent(0.4995)).toBe('49.9%');
127
+ expect(sharePercent(0.5)).toBe('50.0%');
128
+ });
129
+ });
130
+
131
+ describe('density', () => {
132
+ it('scores a padded sentence well below a dense one', () => {
133
+ const padded = words(
134
+ 'So that is why it is the one that you would want to use if you can.',
135
+ );
136
+ const dense = words(
137
+ 'Name each codemod folder after the Core version whose upgrade runs it.',
138
+ );
139
+ expect(density(padded)).toBeLessThan(0.3);
140
+ expect(density(dense)).toBeGreaterThan(0.6);
141
+ });
142
+ });
@@ -0,0 +1,157 @@
1
+ // @generated by scripts/sync-api-types.mjs from the JSDoc in foundation/**/*.mjs.
2
+ // DO NOT EDIT — run `pnpm sync:api-types` to regenerate.
3
+
4
+ /**
5
+ * Check each doc file's values against the published authoring types.
6
+ * @param {DocFile[]} files
7
+ * @param {{packageDir: string, resolveFrom: Array<string | null | undefined>, core?: boolean}} options
8
+ * `core`: the docs are Core's own, so templates are held to TemplateDoc
9
+ * @returns {Promise<DocTypesReport>}
10
+ */
11
+ export function checkDocTypes(files: DocFile[], options: {
12
+ packageDir: string;
13
+ resolveFrom: Array<string | null | undefined>;
14
+ core?: boolean;
15
+ }): Promise<DocTypesReport>;
16
+ /**
17
+ * @typedef {'components' | 'hooks' | 'templates' | 'docs' | 'docs-overlay' | 'themes'} DocRoot
18
+ */
19
+ /**
20
+ * @typedef {object} DocFile
21
+ * @property {string} path absolute path to the doc file
22
+ * @property {DocRoot} root the contribution root it was found in
23
+ */
24
+ /**
25
+ * @typedef {'unknown_field' | 'missing_field' | 'wrong_type'} DocTypeProblem
26
+ */
27
+ /**
28
+ * @typedef {object} DocTypeFinding
29
+ * @property {string} doc the doc file, relative to the package root
30
+ * @property {number} line 1-based line of the field (or of the doc value)
31
+ * @property {string} export the export checked (`default`, `docs`, `docsZh`, …)
32
+ * @property {string} type the authoring type it was checked against
33
+ * @property {string} field the field's path in the doc, such as
34
+ * `usage.bestPractices[2].guidance`; empty for the doc value as a whole
35
+ * @property {DocTypeProblem} problem
36
+ * @property {'warning'} severity
37
+ * @property {string} message what TypeScript reports, shortened
38
+ * @property {string} fix what to change
39
+ */
40
+ /**
41
+ * @typedef {object} DocTypesUnchecked
42
+ * @property {string} doc the doc file, relative to the package root
43
+ * @property {string} reason why it was not checked
44
+ */
45
+ /**
46
+ * @typedef {object} DocTypesReport
47
+ * @property {'checked' | 'skipped'} status `skipped` means nothing was checked,
48
+ * and `reason` says why
49
+ * @property {string} [reason]
50
+ * @property {string} [typescript] the version of the compiler that checked
51
+ * @property {number} docs how many doc values were checked
52
+ * @property {DocTypeFinding[]} findings
53
+ * @property {DocTypesUnchecked[]} unchecked doc files with nothing to check,
54
+ * or not fully checked
55
+ */
56
+ /** The line both surfaces print when the compiler is missing. */
57
+ export const DOC_TYPES_TYPESCRIPT_MISSING_REASON: "TypeScript is not installed in this project, so docs were not checked against the authoring types. On TypeScript 7, add its TypeScript 6 API package (`npm install -D @typescript/typescript6`); otherwise install TypeScript 5.0 through 6 (`npm install -D typescript@6`). Then run this check again.";
58
+ export type DocRoot = "components" | "hooks" | "templates" | "docs" | "docs-overlay" | "themes";
59
+ export type DocFile = {
60
+ /**
61
+ * absolute path to the doc file
62
+ */
63
+ path: string;
64
+ /**
65
+ * the contribution root it was found in
66
+ */
67
+ root: DocRoot;
68
+ };
69
+ export type DocTypeProblem = "unknown_field" | "missing_field" | "wrong_type";
70
+ export type DocTypeFinding = {
71
+ /**
72
+ * the doc file, relative to the package root
73
+ */
74
+ doc: string;
75
+ /**
76
+ * 1-based line of the field (or of the doc value)
77
+ */
78
+ line: number;
79
+ /**
80
+ * the export checked (`default`, `docs`, `docsZh`, …)
81
+ */
82
+ export: string;
83
+ /**
84
+ * the authoring type it was checked against
85
+ */
86
+ type: string;
87
+ /**
88
+ * the field's path in the doc, such as
89
+ * `usage.bestPractices[2].guidance`; empty for the doc value as a whole
90
+ */
91
+ field: string;
92
+ problem: DocTypeProblem;
93
+ severity: "warning";
94
+ /**
95
+ * what TypeScript reports, shortened
96
+ */
97
+ message: string;
98
+ /**
99
+ * what to change
100
+ */
101
+ fix: string;
102
+ };
103
+ export type DocTypesUnchecked = {
104
+ /**
105
+ * the doc file, relative to the package root
106
+ */
107
+ doc: string;
108
+ /**
109
+ * why it was not checked
110
+ */
111
+ reason: string;
112
+ };
113
+ export type DocTypesReport = {
114
+ /**
115
+ * `skipped` means nothing was checked,
116
+ * and `reason` says why
117
+ */
118
+ status: "checked" | "skipped";
119
+ reason?: string | undefined;
120
+ /**
121
+ * the version of the compiler that checked
122
+ */
123
+ typescript?: string | undefined;
124
+ /**
125
+ * how many doc values were checked
126
+ */
127
+ docs: number;
128
+ findings: DocTypeFinding[];
129
+ /**
130
+ * doc files with nothing to check,
131
+ * or not fully checked
132
+ */
133
+ unchecked: DocTypesUnchecked[];
134
+ };
135
+ export type Target = {
136
+ exportName: string;
137
+ /**
138
+ * the doc value's expression
139
+ */
140
+ node: any;
141
+ /**
142
+ * the authoring type, as a type expression
143
+ */
144
+ typeExpr: string;
145
+ /**
146
+ * how findings name that type
147
+ */
148
+ typeName: string;
149
+ /**
150
+ * nodes whose leading JSDoc annotations are blanked
151
+ */
152
+ blank: any[];
153
+ /**
154
+ * source ranges to blank
155
+ */
156
+ blankRanges: Array<[number, number]>;
157
+ };