@astryxdesign/cli 0.1.7 → 0.1.8-canary.07362a9
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 +40 -0
- package/README.md +115 -19
- 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 +13 -10
- package/{src/api → api}/error.mjs +2 -2
- 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 +133 -115
- package/cli/commands/build.mjs +172 -0
- package/cli/commands/cli-postinstall.test.mjs +42 -0
- package/{src → cli}/commands/component/index.mjs +52 -25
- 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 +23 -12
- package/{src → cli}/commands/docs.mjs +42 -10
- 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 +40 -17
- package/{src → cli}/commands/import-hint-correctness.test.mjs +1 -1
- package/cli/commands/init.mjs +195 -0
- package/{src → cli}/commands/init.next-steps.test.mjs +1 -1
- package/cli/commands/interactive-guard.test.mjs +66 -0
- package/{src → cli}/commands/json-contract.test.mjs +2 -2
- package/{src → cli}/commands/layout.mjs +59 -19
- package/{src → cli}/commands/search.mjs +22 -15
- package/{src → cli}/commands/search.test.mjs +1 -1
- package/cli/commands/setup-nudge.test.mjs +108 -0
- package/cli/commands/swizzle.mjs +103 -0
- package/{src → cli}/commands/template.mjs +84 -53
- 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 +291 -77
- package/cli/commands/upgrade.test.mjs +314 -0
- package/{src → cli}/commands/validate-integration.mjs +17 -37
- package/{src → cli}/index.mjs +55 -19
- package/{src/codemods → codemods}/__tests__/registry.test.mjs +1 -0
- package/{src/codemods → codemods}/ensure-jscodeshift.mjs +12 -28
- 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 +4 -1
- package/{src/codemods → codemods}/run-codemod.mjs +18 -11
- package/{src/codemods → codemods}/runner.mjs +24 -14
- 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/__tests__/drop-xds-prefix-imports.test.mjs +42 -7
- package/{src/codemods → codemods}/transforms/v0.1.0/__tests__/migrate-xds-module-specifiers.test.mjs +43 -0
- package/{src/codemods → codemods}/transforms/v0.1.0/drop-xds-prefix-imports.mjs +117 -13
- 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 +86 -15
- 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/codemods/transforms/v0.1.8/__tests__/rename-avatar-size-scale.test.mjs +161 -0
- package/codemods/transforms/v0.1.8/index.mjs +19 -0
- package/codemods/transforms/v0.1.8/rename-avatar-size-scale.mjs +239 -0
- package/docs/cli-integrations.doc.mjs +150 -0
- package/docs/elevation.doc.mjs +79 -1
- package/docs/getting-started.doc.mjs +9 -9
- package/docs/internationalization.doc.mjs +92 -46
- package/docs/migration.doc.mjs +18 -18
- package/docs/principles.doc.dense.mjs +1 -1
- package/docs/principles.doc.mjs +6 -6
- package/docs/principles.doc.zh.mjs +1 -1
- package/docs/styling-libraries.doc.mjs +3 -3
- package/docs/styling.doc.mjs +4 -4
- package/docs/theme.doc.dense.mjs +2 -2
- package/docs/theme.doc.mjs +7 -7
- package/docs/theme.doc.zh.mjs +1 -1
- package/docs/tokens.doc.mjs +1 -1
- package/docs/working-with-ai.doc.mjs +19 -19
- package/{src/commands → lib/agent-docs}/agent-docs.mjs +164 -29
- package/{src/commands → lib/agent-docs}/agent-docs.path-safety.test.mjs +1 -1
- package/{src/commands → lib/agent-docs}/agent-docs.test.mjs +123 -10
- package/{src/lib → lib}/cli-error.mjs +2 -2
- package/{src/lib → lib}/component-discovery.mjs +44 -2
- package/{src/lib → lib}/component-format.mjs +67 -25
- 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 +11 -6
- package/{src/lib → lib}/json-shim.test.mjs +1 -1
- package/{src/lib → lib}/json.mjs +3 -3
- 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/lib/term-log.mjs +57 -0
- 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 +37 -28
- package/scripts/postinstall.mjs +74 -0
- package/templates/blocks/components/Avatar/AvatarFallbackChain.tsx +4 -4
- package/templates/blocks/components/Avatar/AvatarGroup.tsx +2 -2
- package/templates/blocks/components/Avatar/AvatarInitialsFallback.tsx +1 -1
- package/templates/blocks/components/Avatar/AvatarShowcase.tsx +5 -5
- package/templates/blocks/components/Avatar/AvatarUserCard.tsx +1 -1
- package/templates/blocks/components/Avatar/AvatarWithImage.tsx +4 -4
- package/templates/blocks/components/Avatar/AvatarWithStatus.tsx +3 -3
- package/templates/blocks/components/AvatarGroup/AvatarGroupShowcase.tsx +2 -2
- package/templates/blocks/components/AvatarGroupOverflow/AvatarGroupOverflowCustomText.tsx +1 -1
- package/templates/blocks/components/AvatarGroupOverflow/AvatarGroupOverflowDefault.tsx +1 -1
- package/templates/blocks/components/AvatarGroupOverflow/AvatarGroupOverflowShowcase.tsx +2 -2
- package/templates/blocks/components/AvatarStatusDot/AvatarStatusDotShowcase.tsx +3 -3
- package/templates/blocks/components/AvatarStatusDot/AvatarStatusDotVariants.tsx +3 -3
- package/templates/blocks/components/Banner/BannerFloating.doc.mjs +14 -0
- package/templates/blocks/components/Banner/BannerFloating.tsx +16 -0
- package/templates/blocks/components/Button/ButtonFloating.doc.mjs +14 -0
- package/templates/blocks/components/Button/ButtonFloating.tsx +37 -0
- package/templates/blocks/components/ButtonGroup/ButtonGroupFloating.doc.mjs +14 -0
- package/templates/blocks/components/ButtonGroup/ButtonGroupFloating.tsx +23 -0
- package/templates/blocks/components/Card/CardElevations.doc.mjs +14 -0
- package/templates/blocks/components/Card/CardElevations.tsx +32 -0
- package/templates/blocks/components/Card/ClickableCardElevated.doc.mjs +14 -0
- package/templates/blocks/components/Card/ClickableCardElevated.tsx +21 -0
- package/templates/blocks/components/Card/SelectableCardElevated.doc.mjs +14 -0
- package/templates/blocks/components/Card/SelectableCardElevated.tsx +37 -0
- package/templates/blocks/components/Carousel/CarouselSnap.tsx +1 -1
- package/templates/blocks/components/ChatComposer/ChatComposerFlat.doc.mjs +14 -0
- package/templates/blocks/components/ChatComposer/ChatComposerFlat.tsx +75 -0
- package/templates/blocks/components/ChatMessage/ChatMessageAvatarName.tsx +2 -2
- package/templates/blocks/components/ChatMessage/ChatMessageMultiBubble.tsx +1 -1
- package/templates/blocks/components/ChatMessageBubble/ChatMessageBubbleGrouping.tsx +1 -1
- package/templates/blocks/components/ChatMessageBubble/ChatMessageBubbleMetadata.tsx +1 -1
- package/templates/blocks/components/ChatMessageList/ChatMessageListDensity.tsx +5 -9
- package/templates/blocks/components/ChatMessageList/ChatMessageListFullFeatured.tsx +1 -1
- package/templates/blocks/components/CodeBlock/CodeBlockTerminal.tsx +1 -1
- package/templates/blocks/components/HoverCard/HoverCardShowcase.tsx +1 -1
- package/templates/blocks/components/IconButton/IconButtonFloating.doc.mjs +14 -0
- package/templates/blocks/components/IconButton/IconButtonFloating.tsx +37 -0
- 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/templates/blocks/components/Item/ItemWithMedia.tsx +2 -2
- package/templates/blocks/components/ListItem/ListItemWithMedia.tsx +2 -2
- package/templates/blocks/components/OverflowList/OverflowListCappedToolbar.doc.mjs +14 -0
- package/templates/blocks/components/OverflowList/OverflowListCappedToolbar.tsx +39 -0
- package/templates/blocks/components/OverflowList/OverflowListMultiRowTags.doc.mjs +14 -0
- package/templates/blocks/components/OverflowList/OverflowListMultiRowTags.tsx +44 -0
- package/templates/blocks/components/Pagination/PaginationDotsCarousel.tsx +2 -6
- package/templates/blocks/components/Stack/StackFillItem.tsx +2 -6
- package/templates/blocks/components/TabList/TabListTabsWithActions.doc.mjs +1 -1
- package/templates/blocks/components/TabList/TabListTabsWithActions.tsx +2 -7
- package/templates/blocks/components/Table/TableRowStatusTable.doc.mjs +14 -0
- package/templates/blocks/components/Table/TableRowStatusTable.tsx +59 -0
- package/templates/blocks/components/Thumbnail/ThumbnailDisabled.tsx +6 -1
- package/templates/blocks/components/Thumbnail/ThumbnailGallery.tsx +1 -0
- package/templates/blocks/components/Thumbnail/ThumbnailRemovable.tsx +1 -0
- package/templates/blocks/components/TypeaheadItem/TypeaheadItemShowcase.tsx +1 -1
- package/templates/pages/ai-chat/page.tsx +4 -4
- package/templates/pages/dashboard-portfolio/page.tsx +3 -11
- package/templates/pages/detail-page/page.tsx +5 -12
- package/templates/pages/documentation-design/page.tsx +1 -1
- package/templates/pages/messaging-shell/page.tsx +6 -8
- package/templates/pages/table-grouped/page.tsx +9 -14
- package/templates/pages/table-page/page.tsx +7 -9
- package/templates/pages/table-page-heatmap-status/page.tsx +5 -13
- package/{src/types → types}/api.contract.assert.ts +17 -8
- package/{src/types → types}/api.d.ts +110 -9
- package/{src/types → types}/base.d.ts +40 -4
- 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/{src/types → types}/index.d.ts +1 -0
- package/types/jscodeshift.d.ts +19 -0
- package/types/layout.d.ts +74 -0
- package/{src/types → types}/swizzle.d.ts +4 -0
- package/{src/types → types}/template-api.d.ts +4 -1
- package/types/theme.d.ts +53 -0
- package/types/upgrade.d.ts +108 -0
- package/utils/package-manager.mjs +178 -0
- package/utils/package-manager.test.mjs +220 -0
- package/{src/utils → utils}/path-safety.mjs +0 -18
- package/{src/utils → utils}/paths.mjs +4 -1
- package/{src/utils → utils}/update-check.mjs +5 -4
- package/{src/utils → utils}/update-check.test.mjs +3 -3
- package/docs/integration-authoring.md +0 -105
- package/src/commands/build.mjs +0 -196
- package/src/commands/init.mjs +0 -288
- package/src/commands/interactive-guard.test.mjs +0 -69
- package/src/commands/swizzle.mjs +0 -440
- package/src/commands/upgrade.test.mjs +0 -160
- package/src/types/codemod.d.ts +0 -81
- package/src/types/theme.d.ts +0 -23
- package/src/types/upgrade.d.ts +0 -64
- package/src/utils/interactive.mjs +0 -76
- package/src/utils/interactive.test.mjs +0 -70
- package/src/utils/package-manager.mjs +0 -74
- package/src/utils/package-manager.test.mjs +0 -113
- /package/{src/api → api/docs}/docOverlays.test.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/component.test.mjs +0 -0
- /package/{src → cli}/commands/detail-levels.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__/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__/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__/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/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}/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}/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}/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}/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/codemods → codemods}/transforms/v0.1.7/rename-table-renderprops-styles-to-xstyle.mjs
RENAMED
|
@@ -58,7 +58,7 @@ const RENDER_PROP_TYPES = new Set([
|
|
|
58
58
|
]);
|
|
59
59
|
|
|
60
60
|
/** Resolve the base type name from a TS type annotation node. */
|
|
61
|
-
function typeNameOf(typeAnnotation) {
|
|
61
|
+
function typeNameOf(/** @type {any} */ typeAnnotation) {
|
|
62
62
|
// `x: TableRenderProps`
|
|
63
63
|
const t = typeAnnotation?.typeAnnotation ?? typeAnnotation;
|
|
64
64
|
if (!t) return null;
|
|
@@ -68,6 +68,11 @@ function typeNameOf(typeAnnotation) {
|
|
|
68
68
|
return null;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
/**
|
|
72
|
+
* @param {import('../../../types/codemod').AstryxCodemodFile} file
|
|
73
|
+
* @param {import('../../../types/codemod').CodemodTransformApi} api
|
|
74
|
+
* @returns {string | null | undefined}
|
|
75
|
+
*/
|
|
71
76
|
export default function transformer(file, api) {
|
|
72
77
|
const j = api.jscodeshift;
|
|
73
78
|
const root = j(file.source);
|
|
@@ -77,7 +82,7 @@ export default function transformer(file, api) {
|
|
|
77
82
|
// Function/arrow params: (props: TableRenderProps) => ...
|
|
78
83
|
const renderPropBindings = new Set();
|
|
79
84
|
|
|
80
|
-
function collectParam(param) {
|
|
85
|
+
function collectParam(/** @type {any} */ param) {
|
|
81
86
|
if (
|
|
82
87
|
param.type === 'Identifier' &&
|
|
83
88
|
RENDER_PROP_TYPES.has(typeNameOf(param.typeAnnotation))
|
|
@@ -88,19 +93,19 @@ export default function transformer(file, api) {
|
|
|
88
93
|
|
|
89
94
|
root
|
|
90
95
|
.find(j.Function)
|
|
91
|
-
.forEach((p) => (p.node.params ?? []).forEach(collectParam));
|
|
96
|
+
.forEach((/** @type {any} */ p) => (p.node.params ?? []).forEach(collectParam));
|
|
92
97
|
root
|
|
93
98
|
.find(j.FunctionDeclaration)
|
|
94
|
-
.forEach((p) => (p.node.params ?? []).forEach(collectParam));
|
|
99
|
+
.forEach((/** @type {any} */ p) => (p.node.params ?? []).forEach(collectParam));
|
|
95
100
|
root
|
|
96
101
|
.find(j.FunctionExpression)
|
|
97
|
-
.forEach((p) => (p.node.params ?? []).forEach(collectParam));
|
|
102
|
+
.forEach((/** @type {any} */ p) => (p.node.params ?? []).forEach(collectParam));
|
|
98
103
|
root
|
|
99
104
|
.find(j.ArrowFunctionExpression)
|
|
100
|
-
.forEach((p) => (p.node.params ?? []).forEach(collectParam));
|
|
105
|
+
.forEach((/** @type {any} */ p) => (p.node.params ?? []).forEach(collectParam));
|
|
101
106
|
|
|
102
107
|
// Variable declarations: `const rp: BodyCellRenderProps = ...`
|
|
103
|
-
root.find(j.VariableDeclarator).forEach((p) => {
|
|
108
|
+
root.find(j.VariableDeclarator).forEach((/** @type {any} */ p) => {
|
|
104
109
|
const id = p.node.id;
|
|
105
110
|
if (
|
|
106
111
|
id?.type === 'Identifier' &&
|
|
@@ -119,10 +124,10 @@ export default function transformer(file, api) {
|
|
|
119
124
|
// 2. A spread of a tracked render-prop binding (`{...props, styles: [...]}`)
|
|
120
125
|
// — the common "carry the render-prop object forward, override styles"
|
|
121
126
|
// shape. (Only counts when `renderPropBindings` is non-empty.)
|
|
122
|
-
function isRenderPropShapedObject(objExpr) {
|
|
127
|
+
function isRenderPropShapedObject(/** @type {any} */ objExpr) {
|
|
123
128
|
if (objExpr.type !== 'ObjectExpression') return false;
|
|
124
129
|
const keyNames = objExpr.properties
|
|
125
|
-
.map((pr) =>
|
|
130
|
+
.map((/** @type {any} */ pr) =>
|
|
126
131
|
pr.type === 'ObjectProperty' || pr.type === 'Property'
|
|
127
132
|
? pr.key?.name ?? pr.key?.value
|
|
128
133
|
: null,
|
|
@@ -133,7 +138,7 @@ export default function transformer(file, api) {
|
|
|
133
138
|
}
|
|
134
139
|
// Spread of a tracked render-prop binding.
|
|
135
140
|
const spreadsRenderProp = objExpr.properties.some(
|
|
136
|
-
(pr) =>
|
|
141
|
+
(/** @type {any} */ pr) =>
|
|
137
142
|
(pr.type === 'SpreadElement' || pr.type === 'ExperimentalSpreadProperty') &&
|
|
138
143
|
pr.argument?.type === 'Identifier' &&
|
|
139
144
|
renderPropBindings.has(pr.argument.name),
|
|
@@ -146,7 +151,7 @@ export default function transformer(file, api) {
|
|
|
146
151
|
// render-prop-shaped object literals (htmlProps + styles siblings);
|
|
147
152
|
// never touch bare `styles` in this file (too ambiguous).
|
|
148
153
|
let touched = false;
|
|
149
|
-
root.find(j.ObjectExpression).forEach((p) => {
|
|
154
|
+
root.find(j.ObjectExpression).forEach((/** @type {any} */ p) => {
|
|
150
155
|
if (!isRenderPropShapedObject(p.node)) return;
|
|
151
156
|
for (const prop of p.node.properties) {
|
|
152
157
|
if (
|
|
@@ -165,7 +170,7 @@ export default function transformer(file, api) {
|
|
|
165
170
|
}
|
|
166
171
|
|
|
167
172
|
// --- 2. Rewrite `<binding>.styles` member access -> `.xstyle`. ---
|
|
168
|
-
root.find(j.MemberExpression).forEach((p) => {
|
|
173
|
+
root.find(j.MemberExpression).forEach((/** @type {any} */ p) => {
|
|
169
174
|
const {object, property, computed} = p.node;
|
|
170
175
|
if (computed) return;
|
|
171
176
|
if (property?.type !== 'Identifier' || property.name !== 'styles') return;
|
|
@@ -177,7 +182,7 @@ export default function transformer(file, api) {
|
|
|
177
182
|
});
|
|
178
183
|
|
|
179
184
|
// --- 3. Rewrite `styles:` keys on render-prop-shaped object literals. ---
|
|
180
|
-
root.find(j.ObjectExpression).forEach((p) => {
|
|
185
|
+
root.find(j.ObjectExpression).forEach((/** @type {any} */ p) => {
|
|
181
186
|
if (!isRenderPropShapedObject(p.node)) return;
|
|
182
187
|
for (const prop of p.node.properties) {
|
|
183
188
|
if (
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
import {describe, it, expect} from 'vitest';
|
|
4
|
+
|
|
5
|
+
async function applyTransform(source) {
|
|
6
|
+
const {default: transform} = await import('../rename-avatar-size-scale.mjs');
|
|
7
|
+
const jscodeshift = (await import('jscodeshift')).default;
|
|
8
|
+
const j = jscodeshift.withParser('tsx');
|
|
9
|
+
const api = {jscodeshift: j, stats: () => {}, report: () => {}};
|
|
10
|
+
const file = {source, path: 'test.tsx'};
|
|
11
|
+
const result = transform(file, api);
|
|
12
|
+
return result ?? source;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
describe('rename-avatar-size-scale', () => {
|
|
16
|
+
it('renames every named size on an Avatar JSX size attribute', async () => {
|
|
17
|
+
const input = `import {Avatar} from '@astryxdesign/core';
|
|
18
|
+
const a = <Avatar name="A" size="tiny" />;
|
|
19
|
+
const b = <Avatar name="B" size="xsmall" />;
|
|
20
|
+
const c = <Avatar name="C" size="small" />;
|
|
21
|
+
const d = <Avatar name="D" size="medium" />;
|
|
22
|
+
const e = <Avatar name="E" size="large" />;`;
|
|
23
|
+
const output = await applyTransform(input);
|
|
24
|
+
expect(output).toContain(`size='xsm'`);
|
|
25
|
+
expect(output).toContain(`size='sm'`);
|
|
26
|
+
expect(output).toContain(`size='md'`);
|
|
27
|
+
expect(output).toContain(`size='lg'`);
|
|
28
|
+
expect(output).toContain(`size='xl'`);
|
|
29
|
+
for (const old of ['tiny', 'xsmall', 'small', 'medium', 'large']) {
|
|
30
|
+
expect(output).not.toContain(`size="${old}"`);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('renames size on AvatarGroup', async () => {
|
|
35
|
+
const input = `import {AvatarGroup} from '@astryxdesign/core';
|
|
36
|
+
const x = <AvatarGroup size="medium">{kids}</AvatarGroup>;`;
|
|
37
|
+
const output = await applyTransform(input);
|
|
38
|
+
expect(output).toContain(`size='lg'`);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('leaves numeric sizes untouched', async () => {
|
|
42
|
+
const input = `import {Avatar} from '@astryxdesign/core';
|
|
43
|
+
const x = <Avatar name="A" size={48} />;`;
|
|
44
|
+
const output = await applyTransform(input);
|
|
45
|
+
expect(output).toContain('size={48}');
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('is alias-aware', async () => {
|
|
49
|
+
const input = `import {Avatar as Face} from '@astryxdesign/core';
|
|
50
|
+
const x = <Face name="A" size="small" />;`;
|
|
51
|
+
const output = await applyTransform(input);
|
|
52
|
+
expect(output).toContain(`size='md'`);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('renames the subpath and legacy import sources', async () => {
|
|
56
|
+
const sub = `import {Avatar} from '@astryxdesign/core/Avatar';
|
|
57
|
+
const x = <Avatar name="A" size="large" />;`;
|
|
58
|
+
expect(await applyTransform(sub)).toContain(`size='xl'`);
|
|
59
|
+
const legacy = `import {Avatar} from '@xds/core';
|
|
60
|
+
const x = <Avatar name="A" size="tiny" />;`;
|
|
61
|
+
expect(await applyTransform(legacy)).toContain(`size='xsm'`);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('renames a size inside a ternary on an Avatar element', async () => {
|
|
65
|
+
const input = `import {Avatar} from '@astryxdesign/core';
|
|
66
|
+
const x = <Avatar name="A" size={big ? 'large' : 'small'} />;`;
|
|
67
|
+
const output = await applyTransform(input);
|
|
68
|
+
expect(output).toContain(`big ? 'xl' : 'md'`);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('renames the UNIQUE names tiny/xsmall in Storybook options and size args', async () => {
|
|
72
|
+
const input = `import {Avatar} from '@astryxdesign/core';
|
|
73
|
+
const meta = {
|
|
74
|
+
argTypes: {size: {control: 'select', options: ['tiny', 'xsmall']}},
|
|
75
|
+
args: {size: 'tiny'},
|
|
76
|
+
};`;
|
|
77
|
+
const output = await applyTransform(input);
|
|
78
|
+
expect(output).toContain(`['xsm', 'sm']`);
|
|
79
|
+
expect(output).toContain(`size: 'xsm'`);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('renames a FULL Storybook options array (unique name unlocks ambiguous members)', async () => {
|
|
83
|
+
// The presence of a unique name (tiny/xsmall) proves the whole array is the
|
|
84
|
+
// Avatar size enum, so small/medium/large in it are safe to rename too.
|
|
85
|
+
const input = `import {Avatar} from '@astryxdesign/core';
|
|
86
|
+
const meta = {
|
|
87
|
+
argTypes: {size: {control: 'select', options: ['tiny', 'xsmall', 'small', 'medium', 'large']}},
|
|
88
|
+
};`;
|
|
89
|
+
const output = await applyTransform(input);
|
|
90
|
+
expect(output).toContain(`['xsm', 'sm', 'md', 'lg', 'xl']`);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('renames a standalone Avatar-size array literal used with .map()', async () => {
|
|
94
|
+
const input = `import {AvatarGroup} from '@astryxdesign/core';
|
|
95
|
+
const sizes = (['tiny', 'xsmall', 'small', 'medium', 'large'] as const).map(s => s);`;
|
|
96
|
+
const output = await applyTransform(input);
|
|
97
|
+
expect(output).toContain(`['xsm', 'sm', 'md', 'lg', 'xl']`);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it('does NOT rename an array of ambiguous words with no unique Avatar name', async () => {
|
|
101
|
+
// Without tiny/xsmall, the array could be anything (priorities, densities),
|
|
102
|
+
// so ambiguous members are left untouched.
|
|
103
|
+
const input = `import {Avatar} from '@astryxdesign/core';
|
|
104
|
+
const densities = ['small', 'medium', 'large'] as const;`;
|
|
105
|
+
const output = await applyTransform(input);
|
|
106
|
+
expect(output).toContain(`['small', 'medium', 'large']`);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('renames a UNIQUE name in a size-typed union literal', async () => {
|
|
110
|
+
const input = `import {Avatar} from '@astryxdesign/core';
|
|
111
|
+
type Props = {size: 'tiny' | 'xsmall'};`;
|
|
112
|
+
const output = await applyTransform(input);
|
|
113
|
+
expect(output).toContain(`'xsm' | 'sm'`);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// --- Precision guards: ambiguous common words must NOT be corrupted in
|
|
117
|
+
// --- context-blind positions, even in files that import Avatar. ---
|
|
118
|
+
|
|
119
|
+
it('does NOT rename ambiguous names in an unrelated union type', async () => {
|
|
120
|
+
const input = `import {Avatar} from '@astryxdesign/core';
|
|
121
|
+
type TaskPriority = 'urgent' | 'high' | 'medium' | 'low' | 'none';`;
|
|
122
|
+
const output = await applyTransform(input);
|
|
123
|
+
expect(output).toContain(`'medium'`);
|
|
124
|
+
expect(output).not.toContain(`'lg'`);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it('does NOT rename an ambiguous name in a non-size object property', async () => {
|
|
128
|
+
const input = `import {Avatar} from '@astryxdesign/core';
|
|
129
|
+
const cfg = {priority: 'medium', density: 'large'};`;
|
|
130
|
+
const output = await applyTransform(input);
|
|
131
|
+
expect(output).toContain(`priority: 'medium'`);
|
|
132
|
+
expect(output).toContain(`density: 'large'`);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it('does NOT rename an ambiguous name in a size-keyed object property (component unknown)', async () => {
|
|
136
|
+
// A `size: 'small'` object entry could belong to any component; renaming it
|
|
137
|
+
// blind would be unsafe, so it is left for manual migration.
|
|
138
|
+
const input = `import {Avatar} from '@astryxdesign/core';
|
|
139
|
+
const args = {size: 'small'};`;
|
|
140
|
+
const output = await applyTransform(input);
|
|
141
|
+
expect(output).toContain(`size: 'small'`);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it('does not touch files that never import Avatar/AvatarGroup', async () => {
|
|
145
|
+
const input = `import {Badge} from '@astryxdesign/core';
|
|
146
|
+
const x = <Badge size="small" />;
|
|
147
|
+
type P = 'tiny' | 'xsmall';`;
|
|
148
|
+
const output = await applyTransform(input);
|
|
149
|
+
expect(output).toContain(`size="small"`);
|
|
150
|
+
expect(output).toContain(`'tiny' | 'xsmall'`);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it('does not rename an unrelated non-size string in an Avatar file', async () => {
|
|
154
|
+
const input = `import {Avatar} from '@astryxdesign/core';
|
|
155
|
+
const label = 'small';
|
|
156
|
+
const x = <Avatar name="A" size="small" />;`;
|
|
157
|
+
const output = await applyTransform(input);
|
|
158
|
+
expect(output).toContain(`const label = 'small'`);
|
|
159
|
+
expect(output).toContain(`size='md'`);
|
|
160
|
+
});
|
|
161
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file v0.1.8 transform manifest
|
|
5
|
+
*
|
|
6
|
+
* Lists all codemods for the v0.1.8 release in the order they should run.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import renameAvatarSizeScale, {
|
|
10
|
+
meta as renameAvatarSizeScaleMeta,
|
|
11
|
+
} from './rename-avatar-size-scale.mjs';
|
|
12
|
+
|
|
13
|
+
export default [
|
|
14
|
+
{
|
|
15
|
+
name: 'rename-avatar-size-scale',
|
|
16
|
+
transform: renameAvatarSizeScale,
|
|
17
|
+
meta: renameAvatarSizeScaleMeta,
|
|
18
|
+
},
|
|
19
|
+
];
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file Codemod: Rename Avatar named sizes to Icon's abbreviated scale
|
|
5
|
+
* @see https://github.com/facebook/astryx/issues/2672
|
|
6
|
+
*
|
|
7
|
+
* As of v0.1.8, Avatar and AvatarGroup use the same abbreviated size scale as
|
|
8
|
+
* Icon (`xsm`/`sm`/`md`/`lg`/`xl`) instead of full words. Pixel values are
|
|
9
|
+
* unchanged — only the names move:
|
|
10
|
+
*
|
|
11
|
+
* tiny (20px) → xsm
|
|
12
|
+
* xsmall (24px) → sm
|
|
13
|
+
* small (36px) → md ← also the new default (was `small`)
|
|
14
|
+
* medium (48px) → lg
|
|
15
|
+
* large (128px) → xl
|
|
16
|
+
*
|
|
17
|
+
* The default size shifts from `small` to `md`, but that is the SAME 36px, so
|
|
18
|
+
* call sites that relied on the default need no change.
|
|
19
|
+
*
|
|
20
|
+
* ## Precision
|
|
21
|
+
*
|
|
22
|
+
* `small`, `medium`, and `large` are common English words that appear as
|
|
23
|
+
* unrelated string/type literals (priorities, statuses, breakpoints, …). To
|
|
24
|
+
* avoid corrupting those, the three AMBIGUOUS names are renamed ONLY in a
|
|
25
|
+
* precise context: a `size` JSX attribute on a component that resolves to an
|
|
26
|
+
* Avatar/AvatarGroup import (alias-aware).
|
|
27
|
+
*
|
|
28
|
+
* `tiny` and `xsmall` are unique to Avatar's scale, so they are additionally
|
|
29
|
+
* renamed in context-blind positions (object properties keyed `size`/`*Size`,
|
|
30
|
+
* Storybook `options` arrays, and size-typed union literals) within files that
|
|
31
|
+
* import Avatar/AvatarGroup.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
export const meta = {
|
|
35
|
+
title: 'Rename Avatar named sizes tiny/xsmall/small/medium/large → xsm/sm/md/lg/xl',
|
|
36
|
+
description:
|
|
37
|
+
'Avatar and AvatarGroup adopt Icon\'s abbreviated size scale ' +
|
|
38
|
+
'(xsm/sm/md/lg/xl). Pixel values are unchanged; the default moves from ' +
|
|
39
|
+
'`small` to `md` (both 36px). The ambiguous names small/medium/large are ' +
|
|
40
|
+
'only renamed on Avatar/AvatarGroup `size` JSX attributes; the unique ' +
|
|
41
|
+
'names tiny/xsmall are also renamed in size-keyed props, Storybook ' +
|
|
42
|
+
'options, and union types in files importing Avatar/AvatarGroup.',
|
|
43
|
+
pr: '#2672',
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/** Import sources that provide the Astryx Avatar/AvatarGroup components. */
|
|
47
|
+
const IMPORT_SOURCES = new Set([
|
|
48
|
+
'@astryxdesign/core',
|
|
49
|
+
'@astryxdesign/core/Avatar',
|
|
50
|
+
'@astryxdesign/core/AvatarGroup',
|
|
51
|
+
'@xds/core',
|
|
52
|
+
'@xds/core/Avatar',
|
|
53
|
+
'@xds/core/AvatarGroup',
|
|
54
|
+
]);
|
|
55
|
+
|
|
56
|
+
/** Component names whose `size` prop is renamed. */
|
|
57
|
+
const TARGET_IMPORTED_NAMES = new Set(['Avatar', 'AvatarGroup']);
|
|
58
|
+
|
|
59
|
+
/** Old → new size-name mapping. */
|
|
60
|
+
const RENAMES = new Map([
|
|
61
|
+
['tiny', 'xsm'],
|
|
62
|
+
['xsmall', 'sm'],
|
|
63
|
+
['small', 'md'],
|
|
64
|
+
['medium', 'lg'],
|
|
65
|
+
['large', 'xl'],
|
|
66
|
+
]);
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Ambiguous names — common words that must ONLY be renamed in a precise
|
|
70
|
+
* context. `tiny`/`xsmall` are omitted because they are unique to Avatar's
|
|
71
|
+
* scale; their presence in a collection proves it is an Avatar size enum.
|
|
72
|
+
*/
|
|
73
|
+
const AMBIGUOUS = new Set(['small', 'medium', 'large']);
|
|
74
|
+
|
|
75
|
+
/** Names that appear only in Avatar's scale — safe signals of Avatar sizing. */
|
|
76
|
+
const UNIQUE = new Set(['tiny', 'xsmall']);
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Rename a string-literal node if its value is an old size name.
|
|
80
|
+
* Unwraps `'small' as const`. In non-precise contexts, ambiguous names are
|
|
81
|
+
* skipped. Returns true when a rename occurred.
|
|
82
|
+
*/
|
|
83
|
+
function renameValue(/** @type {any} */ node, {precise = false} = {}) {
|
|
84
|
+
if (!node) return false;
|
|
85
|
+
const target = node.type === 'TSAsExpression' ? node.expression : node;
|
|
86
|
+
const isString =
|
|
87
|
+
target.type === 'StringLiteral' || target.type === 'Literal';
|
|
88
|
+
if (!isString || typeof target.value !== 'string') return false;
|
|
89
|
+
const replacement = RENAMES.get(target.value);
|
|
90
|
+
if (!replacement) return false;
|
|
91
|
+
if (!precise && AMBIGUOUS.has(target.value)) return false;
|
|
92
|
+
target.value = replacement;
|
|
93
|
+
if (target.raw) target.raw = undefined;
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Extract a plain string value from a literal-ish node, or null. */
|
|
98
|
+
function literalString(/** @type {any} */ node) {
|
|
99
|
+
const target = node?.type === 'TSAsExpression' ? node.expression : node;
|
|
100
|
+
if (
|
|
101
|
+
target &&
|
|
102
|
+
(target.type === 'StringLiteral' || target.type === 'Literal') &&
|
|
103
|
+
typeof target.value === 'string'
|
|
104
|
+
) {
|
|
105
|
+
return target.value;
|
|
106
|
+
}
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* @param {import('../../../types/codemod').AstryxCodemodFile} file
|
|
112
|
+
* @param {import('../../../types/codemod').CodemodTransformApi} api
|
|
113
|
+
* @returns {string | null | undefined}
|
|
114
|
+
*/
|
|
115
|
+
export default function transformer(file, api) {
|
|
116
|
+
const j = api.jscodeshift;
|
|
117
|
+
const root = j(file.source);
|
|
118
|
+
let hasChanges = false;
|
|
119
|
+
|
|
120
|
+
// Track alias-aware local names for the target components.
|
|
121
|
+
const targetLocals = new Set();
|
|
122
|
+
root.find(j.ImportDeclaration).forEach((/** @type {any} */ path) => {
|
|
123
|
+
if (!IMPORT_SOURCES.has(path.node.source.value)) return;
|
|
124
|
+
for (const spec of path.node.specifiers ?? []) {
|
|
125
|
+
if (
|
|
126
|
+
spec.type === 'ImportSpecifier' &&
|
|
127
|
+
TARGET_IMPORTED_NAMES.has(spec.imported.name)
|
|
128
|
+
) {
|
|
129
|
+
targetLocals.add(spec.local.name);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
if (targetLocals.size === 0) return undefined;
|
|
135
|
+
|
|
136
|
+
function renameArrayElements(/** @type {any} */ node) {
|
|
137
|
+
let arr = node;
|
|
138
|
+
if (arr.type === 'TSAsExpression') arr = arr.expression;
|
|
139
|
+
if (arr.type !== 'ArrayExpression') return;
|
|
140
|
+
// If the array contains a name unique to Avatar's scale (tiny/xsmall), the
|
|
141
|
+
// whole collection is unambiguously the Avatar size enum, so it is safe to
|
|
142
|
+
// rename the ambiguous members too. Otherwise stay conservative.
|
|
143
|
+
const precise = arr.elements.some((/** @type {any} */ el) => UNIQUE.has(literalString(el)));
|
|
144
|
+
for (const el of arr.elements) {
|
|
145
|
+
if (renameValue(el, {precise})) hasChanges = true;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// 1. `size` JSX attributes on target components — PRECISE (component known),
|
|
150
|
+
// so all five names, including the ambiguous ones, are renamed here.
|
|
151
|
+
root.find(j.JSXOpeningElement).forEach((/** @type {any} */ path) => {
|
|
152
|
+
const name = path.node.name;
|
|
153
|
+
const componentName = name.type === 'JSXIdentifier' ? name.name : null;
|
|
154
|
+
if (!componentName || !targetLocals.has(componentName)) return;
|
|
155
|
+
|
|
156
|
+
for (const attr of path.node.attributes) {
|
|
157
|
+
if (attr.type !== 'JSXAttribute' || attr.name?.name !== 'size') continue;
|
|
158
|
+
const value = attr.value;
|
|
159
|
+
|
|
160
|
+
// size="small"
|
|
161
|
+
if (renameValue(value, {precise: true})) {
|
|
162
|
+
hasChanges = true;
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
if (
|
|
166
|
+
value &&
|
|
167
|
+
value.type === 'JSXExpressionContainer' &&
|
|
168
|
+
value.expression
|
|
169
|
+
) {
|
|
170
|
+
// size={'small'}
|
|
171
|
+
if (renameValue(value.expression, {precise: true})) {
|
|
172
|
+
hasChanges = true;
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
// size={cond ? 'small' : 'large'}
|
|
176
|
+
if (value.expression.type === 'ConditionalExpression') {
|
|
177
|
+
if (renameValue(value.expression.consequent, {precise: true}))
|
|
178
|
+
hasChanges = true;
|
|
179
|
+
if (renameValue(value.expression.alternate, {precise: true}))
|
|
180
|
+
hasChanges = true;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
// 2. Object properties keyed `size` (or `*Size`) + Storybook `options`
|
|
187
|
+
// arrays — NON-PRECISE (the component isn't known here), so only the
|
|
188
|
+
// unique names tiny/xsmall are renamed.
|
|
189
|
+
const PropertyType = j.ObjectProperty ?? j.Property;
|
|
190
|
+
root.find(PropertyType).forEach((/** @type {any} */ path) => {
|
|
191
|
+
const key = path.node.key;
|
|
192
|
+
const keyName =
|
|
193
|
+
key.type === 'Identifier'
|
|
194
|
+
? key.name
|
|
195
|
+
: key.type === 'StringLiteral' || key.type === 'Literal'
|
|
196
|
+
? key.value
|
|
197
|
+
: null;
|
|
198
|
+
if (typeof keyName !== 'string') return;
|
|
199
|
+
|
|
200
|
+
const lower = keyName.toLowerCase();
|
|
201
|
+
if (lower !== 'size' && !lower.endsWith('size')) return;
|
|
202
|
+
|
|
203
|
+
const value = path.node.value;
|
|
204
|
+
// size: 'tiny'
|
|
205
|
+
if (renameValue(value)) {
|
|
206
|
+
hasChanges = true;
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
// size: { control: 'select', options: ['tiny', ...] }
|
|
210
|
+
if (value.type === 'ObjectExpression') {
|
|
211
|
+
const optionsProp = value.properties.find(
|
|
212
|
+
(/** @type {any} */ p) => p.key && (p.key.name === 'options' || p.key.value === 'options'),
|
|
213
|
+
);
|
|
214
|
+
if (optionsProp) renameArrayElements(optionsProp.value);
|
|
215
|
+
}
|
|
216
|
+
// size: ['tiny', 'xsmall', ...]
|
|
217
|
+
renameArrayElements(value);
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
// 3. Union-type literals — NON-PRECISE, so only the unique names tiny/xsmall
|
|
221
|
+
// are renamed. This avoids corrupting unrelated unions that happen to use
|
|
222
|
+
// common words like 'medium' (e.g. a priority or breakpoint type) in a
|
|
223
|
+
// file that also imports Avatar.
|
|
224
|
+
root.find(j.TSLiteralType).forEach((/** @type {any} */ path) => {
|
|
225
|
+
if (renameValue(path.node.literal)) hasChanges = true;
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
// 4. Standalone array literals whose members are exactly the Avatar size
|
|
229
|
+
// scale (identified by the presence of a unique name like tiny/xsmall) —
|
|
230
|
+
// e.g. `(['tiny', 'xsmall', 'small', 'medium', 'large'] as const).map(...)`
|
|
231
|
+
// used to render every size. The unique name proves the whole array is the
|
|
232
|
+
// Avatar enum, so its ambiguous members can be renamed safely.
|
|
233
|
+
root.find(j.ArrayExpression).forEach((/** @type {any} */ path) => {
|
|
234
|
+
renameArrayElements(path.node);
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
if (!hasChanges) return undefined;
|
|
238
|
+
return root.toSource({quote: 'single'});
|
|
239
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/** @type {import('../../core/src/docs-types').ReferenceDoc} */
|
|
4
|
+
|
|
5
|
+
export const docs = {
|
|
6
|
+
name: 'cli-integrations',
|
|
7
|
+
title: 'CLI Integrations',
|
|
8
|
+
category: 'guide',
|
|
9
|
+
description:
|
|
10
|
+
'Author an npm package that contributes components, templates, and upgrade codemods to Astryx.',
|
|
11
|
+
|
|
12
|
+
sections: [
|
|
13
|
+
{
|
|
14
|
+
title: 'Overview',
|
|
15
|
+
category: 'guide',
|
|
16
|
+
content: [
|
|
17
|
+
{
|
|
18
|
+
type: 'prose',
|
|
19
|
+
text: 'An integration is an npm package that contributes components, templates, and/or upgrade codemods to a consumer\u2019s design-system workflow. Consumers install the package and add it to their `astryx.config`; from then on the integration\u2019s contributions show up alongside core\u2019s in the same CLI commands.',
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
type: 'prose',
|
|
23
|
+
text: 'The system runs on two files. The consumer writes `astryx.config.{ts,mjs,js}` at their project root to list which packages to load. The author writes `astryx.integration.{ts,mjs,js}` at the package root to declare what the package contributes. This page is the author\u2019s guide. For the consumer side, run `npx astryx docs getting-started`.',
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
type: 'prose',
|
|
27
|
+
text: 'On the consumer side, adding your package is one line:',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
type: 'code',
|
|
31
|
+
lang: 'typescript',
|
|
32
|
+
code: "import {createConfig} from '@astryxdesign/core/config';\n\nexport default createConfig({\n integrations: ['@acme/astryx-widgets'],\n});",
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
type: 'prose',
|
|
36
|
+
text: 'Your components and templates then appear next to core\u2019s:',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
type: 'code',
|
|
40
|
+
lang: 'bash',
|
|
41
|
+
code: 'astryx component --list --package @acme/astryx-widgets\nastryx component AcmeCarousel --props',
|
|
42
|
+
},
|
|
43
|
+
],
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
title: 'The Integration File',
|
|
47
|
+
category: 'guide',
|
|
48
|
+
content: [
|
|
49
|
+
{
|
|
50
|
+
type: 'prose',
|
|
51
|
+
text: 'To register your package as an integration, add an `astryx.integration.{ts,mjs,js}` file as a sibling of your `package.json`. It tells the CLI where to find your components, templates, and codemods. Identity (name, version) comes from your `package.json`, not this file.',
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
type: 'code',
|
|
55
|
+
lang: 'typescript',
|
|
56
|
+
code: "// astryx.integration.ts\nimport {createIntegration} from '@astryxdesign/core/authoring';\n\nexport default createIntegration({\n components: './components',\n templates: './templates',\n codemods: './codemods',\n issuesUrl: 'https://github.com/acme/widgets/issues',\n});",
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
type: 'prose',
|
|
60
|
+
text: 'Every field is optional. Declare only the contribution roots your package ships. `createIntegration` is a type-preserving helper for editor autocomplete and type-checking. It lives in `@astryxdesign/core/authoring` and is also re-exported from `@astryxdesign/cli/integration` for back-compat.',
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
title: 'Components',
|
|
66
|
+
category: 'guide',
|
|
67
|
+
content: [
|
|
68
|
+
{
|
|
69
|
+
type: 'prose',
|
|
70
|
+
text: 'Export your components from your library however you like, and consumers still import them from your package. For each component the CLI should document, ship a `.doc.{ts,mjs,js}` file with the same stem, for example `AcmeCarousel.tsx` alongside `AcmeCarousel.doc.ts`.',
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
type: 'code',
|
|
74
|
+
lang: 'typescript',
|
|
75
|
+
code: "// AcmeCarousel.doc.ts\nimport {createComponentDoc} from '@astryxdesign/core/authoring';\n\nexport default createComponentDoc({\n name: 'AcmeCarousel',\n description: 'A carousel that cycles through slides.',\n // props, usage, examples, ...\n});",
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
title: 'Templates',
|
|
81
|
+
category: 'guide',
|
|
82
|
+
content: [
|
|
83
|
+
{
|
|
84
|
+
type: 'prose',
|
|
85
|
+
text: 'Templates are usually not exported from the package directly. Instead, consumers browse them through the CLI and materialize them into their app. Define a template with `createPageTemplate` (full pages) or `createBlockTemplate` (smaller chunks) in a `.template.{ts,mjs,js}` file next to the source, for example `AcmeLandingPage.tsx` and `AcmeLandingPage.template.ts`.',
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
type: 'code',
|
|
89
|
+
lang: 'typescript',
|
|
90
|
+
code: "// AcmeLandingPage.template.ts\nimport {createPageTemplate} from '@astryxdesign/core/authoring';\n\nexport default createPageTemplate({\n // name, description, preview, ...\n});",
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
type: 'prose',
|
|
94
|
+
text: 'The CLI needs the template source at consume time, so make sure it is included in your published package. This is typically done via the `exports` key in `package.json`. It also lets the docsite render template previews in the future.',
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
type: 'code',
|
|
98
|
+
lang: 'jsonc',
|
|
99
|
+
code: '{\n "exports": {\n // ...\n "./templates/*.tsx": "./templates/*.tsx"\n }\n}',
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
type: 'prose',
|
|
103
|
+
text: 'To verify it resolves, try importing the template component with its `.tsx` extension. An extensionless specifier will not resolve under `moduleResolution: bundler`, and the extensionful export above is what lets this type-check without consumers enabling `allowImportingTsExtensions`.',
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
type: 'code',
|
|
107
|
+
lang: 'typescript',
|
|
108
|
+
code: "import('@acme/astryx-widgets/templates/AcmeLandingPage.tsx');",
|
|
109
|
+
},
|
|
110
|
+
],
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
title: 'Codemods',
|
|
114
|
+
category: 'guide',
|
|
115
|
+
content: [
|
|
116
|
+
{
|
|
117
|
+
type: 'prose',
|
|
118
|
+
text: 'Ship codemods so `astryx upgrade` can migrate consumers across breaking changes in your package. Point the integration file\u2019s `codemods` field at your codemods root, and author each one with `createCodemod` (transforms source files) or `createConfigCodemod` (rewrites the consumer\u2019s `astryx.config`).',
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
type: 'code',
|
|
122
|
+
lang: 'typescript',
|
|
123
|
+
code: "// codemods/v2-rename-prop.ts\nimport {createCodemod} from '@astryxdesign/cli/codemod';\n\nexport default createCodemod({\n // version, description, transform, ...\n});",
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
type: 'prose',
|
|
127
|
+
text: 'The codemod helpers live in `@astryxdesign/cli/codemod`, not `@astryxdesign/core/authoring` like the doc, integration, and template helpers. Consumers can also run their own post-codemod hooks, such as a reinstall or rebuild, via `hooks.postCodemod` in their `astryx.config`.',
|
|
128
|
+
},
|
|
129
|
+
],
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
title: 'How It Works',
|
|
133
|
+
category: 'guide',
|
|
134
|
+
content: [
|
|
135
|
+
{
|
|
136
|
+
type: 'prose',
|
|
137
|
+
text: 'Every CLI command loads the consumer\u2019s `astryx.config`, resolves each listed integration\u2019s manifest from `node_modules`, and discovers its contributions. Everything is validated against one strict schema at the load boundary. The `create*` helpers do not validate. They are identity functions whose value is their TypeScript surface, so validation happens when the CLI loads the file, not when you author it.',
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
type: 'prose',
|
|
141
|
+
text: 'Discovery is resilient. A broken or misconfigured integration is skipped with a single non-blocking warning on stderr instead of crashing the CLI, and it never corrupts a `--json` stdout envelope. Everyday commands keep working with the remaining valid contributions.',
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
type: 'prose',
|
|
145
|
+
text: 'To inspect problems, run `astryx validate-integration <package>` for a detailed report on one package, or `astryx doctor` for an overall health check of the setup.',
|
|
146
|
+
},
|
|
147
|
+
],
|
|
148
|
+
},
|
|
149
|
+
],
|
|
150
|
+
};
|