@astryxdesign/cli 0.7.2-canary.fdd384f → 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.
- package/CHANGELOG.md +119 -0
- package/README.md +169 -149
- package/api/build/_adapter.d.mts +8 -0
- package/api/build/_adapter.mjs +12 -1
- package/api/build/build.doc.mjs +4 -0
- package/api/build/kit/kit.mjs +3 -11
- package/api/component/_adapter.d.mts +31 -0
- package/api/component/_adapter.mjs +119 -11
- package/api/component/component.doc.mjs +6 -1
- package/api/component/component.mjs +60 -10
- package/api/component/doc-links.test.mjs +386 -0
- package/api/discover/_adapter.d.mts +132 -12
- package/api/discover/_adapter.mjs +488 -27
- package/api/discover/_adapter.test.mjs +599 -17
- package/api/discover/_catalog-view.d.mts +16 -5
- package/api/discover/_catalog-view.mjs +32 -8
- package/api/discover/detail/doc/doc.mjs +9 -1
- package/api/discover/discover.d.mts +11 -0
- package/api/discover/discover.doc.mjs +9 -7
- package/api/discover/discover.mjs +121 -19
- package/api/discover/discover.type.d.mts +20 -7
- package/api/discover/discover.type.mjs +17 -7
- package/api/discover/list/list.d.mts +4 -3
- package/api/discover/list/list.mjs +17 -10
- package/api/docs/_adapter.d.mts +63 -0
- package/api/docs/_adapter.mjs +312 -18
- package/api/docs/docs.doc.mjs +2 -1
- package/api/docs/docs.mjs +2 -1
- package/api/docs/docs.test.mjs +5 -2
- package/api/docs/integration-tree.test.mjs +22 -0
- package/api/docs/list/list.mjs +12 -2
- package/api/docs/reference-blocks.test.mjs +1 -3
- package/api/doctor/_adapter.d.mts +108 -0
- package/api/doctor/_adapter.mjs +223 -4
- package/api/doctor/doctor.d.mts +199 -0
- package/api/doctor/doctor.doc.mjs +3 -2
- package/api/doctor/doctor.mjs +530 -34
- package/api/doctor/doctor.test.mjs +180 -14
- package/api/doctor/release-checks.test.mjs +156 -0
- package/api/doctor/theme-checks.mjs +16 -3
- package/api/doctor/theme-checks.test.mjs +223 -7
- package/api/error.d.mts +10 -0
- package/api/error.mjs +25 -0
- package/api/gap-report/gap-report.d.mts +3 -0
- package/api/gap-report/gap-report.doc.mjs +11 -3
- package/api/gap-report/gap-report.mjs +152 -48
- package/api/gap-report/gap-report.test.mjs +233 -0
- package/api/gap-report/gap-report.type.d.mts +41 -0
- package/api/gap-report/gap-report.type.mjs +18 -0
- package/api/hook/_adapter.mjs +3 -11
- package/api/hook/hook.doc.mjs +4 -0
- package/api/hook/list/list.d.mts +1 -1
- package/api/init/_adapter.d.mts +22 -0
- package/api/init/_adapter.mjs +59 -0
- package/api/init/init.d.mts +7 -5
- package/api/init/init.doc.mjs +28 -7
- package/api/init/init.mjs +28 -4
- package/api/init/init.type.d.mts +48 -3
- package/api/init/init.type.mjs +37 -3
- package/api/init/run/run.d.mts +1 -1
- package/api/init/run/run.mjs +15 -4
- package/api/init/user/user.d.mts +14 -0
- package/api/init/user/user.mjs +87 -0
- package/api/init/user/user.test.mjs +232 -0
- package/api/integration/_adapter.d.mts +33 -0
- package/api/integration/_adapter.mjs +58 -0
- package/api/integration/authoring-checks.mjs +100 -5
- package/api/integration/authoring-checks.test.mjs +769 -0
- package/api/integration/authoring-checks.type.d.mts +134 -0
- package/api/integration/authoring-checks.type.mjs +60 -1
- package/api/integration/integrationCheck.doc.mjs +1 -1
- package/api/integration/integrationComponentConflicts.doc.mjs +11 -3
- package/api/integration/integrationDocConflicts.doc.mjs +22 -5
- package/api/integration/pack-check.mjs +303 -13
- package/api/integration/pack-check.test.mjs +371 -10
- package/api/integration/validate-integration-fixes.test.mjs +67 -0
- package/api/integration/validate-integration.d.mts +8 -0
- package/api/integration/validate-integration.mjs +55 -9
- package/api/integration/validate-integration.test.mjs +77 -8
- package/api/integration/validate-integration.type.d.mts +8 -0
- package/api/integration/validate-integration.type.mjs +3 -1
- package/api/integration/validate-unread-theme-folders.test.mjs +3 -2
- package/api/integration/validateIntegration.doc.mjs +4 -2
- package/api/search/_adapter.d.mts +11 -0
- package/api/search/_adapter.mjs +25 -0
- package/api/search/search.d.mts +73 -13
- package/api/search/search.doc.mjs +8 -3
- package/api/search/search.domain-priority.test.mjs +108 -18
- package/api/search/search.mjs +541 -52
- package/api/search/search.test.mjs +143 -1
- package/api/search/search.type.d.mts +14 -1
- package/api/search/search.type.mjs +6 -1
- package/api/swizzle/_adapter.mjs +2 -2
- package/api/swizzle/copy/copy.mjs +1 -1
- package/api/template/template-integration.test.mjs +1 -1
- package/api/theme/_adapter.d.mts +16 -0
- package/api/theme/_adapter.mjs +32 -5
- package/api/theme/build/build.d.mts +2 -1
- package/api/theme/build/build.mjs +70 -14
- package/api/theme/build/build.packed-old-core.test.mjs +20 -3
- package/api/theme/build/font-warning.mjs +5 -3
- package/api/theme/build/font-warning.test.mjs +2 -1
- package/api/theme/remove/remove.test.mjs +2 -2
- package/api/theme/targets/targets.mjs +3 -10
- package/api/theme/themeTargets.doc.mjs +4 -0
- package/api/theme/use/use.test.mjs +1 -1
- package/api/upgrade/_adapter.d.mts +40 -2
- package/api/upgrade/_adapter.mjs +118 -5
- package/api/upgrade/run/cli-behind-core.test.mjs +438 -0
- package/api/upgrade/run/run.mjs +35 -2
- package/api/upgrade/status/status.d.mts +21 -5
- package/api/upgrade/status/status.mjs +45 -8
- package/api/upgrade/upgrade.doc.mjs +6 -3
- package/api/upgrade/upgrade.mjs +5 -1
- package/api/upgrade/upgrade.type.d.mts +23 -0
- package/api/upgrade/upgrade.type.mjs +16 -1
- package/assets/codemods/__tests__/registry.test.mjs +1 -0
- package/assets/codemods/registry.mjs +1 -0
- package/assets/codemods/runner.mjs +7 -1
- package/assets/codemods/transforms/next/index.mjs +1 -11
- package/assets/codemods/transforms/v0.7.2/index.mjs +20 -0
- package/assets/discover/official-packages.json +367 -0
- package/assets/docs/author-a-theme.doc.mjs +2 -2
- package/assets/docs/browser-support.doc.mjs +1 -1
- package/assets/docs/getting-started.doc.mjs +23 -3
- package/assets/docs/styling-overview.doc.mjs +1 -1
- package/assets/docs/theme.doc.mjs +1 -1
- package/assets/docs/tree/add-a-component.doc.mjs +12 -2
- package/assets/docs/tree/add-a-theme.doc.mjs +13 -3
- package/assets/docs/tree/add-a-topic.doc.mjs +54 -9
- package/assets/docs/tree/agent-guidance.doc.mjs +19 -5
- package/assets/docs/tree/block-template.doc.mjs +6 -18
- package/assets/docs/tree/build-the-template.doc.mjs +1 -1
- package/assets/docs/tree/building-blocks.doc.mjs +4 -0
- package/assets/docs/tree/check-the-props.doc.mjs +8 -3
- package/assets/docs/tree/check-your-docs.doc.mjs +30 -13
- package/assets/docs/tree/checks.doc.mjs +17 -17
- package/assets/docs/tree/ci-and-containers.doc.mjs +88 -0
- package/assets/docs/tree/cli-command.doc.mjs +142 -0
- package/assets/docs/tree/cli.doc.mjs +6 -0
- package/assets/docs/tree/codemods.doc.mjs +17 -7
- package/assets/docs/tree/commands.doc.mjs +7 -1
- package/assets/docs/tree/component-family.doc.mjs +3 -5
- package/assets/docs/tree/component-imports.doc.mjs +13 -3
- package/assets/docs/tree/components.doc.mjs +7 -1
- package/assets/docs/tree/computer-agent-guide.doc.mjs +160 -0
- package/assets/docs/tree/computer-integrations.doc.mjs +93 -0
- package/assets/docs/tree/configuration.doc.mjs +7 -3
- package/assets/docs/tree/debug-and-gap-reports.doc.mjs +41 -22
- package/assets/docs/tree/define-the-theme.doc.mjs +6 -5
- package/assets/docs/tree/describe-the-component.doc.mjs +2 -2
- package/assets/docs/tree/docs.doc.mjs +9 -3
- package/assets/docs/tree/document-the-template.doc.mjs +1 -1
- package/assets/docs/tree/document-the-theme.doc.mjs +3 -3
- package/assets/docs/tree/export-template-assets.doc.mjs +1 -1
- package/assets/docs/tree/extend-or-replace.doc.mjs +19 -9
- package/assets/docs/tree/fonts-and-assets.doc.mjs +2 -2
- package/assets/docs/tree/generate-a-palette.doc.mjs +7 -5
- package/assets/docs/tree/global-integrations.doc.mjs +124 -0
- package/assets/docs/tree/global.doc.mjs +131 -0
- package/assets/docs/tree/grade-template-with-agent.doc.mjs +5 -5
- package/assets/docs/tree/install-once.doc.mjs +105 -0
- package/assets/docs/tree/integrations.doc.mjs +13 -1
- package/assets/docs/tree/layout-spacing.doc.mjs +2 -3
- package/assets/docs/tree/layout.doc.mjs +6 -6
- package/assets/docs/tree/links.doc.mjs +6 -5
- package/assets/docs/tree/migration-setup.doc.mjs +3 -2
- package/assets/docs/tree/migration-verification.doc.mjs +0 -1
- package/assets/docs/tree/migration.doc.mjs +0 -1
- package/assets/docs/tree/monorepos.doc.mjs +84 -0
- package/assets/docs/tree/package-and-test.doc.mjs +1 -1
- package/assets/docs/tree/page-template.doc.mjs +3 -7
- package/assets/docs/tree/problems.doc.mjs +205 -0
- package/assets/docs/tree/project-global-or-both.doc.mjs +131 -0
- package/assets/docs/tree/publishing.doc.mjs +6 -6
- package/assets/docs/tree/quick-start.doc.mjs +52 -26
- package/assets/docs/tree/reference.doc.mjs +192 -0
- package/assets/docs/tree/replace-a-core-component.doc.mjs +15 -7
- package/assets/docs/tree/replace-a-core-template.doc.mjs +9 -11
- package/assets/docs/tree/scaffold.doc.mjs +1 -1
- package/assets/docs/tree/sections-and-placement.doc.mjs +9 -11
- package/assets/docs/tree/see-it-in-an-app.doc.mjs +17 -5
- package/assets/docs/tree/short-and-findable.doc.mjs +9 -8
- package/assets/docs/tree/single-component.doc.mjs +14 -6
- package/assets/docs/tree/start-a-template.doc.mjs +18 -8
- package/assets/docs/tree/subcomponent.doc.mjs +6 -6
- package/assets/docs/tree/template-assets.doc.mjs +2 -2
- package/assets/docs/tree/template-doc-overview.doc.mjs +6 -17
- package/assets/docs/tree/template-fonts.doc.mjs +1 -1
- package/assets/docs/tree/template-icons.doc.mjs +1 -1
- package/assets/docs/tree/template-images-media.doc.mjs +1 -1
- package/assets/docs/tree/template-styles.doc.mjs +2 -2
- package/assets/docs/tree/templates.doc.mjs +7 -1
- package/assets/docs/tree/test-in-an-app.doc.mjs +7 -7
- package/assets/docs/tree/test-template-in-app.doc.mjs +5 -5
- package/assets/docs/tree/themes.doc.mjs +4 -0
- package/assets/docs/tree/tokens-and-setup.doc.mjs +19 -15
- package/assets/docs/tree/troubleshooting.doc.mjs +22 -14
- package/assets/docs/tree/uninstall.doc.mjs +109 -0
- package/assets/docs/tree/updates.doc.mjs +92 -0
- package/assets/docs/tree/upgrading.doc.mjs +6 -6
- package/assets/docs/tree/use-a-theme-in-an-app.doc.mjs +14 -2
- package/assets/docs/tree/verify-packed-template.doc.mjs +3 -3
- package/assets/docs/tree/versioning.doc.mjs +9 -9
- package/assets/docs/tree/who-answers.doc.mjs +119 -0
- package/assets/docs/tree/write-the-template-file.doc.mjs +5 -5
- package/assets/docs/working-with-ai.doc.mjs +23 -9
- package/authoring/codemod/codemod.doc.mjs +7 -3
- package/authoring/config/config.doc.mjs +9 -6
- package/authoring/config/type.ts +4 -2
- package/authoring/debug/parse.d.mts +5 -5
- package/authoring/discover/discover.doc.mjs +7 -1
- package/authoring/doctypes/_schema.d.mts +8 -3
- package/authoring/doctypes/_schema.mjs +1 -0
- package/authoring/doctypes/base/graph-fields.doc.mjs +6 -4
- package/authoring/doctypes/command/command.doc.mjs +20 -12
- package/authoring/doctypes/command/type.ts +14 -0
- package/authoring/doctypes/component/component.doc.mjs +29 -26
- package/authoring/doctypes/component/type.ts +15 -5
- package/authoring/doctypes/enum/enum.doc.mjs +7 -4
- package/authoring/doctypes/function/function.doc.mjs +9 -8
- package/authoring/doctypes/hook/hook.doc.mjs +5 -4
- package/authoring/doctypes/hook/type.ts +4 -0
- package/authoring/doctypes/namespace/namespace.doc.mjs +7 -6
- package/authoring/doctypes/reference/reference.doc.mjs +12 -11
- package/authoring/doctypes/schema/schema.doc.mjs +9 -9
- package/authoring/doctypes/template/template.doc.mjs +2 -2
- package/authoring/doctypes/theme/theme.doc.mjs +2 -2
- package/authoring/gap-report/gap-report.doc.mjs +2 -2
- package/authoring/identity/identity.doc.mjs +3 -3
- package/authoring/index.d.ts +1 -0
- package/authoring/integration/integration.doc.mjs +22 -5
- package/authoring/integration/parse.test.mjs +11 -0
- package/authoring/integration/schema.d.mts +14 -3
- package/authoring/integration/schema.mjs +33 -2
- package/authoring/integration/type.ts +8 -0
- package/clients/cli/bin/astryx.mjs +20 -3
- package/clients/cli/cli-command.test.mjs +166 -0
- package/clients/cli/commands/blog.doc.mjs +1 -0
- package/clients/cli/commands/build-theme.batch-report.test.mjs +14 -2
- package/clients/cli/commands/build-theme.font-warning.test.mjs +3 -3
- package/clients/cli/commands/build-theme.mjs +25 -12
- package/clients/cli/commands/build.doc.mjs +1 -0
- package/clients/cli/commands/build.exit-codes-doc.test.mjs +4 -0
- package/clients/cli/commands/cli-postinstall.test.mjs +49 -1
- package/clients/cli/commands/component.doc.mjs +1 -0
- package/clients/cli/commands/discover.broken-integration.test.mjs +11 -7
- package/clients/cli/commands/discover.doc.mjs +9 -1
- package/clients/cli/commands/discover.mjs +144 -93
- package/clients/cli/commands/discover.no-source.test.mjs +448 -33
- package/clients/cli/commands/discover.sources.test.mjs +20 -1
- package/clients/cli/commands/docs.doc.mjs +1 -0
- package/clients/cli/commands/docs.mjs +49 -19
- package/clients/cli/commands/docs.test.mjs +2 -2
- package/clients/cli/commands/doctor-integration-components.doc.mjs +7 -3
- package/clients/cli/commands/doctor-integration-docs.doc.mjs +20 -5
- package/clients/cli/commands/doctor-integration-templates.doc.mjs +1 -0
- package/clients/cli/commands/doctor-integration-validate.doc.mjs +13 -2
- package/clients/cli/commands/doctor-integration.test.mjs +52 -4
- package/clients/cli/commands/doctor.doc.mjs +12 -2
- package/clients/cli/commands/doctor.mjs +102 -7
- package/clients/cli/commands/doctor.test.mjs +10 -4
- package/clients/cli/commands/gap-report.doc.mjs +15 -2
- package/clients/cli/commands/gap-report.mjs +24 -2
- package/clients/cli/commands/gap-report.test.mjs +79 -0
- package/clients/cli/commands/hook.doc.mjs +1 -0
- package/clients/cli/commands/init.behavior.test.mjs +5 -0
- package/clients/cli/commands/init.doc.mjs +29 -3
- package/clients/cli/commands/integration-add.doc.mjs +7 -0
- package/clients/cli/commands/integration-authoring.test.mjs +49 -3
- package/clients/cli/commands/integration-check.doc.mjs +10 -2
- package/clients/cli/commands/integration-check.test.mjs +175 -1
- package/clients/cli/commands/integration-pack.doc.mjs +8 -1
- package/clients/cli/commands/integration-verify.doc.mjs +8 -1
- package/clients/cli/commands/integration.mjs +15 -9
- package/clients/cli/commands/json-contract.test.mjs +11 -2
- package/clients/cli/commands/manifest.doc.mjs +1 -0
- package/clients/cli/commands/outside-project.test.mjs +774 -0
- package/clients/cli/commands/search.doc.mjs +1 -0
- package/clients/cli/commands/search.mjs +16 -11
- package/clients/cli/commands/search.test.mjs +429 -296
- package/clients/cli/commands/setup-nudge.test.mjs +102 -2
- package/clients/cli/commands/swizzle.doc.mjs +7 -0
- package/clients/cli/commands/swizzle.mjs +5 -3
- package/clients/cli/commands/swizzle.routing.test.mjs +19 -2
- package/clients/cli/commands/template.doc.mjs +1 -0
- package/clients/cli/commands/theme-add-lifecycle.test.mjs +3 -3
- package/clients/cli/commands/theme-add.doc.mjs +8 -1
- package/clients/cli/commands/theme-build.doc.mjs +1 -0
- package/clients/cli/commands/theme-eject.doc.mjs +1 -0
- package/clients/cli/commands/theme-list.behavior.test.mjs +6 -0
- package/clients/cli/commands/theme-list.doc.mjs +1 -0
- package/clients/cli/commands/theme-palette-generate.doc.mjs +1 -0
- package/clients/cli/commands/theme-remove.doc.mjs +7 -0
- package/clients/cli/commands/theme-targets.doc.mjs +1 -0
- package/clients/cli/commands/theme-template.doc.mjs +1 -0
- package/clients/cli/commands/theme-use.doc.mjs +7 -0
- package/clients/cli/commands/upgrade.config-ordering.test.mjs +2 -1
- package/clients/cli/commands/upgrade.doc.mjs +22 -1
- package/clients/cli/commands/upgrade.file-protection.test.mjs +3 -2
- package/clients/cli/commands/upgrade.hook-output.test.mjs +2 -1
- package/clients/cli/commands/upgrade.older-cli.test.mjs +160 -0
- package/clients/cli/index.mjs +111 -16
- package/clients/cli/lib/cli-error.mjs +4 -1
- package/clients/cli/lib/component-format.test.mjs +1 -1
- package/clients/cli/lib/define-command.mjs +2 -2
- package/clients/cli/lib/json-shim.mjs +3 -1
- package/clients/cli/lib/manifest.d.ts +9 -0
- package/clients/cli/lib/manifest.mjs +17 -1
- package/clients/cli/lib/manifest.test.mjs +25 -0
- package/foundation/agent-docs/agent-doc-state.d.mts +35 -6
- package/foundation/agent-docs/agent-doc-state.mjs +66 -6
- package/foundation/agent-docs/agent-docs.d.mts +4 -3
- package/foundation/agent-docs/agent-docs.mjs +11 -9
- package/foundation/agent-docs/computer-agent-text.d.mts +133 -0
- package/foundation/agent-docs/computer-agent-text.mjs +623 -0
- package/foundation/agent-docs/computer-agent-text.test.mjs +602 -0
- package/foundation/config/project.d.mts +35 -3
- package/foundation/config/project.mjs +145 -8
- package/foundation/config/project.test.mjs +66 -0
- package/foundation/config/theme-state.mjs +5 -4
- package/foundation/discovery/authoring-self-docs.mjs +1 -1
- package/foundation/discovery/cli-self-docs.mjs +20 -3
- package/foundation/discovery/cli-self-docs.test.mjs +3 -2
- package/foundation/discovery/component-replacement.mjs +2 -1
- package/foundation/discovery/copied-passages.d.mts +216 -0
- package/foundation/discovery/copied-passages.mjs +720 -0
- package/foundation/discovery/copied-passages.test.mjs +124 -0
- package/foundation/discovery/doc-consistency.d.mts +34 -0
- package/foundation/discovery/doc-consistency.mjs +513 -0
- package/foundation/discovery/doc-consistency.test.mjs +347 -0
- package/foundation/discovery/doc-fluff.d.mts +112 -0
- package/foundation/discovery/doc-fluff.mjs +328 -0
- package/foundation/discovery/doc-fluff.test.mjs +142 -0
- package/foundation/discovery/doc-types.d.mts +1 -1
- package/foundation/discovery/doc-types.mjs +15 -8
- package/foundation/discovery/doc-types.test.mjs +94 -2
- package/foundation/discovery/docs-discovery.d.mts +7 -0
- package/foundation/discovery/docs-discovery.mjs +26 -2
- package/foundation/discovery/project-typescript.d.mts +11 -2
- package/foundation/discovery/project-typescript.mjs +32 -4
- package/foundation/discovery/prop-drift.d.mts +26 -7
- package/foundation/discovery/prop-drift.mjs +173 -8
- package/foundation/discovery/prop-drift.test.mjs +120 -2
- package/foundation/discovery/runner-allowlist.d.mts +40 -0
- package/foundation/discovery/runner-allowlist.mjs +53 -0
- package/foundation/discovery/stray-pointers.d.mts +52 -0
- package/foundation/discovery/stray-pointers.mjs +293 -0
- package/foundation/discovery/stray-pointers.test.mjs +86 -0
- package/foundation/discovery/template-needs.mjs +5 -2
- package/foundation/discovery/theme-imports.mjs +8 -4
- package/foundation/discovery/theme-imports.test.mjs +1 -1
- package/foundation/discovery/type-text.mjs +1 -1
- package/foundation/discovery/type-text.test.mjs +1 -1
- package/foundation/doc-compiler/doc-loads.test.mjs +42 -2
- package/foundation/doc-compiler/inputs.mjs +4 -1
- package/foundation/doc-compiler/links.d.mts +32 -0
- package/foundation/doc-compiler/links.mjs +163 -26
- package/foundation/doc-compiler/links.test.mjs +97 -4
- package/foundation/doc-compiler/read.d.mts +1 -1
- package/foundation/doc-compiler/tree.mjs +30 -1
- package/foundation/doc-compiler/tree.test.mjs +8 -1
- package/foundation/env/cli-command.d.mts +83 -0
- package/foundation/env/cli-command.mjs +152 -0
- package/foundation/env/cli-command.test.mjs +129 -0
- package/foundation/env/node-version.test.mjs +15 -3
- package/foundation/env/package-manager.d.mts +93 -9
- package/foundation/env/package-manager.global.test.mjs +66 -0
- package/foundation/env/package-manager.mjs +184 -13
- package/foundation/env/package-manager.test.mjs +341 -15
- package/foundation/env/project-scope.d.mts +9 -0
- package/foundation/env/project-scope.mjs +33 -0
- package/foundation/env/search-path.d.mts +42 -0
- package/foundation/env/search-path.mjs +205 -0
- package/foundation/env/search-path.test.mjs +122 -0
- package/foundation/env/user-dirs.d.mts +39 -0
- package/foundation/env/user-dirs.mjs +93 -0
- package/foundation/env/user-dirs.test.mjs +72 -0
- package/foundation/env/user-settings.d.mts +46 -0
- package/foundation/env/user-settings.mjs +106 -0
- package/foundation/env/user-settings.test.mjs +64 -0
- package/foundation/fs/file-protection.mjs +15 -1
- package/foundation/fs/module-loader.d.mts +2 -1
- package/foundation/fs/module-loader.mjs +60 -4
- package/foundation/fs/module-loader.stdout.test.mjs +3 -2
- package/foundation/fs/module-loader.test.mjs +194 -0
- package/foundation/fs/path-compare.d.mts +33 -0
- package/foundation/fs/path-compare.mjs +73 -0
- package/foundation/fs/paths.d.mts +57 -1
- package/foundation/fs/paths.mjs +131 -3
- package/foundation/fs/paths.test.mjs +10 -1
- package/foundation/integrations/computer-integrations.d.mts +78 -0
- package/foundation/integrations/computer-integrations.mjs +316 -0
- package/foundation/integrations/computer-integrations.test.mjs +292 -0
- package/foundation/integrations/contribution-inventory.d.mts +11 -0
- package/foundation/integrations/contribution-inventory.mjs +50 -2
- package/foundation/integrations/integration-warnings.mjs +3 -2
- package/foundation/integrations/integration-warnings.test.mjs +8 -9
- package/foundation/integrations/integrations.d.mts +25 -1
- package/foundation/integrations/integrations.mjs +46 -3
- package/foundation/integrations/issue.ts +6 -0
- package/foundation/integrations/validate-contributions.d.mts +2 -0
- package/foundation/integrations/validate-contributions.mjs +41 -1
- package/foundation/release/agent-text-worker.d.mts +4 -0
- package/foundation/release/agent-text-worker.mjs +52 -0
- package/foundation/release/cache.d.mts +310 -0
- package/foundation/release/cache.mjs +1216 -0
- package/foundation/release/cache.test.mjs +920 -0
- package/foundation/release/choose.d.mts +207 -0
- package/foundation/release/choose.mjs +677 -0
- package/foundation/release/choose.test.mjs +427 -0
- package/foundation/release/core-worker.d.mts +4 -0
- package/foundation/release/core-worker.mjs +38 -0
- package/foundation/release/global-state.d.mts +259 -0
- package/foundation/release/global-state.mjs +472 -0
- package/foundation/release/global-state.test.mjs +381 -0
- package/foundation/release/handoff.d.mts +60 -0
- package/foundation/release/handoff.e2e.test.mjs +278 -0
- package/foundation/release/handoff.mjs +357 -0
- package/foundation/release/lock-lease.d.mts +23 -0
- package/foundation/release/lock-lease.mjs +80 -0
- package/foundation/release/notices.d.mts +253 -0
- package/foundation/release/notices.mjs +596 -0
- package/foundation/release/notices.test.mjs +565 -0
- package/foundation/release/npm-guard.d.mts +4 -0
- package/foundation/release/npm-guard.mjs +126 -0
- package/foundation/release/project.d.mts +141 -0
- package/foundation/release/project.mjs +466 -0
- package/foundation/release/project.test.mjs +288 -0
- package/foundation/release/refresh-worker.d.mts +4 -0
- package/foundation/release/refresh-worker.mjs +27 -0
- package/foundation/release/run-context.d.mts +47 -0
- package/foundation/release/run-context.mjs +149 -0
- package/foundation/release/update-notice-env.d.mts +28 -0
- package/foundation/release/update-notice-env.mjs +39 -0
- package/foundation/response/base.d.ts +26 -3
- package/foundation/response/error-codes.d.mts +3 -1
- package/foundation/response/error-codes.doc.mjs +12 -0
- package/foundation/response/error-codes.mjs +17 -0
- package/foundation/response/error-codes.test.mjs +2 -0
- package/foundation/response/json-contract.test.mjs +7 -2
- package/foundation/response/json.mjs +4 -1
- package/foundation/response/response-types.doc.mjs +17 -11
- package/foundation/response/response-types.doc.test.mjs +46 -0
- package/foundation/response/response.doc.mjs +3 -3
- package/foundation/xle/browser-imports.test.mjs +74 -0
- package/package.json +11 -11
- package/scripts/postinstall.mjs +24 -5
- /package/assets/codemods/transforms/{next → v0.7.2}/__tests__/migrate-list-edge-compensation-to-edge.test.mjs +0 -0
- /package/assets/codemods/transforms/{next → v0.7.2}/migrate-list-edge-compensation-to-edge.mjs +0 -0
|
@@ -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
|
+
});
|
|
@@ -54,7 +54,7 @@ export function checkDocTypes(files: DocFile[], options: {
|
|
|
54
54
|
* or not fully checked
|
|
55
55
|
*/
|
|
56
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.
|
|
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
58
|
export type DocRoot = "components" | "hooks" | "templates" | "docs" | "docs-overlay" | "themes";
|
|
59
59
|
export type DocFile = {
|
|
60
60
|
/**
|
|
@@ -41,6 +41,7 @@ import * as path from 'node:path';
|
|
|
41
41
|
import {fileURLToPath} from 'node:url';
|
|
42
42
|
import {
|
|
43
43
|
resolveProjectTypeScript,
|
|
44
|
+
TYPESCRIPT_FIX,
|
|
44
45
|
unusableTypeScriptReason,
|
|
45
46
|
} from './project-typescript.mjs';
|
|
46
47
|
|
|
@@ -91,8 +92,7 @@ import {
|
|
|
91
92
|
*/
|
|
92
93
|
|
|
93
94
|
/** The line both surfaces print when the compiler is missing. */
|
|
94
|
-
export const DOC_TYPES_TYPESCRIPT_MISSING_REASON =
|
|
95
|
-
'TypeScript is not installed in this project, so docs were not checked against the authoring types. Install typescript and run this check again.';
|
|
95
|
+
export const DOC_TYPES_TYPESCRIPT_MISSING_REASON = `TypeScript is not installed in this project, so docs were not checked against the authoring types. ${TYPESCRIPT_FIX}`;
|
|
96
96
|
|
|
97
97
|
const AUTHORING = '@astryxdesign/cli/authoring';
|
|
98
98
|
const AUTHORING_TYPES = path.resolve(
|
|
@@ -827,16 +827,23 @@ function findingsFor(ts, diagnostic, astPath, where) {
|
|
|
827
827
|
named != null && /^[A-Za-z_$][\w$]*$/.test(named)
|
|
828
828
|
? named
|
|
829
829
|
: where.typeName;
|
|
830
|
+
// One diagnostic can list several missing fields; each finding's message
|
|
831
|
+
// names only its own field, so two findings never share one message.
|
|
832
|
+
const source = /^Type '(.*)' is missing the following properties/.exec(
|
|
833
|
+
leaf,
|
|
834
|
+
)?.[1];
|
|
830
835
|
return missing.map(name => {
|
|
831
|
-
const
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
836
|
+
const key = unquote(/** @type {string} */ (name));
|
|
837
|
+
const field = formatPath([...parts, key]);
|
|
838
|
+
const message =
|
|
839
|
+
missing.length > 1
|
|
840
|
+
? `Property '${key}' is missing${source == null ? '' : ` in type '${source}'`} but required in type '${ownerType}'.`
|
|
841
|
+
: leaf;
|
|
835
842
|
return {
|
|
836
843
|
...base,
|
|
837
844
|
field,
|
|
838
845
|
problem: /** @type {const} */ ('missing_field'),
|
|
839
|
-
message: shorten(
|
|
846
|
+
message: shorten(message),
|
|
840
847
|
fix: `Add \`${field}\`: ${shorten(ownerType)} requires it.`,
|
|
841
848
|
};
|
|
842
849
|
});
|
|
@@ -933,7 +940,7 @@ export async function checkDocTypes(files, options) {
|
|
|
933
940
|
if (major < needMajor || (major === needMajor && minor < needMinor)) {
|
|
934
941
|
return {
|
|
935
942
|
status: 'skipped',
|
|
936
|
-
reason: `TypeScript ${version} cannot check ${hasJs ? 'a JavaScript doc' : 'a doc'} against its type (that needs TypeScript ${needMajor}.${needMinor} or later), so docs were not checked.
|
|
943
|
+
reason: `TypeScript ${version} cannot check ${hasJs ? 'a JavaScript doc' : 'a doc'} against its type (that needs TypeScript ${needMajor}.${needMinor} or later), so docs were not checked. ${TYPESCRIPT_FIX}`,
|
|
937
944
|
docs: 0,
|
|
938
945
|
findings: [],
|
|
939
946
|
unchecked: [],
|
|
@@ -40,6 +40,37 @@ function withTypeScript() {
|
|
|
40
40
|
);
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
/**
|
|
44
|
+
* TypeScript 7 (no JavaScript compiler API) with the TypeScript 6 API package
|
|
45
|
+
* beside it, which re-exports a real TypeScript.
|
|
46
|
+
*/
|
|
47
|
+
function withTypeScript7AndItsTypeScript6Api() {
|
|
48
|
+
const ts7 = path.join(pkg, 'node_modules', 'typescript');
|
|
49
|
+
fs.mkdirSync(ts7, {recursive: true});
|
|
50
|
+
fs.writeFileSync(
|
|
51
|
+
path.join(ts7, 'package.json'),
|
|
52
|
+
JSON.stringify({
|
|
53
|
+
name: 'typescript',
|
|
54
|
+
version: '7.0.2',
|
|
55
|
+
exports: {'./package.json': './package.json'},
|
|
56
|
+
}),
|
|
57
|
+
);
|
|
58
|
+
const ts6 = path.join(pkg, 'node_modules', '@typescript', 'typescript6');
|
|
59
|
+
fs.mkdirSync(ts6, {recursive: true});
|
|
60
|
+
fs.writeFileSync(
|
|
61
|
+
path.join(ts6, 'package.json'),
|
|
62
|
+
JSON.stringify({
|
|
63
|
+
name: '@typescript/typescript6',
|
|
64
|
+
version: '6.0.2',
|
|
65
|
+
main: 'index.js',
|
|
66
|
+
}),
|
|
67
|
+
);
|
|
68
|
+
fs.writeFileSync(
|
|
69
|
+
path.join(ts6, 'index.js'),
|
|
70
|
+
`module.exports = require(${JSON.stringify(TYPESCRIPT_DIR)});\n`,
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
43
74
|
/**
|
|
44
75
|
* @param {string} rel
|
|
45
76
|
* @param {string} text
|
|
@@ -117,6 +148,10 @@ describe('checkDocTypes', () => {
|
|
|
117
148
|
|
|
118
149
|
const report = await check([['components/Badge.doc.mjs', 'components']]);
|
|
119
150
|
|
|
151
|
+
// The reason names the version and the fix, so a --strict failure
|
|
152
|
+
// says what to install.
|
|
153
|
+
expect(report.reason).toContain('TypeScript 7.0.0');
|
|
154
|
+
expect(report.reason).toContain('npm install -D @typescript/typescript6');
|
|
120
155
|
expect(report).toEqual({
|
|
121
156
|
status: 'skipped',
|
|
122
157
|
reason: unusableTypeScriptReason('7.0.0', 'docs were not checked'),
|
|
@@ -128,6 +163,19 @@ describe('checkDocTypes', () => {
|
|
|
128
163
|
}
|
|
129
164
|
});
|
|
130
165
|
|
|
166
|
+
it("checks with TypeScript 7's TypeScript 6 API package when the project has one", async () => {
|
|
167
|
+
write(
|
|
168
|
+
'components/Badge.doc.mjs',
|
|
169
|
+
`export default ${JSON.stringify(COMPONENT)};\n`,
|
|
170
|
+
);
|
|
171
|
+
withTypeScript7AndItsTypeScript6Api();
|
|
172
|
+
|
|
173
|
+
const report = await check([['components/Badge.doc.mjs', 'components']]);
|
|
174
|
+
|
|
175
|
+
expect(report.status).toBe('checked');
|
|
176
|
+
expect(report.docs).toBe(1);
|
|
177
|
+
});
|
|
178
|
+
|
|
131
179
|
it('says there is nothing to check when the package has no doc files, with or without TypeScript', async () => {
|
|
132
180
|
const without = await check([]);
|
|
133
181
|
withTypeScript();
|
|
@@ -517,7 +565,7 @@ describe('checkDocTypes', () => {
|
|
|
517
565
|
'components/Badge.doc.mjs',
|
|
518
566
|
[
|
|
519
567
|
`export default ${JSON.stringify(COMPONENT)};`,
|
|
520
|
-
"export const docsDense = {name: 'Badge', description: 'count chip'};",
|
|
568
|
+
"export const docsDense = {name: 'Badge', displayName: 'Badge', summary: 'chip', description: 'count chip'};",
|
|
521
569
|
`export const docsZh = ${JSON.stringify({...COMPONENT, displayName: undefined, keyword: []})};`,
|
|
522
570
|
'',
|
|
523
571
|
].join('\n'),
|
|
@@ -527,12 +575,56 @@ describe('checkDocTypes', () => {
|
|
|
527
575
|
|
|
528
576
|
expect(report.docs).toBe(3);
|
|
529
577
|
expect(summary(report)).toEqual([
|
|
530
|
-
'components/Badge.doc.mjs docsDense
|
|
578
|
+
'components/Badge.doc.mjs docsDense summary unknown_field',
|
|
531
579
|
'components/Badge.doc.mjs docsZh keyword unknown_field',
|
|
532
580
|
]);
|
|
533
581
|
expect(report.findings[0].type).toBe('ComponentTranslationDoc');
|
|
534
582
|
});
|
|
535
583
|
|
|
584
|
+
it('allows a translation overlay to name its component, as Core overlays do', async () => {
|
|
585
|
+
withTypeScript();
|
|
586
|
+
write(
|
|
587
|
+
'components/Badge.doc.mjs',
|
|
588
|
+
[
|
|
589
|
+
`export default ${JSON.stringify(COMPONENT)};`,
|
|
590
|
+
"export const docsZh = {name: 'Badge', displayName: '徽章', description: '计数'};",
|
|
591
|
+
"export const docsDense = {name: 'Badge', displayName: 'Badge', description: 'count chip'};",
|
|
592
|
+
'',
|
|
593
|
+
].join('\n'),
|
|
594
|
+
);
|
|
595
|
+
|
|
596
|
+
const report = await check([['components/Badge.doc.mjs', 'components']]);
|
|
597
|
+
|
|
598
|
+
expect(summary(report)).toEqual([]);
|
|
599
|
+
});
|
|
600
|
+
|
|
601
|
+
it('gives each field TypeScript reports missing together a message naming only that field', async () => {
|
|
602
|
+
withTypeScript();
|
|
603
|
+
write(
|
|
604
|
+
'components/Badge.doc.mjs',
|
|
605
|
+
[
|
|
606
|
+
'export default {',
|
|
607
|
+
" type: 'component',",
|
|
608
|
+
" name: 'Badge',",
|
|
609
|
+
" props: [{name: 'label', type: 'string', description: 'Text.'}],",
|
|
610
|
+
'};',
|
|
611
|
+
'',
|
|
612
|
+
].join('\n'),
|
|
613
|
+
);
|
|
614
|
+
|
|
615
|
+
const report = await check([['components/Badge.doc.mjs', 'components']]);
|
|
616
|
+
const missing = report.findings.filter(f => f.problem === 'missing_field');
|
|
617
|
+
|
|
618
|
+
expect(missing.length).toBeGreaterThan(1);
|
|
619
|
+
expect(new Set(missing.map(f => f.message)).size).toBe(missing.length);
|
|
620
|
+
for (const finding of missing) {
|
|
621
|
+
const others = missing.filter(f => f !== finding).map(f => f.field);
|
|
622
|
+
expect(finding.message).toContain(`'${finding.field}'`);
|
|
623
|
+
for (const other of others)
|
|
624
|
+
expect(finding.message).not.toContain(`'${other}'`);
|
|
625
|
+
}
|
|
626
|
+
});
|
|
627
|
+
|
|
536
628
|
it('checks a template, a docs topic by its stamp, a topic overlay, and a theme', async () => {
|
|
537
629
|
withTypeScript();
|
|
538
630
|
write(
|
|
@@ -39,6 +39,13 @@
|
|
|
39
39
|
* @returns {Record<string, string>} topic name → absolute doc path
|
|
40
40
|
*/
|
|
41
41
|
export function discoverBuiltinTopics(): Record<string, string>;
|
|
42
|
+
/**
|
|
43
|
+
* The CLI's own guide files: every flat topic and every doc in its docs tree,
|
|
44
|
+
* without the dense, translated, and draft variants.
|
|
45
|
+
*
|
|
46
|
+
* @returns {string[]}
|
|
47
|
+
*/
|
|
48
|
+
export function builtinGuideFiles(): string[];
|
|
42
49
|
/**
|
|
43
50
|
* Load a topic doc from disk. A `.ts` doc is loaded through jiti, the rest
|
|
44
51
|
* natively; both the historical `export const docs` and the stamped
|