@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
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file Detect the project's package manager from lockfiles.
|
|
5
|
+
*
|
|
6
|
+
* Returns the correct command prefix for running package binaries
|
|
7
|
+
* (e.g. 'npx astryx', 'yarn astryx', 'pnpm exec astryx').
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import * as fs from 'node:fs';
|
|
11
|
+
import * as path from 'node:path';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A package manager we can install with and run binaries through.
|
|
15
|
+
* @typedef {'yarn' | 'pnpm' | 'bun' | 'npm'} PackageManager
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Result of package-manager detection. `'npx'` is the sentinel for "nothing
|
|
20
|
+
* detected" — no lockfile, no `packageManager` field, no runner user-agent —
|
|
21
|
+
* so callers fall back to npm/npx. It is a distinct value from {@link PackageManager}
|
|
22
|
+
* because it means "undetected", not "npm was chosen".
|
|
23
|
+
* @typedef {PackageManager | 'npx'} DetectedPackageManager
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/** @type {readonly PackageManager[]} */
|
|
27
|
+
const KNOWN_PMS = ['yarn', 'pnpm', 'bun', 'npm'];
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Narrow an arbitrary string to a known {@link PackageManager}.
|
|
31
|
+
* @param {string} name
|
|
32
|
+
* @returns {name is PackageManager}
|
|
33
|
+
*/
|
|
34
|
+
function isKnownPackageManager(name) {
|
|
35
|
+
return /** @type {readonly string[]} */ (KNOWN_PMS).includes(name);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Detect the package manager used in a project directory.
|
|
40
|
+
* Walks up from targetDir looking for lockfiles.
|
|
41
|
+
*
|
|
42
|
+
* Returns `'npx'` when nothing can be detected — see {@link DetectedPackageManager}.
|
|
43
|
+
*
|
|
44
|
+
* @param {string} [targetDir=process.cwd()]
|
|
45
|
+
* @returns {DetectedPackageManager}
|
|
46
|
+
*/
|
|
47
|
+
export function detectPackageManager(targetDir = process.cwd()) {
|
|
48
|
+
let dir = path.resolve(targetDir);
|
|
49
|
+
const root = path.parse(dir).root;
|
|
50
|
+
|
|
51
|
+
while (dir !== root) {
|
|
52
|
+
// 1. Lockfiles (highest priority)
|
|
53
|
+
if (fs.existsSync(path.join(dir, 'yarn.lock'))) return 'yarn';
|
|
54
|
+
if (fs.existsSync(path.join(dir, 'pnpm-lock.yaml'))) return 'pnpm';
|
|
55
|
+
if (fs.existsSync(path.join(dir, 'bun.lockb')) || fs.existsSync(path.join(dir, 'bun.lock'))) return 'bun';
|
|
56
|
+
if (fs.existsSync(path.join(dir, 'package-lock.json'))) return 'npm';
|
|
57
|
+
|
|
58
|
+
// 2. packageManager field in package.json
|
|
59
|
+
const pkgPath = path.join(dir, 'package.json');
|
|
60
|
+
if (fs.existsSync(pkgPath)) {
|
|
61
|
+
try {
|
|
62
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
63
|
+
if (pkg.packageManager) {
|
|
64
|
+
const name = pkg.packageManager.split('@')[0];
|
|
65
|
+
if (isKnownPackageManager(name)) return name;
|
|
66
|
+
}
|
|
67
|
+
} catch {
|
|
68
|
+
// Best-effort: unreadable/invalid package.json — keep walking up.
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
dir = path.dirname(dir);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// 3. npm_config_user_agent env var (set by all PMs when running scripts)
|
|
76
|
+
const ua = process.env.npm_config_user_agent;
|
|
77
|
+
if (ua) {
|
|
78
|
+
const name = ua.split('/')[0];
|
|
79
|
+
if (isKnownPackageManager(name)) return name;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return 'npx';
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Get the command prefix for running a package binary.
|
|
87
|
+
*
|
|
88
|
+
* @param {string} [targetDir]
|
|
89
|
+
* @returns {string} e.g. 'npx', 'yarn', 'pnpm exec', 'bunx'
|
|
90
|
+
*/
|
|
91
|
+
export function getRunPrefix(targetDir) {
|
|
92
|
+
const pm = detectPackageManager(targetDir);
|
|
93
|
+
switch (pm) {
|
|
94
|
+
case 'yarn': return 'yarn';
|
|
95
|
+
case 'pnpm': return 'pnpm exec';
|
|
96
|
+
case 'bun': return 'bunx';
|
|
97
|
+
case 'npm':
|
|
98
|
+
default: return 'npx';
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** The published CLI package name — used for one-off (uninstalled) invocations. */
|
|
103
|
+
export const CLI_PACKAGE = '@astryxdesign/cli';
|
|
104
|
+
|
|
105
|
+
/** The CLI binary name — only resolves once the CLI is installed (or run via CLI_PACKAGE). */
|
|
106
|
+
export const CLI_BIN = 'astryx';
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Get the one-off ("dlx") runner for the detected package manager.
|
|
110
|
+
*
|
|
111
|
+
* Unlike {@link getRunPrefix} (which runs an *installed* binary), this fetches
|
|
112
|
+
* and runs a package on demand — so it is always paired with the scoped
|
|
113
|
+
* {@link CLI_PACKAGE}, never the bare `astryx` bin. Running bare `npx astryx`
|
|
114
|
+
* without the CLI installed resolves to an unrelated package on the registry.
|
|
115
|
+
*
|
|
116
|
+
* @param {string} [targetDir]
|
|
117
|
+
* @returns {string} e.g. 'npx', 'pnpm dlx', 'yarn dlx', 'bunx'
|
|
118
|
+
*/
|
|
119
|
+
export function getDlxPrefix(targetDir) {
|
|
120
|
+
const pm = detectPackageManager(targetDir);
|
|
121
|
+
switch (pm) {
|
|
122
|
+
case 'yarn': return 'yarn dlx';
|
|
123
|
+
case 'pnpm': return 'pnpm dlx';
|
|
124
|
+
case 'bun': return 'bunx';
|
|
125
|
+
case 'npm':
|
|
126
|
+
default: return 'npx';
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Heuristic: was the running CLI launched one-off via a package runner
|
|
132
|
+
* (npx / pnpm dlx / yarn dlx / bunx) rather than from an installed dependency?
|
|
133
|
+
*
|
|
134
|
+
* We sniff the entry path (`process.argv[1]`) for well-known runner-cache
|
|
135
|
+
* markers. This errs safe in both directions: a false negative falls back to
|
|
136
|
+
* the installed form (`<prefix> astryx`, the historical behavior), and a false
|
|
137
|
+
* positive emits the always-valid scoped form (`<dlx> @astryxdesign/cli`).
|
|
138
|
+
*
|
|
139
|
+
* @returns {boolean}
|
|
140
|
+
*/
|
|
141
|
+
export function isCliOneOff() {
|
|
142
|
+
const entry = String(process.argv[1] || '').replace(/\\/g, '/');
|
|
143
|
+
return /\/_npx\/|\/dlx[-/]|\/\.bun\/install\/cache\/|\/bunx-/.test(entry);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* The safe, install-aware CLI invocation stem to suggest to users.
|
|
148
|
+
*
|
|
149
|
+
* - Installed / global / dev: `<run-prefix> astryx` (e.g. `pnpm exec astryx`).
|
|
150
|
+
* Bare `astryx` resolves to the local (or global) binary.
|
|
151
|
+
* - One-off (npx/dlx cache): `<dlx-prefix> @astryxdesign/cli` — the bare
|
|
152
|
+
* `astryx` name isn't on disk, so npm would fetch an unrelated registry
|
|
153
|
+
* package; the scoped package always resolves to us.
|
|
154
|
+
*
|
|
155
|
+
* @param {string} [targetDir]
|
|
156
|
+
* @returns {string}
|
|
157
|
+
*/
|
|
158
|
+
export function getCliInvocation(targetDir) {
|
|
159
|
+
if (isCliOneOff()) return `${getDlxPrefix(targetDir)} ${CLI_PACKAGE}`;
|
|
160
|
+
return `${getRunPrefix(targetDir)} ${CLI_BIN}`;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Format a full, runnable CLI command from a subcommand string.
|
|
165
|
+
*
|
|
166
|
+
* Accepts either `astryx component Button` or `component Button` (a leading
|
|
167
|
+
* `astryx` token is stripped) and prepends the install-aware invocation stem
|
|
168
|
+
* from {@link getCliInvocation}.
|
|
169
|
+
*
|
|
170
|
+
* @param {string} command e.g. 'astryx component Button' | 'docs tokens'
|
|
171
|
+
* @param {string} [targetDir]
|
|
172
|
+
* @returns {string}
|
|
173
|
+
*/
|
|
174
|
+
export function formatCliCommand(command, targetDir) {
|
|
175
|
+
const sub = String(command).replace(/^\s*astryx\b\s*/, '').trim();
|
|
176
|
+
const stem = getCliInvocation(targetDir);
|
|
177
|
+
return sub ? `${stem} ${sub}` : stem;
|
|
178
|
+
}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
import {describe, it, expect, afterEach, vi} from 'vitest';
|
|
4
|
+
import * as fs from 'node:fs';
|
|
5
|
+
import * as path from 'node:path';
|
|
6
|
+
import * as os from 'node:os';
|
|
7
|
+
import {
|
|
8
|
+
detectPackageManager,
|
|
9
|
+
getDlxPrefix,
|
|
10
|
+
isCliOneOff,
|
|
11
|
+
getCliInvocation,
|
|
12
|
+
formatCliCommand,
|
|
13
|
+
} from './package-manager.mjs';
|
|
14
|
+
|
|
15
|
+
let tmpDir;
|
|
16
|
+
const ORIGINAL_ARGV1 = process.argv[1];
|
|
17
|
+
|
|
18
|
+
afterEach(() => {
|
|
19
|
+
if (tmpDir) {
|
|
20
|
+
fs.rmSync(tmpDir, {recursive: true, force: true});
|
|
21
|
+
tmpDir = null;
|
|
22
|
+
}
|
|
23
|
+
vi.restoreAllMocks();
|
|
24
|
+
delete process.env.npm_config_user_agent;
|
|
25
|
+
process.argv[1] = ORIGINAL_ARGV1;
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
function makeTmpDir() {
|
|
29
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-pm-test-'));
|
|
30
|
+
return tmpDir;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
describe('detectPackageManager', () => {
|
|
34
|
+
it('detects yarn from yarn.lock', () => {
|
|
35
|
+
const dir = makeTmpDir();
|
|
36
|
+
fs.writeFileSync(path.join(dir, 'yarn.lock'), '');
|
|
37
|
+
expect(detectPackageManager(dir)).toBe('yarn');
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('detects pnpm from pnpm-lock.yaml', () => {
|
|
41
|
+
const dir = makeTmpDir();
|
|
42
|
+
fs.writeFileSync(path.join(dir, 'pnpm-lock.yaml'), '');
|
|
43
|
+
expect(detectPackageManager(dir)).toBe('pnpm');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('detects npm from package-lock.json', () => {
|
|
47
|
+
const dir = makeTmpDir();
|
|
48
|
+
fs.writeFileSync(path.join(dir, 'package-lock.json'), '{}');
|
|
49
|
+
expect(detectPackageManager(dir)).toBe('npm');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('detects bun from bun.lockb', () => {
|
|
53
|
+
const dir = makeTmpDir();
|
|
54
|
+
fs.writeFileSync(path.join(dir, 'bun.lockb'), '');
|
|
55
|
+
expect(detectPackageManager(dir)).toBe('bun');
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('detects from packageManager field in package.json (no lockfile)', () => {
|
|
59
|
+
const dir = makeTmpDir();
|
|
60
|
+
fs.writeFileSync(
|
|
61
|
+
path.join(dir, 'package.json'),
|
|
62
|
+
JSON.stringify({packageManager: 'yarn@4.1.0'}),
|
|
63
|
+
);
|
|
64
|
+
expect(detectPackageManager(dir)).toBe('yarn');
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('detects pnpm from packageManager field', () => {
|
|
68
|
+
const dir = makeTmpDir();
|
|
69
|
+
fs.writeFileSync(
|
|
70
|
+
path.join(dir, 'package.json'),
|
|
71
|
+
JSON.stringify({packageManager: 'pnpm@8.0.0'}),
|
|
72
|
+
);
|
|
73
|
+
expect(detectPackageManager(dir)).toBe('pnpm');
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('ignores unknown packageManager values', () => {
|
|
77
|
+
const dir = makeTmpDir();
|
|
78
|
+
fs.writeFileSync(
|
|
79
|
+
path.join(dir, 'package.json'),
|
|
80
|
+
JSON.stringify({packageManager: 'unknown@1.0.0'}),
|
|
81
|
+
);
|
|
82
|
+
expect(detectPackageManager(dir)).toBe('npx');
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('lockfile takes priority over packageManager field', () => {
|
|
86
|
+
const dir = makeTmpDir();
|
|
87
|
+
fs.writeFileSync(path.join(dir, 'yarn.lock'), '');
|
|
88
|
+
fs.writeFileSync(
|
|
89
|
+
path.join(dir, 'package.json'),
|
|
90
|
+
JSON.stringify({packageManager: 'pnpm@8.0.0'}),
|
|
91
|
+
);
|
|
92
|
+
expect(detectPackageManager(dir)).toBe('yarn');
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('detects from npm_config_user_agent env var', () => {
|
|
96
|
+
const dir = makeTmpDir();
|
|
97
|
+
process.env.npm_config_user_agent = 'yarn/1.22.22 node/v20.0.0';
|
|
98
|
+
expect(detectPackageManager(dir)).toBe('yarn');
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('detects pnpm from npm_config_user_agent env var', () => {
|
|
102
|
+
const dir = makeTmpDir();
|
|
103
|
+
process.env.npm_config_user_agent = 'pnpm/8.15.0 node/v20.0.0';
|
|
104
|
+
expect(detectPackageManager(dir)).toBe('pnpm');
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('falls back to npx when no signals present', () => {
|
|
108
|
+
const dir = makeTmpDir();
|
|
109
|
+
expect(detectPackageManager(dir)).toBe('npx');
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('packageManager field takes priority over npm_config_user_agent', () => {
|
|
113
|
+
const dir = makeTmpDir();
|
|
114
|
+
fs.writeFileSync(
|
|
115
|
+
path.join(dir, 'package.json'),
|
|
116
|
+
JSON.stringify({packageManager: 'bun@1.0.0'}),
|
|
117
|
+
);
|
|
118
|
+
process.env.npm_config_user_agent = 'npm/10.0.0 node/v20.0.0';
|
|
119
|
+
expect(detectPackageManager(dir)).toBe('bun');
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
describe('getDlxPrefix', () => {
|
|
124
|
+
it('returns "pnpm dlx" for pnpm projects', () => {
|
|
125
|
+
const dir = makeTmpDir();
|
|
126
|
+
fs.writeFileSync(path.join(dir, 'pnpm-lock.yaml'), '');
|
|
127
|
+
expect(getDlxPrefix(dir)).toBe('pnpm dlx');
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('returns "yarn dlx" for yarn projects', () => {
|
|
131
|
+
const dir = makeTmpDir();
|
|
132
|
+
fs.writeFileSync(path.join(dir, 'yarn.lock'), '');
|
|
133
|
+
expect(getDlxPrefix(dir)).toBe('yarn dlx');
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('returns "bunx" for bun projects', () => {
|
|
137
|
+
const dir = makeTmpDir();
|
|
138
|
+
fs.writeFileSync(path.join(dir, 'bun.lockb'), '');
|
|
139
|
+
expect(getDlxPrefix(dir)).toBe('bunx');
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('falls back to "npx" with no signals', () => {
|
|
143
|
+
const dir = makeTmpDir();
|
|
144
|
+
delete process.env.npm_config_user_agent;
|
|
145
|
+
expect(getDlxPrefix(dir)).toBe('npx');
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
describe('isCliOneOff', () => {
|
|
150
|
+
it('detects an npm npx cache entry', () => {
|
|
151
|
+
process.argv[1] = '/home/u/.npm/_npx/a1b2/node_modules/.bin/astryx';
|
|
152
|
+
expect(isCliOneOff()).toBe(true);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('detects a pnpm dlx cache entry', () => {
|
|
156
|
+
process.argv[1] = '/home/u/.cache/pnpm/dlx/9f/node_modules/@astryxdesign/cli/bin/astryx.mjs';
|
|
157
|
+
expect(isCliOneOff()).toBe(true);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it('detects a bunx cache entry', () => {
|
|
161
|
+
process.argv[1] = '/home/u/.bun/install/cache/@astryxdesign/cli/bin/astryx.mjs';
|
|
162
|
+
expect(isCliOneOff()).toBe(true);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it('is false for an installed node_modules entry', () => {
|
|
166
|
+
process.argv[1] = '/proj/node_modules/@astryxdesign/cli/bin/astryx.mjs';
|
|
167
|
+
expect(isCliOneOff()).toBe(false);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it('is false for a source checkout (dev) entry', () => {
|
|
171
|
+
process.argv[1] = '/repo/packages/cli/bin/astryx.mjs';
|
|
172
|
+
expect(isCliOneOff()).toBe(false);
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
describe('getCliInvocation', () => {
|
|
177
|
+
it('uses the run-prefix + bare bin when installed (not one-off)', () => {
|
|
178
|
+
process.argv[1] = '/proj/node_modules/@astryxdesign/cli/bin/astryx.mjs';
|
|
179
|
+
const dir = makeTmpDir();
|
|
180
|
+
fs.writeFileSync(path.join(dir, 'pnpm-lock.yaml'), '');
|
|
181
|
+
expect(getCliInvocation(dir)).toBe('pnpm exec astryx');
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it('uses the dlx runner + scoped package when run one-off', () => {
|
|
185
|
+
process.argv[1] = '/home/u/.npm/_npx/a1b2/node_modules/.bin/astryx';
|
|
186
|
+
const dir = makeTmpDir();
|
|
187
|
+
delete process.env.npm_config_user_agent;
|
|
188
|
+
expect(getCliInvocation(dir)).toBe('npx @astryxdesign/cli');
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it('pairs the dlx runner with the scoped package for pnpm one-off', () => {
|
|
192
|
+
process.argv[1] = '/home/u/.cache/pnpm/dlx/9f/node_modules/@astryxdesign/cli/bin/astryx.mjs';
|
|
193
|
+
const dir = makeTmpDir();
|
|
194
|
+
fs.writeFileSync(path.join(dir, 'pnpm-lock.yaml'), '');
|
|
195
|
+
expect(getCliInvocation(dir)).toBe('pnpm dlx @astryxdesign/cli');
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
describe('formatCliCommand', () => {
|
|
200
|
+
it('strips a leading "astryx" token and prepends the invocation stem', () => {
|
|
201
|
+
process.argv[1] = '/proj/node_modules/@astryxdesign/cli/bin/astryx.mjs';
|
|
202
|
+
const dir = makeTmpDir();
|
|
203
|
+
fs.writeFileSync(path.join(dir, 'pnpm-lock.yaml'), '');
|
|
204
|
+
expect(formatCliCommand('astryx component Button', dir)).toBe('pnpm exec astryx component Button');
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it('accepts a bare subcommand (no leading astryx)', () => {
|
|
208
|
+
process.argv[1] = '/proj/node_modules/@astryxdesign/cli/bin/astryx.mjs';
|
|
209
|
+
const dir = makeTmpDir();
|
|
210
|
+
fs.writeFileSync(path.join(dir, 'package-lock.json'), '{}');
|
|
211
|
+
expect(formatCliCommand('docs tokens', dir)).toBe('npx astryx docs tokens');
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it('rewrites to the scoped package for one-off invocations', () => {
|
|
215
|
+
process.argv[1] = '/home/u/.npm/_npx/a1b2/node_modules/.bin/astryx';
|
|
216
|
+
const dir = makeTmpDir();
|
|
217
|
+
fs.writeFileSync(path.join(dir, 'package-lock.json'), '{}');
|
|
218
|
+
expect(formatCliCommand('astryx component Button', dir)).toBe('npx @astryxdesign/cli component Button');
|
|
219
|
+
});
|
|
220
|
+
});
|
|
@@ -165,21 +165,3 @@ export function isFilePathArg(pathArg) {
|
|
|
165
165
|
const ext = path.extname(base).toLowerCase();
|
|
166
166
|
return ext.length > 0 && FILE_EXTENSIONS.has(ext);
|
|
167
167
|
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* True when the process is running non-interactively (no TTY) or when the
|
|
171
|
-
* caller has signaled JSON / scripted use. Commands consult this before
|
|
172
|
-
* prompting for confirmation; in scripted mode they require an explicit
|
|
173
|
-
* `--overwrite` flag instead.
|
|
174
|
-
*
|
|
175
|
-
* @param {object} [options]
|
|
176
|
-
* @param {boolean} [options.json] - Caller's --json flag.
|
|
177
|
-
* @returns {boolean}
|
|
178
|
-
*/
|
|
179
|
-
export function isNonInteractive({json = false} = {}) {
|
|
180
|
-
if (json) return true;
|
|
181
|
-
// stdin not a TTY means piped input or scripted execution.
|
|
182
|
-
if (process.stdin && process.stdin.isTTY === false) return true;
|
|
183
|
-
if (process.stdout && process.stdout.isTTY === false) return true;
|
|
184
|
-
return false;
|
|
185
|
-
}
|
|
@@ -13,7 +13,7 @@ import {fileURLToPath} from 'node:url';
|
|
|
13
13
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
14
14
|
|
|
15
15
|
/** Root of the @astryxdesign/cli package */
|
|
16
|
-
export const CLI_ROOT = path.resolve(__dirname, '..'
|
|
16
|
+
export const CLI_ROOT = path.resolve(__dirname, '..');
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* Find packages/core directory by walking up from startDir.
|
|
@@ -78,6 +78,7 @@ export function findProjectRoot(startDir = process.cwd()) {
|
|
|
78
78
|
* Returns array of { name, category, docsDir, blocksDir }.
|
|
79
79
|
*/
|
|
80
80
|
export function discoverExternalPackages(startDir = process.cwd()) {
|
|
81
|
+
/** @type {Array<{name: string, category: string, docsDir: string, blocksDir: string | null}>} */
|
|
81
82
|
const externals = [];
|
|
82
83
|
let dir = startDir;
|
|
83
84
|
|
|
@@ -96,6 +97,7 @@ export function discoverExternalPackages(startDir = process.cwd()) {
|
|
|
96
97
|
|
|
97
98
|
if (!nodeModulesDir) return externals;
|
|
98
99
|
|
|
100
|
+
/** @param {string} searchDir */
|
|
99
101
|
const scanDir = (searchDir) => {
|
|
100
102
|
if (!fs.existsSync(searchDir)) return;
|
|
101
103
|
const entries = fs.readdirSync(searchDir, {withFileTypes: true});
|
|
@@ -141,6 +143,7 @@ export function discoverExternalPackages(startDir = process.cwd()) {
|
|
|
141
143
|
/**
|
|
142
144
|
* List available component directories in packages/core/src.
|
|
143
145
|
* Returns directory names that contain Astryx*.tsx files.
|
|
146
|
+
* @param {string} coreDir
|
|
144
147
|
*/
|
|
145
148
|
export function listComponents(coreDir) {
|
|
146
149
|
const srcDir = path.join(coreDir, 'src');
|
|
@@ -14,12 +14,13 @@
|
|
|
14
14
|
import * as fs from 'node:fs';
|
|
15
15
|
import * as path from 'node:path';
|
|
16
16
|
import {semverGt} from './semver.mjs';
|
|
17
|
+
import {getCliInvocation} from './package-manager.mjs';
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
20
|
* Read the latest available version from local signals.
|
|
20
|
-
* No network calls — purely
|
|
21
|
+
* No network calls — purely an env-var check ($ASTRYX_LATEST_VERSION),
|
|
22
|
+
* so it takes no arguments.
|
|
21
23
|
*
|
|
22
|
-
* @param {string} [cwd] - Project directory (default: process.cwd())
|
|
23
24
|
* @returns {string|null} Latest version string, or null if unknown
|
|
24
25
|
*/
|
|
25
26
|
export function getLatestVersion() {
|
|
@@ -63,7 +64,7 @@ export function getInstalledVersion(cwd = process.cwd()) {
|
|
|
63
64
|
* @returns {string|null} FYI hint string, or null if up to date / unknown
|
|
64
65
|
*/
|
|
65
66
|
export function checkForUpdate(cwd = process.cwd()) {
|
|
66
|
-
const latest = getLatestVersion(
|
|
67
|
+
const latest = getLatestVersion();
|
|
67
68
|
if (!latest) return null;
|
|
68
69
|
|
|
69
70
|
// Persist for subsequent commands in this shell session
|
|
@@ -75,7 +76,7 @@ export function checkForUpdate(cwd = process.cwd()) {
|
|
|
75
76
|
// Use semver-aware comparison so '0.0.20' is correctly treated as greater
|
|
76
77
|
// than '0.0.5' (lexicographic compare gets that backwards).
|
|
77
78
|
if (semverGt(latest, installed)) {
|
|
78
|
-
return `FYI: A newer version of @astryxdesign/core (${latest}) is available. Install the new package version, then run:
|
|
79
|
+
return `FYI: A newer version of @astryxdesign/core (${latest}) is available. Install the new package version, then run: ${getCliInvocation()} upgrade --from <old-version> --apply`;
|
|
79
80
|
}
|
|
80
81
|
|
|
81
82
|
return null;
|
|
@@ -33,12 +33,12 @@ afterEach(() => {
|
|
|
33
33
|
describe('getLatestVersion', () => {
|
|
34
34
|
it('reads from ASTRYX_LATEST_VERSION env var', () => {
|
|
35
35
|
process.env.ASTRYX_LATEST_VERSION = '0.0.8';
|
|
36
|
-
expect(getLatestVersion(
|
|
36
|
+
expect(getLatestVersion()).toBe('0.0.8');
|
|
37
37
|
});
|
|
38
38
|
|
|
39
39
|
it('ignores invalid env var values', () => {
|
|
40
40
|
process.env.ASTRYX_LATEST_VERSION = 'not-a-version';
|
|
41
|
-
expect(getLatestVersion(
|
|
41
|
+
expect(getLatestVersion()).toBeNull();
|
|
42
42
|
});
|
|
43
43
|
|
|
44
44
|
it('returns null when no signals exist', () => {
|
|
@@ -46,7 +46,7 @@ describe('getLatestVersion', () => {
|
|
|
46
46
|
path.join(tmpDir, 'package.json'),
|
|
47
47
|
JSON.stringify({name: 'test'}),
|
|
48
48
|
);
|
|
49
|
-
expect(getLatestVersion(
|
|
49
|
+
expect(getLatestVersion()).toBeNull();
|
|
50
50
|
});
|
|
51
51
|
});
|
|
52
52
|
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
# Authoring an Astryx Integration
|
|
2
|
-
|
|
3
|
-
> **Status:** working notes. This should eventually move to the public wiki
|
|
4
|
-
> alongside the rest of the integration-authoring guidance; it lives here for
|
|
5
|
-
> now so it ships and is versioned with the CLI.
|
|
6
|
-
|
|
7
|
-
An **Integration** is an npm package that contributes components, templates, and/or
|
|
8
|
-
codemods to a consumer's design-system workflow. Consumers install the 3rd party
|
|
9
|
-
package, add a line to their astryx.config file:
|
|
10
|
-
|
|
11
|
-
```js
|
|
12
|
-
import {createConfig} from '@astryxdesign/cli/config';
|
|
13
|
-
|
|
14
|
-
export default createConfig({
|
|
15
|
-
integrations: ['@acme/astryx-widgets'],
|
|
16
|
-
...
|
|
17
|
-
});
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
Then the integration's components and templates will be surfaced alongside Astryx
|
|
21
|
-
components in the Astryx CLI.
|
|
22
|
-
|
|
23
|
-
```sh
|
|
24
|
-
astryx component AcmeCarousel --props
|
|
25
|
-
astryx component --list --package @acme/astryx-widgets
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
## The Integration File
|
|
29
|
-
|
|
30
|
-
In order to register your package as an Astryx Integration, create an
|
|
31
|
-
`astryx.integration.{ts,mjs,js}` file as a sibling to your `package.json`. This file
|
|
32
|
-
tells Astryx where to find your components, templates, codemods, etc.
|
|
33
|
-
|
|
34
|
-
```js
|
|
35
|
-
// astryx.integration.{ts,mjs,js}
|
|
36
|
-
import {createIntegration} from '@astryxdesign/cli/integration';
|
|
37
|
-
|
|
38
|
-
export default createIntegration({
|
|
39
|
-
components: './components',
|
|
40
|
-
templates: './templates',
|
|
41
|
-
codemods: './codemods',
|
|
42
|
-
issuesUrl: 'https://github.com/acme/widgets/issues',
|
|
43
|
-
});
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
## Components
|
|
47
|
-
|
|
48
|
-
Your components themselves may be exported from your library as you see fit (consumers
|
|
49
|
-
will still import them from your package) but Astryx CLI will look for a .doc.{ts,mjs,js}
|
|
50
|
-
file with the same stem e.g. `AcmeCarousel.tsx` and `AcmeCarousel.doc.ts`.
|
|
51
|
-
|
|
52
|
-
```js
|
|
53
|
-
// AcmeCarousel.doc.ts
|
|
54
|
-
import {createComponentDoc} from '@astryxdesign/cli/doc';
|
|
55
|
-
|
|
56
|
-
export default createComponentDoc({
|
|
57
|
-
name: 'AcmeCarousel',
|
|
58
|
-
description: '...',
|
|
59
|
-
...
|
|
60
|
-
});
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
## Templates
|
|
64
|
-
|
|
65
|
-
Templates are typically not exported from the package directly, but instead accessed
|
|
66
|
-
via the Astryx CLI. Consumers can look through your templates and materialize them
|
|
67
|
-
into their apps.
|
|
68
|
-
|
|
69
|
-
You define a template with the `createPageTemplate` (for full pages) or `createBlockTemplate`
|
|
70
|
-
(for smaller chunks). e.g. `AcmeLandingPage.tsx`, `AcmeLandingPage.template.ts`
|
|
71
|
-
|
|
72
|
-
```js
|
|
73
|
-
// AcmeLandingPage.template.ts
|
|
74
|
-
import {createPageTemplate} from '@astryxdesign/cli/template';
|
|
75
|
-
|
|
76
|
-
export default createPageTemplate({
|
|
77
|
-
...
|
|
78
|
-
});
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
Note that, since the CLI needs access to the template source code, you need to make sure
|
|
82
|
-
that it is included in your published package. This will also allow us to render previews
|
|
83
|
-
of templates in the future by bundling your template into a doc site build.
|
|
84
|
-
|
|
85
|
-
Typically, this is done via the package.json `exports` key.
|
|
86
|
-
|
|
87
|
-
```jsonc
|
|
88
|
-
{
|
|
89
|
-
"exports": {
|
|
90
|
-
// ...
|
|
91
|
-
"./templates/*.tsx": "./templates/*.tsx",
|
|
92
|
-
},
|
|
93
|
-
}
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
In order to verify that it's working, you can test importing the template component like this:
|
|
97
|
-
|
|
98
|
-
```ts
|
|
99
|
-
import('@acme/astryx-widgets/templates/AcmeLandingPage.tsx');
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
Import **with the `.tsx` extension** — an extensionless specifier won't resolve
|
|
103
|
-
under `moduleResolution: bundler`. The extensionful `"./templates/*.tsx"` export
|
|
104
|
-
above is what lets that import type-check without consumers enabling
|
|
105
|
-
`allowImportingTsExtensions`.
|