@astryxdesign/cli 0.1.8-canary.0c4d8d7 → 0.1.8-canary.0db5dfd
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/{src/api → api/blog}/blog.mjs +42 -6
- package/{src/api → api/blog}/blog.test.mjs +2 -2
- package/api/build/build.mjs +92 -0
- package/api/build/build.test.mjs +92 -0
- package/{src/api → api/component}/component.mjs +49 -26
- package/{src/api → api/discover}/discover.mjs +55 -18
- package/{src/api → api/docs}/docs.mjs +47 -21
- package/{src/api → api/doctor}/doctor.mjs +11 -8
- package/{src/api → api/hook}/hook.mjs +11 -11
- package/{src/api → api}/index.mjs +16 -9
- package/{src/api → api/integration}/validate-integration.mjs +48 -15
- package/{src/api → api/integration}/validate-integration.test.mjs +1 -1
- package/{src/api → api/layout}/layout.mjs +66 -17
- package/{src/api → api/layout}/layout.test.mjs +1 -1
- package/{src/api → api/search}/search.mjs +71 -12
- package/api/swizzle/swizzle.mjs +283 -0
- package/{src/commands → api/swizzle}/swizzle.test.mjs +26 -1
- package/{src/api → api/template}/template-integration.test.mjs +2 -2
- package/{src/api → api/template}/template-suffix.test.mjs +3 -3
- package/{src/api → api/template}/template.mjs +96 -19
- package/{src/api → api/theme}/theme-add.mjs +35 -7
- package/{src → authoring}/codemod.mjs +6 -6
- package/{src → authoring}/config.test.mjs +1 -1
- package/{src → authoring}/doc.mjs +1 -1
- package/{src → authoring}/doc.test.mjs +1 -1
- package/{src → authoring}/template.mjs +1 -1
- package/bin/astryx.mjs +12 -10
- package/{src → cli}/commands/blog.mjs +48 -7
- package/{src → cli}/commands/build-theme.mjs +125 -46
- package/{src → cli}/commands/build.mjs +33 -57
- package/{src → cli}/commands/component/index.mjs +49 -22
- package/{src → cli}/commands/component-ownership.test.mjs +3 -3
- package/{src → cli}/commands/component-package.test.mjs +1 -1
- package/{src → cli}/commands/component-resolution.test.mjs +2 -2
- package/{src → cli}/commands/discover.mjs +17 -8
- package/{src → cli}/commands/docs.mjs +39 -7
- package/{src → cli}/commands/docs.test.mjs +1 -1
- package/{src → cli}/commands/doctor.mjs +3 -3
- package/{src → cli}/commands/doctor.test.mjs +2 -2
- package/{src → cli}/commands/ensure-core-built.mjs +3 -2
- package/{src → cli}/commands/external-showcase.test.mjs +1 -1
- package/{src → cli}/commands/hook/index.mjs +37 -14
- package/{src → cli}/commands/import-hint-correctness.test.mjs +1 -1
- package/{src → cli}/commands/init.mjs +20 -9
- package/{src → cli}/commands/layout.mjs +58 -18
- package/{src → cli}/commands/search.mjs +19 -12
- package/{src → cli}/commands/search.test.mjs +1 -1
- package/{src → cli}/commands/setup-nudge.test.mjs +1 -1
- package/cli/commands/swizzle.mjs +103 -0
- package/{src → cli}/commands/template.mjs +73 -22
- package/{src → cli}/commands/template.path-safety.test.mjs +2 -2
- package/{src → cli}/commands/upgrade.integration-policy.test.mjs +1 -1
- package/{src → cli}/commands/upgrade.mjs +160 -52
- package/{src → cli}/commands/upgrade.test.mjs +1 -1
- package/{src → cli}/commands/validate-integration.mjs +17 -37
- package/{src → cli}/index.mjs +17 -15
- package/{src/codemods → codemods}/ensure-jscodeshift.mjs +1 -1
- package/{src/codemods → codemods}/integration-discovery.mjs +6 -3
- package/{src/codemods → codemods}/integration-discovery.test.mjs +1 -1
- package/{src/codemods → codemods}/integration-runner.mjs +8 -3
- package/{src/codemods → codemods}/registry.mjs +3 -1
- package/{src/codemods → codemods}/run-codemod.mjs +17 -10
- package/{src/codemods → codemods}/runner.mjs +22 -12
- package/{src/codemods → codemods}/transforms/v0.0.10/remove-size-props.mjs +9 -4
- package/{src/codemods → codemods}/transforms/v0.0.12/add-is-icon-only.mjs +27 -22
- package/{src/codemods → codemods}/transforms/v0.0.13/icon-name-deprecations.mjs +12 -5
- package/{src/codemods → codemods}/transforms/v0.0.13/rename-attachments-to-drawer.mjs +15 -8
- package/{src/codemods → codemods}/transforms/v0.0.13/toolbar-density-to-size.mjs +10 -4
- package/{src/codemods → codemods}/transforms/v0.0.14/rename-action-props.mjs +11 -5
- package/{src/codemods → codemods}/transforms/v0.0.14/rename-section-wash-to-muted.mjs +11 -6
- package/{src/codemods → codemods}/transforms/v0.0.14/rename-status-variants.mjs +15 -10
- package/{src/codemods → codemods}/transforms/v0.0.15/migrate-item-children-to-endcontent.mjs +13 -8
- package/{src/codemods → codemods}/transforms/v0.0.15/migrate-selector-children-to-render-option.mjs +18 -13
- package/{src/codemods → codemods}/transforms/v0.0.15/migrate-theme-selectors-to-data-attrs.mjs +8 -4
- package/{src/codemods → codemods}/transforms/v0.0.15/rename-date-picker-to-input.mjs +11 -6
- package/{src/codemods → codemods}/transforms/v0.0.15/rename-imperative-ref-to-handleRef.mjs +6 -1
- package/{src/codemods → codemods}/transforms/v0.0.15/rename-isStreaming-to-isStopShown.mjs +6 -1
- package/{src/codemods → codemods}/transforms/v0.0.15/rename-stack-element-to-as.mjs +8 -3
- package/{src/codemods → codemods}/transforms/v0.0.2/migrate-badge-dot-to-statusdot.mjs +17 -10
- package/{src/codemods → codemods}/transforms/v0.0.2/migrate-gap-to-numeric.mjs +7 -1
- package/{src/codemods → codemods}/transforms/v0.0.2/migrate-isFullBleed-to-padding.mjs +9 -4
- package/{src/codemods → codemods}/transforms/v0.0.2/migrate-useXDSIcon-to-getIcon.mjs +12 -7
- package/{src/codemods → codemods}/transforms/v0.0.2/rename-banner-endButton-to-endContent.mjs +7 -2
- package/{src/codemods → codemods}/transforms/v0.0.2/rename-form-tooltip-startIcon.mjs +8 -2
- package/{src/codemods → codemods}/transforms/v0.0.2/rename-isShown-to-isOpen.mjs +7 -2
- package/{src/codemods → codemods}/transforms/v0.0.2/rename-selector-items-to-options.mjs +7 -2
- package/{src/codemods → codemods}/transforms/v0.0.2/rename-sidenav-header-to-heading.mjs +11 -4
- package/{src/codemods → codemods}/transforms/v0.0.2/rename-topnav-title-to-heading.mjs +10 -4
- package/{src/codemods → codemods}/transforms/v0.0.2/unify-uncontrolled-to-defaultX.mjs +7 -2
- package/{src/codemods → codemods}/transforms/v0.0.2/unify-visibility-to-onOpenChange.mjs +10 -5
- package/{src/codemods → codemods}/transforms/v0.0.6/migrate-badge-children-to-label.mjs +7 -2
- package/{src/codemods → codemods}/transforms/v0.0.6/migrate-collapse-to-collapsible.mjs +9 -3
- package/{src/codemods → codemods}/transforms/v0.0.6/migrate-radius-tokens.mjs +11 -5
- package/{src/codemods → codemods}/transforms/v0.0.6/migrate-shadow-tokens.mjs +13 -6
- package/{src/codemods → codemods}/transforms/v0.0.6/migrate-skeleton-radius.mjs +7 -1
- package/{src/codemods → codemods}/transforms/v0.0.6/migrate-token-names.mjs +11 -5
- package/{src/codemods → codemods}/transforms/v0.0.7/rename-banner-variant-to-container.mjs +8 -3
- package/{src/codemods → codemods}/transforms/v0.0.8/migrate-token-renames.mjs +15 -8
- package/{src/codemods → codemods}/transforms/v0.0.8/rename-endslot-to-endcontent.mjs +7 -2
- package/{src/codemods → codemods}/transforms/v0.1.0/drop-xds-prefix-imports.mjs +19 -14
- package/{src/codemods → codemods}/transforms/v0.1.0/migrate-xds-css-surfaces.mjs +21 -17
- package/{src/codemods → codemods}/transforms/v0.1.0/migrate-xds-declare-module.mjs +7 -2
- package/{src/codemods → codemods}/transforms/v0.1.0/migrate-xds-module-specifiers.mjs +16 -11
- package/{src/codemods → codemods}/transforms/v0.1.2/rename-text-color-active-to-accent.mjs +15 -9
- package/{src/codemods → codemods}/transforms/v0.1.3/migrate-layout-components-to-experimental.mjs +17 -12
- package/{src/codemods → codemods}/transforms/v0.1.5/rename-switch-label-spacing-default-to-hug.mjs +15 -9
- package/{src/codemods → codemods}/transforms/v0.1.7/migrate-table-tableprops-to-direct-props.mjs +17 -10
- package/{src/codemods → codemods}/transforms/v0.1.7/rename-table-renderprops-styles-to-xstyle.mjs +18 -13
- package/{src/codemods → codemods}/transforms/v0.1.8/rename-avatar-size-scale.mjs +15 -10
- package/docs/internationalization.doc.mjs +92 -46
- package/{src/commands → lib/agent-docs}/agent-docs.mjs +30 -11
- package/{src/commands → lib/agent-docs}/agent-docs.path-safety.test.mjs +1 -1
- package/{src/lib → lib}/component-discovery.mjs +44 -2
- package/{src/lib → lib}/component-format.mjs +65 -24
- package/{src/lib → lib}/component-loader.mjs +27 -13
- package/{src/lib → lib}/componentDocOverlay.test.mjs +0 -1
- package/{src/lib → lib}/error-codes.test.mjs +1 -1
- package/{src/lib → lib}/hook-discovery.mjs +14 -1
- package/{src/lib → lib}/hook-format.mjs +29 -5
- package/{src/lib → lib}/integration-warnings.mjs +2 -2
- package/{src/lib → lib}/integrations.mjs +20 -0
- package/{src/lib → lib}/integrations.test.mjs +1 -1
- package/{src/lib → lib}/json-contract.test.mjs +1 -1
- package/{src/lib → lib}/json-shim.mjs +10 -5
- package/{src/lib → lib}/json-shim.test.mjs +1 -1
- package/{src/lib → lib}/levenshtein.mjs +6 -0
- package/{src/lib → lib}/manifest.mjs +7 -5
- package/{src/lib → lib}/manifest.test.mjs +2 -2
- package/{src/lib → lib}/module-loader.mjs +1 -0
- package/{src/lib → lib}/package-scanner.mjs +47 -0
- package/{src/lib → lib}/project.mjs +48 -18
- package/{src/lib → lib}/project.test.mjs +1 -1
- package/{src/lib → lib}/resolve-theme.mjs +5 -0
- package/{src/lib → lib}/string-utils.mjs +15 -0
- package/{src/lib → lib}/term-log.mjs +12 -3
- package/{src/lib → lib}/xle/browser.mjs +18 -8
- package/{src/lib → lib}/xle/expand.mjs +155 -22
- package/{src/lib → lib}/xle/parse.mjs +119 -13
- package/{src/lib → lib}/xle/print.mjs +54 -14
- package/{src/lib → lib}/xle/registry-core.mjs +28 -3
- package/{src/lib → lib}/xle/registry.mjs +9 -4
- package/{src/lib → lib}/xle/splice.mjs +13 -2
- package/{src/lib → lib}/xle/validate.mjs +95 -14
- package/lib/xle/xle-ast.d.ts +214 -0
- package/package.json +33 -26
- package/scripts/postinstall.mjs +4 -4
- package/templates/blocks/components/Avatar/AvatarShowcase.tsx +1 -1
- package/templates/blocks/components/InternationalizationProvider/InternationalizationProvider01ShippedLocale.doc.mjs +19 -0
- package/templates/blocks/components/InternationalizationProvider/InternationalizationProvider01ShippedLocale.tsx +46 -0
- package/templates/blocks/components/InternationalizationProvider/InternationalizationProvider02Overrides.doc.mjs +14 -0
- package/templates/blocks/components/InternationalizationProvider/InternationalizationProvider02Overrides.tsx +33 -0
- package/{src/types → types}/api.contract.assert.ts +17 -8
- package/{src/types → types}/api.d.ts +106 -0
- package/{src/types → types}/base.d.ts +17 -2
- package/types/build.d.ts +53 -0
- package/types/codemod.d.ts +166 -0
- package/{src/types → types}/component.d.ts +1 -1
- package/{src/types → types}/discover.d.ts +1 -1
- package/{src/types → types}/docs.d.ts +1 -4
- package/{src/types → types}/hook.d.ts +1 -1
- package/types/jscodeshift.d.ts +19 -0
- package/types/layout.d.ts +74 -0
- package/types/theme.d.ts +53 -0
- package/{src/types → types}/upgrade.d.ts +8 -1
- package/{src/utils → utils}/paths.mjs +4 -1
- package/src/commands/swizzle.mjs +0 -417
- package/src/types/build.d.ts +0 -23
- package/src/types/codemod.d.ts +0 -81
- package/src/types/theme.d.ts +0 -23
- /package/{src/api → api/docs}/docOverlays.test.mjs +0 -0
- /package/{src/api → api}/error.mjs +0 -0
- /package/{src/api → api/integration}/integration-block-exports.test.mjs +0 -0
- /package/{src/api → api/template}/template.test.mjs +0 -0
- /package/{src → authoring}/codemod.test.mjs +0 -0
- /package/{src → authoring}/config.mjs +0 -0
- /package/{src → authoring}/integration.mjs +0 -0
- /package/{src → authoring}/template.test.mjs +0 -0
- /package/{src → cli}/cli-exit-codes.test.mjs +0 -0
- /package/{src → cli}/commands/build-theme.color-scheme.test.mjs +0 -0
- /package/{src → cli}/commands/build-theme.import-path.test.mjs +0 -0
- /package/{src → cli}/commands/build-theme.path-safety.test.mjs +0 -0
- /package/{src → cli}/commands/build-theme.prose.test.mjs +0 -0
- /package/{src → cli}/commands/build-theme.variants.test.mjs +0 -0
- /package/{src → cli}/commands/build-theme.watch.test.mjs +0 -0
- /package/{src → cli}/commands/cli-postinstall.test.mjs +0 -0
- /package/{src → cli}/commands/component.test.mjs +0 -0
- /package/{src → cli}/commands/detail-levels.test.mjs +0 -0
- /package/{src → cli}/commands/init.next-steps.test.mjs +0 -0
- /package/{src → cli}/commands/interactive-guard.test.mjs +0 -0
- /package/{src → cli}/commands/json-contract.test.mjs +0 -0
- /package/{src → cli}/commands/swizzle.path-safety.test.mjs +0 -0
- /package/{src → cli}/commands/swizzle.routing.test.mjs +0 -0
- /package/{src → cli}/commands/template.test.mjs +0 -0
- /package/{src → cli}/commands/upgrade.config-ordering.test.mjs +0 -0
- /package/{src → cli}/commands/validate-integration.test.mjs +0 -0
- /package/{src → cli}/update-hint-commands.test.mjs +0 -0
- /package/{src/codemods → codemods}/__tests__/registry.test.mjs +0 -0
- /package/{src/codemods → codemods}/__tests__/rename-imperative-ref-to-handleRef.test.mjs +0 -0
- /package/{src/codemods → codemods}/__tests__/rename-isStreaming-to-isStopShown.test.mjs +0 -0
- /package/{src/codemods → codemods}/__tests__/rename-section-wash-to-muted.test.mjs +0 -0
- /package/{src/codemods → codemods}/__tests__/runner.test.mjs +0 -0
- /package/{src/codemods → codemods}/__tests__/toolbar-density-to-size.test.mjs +0 -0
- /package/{src/codemods → codemods}/__tests__/validation.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.10/__tests__/remove-size-props.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.10/index.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.12/__tests__/add-is-icon-only.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.12/index.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.13/__tests__/icon-name-deprecations.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.13/__tests__/rename-attachments-to-drawer.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.13/index.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.14/__tests__/rename-action-props.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.14/__tests__/rename-status-variants.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.14/index.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.15/__tests__/migrate-item-children-to-endcontent.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.15/__tests__/migrate-selector-children-to-render-option.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.15/__tests__/migrate-theme-selectors-to-data-attrs.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.15/__tests__/rename-date-picker-to-input.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.15/__tests__/rename-stack-element-to-as.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.15/index.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/migrate-badge-dot-to-statusdot.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/migrate-gap-to-numeric.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/migrate-isFullBleed-to-padding.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/migrate-useXDSIcon-to-getIcon.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/rename-banner-endButton-to-endContent.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/rename-form-tooltip-startIcon.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/rename-isShown-to-isOpen.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/rename-selector-items-to-options.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/rename-sidenav-header-to-heading.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/rename-topnav-title-to-heading.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/unify-uncontrolled-to-defaultX.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/unify-visibility-to-onOpenChange.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.2/index.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.6/__tests__/migrate-collapse-to-collapsible.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.6/__tests__/migrate-radius-tokens.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.6/__tests__/migrate-shadow-tokens.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.6/__tests__/migrate-skeleton-radius.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.6/__tests__/migrate-token-names.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.6/index.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.7/__tests__/rename-banner-variant-to-container.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.7/index.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.8/__tests__/migrate-token-renames.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.8/__tests__/rename-endslot-to-endcontent.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.8/index.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.1.0/__tests__/drop-xds-prefix-imports.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.1.0/__tests__/migrate-xds-css-surfaces.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.1.0/__tests__/migrate-xds-declare-module.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.1.0/__tests__/migrate-xds-module-specifiers.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.1.0/__tests__/v0.1.0-ordering.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.1.0/index.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.1.2/__tests__/rename-text-color-active-to-accent.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.1.2/index.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.1.3/__tests__/migrate-layout-components-to-experimental.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.1.3/index.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.1.5/__tests__/rename-switch-label-spacing-default-to-hug.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.1.5/index.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.1.7/__tests__/migrate-table-tableprops-to-direct-props.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.1.7/__tests__/rename-table-renderprops-styles-to-xstyle.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.1.7/index.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.1.8/__tests__/rename-avatar-size-scale.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.1.8/index.mjs +0 -0
- /package/{src/commands → lib/agent-docs}/agent-docs.test.mjs +0 -0
- /package/{src/lib → lib}/cli-error.mjs +0 -0
- /package/{src/lib → lib}/cli-error.test.mjs +0 -0
- /package/{src/lib → lib}/component-discovery.importpath.test.mjs +0 -0
- /package/{src/lib → lib}/component-format.test.mjs +0 -0
- /package/{src/lib → lib}/component-loader.test.mjs +0 -0
- /package/{src/lib → lib}/config-cache.mjs +0 -0
- /package/{src/lib → lib}/config-cache.test.mjs +0 -0
- /package/{src/lib → lib}/config-schema.mjs +0 -0
- /package/{src/lib → lib}/error-codes.mjs +0 -0
- /package/{src/lib → lib}/integration-warnings.test.mjs +0 -0
- /package/{src/lib → lib}/json.mjs +0 -0
- /package/{src/lib → lib}/module-loader.test.mjs +0 -0
- /package/{src/lib → lib}/node-version.mjs +0 -0
- /package/{src/lib → lib}/node-version.test.mjs +0 -0
- /package/{src/lib → lib}/parse.mjs +0 -0
- /package/{src/lib → lib}/site.mjs +0 -0
- /package/{src/lib → lib}/xle/browser.d.ts +0 -0
- /package/{src/lib → lib}/xle/xle.test.mjs +0 -0
- /package/{src/schemas → schemas}/doc-schema.mjs +0 -0
- /package/{src/schemas → schemas}/template-schema.mjs +0 -0
- /package/{src/types → types}/config.d.ts +0 -0
- /package/{src/types → types}/doc.d.ts +0 -0
- /package/{src/types → types}/doctor.d.ts +0 -0
- /package/{src/types → types}/error-codes.d.ts +0 -0
- /package/{src/types → types}/index.d.ts +0 -0
- /package/{src/types → types}/integration.d.ts +0 -0
- /package/{src/types → types}/manifest.d.ts +0 -0
- /package/{src/types → types}/search.d.ts +0 -0
- /package/{src/types → types}/swizzle.d.ts +0 -0
- /package/{src/types → types}/template-api.d.ts +0 -0
- /package/{src/types → types}/template.d.ts +0 -0
- /package/{src/types → types}/validate-integration.d.ts +0 -0
- /package/{src/utils → utils}/github.mjs +0 -0
- /package/{src/utils → utils}/package-manager.mjs +0 -0
- /package/{src/utils → utils}/package-manager.test.mjs +0 -0
- /package/{src/utils → utils}/path-safety.mjs +0 -0
- /package/{src/utils → utils}/path-safety.test.mjs +0 -0
- /package/{src/utils → utils}/paths.test.mjs +0 -0
- /package/{src/utils → utils}/semver.mjs +0 -0
- /package/{src/utils → utils}/semver.test.mjs +0 -0
- /package/{src/utils → utils}/update-check.mjs +0 -0
- /package/{src/utils → utils}/update-check.test.mjs +0 -0
|
@@ -33,19 +33,34 @@
|
|
|
33
33
|
import * as fs from 'node:fs';
|
|
34
34
|
import * as path from 'node:path';
|
|
35
35
|
import {pathToFileURL} from 'node:url';
|
|
36
|
-
import {findCoreDir, CLI_ROOT} from '
|
|
36
|
+
import {findCoreDir, CLI_ROOT} from '../../utils/paths.mjs';
|
|
37
37
|
import {
|
|
38
38
|
discoverComponents,
|
|
39
39
|
findComponentReadme,
|
|
40
40
|
resolveImportPath,
|
|
41
|
-
} from '
|
|
42
|
-
import {discoverHooks, findHookDoc} from '
|
|
43
|
-
import {levenshteinDistance} from '
|
|
44
|
-
import {discoverTemplates, extractComponents} from '
|
|
45
|
-
import {AstryxError} from '
|
|
41
|
+
} from '../../lib/component-discovery.mjs';
|
|
42
|
+
import {discoverHooks, findHookDoc} from '../../lib/hook-discovery.mjs';
|
|
43
|
+
import {levenshteinDistance} from '../../lib/string-utils.mjs';
|
|
44
|
+
import {discoverTemplates, extractComponents} from '../template/template.mjs';
|
|
45
|
+
import {AstryxError} from '../error.mjs';
|
|
46
46
|
|
|
47
47
|
const DOCS_DIR = path.join(CLI_ROOT, 'docs');
|
|
48
48
|
|
|
49
|
+
/**
|
|
50
|
+
* A search candidate gathered from one content domain. Extra underscore-
|
|
51
|
+
* prefixed fields carry domain-specific payload used only by {@link toResult}.
|
|
52
|
+
* @typedef {object} Candidate
|
|
53
|
+
* @property {'component'|'hook'|'doc'|'template'} domain
|
|
54
|
+
* @property {string} name
|
|
55
|
+
* @property {string[]} [keywords]
|
|
56
|
+
* @property {string} [description]
|
|
57
|
+
* @property {string[]} [prose]
|
|
58
|
+
* @property {string} [_import]
|
|
59
|
+
* @property {string} [_title]
|
|
60
|
+
* @property {string} [_displayName]
|
|
61
|
+
* @property {'page'|'block'} [_kind]
|
|
62
|
+
*/
|
|
63
|
+
|
|
49
64
|
/**
|
|
50
65
|
* Synonym / intent map: product-language terms an agent is likely to type,
|
|
51
66
|
* expanded to the catalog's vocabulary so oblique queries still rank. Keys and
|
|
@@ -72,10 +87,19 @@ const SYNONYMS = {
|
|
|
72
87
|
|
|
73
88
|
// Flatten into a token -> Set(expansions) lookup (bidirectional).
|
|
74
89
|
const SYNONYM_INDEX = (() => {
|
|
90
|
+
/** @type {Map<string, Set<string>>} */
|
|
75
91
|
const idx = new Map();
|
|
92
|
+
/**
|
|
93
|
+
* @param {string} a
|
|
94
|
+
* @param {string} b
|
|
95
|
+
*/
|
|
76
96
|
const add = (a, b) => {
|
|
77
|
-
|
|
78
|
-
|
|
97
|
+
let set = idx.get(a);
|
|
98
|
+
if (!set) {
|
|
99
|
+
set = new Set();
|
|
100
|
+
idx.set(a, set);
|
|
101
|
+
}
|
|
102
|
+
set.add(b);
|
|
79
103
|
};
|
|
80
104
|
for (const [key, vals] of Object.entries(SYNONYMS)) {
|
|
81
105
|
for (const v of vals) {
|
|
@@ -159,6 +183,8 @@ const MIN_TOKEN_SCORE = 50;
|
|
|
159
183
|
/**
|
|
160
184
|
* Best score for a token against a candidate, fanning out through synonyms
|
|
161
185
|
* (synonym hits are discounted so a direct hit always wins).
|
|
186
|
+
* @param {string} tok
|
|
187
|
+
* @param {Candidate} candidate
|
|
162
188
|
* @returns {{score: number, reason: string} | null}
|
|
163
189
|
*/
|
|
164
190
|
function bestForToken(tok, candidate) {
|
|
@@ -176,6 +202,12 @@ function bestForToken(tok, candidate) {
|
|
|
176
202
|
return best;
|
|
177
203
|
}
|
|
178
204
|
|
|
205
|
+
/**
|
|
206
|
+
* @param {string} term - Lowercased full query.
|
|
207
|
+
* @param {string[]} tokens - Content tokens from tokenizeQuery(term).
|
|
208
|
+
* @param {Candidate} candidate
|
|
209
|
+
* @returns {{score: number, reason: string} | null}
|
|
210
|
+
*/
|
|
179
211
|
export function scoreQuery(term, tokens, candidate) {
|
|
180
212
|
const full = scoreCandidate(term, candidate);
|
|
181
213
|
|
|
@@ -192,6 +224,7 @@ export function scoreQuery(term, tokens, candidate) {
|
|
|
192
224
|
// strong hits, then reward coverage so candidates matching more terms win.
|
|
193
225
|
let sum = 0;
|
|
194
226
|
let matched = 0;
|
|
227
|
+
/** @type {string[]} */
|
|
195
228
|
const hitTerms = [];
|
|
196
229
|
for (const tok of tokens) {
|
|
197
230
|
const h = bestForToken(tok, candidate);
|
|
@@ -235,6 +268,10 @@ export function scoreQuery(term, tokens, candidate) {
|
|
|
235
268
|
export function scoreCandidate(term, {name, keywords = [], description = '', prose = []}) {
|
|
236
269
|
let best = 0;
|
|
237
270
|
let reason = '';
|
|
271
|
+
/**
|
|
272
|
+
* @param {number} score
|
|
273
|
+
* @param {string} why
|
|
274
|
+
*/
|
|
238
275
|
const consider = (score, why) => {
|
|
239
276
|
if (score > best) {
|
|
240
277
|
best = score;
|
|
@@ -299,7 +336,12 @@ export function scoreCandidate(term, {name, keywords = [], description = '', pro
|
|
|
299
336
|
return best > 0 ? {score: best, reason} : null;
|
|
300
337
|
}
|
|
301
338
|
|
|
302
|
-
/**
|
|
339
|
+
/**
|
|
340
|
+
* Load a doc module's `docs`/`doc` export, swallowing errors.
|
|
341
|
+
* @param {string} docPath
|
|
342
|
+
* @param {string} [exportName]
|
|
343
|
+
* @returns {Promise<any>}
|
|
344
|
+
*/
|
|
303
345
|
async function loadModuleDoc(docPath, exportName = 'docs') {
|
|
304
346
|
try {
|
|
305
347
|
const mod = await import(pathToFileURL(docPath).href);
|
|
@@ -313,13 +355,16 @@ async function loadModuleDoc(docPath, exportName = 'docs') {
|
|
|
313
355
|
* Build component candidates: name + keywords + usage/description from the
|
|
314
356
|
* component's .doc.mjs.
|
|
315
357
|
* @param {string} coreDir
|
|
358
|
+
* @returns {Promise<Candidate[]>}
|
|
316
359
|
*/
|
|
317
360
|
async function gatherComponents(coreDir) {
|
|
318
361
|
const grouped = discoverComponents(coreDir);
|
|
319
362
|
const names = Object.values(grouped).flat();
|
|
363
|
+
/** @type {Candidate[]} */
|
|
320
364
|
const candidates = [];
|
|
321
365
|
for (const comp of names) {
|
|
322
366
|
const readme = findComponentReadme(coreDir, comp);
|
|
367
|
+
/** @type {string[]} */
|
|
323
368
|
let keywords = [];
|
|
324
369
|
let description = '';
|
|
325
370
|
if (readme && readme.endsWith('.doc.mjs')) {
|
|
@@ -344,13 +389,16 @@ async function gatherComponents(coreDir) {
|
|
|
344
389
|
* Build hook candidates: name + keywords + usage/description from the hook's
|
|
345
390
|
* .doc.mjs.
|
|
346
391
|
* @param {string} coreDir
|
|
392
|
+
* @returns {Promise<Candidate[]>}
|
|
347
393
|
*/
|
|
348
394
|
async function gatherHooks(coreDir) {
|
|
349
395
|
const grouped = discoverHooks(coreDir);
|
|
350
396
|
const names = Object.values(grouped).flat();
|
|
397
|
+
/** @type {Candidate[]} */
|
|
351
398
|
const candidates = [];
|
|
352
399
|
for (const hookName of names) {
|
|
353
400
|
const docPath = findHookDoc(coreDir, hookName);
|
|
401
|
+
/** @type {string[]} */
|
|
354
402
|
let keywords = [];
|
|
355
403
|
let description = '';
|
|
356
404
|
let importPath = '@astryxdesign/core/hooks';
|
|
@@ -373,9 +421,13 @@ async function gatherHooks(coreDir) {
|
|
|
373
421
|
return candidates;
|
|
374
422
|
}
|
|
375
423
|
|
|
376
|
-
/**
|
|
424
|
+
/**
|
|
425
|
+
* Build doc-topic candidates: topic name + description + section prose.
|
|
426
|
+
* @returns {Promise<Candidate[]>}
|
|
427
|
+
*/
|
|
377
428
|
async function gatherDocs() {
|
|
378
429
|
if (!fs.existsSync(DOCS_DIR)) return [];
|
|
430
|
+
/** @type {Candidate[]} */
|
|
379
431
|
const candidates = [];
|
|
380
432
|
for (const file of fs.readdirSync(DOCS_DIR)) {
|
|
381
433
|
const match = file.match(/^([\w-]+)\.doc\.mjs$/);
|
|
@@ -383,6 +435,7 @@ async function gatherDocs() {
|
|
|
383
435
|
const topic = match[1];
|
|
384
436
|
const doc = await loadModuleDoc(path.join(DOCS_DIR, file));
|
|
385
437
|
let description = '';
|
|
438
|
+
/** @type {string[]} */
|
|
386
439
|
const prose = [];
|
|
387
440
|
if (doc) {
|
|
388
441
|
description = doc.description || '';
|
|
@@ -405,7 +458,11 @@ async function gatherDocs() {
|
|
|
405
458
|
return candidates;
|
|
406
459
|
}
|
|
407
460
|
|
|
408
|
-
/**
|
|
461
|
+
/**
|
|
462
|
+
* Build template candidates (page + block) from the template discovery API.
|
|
463
|
+
* @param {string} cwd
|
|
464
|
+
* @returns {Promise<Candidate[]>}
|
|
465
|
+
*/
|
|
409
466
|
async function gatherTemplates(cwd) {
|
|
410
467
|
let templates;
|
|
411
468
|
try {
|
|
@@ -444,7 +501,7 @@ async function gatherTemplates(cwd) {
|
|
|
444
501
|
* carries enough to act on it: the domain, name, a one-line description, and
|
|
445
502
|
* the follow-up command (and import path where relevant).
|
|
446
503
|
*
|
|
447
|
-
* @param {
|
|
504
|
+
* @param {Candidate} c - candidate
|
|
448
505
|
* @param {number} score
|
|
449
506
|
* @param {string} reason
|
|
450
507
|
*/
|
|
@@ -522,6 +579,7 @@ export async function search(query, options = {}) {
|
|
|
522
579
|
}
|
|
523
580
|
|
|
524
581
|
// Gather candidates from each requested domain in parallel.
|
|
582
|
+
/** @param {string} d */
|
|
525
583
|
const wants = d => !type || type === d;
|
|
526
584
|
const [components, hooks, docTopics, templates] = await Promise.all([
|
|
527
585
|
wants('component') ? gatherComponents(coreDir) : [],
|
|
@@ -543,6 +601,7 @@ export async function search(query, options = {}) {
|
|
|
543
601
|
}
|
|
544
602
|
|
|
545
603
|
// Sort by score desc, then domain (stable order), then name.
|
|
604
|
+
/** @type {Record<string, number>} */
|
|
546
605
|
const domainOrder = {component: 0, hook: 1, doc: 2, template: 3};
|
|
547
606
|
scored.sort(
|
|
548
607
|
(a, b) =>
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file swizzle API — copy a component's source into the consumer project for
|
|
5
|
+
* customization, rewriting escaping relative imports to the OWNER package's
|
|
6
|
+
* subpaths.
|
|
7
|
+
*
|
|
8
|
+
* Side-effecting: `swizzle(name, ...)` writes files and returns a
|
|
9
|
+
* `swizzle.copy` receipt describing what it did; with no name (or `list`) it
|
|
10
|
+
* returns `swizzle.list`. Errors throw AstryxError (stable code + suggestions).
|
|
11
|
+
* All human prose / package-manager prefixing lives in the CLI renderer.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import * as fs from 'node:fs';
|
|
15
|
+
import * as path from 'node:path';
|
|
16
|
+
import {findCoreDir, listComponents} from '../../utils/paths.mjs';
|
|
17
|
+
import {assertWithin, PathSafetyError} from '../../utils/path-safety.mjs';
|
|
18
|
+
import {checkGhCli} from '../../utils/github.mjs';
|
|
19
|
+
import {Project} from '../../lib/project.mjs';
|
|
20
|
+
import {
|
|
21
|
+
CORE_PACKAGE,
|
|
22
|
+
findIntegrationComponentDoc,
|
|
23
|
+
findIntegrationComponentSource,
|
|
24
|
+
} from '../../lib/component-discovery.mjs';
|
|
25
|
+
import {ERROR_CODES} from '../../lib/error-codes.mjs';
|
|
26
|
+
import {AstryxError} from '../error.mjs';
|
|
27
|
+
|
|
28
|
+
/** Default issue tracker for maintainer feedback after swizzling. */
|
|
29
|
+
const DEFAULT_ISSUES_URL = 'https://github.com/facebook/astryx/issues/new';
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Rewrite relative imports that point outside the component directory to use
|
|
33
|
+
* the OWNER package's subpaths. Imports within the copied directory (./x) are
|
|
34
|
+
* left untouched.
|
|
35
|
+
*
|
|
36
|
+
* e.g. with ownerPackage '@astryxdesign/core':
|
|
37
|
+
* '../theme/tokens.stylex' -> '@astryxdesign/core/theme'
|
|
38
|
+
* '../utils/mergeProps' -> '@astryxdesign/core/utils'
|
|
39
|
+
*
|
|
40
|
+
* @param {string} content
|
|
41
|
+
* @param {string} [ownerPackage]
|
|
42
|
+
*/
|
|
43
|
+
export function rewriteImports(content, ownerPackage = CORE_PACKAGE) {
|
|
44
|
+
return content.replace(
|
|
45
|
+
/(from\s+['"])(\.\.\/.+?)(['"])/g,
|
|
46
|
+
(match, prefix, importPath, suffix) => {
|
|
47
|
+
const parts = importPath.replace(/^\.\.\//, '').split('/');
|
|
48
|
+
const topDir = parts[0];
|
|
49
|
+
return `${prefix}${ownerPackage}/${topDir}${suffix}`;
|
|
50
|
+
},
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Build the maintainer feedback note for a swizzled component.
|
|
56
|
+
* @param {string} component
|
|
57
|
+
* @param {string|undefined} issuesUrl
|
|
58
|
+
* @returns {{issuesUrl: string, ghCommand?: string} | null}
|
|
59
|
+
*/
|
|
60
|
+
function buildFeedback(component, issuesUrl) {
|
|
61
|
+
if (!issuesUrl) return null;
|
|
62
|
+
/** @type {{issuesUrl: string, ghCommand?: string}} */
|
|
63
|
+
const feedback = {issuesUrl};
|
|
64
|
+
const match = issuesUrl.match(
|
|
65
|
+
/^https:\/\/github\.com\/([^/]+)\/([^/]+)\/issues(?:\/new)?\/?$/,
|
|
66
|
+
);
|
|
67
|
+
if (match && checkGhCli()) {
|
|
68
|
+
const [, owner, repo] = match;
|
|
69
|
+
feedback.ghCommand = `gh issue create --repo ${owner}/${repo} --title "[${component}] Swizzle feedback"`;
|
|
70
|
+
}
|
|
71
|
+
return feedback;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Load the configured integrations + core issues URL for `cwd`, swallowing any
|
|
76
|
+
* config errors so swizzle never hard-fails on a malformed/absent config.
|
|
77
|
+
* @param {string} cwd
|
|
78
|
+
* @returns {Promise<{loadedIntegrations: import('../../lib/integrations.mjs').LoadedIntegration[], issuesUrl: string|undefined, project: Project|null}>}
|
|
79
|
+
*/
|
|
80
|
+
async function loadConfigSafely(cwd) {
|
|
81
|
+
try {
|
|
82
|
+
const project = await Project.load(cwd);
|
|
83
|
+
return {
|
|
84
|
+
loadedIntegrations: project.loadedIntegrations,
|
|
85
|
+
issuesUrl: project.config.issuesUrl,
|
|
86
|
+
project,
|
|
87
|
+
};
|
|
88
|
+
} catch {
|
|
89
|
+
return {loadedIntegrations: [], issuesUrl: undefined, project: null};
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Build the set of OWNER packages that provide a component named `name` across
|
|
95
|
+
* core + every loaded integration.
|
|
96
|
+
* @param {string} coreDir
|
|
97
|
+
* @param {Array<{name: string, components?: string, issuesUrl?: string}>} loadedIntegrations
|
|
98
|
+
* @param {string} name
|
|
99
|
+
* @param {string|undefined} coreIssuesUrl
|
|
100
|
+
* @returns {Array<{package: string, sourceDir: string|null, ownerPackage: string, issuesUrl: string|undefined}>}
|
|
101
|
+
*/
|
|
102
|
+
function resolveOwners(coreDir, loadedIntegrations, name, coreIssuesUrl) {
|
|
103
|
+
const owners = [];
|
|
104
|
+
const coreComponentDir = path.join(coreDir, 'src', name);
|
|
105
|
+
if (fs.existsSync(coreComponentDir)) {
|
|
106
|
+
owners.push({
|
|
107
|
+
package: CORE_PACKAGE,
|
|
108
|
+
sourceDir: coreComponentDir,
|
|
109
|
+
ownerPackage: CORE_PACKAGE,
|
|
110
|
+
issuesUrl: coreIssuesUrl || DEFAULT_ISSUES_URL,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
for (const integration of loadedIntegrations) {
|
|
114
|
+
const docPath = findIntegrationComponentDoc(integration, name);
|
|
115
|
+
if (!docPath) continue;
|
|
116
|
+
const sourcePath = findIntegrationComponentSource(integration, name);
|
|
117
|
+
owners.push({
|
|
118
|
+
package: integration.name,
|
|
119
|
+
sourceDir: sourcePath ? path.dirname(sourcePath) : null,
|
|
120
|
+
ownerPackage: integration.name,
|
|
121
|
+
issuesUrl: integration.issuesUrl,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
return owners;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** @param {string} file */
|
|
128
|
+
function isExcludedFromCopy(file) {
|
|
129
|
+
return (
|
|
130
|
+
file.includes('.test.') || file.includes('.doc.') || file === 'README.md'
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* List swizzlable components, or copy one component's source for customization.
|
|
136
|
+
*
|
|
137
|
+
* @param {string} [component] bare or XDS-prefixed component name; omit to list
|
|
138
|
+
* @param {{cwd?: string, output?: string, package?: string, list?: boolean, overwrite?: boolean}} [options]
|
|
139
|
+
* @returns {Promise<import('../../types/swizzle').SwizzleListResponse | import('../../types/swizzle').SwizzleCopyResponse>}
|
|
140
|
+
*/
|
|
141
|
+
export async function swizzle(component, options = {}) {
|
|
142
|
+
const {
|
|
143
|
+
cwd = process.cwd(),
|
|
144
|
+
output = './components/astryx',
|
|
145
|
+
package: pkg,
|
|
146
|
+
list = false,
|
|
147
|
+
overwrite = false,
|
|
148
|
+
} = options;
|
|
149
|
+
|
|
150
|
+
const coreDir = findCoreDir(cwd);
|
|
151
|
+
if (!coreDir) {
|
|
152
|
+
throw new AstryxError(
|
|
153
|
+
'Could not find @astryxdesign/core package. Make sure you are inside the design system monorepo or have @astryxdesign/core installed.',
|
|
154
|
+
[],
|
|
155
|
+
ERROR_CODES.ERR_CORE_NOT_FOUND,
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const components = listComponents(coreDir);
|
|
160
|
+
|
|
161
|
+
if (list || !component) {
|
|
162
|
+
return {type: 'swizzle.list', data: components};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const dirName = component.replace(/^XDS/, '');
|
|
166
|
+
|
|
167
|
+
const {loadedIntegrations, project} = await loadConfigSafely(cwd);
|
|
168
|
+
const coreIssuesUrl = project
|
|
169
|
+
? project.issuesUrl({package: CORE_PACKAGE})
|
|
170
|
+
: undefined;
|
|
171
|
+
const allOwners = resolveOwners(coreDir, loadedIntegrations, dirName, coreIssuesUrl);
|
|
172
|
+
|
|
173
|
+
if (allOwners.length === 0) {
|
|
174
|
+
throw new AstryxError(
|
|
175
|
+
`Component "${component}" not found.`,
|
|
176
|
+
components.slice(0, 10).map(n => ({name: n})),
|
|
177
|
+
ERROR_CODES.ERR_UNKNOWN_COMPONENT,
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
let owner;
|
|
182
|
+
if (pkg) {
|
|
183
|
+
owner = allOwners.find(o => o.package === pkg);
|
|
184
|
+
if (!owner) {
|
|
185
|
+
throw new AstryxError(
|
|
186
|
+
`Component "${dirName}" is not provided by package "${pkg}".`,
|
|
187
|
+
allOwners.map(o => ({name: o.package, reason: 'provides this component'})),
|
|
188
|
+
ERROR_CODES.ERR_UNKNOWN_COMPONENT,
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
} else if (allOwners.length > 1) {
|
|
192
|
+
throw new AstryxError(
|
|
193
|
+
`Component "${dirName}" is provided by multiple packages. Re-run with --package <pkg> to choose one.`,
|
|
194
|
+
allOwners.map(o => ({name: o.package, reason: 'provides this component'})),
|
|
195
|
+
ERROR_CODES.ERR_AMBIGUOUS_COMPONENT,
|
|
196
|
+
);
|
|
197
|
+
} else {
|
|
198
|
+
owner = allOwners[0];
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (!owner.sourceDir || !fs.existsSync(owner.sourceDir)) {
|
|
202
|
+
throw new AstryxError(
|
|
203
|
+
`No source found for "${dirName}" in package "${owner.package}".`,
|
|
204
|
+
[],
|
|
205
|
+
ERROR_CODES.ERR_NO_SOURCE,
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const componentDir = owner.sourceDir;
|
|
210
|
+
|
|
211
|
+
// Path-safety: --output must resolve inside cwd.
|
|
212
|
+
let outputBase;
|
|
213
|
+
try {
|
|
214
|
+
outputBase = assertWithin(output, cwd, {label: 'output directory'});
|
|
215
|
+
} catch (err) {
|
|
216
|
+
if (err instanceof PathSafetyError) {
|
|
217
|
+
throw new AstryxError(err.message, [], ERROR_CODES.ERR_PATH_TRAVERSAL);
|
|
218
|
+
}
|
|
219
|
+
throw err;
|
|
220
|
+
}
|
|
221
|
+
const outputDir = path.join(outputBase, dirName);
|
|
222
|
+
|
|
223
|
+
// Pre-flight overwrite check before any mkdir/writeFile.
|
|
224
|
+
const sourceFiles = fs.readdirSync(componentDir).filter(file => {
|
|
225
|
+
if (isExcludedFromCopy(file)) return false;
|
|
226
|
+
return fs.statSync(path.join(componentDir, file)).isFile();
|
|
227
|
+
});
|
|
228
|
+
const existingFiles = sourceFiles.filter(f =>
|
|
229
|
+
fs.existsSync(path.join(outputDir, f)),
|
|
230
|
+
);
|
|
231
|
+
if (existingFiles.length > 0 && !overwrite) {
|
|
232
|
+
const relOutputForMsg = path.relative(cwd, outputDir) || '.';
|
|
233
|
+
throw new AstryxError(
|
|
234
|
+
`Refusing to overwrite ${existingFiles.length} existing file(s) in ${relOutputForMsg}/. ` +
|
|
235
|
+
`Re-run with --overwrite (or -f) to replace them.`,
|
|
236
|
+
[],
|
|
237
|
+
ERROR_CODES.ERR_FILE_EXISTS,
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
fs.mkdirSync(outputDir, {recursive: true});
|
|
242
|
+
|
|
243
|
+
const files = fs.readdirSync(componentDir);
|
|
244
|
+
let copied = 0;
|
|
245
|
+
let usesStyleX = false;
|
|
246
|
+
for (const file of files) {
|
|
247
|
+
if (isExcludedFromCopy(file)) continue;
|
|
248
|
+
const srcPath = path.join(componentDir, file);
|
|
249
|
+
if (!fs.statSync(srcPath).isFile()) continue;
|
|
250
|
+
let content = fs.readFileSync(srcPath, 'utf-8');
|
|
251
|
+
if (file.endsWith('.ts') || file.endsWith('.tsx')) {
|
|
252
|
+
content = rewriteImports(content, owner.ownerPackage);
|
|
253
|
+
}
|
|
254
|
+
if (
|
|
255
|
+
(file.endsWith('.ts') || file.endsWith('.tsx')) &&
|
|
256
|
+
content.includes('@stylexjs/stylex')
|
|
257
|
+
) {
|
|
258
|
+
usesStyleX = true;
|
|
259
|
+
}
|
|
260
|
+
fs.writeFileSync(path.join(outputDir, file), content);
|
|
261
|
+
copied++;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const relOutput = path.relative(cwd, outputDir);
|
|
265
|
+
const copiedFiles = files.filter(
|
|
266
|
+
f =>
|
|
267
|
+
!isExcludedFromCopy(f) &&
|
|
268
|
+
fs.statSync(path.join(componentDir, f)).isFile(),
|
|
269
|
+
);
|
|
270
|
+
const feedback = buildFeedback(dirName, owner.issuesUrl);
|
|
271
|
+
|
|
272
|
+
/** @type {import('../../types/swizzle').SwizzleCopyResponse['data']} */
|
|
273
|
+
const data = {
|
|
274
|
+
component: dirName,
|
|
275
|
+
package: owner.package,
|
|
276
|
+
outputDir: relOutput,
|
|
277
|
+
filesCopied: copied,
|
|
278
|
+
files: copiedFiles.map(f => f),
|
|
279
|
+
usesStyleX,
|
|
280
|
+
};
|
|
281
|
+
if (feedback) data.feedback = feedback;
|
|
282
|
+
return {type: 'swizzle.copy', data};
|
|
283
|
+
}
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
2
|
|
|
3
3
|
import {describe, it, expect} from 'vitest';
|
|
4
|
-
import
|
|
4
|
+
import * as path from 'node:path';
|
|
5
|
+
import {fileURLToPath} from 'node:url';
|
|
6
|
+
import {rewriteImports, swizzle} from './swizzle.mjs';
|
|
7
|
+
|
|
8
|
+
// api/swizzle/ -> up 3 = packages/cli, up 4 = repo root (has packages/core).
|
|
9
|
+
const REPO = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../..');
|
|
5
10
|
|
|
6
11
|
describe('rewriteImports', () => {
|
|
7
12
|
it('rewrites ../theme/tokens to @astryxdesign/core/theme', () => {
|
|
@@ -51,3 +56,23 @@ describe('rewriteImports', () => {
|
|
|
51
56
|
);
|
|
52
57
|
});
|
|
53
58
|
});
|
|
59
|
+
|
|
60
|
+
describe('swizzle() API', () => {
|
|
61
|
+
it('no component → swizzle.list of core components', async () => {
|
|
62
|
+
const r = await swizzle(undefined, {cwd: REPO});
|
|
63
|
+
expect(r.type).toBe('swizzle.list');
|
|
64
|
+
expect(Array.isArray(r.data)).toBe(true);
|
|
65
|
+
expect(r.data).toContain('Button');
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('--list → swizzle.list even with a component arg', async () => {
|
|
69
|
+
const r = await swizzle('Button', {cwd: REPO, list: true});
|
|
70
|
+
expect(r.type).toBe('swizzle.list');
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('unknown component → AstryxError ERR_UNKNOWN_COMPONENT with suggestions', async () => {
|
|
74
|
+
await expect(swizzle('NotARealComponent99', {cwd: REPO})).rejects.toMatchObject({
|
|
75
|
+
code: 'ERR_UNKNOWN_COMPONENT',
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
});
|
|
@@ -62,7 +62,7 @@ function writeTemplate(pkgDir, id, {kind, body, withSource = true}) {
|
|
|
62
62
|
fs.writeFileSync(
|
|
63
63
|
docPath,
|
|
64
64
|
body ??
|
|
65
|
-
`import {${create}} from '${CLI_PKG}/
|
|
65
|
+
`import {${create}} from '${CLI_PKG}/authoring/template.mjs';\n` +
|
|
66
66
|
`export default ${create}({name: '${id} name', description: '${id} desc'});\n`,
|
|
67
67
|
);
|
|
68
68
|
if (withSource) {
|
|
@@ -166,7 +166,7 @@ describe('integration template discovery', () => {
|
|
|
166
166
|
);
|
|
167
167
|
fs.writeFileSync(
|
|
168
168
|
path.join(pkg2, 'templates', 'hero.doc.mjs'),
|
|
169
|
-
`import {createBlockTemplate} from '${CLI_PKG}/
|
|
169
|
+
`import {createBlockTemplate} from '${CLI_PKG}/authoring/template.mjs';\n` +
|
|
170
170
|
`export default createBlockTemplate({name: 'Hero block', description: 'b'});\n`,
|
|
171
171
|
);
|
|
172
172
|
fs.writeFileSync(
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
findRelatedBlocks,
|
|
22
22
|
} from './template.mjs';
|
|
23
23
|
|
|
24
|
-
/** Absolute path to the CLI package so fixtures can import /
|
|
24
|
+
/** Absolute path to the CLI package so fixtures can import /authoring/template.mjs. */
|
|
25
25
|
const CLI_PKG = path.resolve(import.meta.dirname, '..', '..');
|
|
26
26
|
|
|
27
27
|
let tmpDir;
|
|
@@ -68,7 +68,7 @@ function writeTemplate(pkgDir, id, {kind, suffix}) {
|
|
|
68
68
|
kind === 'page' ? 'createPageTemplate' : 'createBlockTemplate';
|
|
69
69
|
fs.writeFileSync(
|
|
70
70
|
docPath,
|
|
71
|
-
`import {${create}} from '${CLI_PKG}/
|
|
71
|
+
`import {${create}} from '${CLI_PKG}/authoring/template.mjs';\n` +
|
|
72
72
|
`export default ${create}({name: '${id} name', description: '${id} desc'});\n`,
|
|
73
73
|
);
|
|
74
74
|
fs.writeFileSync(
|
|
@@ -177,7 +177,7 @@ describe('external showcase blocks: .template.* discovered like legacy .doc.*',
|
|
|
177
177
|
fs.mkdirSync(fooDir, {recursive: true});
|
|
178
178
|
fs.writeFileSync(
|
|
179
179
|
path.join(fooDir, 'FooShowcase.template.ts'),
|
|
180
|
-
`import {createBlockTemplate} from '${CLI_PKG}/
|
|
180
|
+
`import {createBlockTemplate} from '${CLI_PKG}/authoring/template.mjs';\n` +
|
|
181
181
|
`export default createBlockTemplate({\n` +
|
|
182
182
|
` name: 'Foo — Showcase',\n` +
|
|
183
183
|
` description: 'Foo showcase.',\n` +
|