@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/lib/term-log.mjs
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file Minimal non-interactive terminal logger.
|
|
5
|
+
*
|
|
6
|
+
* @input message strings from CLI commands/codemods
|
|
7
|
+
* @output plain lines on stdout via humanLog (suppressed in --json mode)
|
|
8
|
+
* @position src/lib — shared output helper, no side effects on import
|
|
9
|
+
*
|
|
10
|
+
* The CLI is fully non-interactive: it never prompts, so it only needs plain,
|
|
11
|
+
* unbuffered output. This provides the *output-only* surface (`log.*`, `intro`,
|
|
12
|
+
* `outro`) the CLI needs, so it has no dependency on any prompt library.
|
|
13
|
+
*
|
|
14
|
+
* All output is routed through `humanLog`, the CLI's stdout-discipline
|
|
15
|
+
* primitive, which is a no-op in `--json` mode — so these human logs can never
|
|
16
|
+
* corrupt a JSON envelope.
|
|
17
|
+
*
|
|
18
|
+
* Call sites use it as `import * as p from './term-log.mjs'` and call
|
|
19
|
+
* `p.log.info(...)`, `p.intro(...)`, `p.outro(...)`.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import {humanLog} from './json.mjs';
|
|
23
|
+
|
|
24
|
+
/** @param {unknown} msg */
|
|
25
|
+
const toStr = (msg) => (msg === undefined || msg === null ? '' : String(msg));
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Human-facing log surface (the small `log` API the CLI uses). All lines go to
|
|
29
|
+
* stdout via humanLog; the level prefixes are cosmetic. `--json` mode suppresses
|
|
30
|
+
* every one of these, keeping machine-readable stdout clean.
|
|
31
|
+
*/
|
|
32
|
+
export const log = {
|
|
33
|
+
/** @param {unknown} msg */
|
|
34
|
+
message: (msg) => humanLog(toStr(msg)),
|
|
35
|
+
/** @param {unknown} msg */
|
|
36
|
+
info: (msg) => humanLog(toStr(msg)),
|
|
37
|
+
/** @param {unknown} msg */
|
|
38
|
+
step: (msg) => humanLog(toStr(msg)),
|
|
39
|
+
/** @param {unknown} msg */
|
|
40
|
+
success: (msg) => humanLog(`✓ ${toStr(msg)}`),
|
|
41
|
+
/** @param {unknown} msg */
|
|
42
|
+
warn: (msg) => humanLog(`⚠ ${toStr(msg)}`),
|
|
43
|
+
/** @param {unknown} msg */
|
|
44
|
+
error: (msg) => humanLog(`✗ ${toStr(msg)}`),
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/** Banner printed at the start of a multi-step command.
|
|
48
|
+
* @param {unknown} title */
|
|
49
|
+
export function intro(title) {
|
|
50
|
+
humanLog(`\n${toStr(title)}`);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Footer printed at the end of a multi-step command.
|
|
54
|
+
* @param {unknown} message */
|
|
55
|
+
export function outro(message) {
|
|
56
|
+
humanLog(`${toStr(message)}\n`);
|
|
57
|
+
}
|
|
@@ -23,11 +23,21 @@ import {hydrateRegistry} from './registry-core.mjs';
|
|
|
23
23
|
export {parse, detectForm, XLEParseError, validate, expand, toCompact, toOutline};
|
|
24
24
|
export {hydrateRegistry, serializeRegistry, ALIAS_TABLE, resolveComponent, SPACING_STEPS} from './registry-core.mjs';
|
|
25
25
|
|
|
26
|
-
/**
|
|
26
|
+
/**
|
|
27
|
+
* Accept either a hydrated registry (Map fields) or serialized JSON.
|
|
28
|
+
* @param {import('./xle-ast').Registry | import('./browser').SerializedRegistry | object} registry
|
|
29
|
+
* @returns {import('./xle-ast').Registry}
|
|
30
|
+
*/
|
|
27
31
|
function asRegistry(registry) {
|
|
28
|
-
return registry && registry.components instanceof Map
|
|
32
|
+
return registry && /** @type {any} */ (registry).components instanceof Map
|
|
33
|
+
? /** @type {import('./xle-ast').Registry} */ (registry)
|
|
34
|
+
: hydrateRegistry(/** @type {import('./browser').SerializedRegistry} */ (registry));
|
|
29
35
|
}
|
|
30
36
|
|
|
37
|
+
/**
|
|
38
|
+
* @param {import('./xle-ast').RawIssue | {message: string, line?: number, col?: number}} issue
|
|
39
|
+
* @returns {string}
|
|
40
|
+
*/
|
|
31
41
|
function formatIssue(issue) {
|
|
32
42
|
const where = issue.line != null ? `line ${issue.line}: ` : '';
|
|
33
43
|
return `${where}${issue.message}`;
|
|
@@ -38,12 +48,12 @@ function formatIssue(issue) {
|
|
|
38
48
|
* twin of `layout check`. Never throws on invalid input; returns the errors.
|
|
39
49
|
*
|
|
40
50
|
* @param {string} expression
|
|
41
|
-
* @param {object} registry - serialized or hydrated
|
|
51
|
+
* @param {import('./xle-ast').Registry | import('./browser').SerializedRegistry | object} registry - serialized or hydrated
|
|
42
52
|
* @param {object} [opts]
|
|
43
|
-
* @param {
|
|
53
|
+
* @param {import('./browser').XLEBlock[]} [opts.blocks] - block list for {hint} resolution (default [])
|
|
44
54
|
* @param {'compact'|'outline'|'auto'} [opts.form]
|
|
45
55
|
* @param {boolean} [opts.loose]
|
|
46
|
-
* @returns {
|
|
56
|
+
* @returns {import('./browser').CheckResult}
|
|
47
57
|
*/
|
|
48
58
|
export function checkExpression(expression, registry, opts = {}) {
|
|
49
59
|
const {blocks = [], form = 'auto', loose = false} = opts;
|
|
@@ -79,13 +89,13 @@ export function checkExpression(expression, registry, opts = {}) {
|
|
|
79
89
|
* Returns either {code, ...} or {errors} (never writes files).
|
|
80
90
|
*
|
|
81
91
|
* @param {string} expression
|
|
82
|
-
* @param {object} registry
|
|
92
|
+
* @param {import('./xle-ast').Registry | import('./browser').SerializedRegistry | object} registry
|
|
83
93
|
* @param {object} [opts]
|
|
84
|
-
* @param {
|
|
94
|
+
* @param {import('./browser').XLEBlock[]} [opts.blocks]
|
|
85
95
|
* @param {'compact'|'outline'|'auto'} [opts.form]
|
|
86
96
|
* @param {boolean} [opts.loose]
|
|
87
97
|
* @param {string} [opts.name] - generated component name (PascalCase)
|
|
88
|
-
* @param {Map} [opts.blockModules] - prepared block sources/imports for splicing;
|
|
98
|
+
* @param {Map<string, import('./xle-ast').BlockModule>} [opts.blockModules] - prepared block sources/imports for splicing;
|
|
89
99
|
* omit in the browser (hints stay as TODO markers without sources)
|
|
90
100
|
*/
|
|
91
101
|
export function expandExpression(expression, registry, opts = {}) {
|
|
@@ -21,24 +21,31 @@ import {mergeImports, renderImport, prepareSpliceModule} from './splice.mjs';
|
|
|
21
21
|
|
|
22
22
|
const INDENT = ' ';
|
|
23
23
|
|
|
24
|
+
/** @param {string | null | undefined} text */
|
|
24
25
|
function slugify(text) {
|
|
25
26
|
return String(text).toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '');
|
|
26
27
|
}
|
|
27
28
|
|
|
29
|
+
/** @param {string} text */
|
|
28
30
|
function camelCase(text) {
|
|
29
31
|
const parts = slugify(text).split('-').filter(Boolean);
|
|
30
32
|
if (parts.length === 0) return 'item';
|
|
31
33
|
return parts[0] + parts.slice(1).map(p => p[0].toUpperCase() + p.slice(1)).join('');
|
|
32
34
|
}
|
|
33
35
|
|
|
36
|
+
/** @param {import('./xle-ast').XLEValue} value */
|
|
34
37
|
function escapeAttr(value) {
|
|
35
38
|
return String(value).replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
36
39
|
}
|
|
37
40
|
|
|
41
|
+
/**
|
|
42
|
+
* @param {import('./xle-ast').XLEItem} item
|
|
43
|
+
* @returns {import('./xle-ast').XLEItem}
|
|
44
|
+
*/
|
|
38
45
|
function cloneItem(item) {
|
|
39
46
|
// .bound holds a registry reference (Map props) — rebuild it after the
|
|
40
47
|
// JSON round-trip of the plain AST fields.
|
|
41
|
-
const {bound, ...rest} = item;
|
|
48
|
+
const {bound, ...rest} = /** @type {import('./xle-ast').XLENode} */ (item);
|
|
42
49
|
const copy = JSON.parse(JSON.stringify(rest, (key, value) => {
|
|
43
50
|
if (key === 'bound') return undefined;
|
|
44
51
|
return value;
|
|
@@ -58,16 +65,25 @@ function cloneItem(item) {
|
|
|
58
65
|
/**
|
|
59
66
|
* Substitute Emmet-style `$` counters in payloads and string props.
|
|
60
67
|
* `\$` escapes a literal dollar sign (prices etc.).
|
|
68
|
+
* @param {string} text
|
|
69
|
+
* @param {number} index
|
|
61
70
|
*/
|
|
62
71
|
function subCounterText(text, index) {
|
|
63
72
|
return text.replace(/\\\$|\$/g, m => (m === '\\$' ? '$' : String(index)));
|
|
64
73
|
}
|
|
65
74
|
|
|
66
|
-
/**
|
|
75
|
+
/**
|
|
76
|
+
* Strip `\$` escapes when a node is NOT repeated (single emission).
|
|
77
|
+
* @param {string} text
|
|
78
|
+
*/
|
|
67
79
|
function unescapeCounterText(text) {
|
|
68
80
|
return text.replace(/\\\$/g, '$');
|
|
69
81
|
}
|
|
70
82
|
|
|
83
|
+
/**
|
|
84
|
+
* @param {import('./xle-ast').XLEItem} node
|
|
85
|
+
* @param {number} index
|
|
86
|
+
*/
|
|
71
87
|
function substituteCounter(node, index) {
|
|
72
88
|
if (node.kind === 'group') {
|
|
73
89
|
for (const child of node.children) substituteCounter(child, index);
|
|
@@ -86,44 +102,69 @@ function substituteCounter(node, index) {
|
|
|
86
102
|
}
|
|
87
103
|
|
|
88
104
|
class Emitter {
|
|
105
|
+
/**
|
|
106
|
+
* @param {import('./xle-ast').Registry} registry
|
|
107
|
+
* @param {{componentName?: string, blockModules?: Map<string, import('./xle-ast').BlockModule>}} [options]
|
|
108
|
+
*/
|
|
89
109
|
constructor(registry, options = {}) {
|
|
90
110
|
this.registry = registry;
|
|
91
111
|
// importPath → {named:Set, types:Set, default, namespace, sideEffect}
|
|
112
|
+
/** @type {Map<string, import('./xle-ast').ImportEntry>} */
|
|
92
113
|
this.imports = new Map();
|
|
114
|
+
/** @type {import('./xle-ast').StateEntry[]} */
|
|
93
115
|
this.states = [];
|
|
116
|
+
/** @type {Set<string>} */
|
|
94
117
|
this.usedStateNames = new Set();
|
|
118
|
+
/** @type {string[]} */
|
|
95
119
|
this.todos = [];
|
|
120
|
+
/** @type {Set<string>} */
|
|
96
121
|
this.componentsUsed = new Set();
|
|
97
122
|
this.componentName = options.componentName || 'GeneratedLayout';
|
|
98
123
|
// canonical block key → prepared module ({mode, componentName, ...})
|
|
99
124
|
this.blockModules = options.blockModules || new Map();
|
|
100
125
|
// names of blocks already co-defined in this module (dedup)
|
|
126
|
+
/** @type {Map<string, string>} */
|
|
101
127
|
this.splicedBlocks = new Map(); // key → componentName
|
|
128
|
+
/** @type {string[]} */
|
|
102
129
|
this.blockDefs = []; // co-defined block source bodies, in first-use order
|
|
103
130
|
}
|
|
104
131
|
|
|
132
|
+
/**
|
|
133
|
+
* @param {string} source
|
|
134
|
+
* @returns {import('./xle-ast').ImportEntry}
|
|
135
|
+
*/
|
|
105
136
|
importEntry(source) {
|
|
106
137
|
if (!this.imports.has(source)) {
|
|
107
138
|
this.imports.set(source, {named: new Set(), types: new Set(), default: null, namespace: null, sideEffect: false});
|
|
108
139
|
}
|
|
109
|
-
return this.imports.get(source);
|
|
140
|
+
return /** @type {import('./xle-ast').ImportEntry} */ (this.imports.get(source));
|
|
110
141
|
}
|
|
111
142
|
|
|
143
|
+
/** @param {import('./xle-ast').RegistryComponent} component */
|
|
112
144
|
addImport(component) {
|
|
113
145
|
this.importEntry(component.importPath).named.add(component.exportName);
|
|
114
146
|
this.componentsUsed.add(component.name);
|
|
115
147
|
}
|
|
116
148
|
|
|
149
|
+
/**
|
|
150
|
+
* @param {string} source
|
|
151
|
+
* @param {string} name
|
|
152
|
+
*/
|
|
117
153
|
addNamedImport(source, name) {
|
|
118
154
|
this.importEntry(source).named.add(name);
|
|
119
155
|
}
|
|
120
156
|
|
|
157
|
+
/**
|
|
158
|
+
* @param {string} name
|
|
159
|
+
* @returns {import('./xle-ast').RegistryComponent | undefined}
|
|
160
|
+
*/
|
|
121
161
|
requireComponent(name) {
|
|
122
162
|
const component = this.registry.components.get(name);
|
|
123
163
|
if (component) this.addImport(component);
|
|
124
164
|
return component;
|
|
125
165
|
}
|
|
126
166
|
|
|
167
|
+
/** @param {string} base */
|
|
127
168
|
stateName(base) {
|
|
128
169
|
let name = camelCase(base);
|
|
129
170
|
if (!/^[a-z]/.test(name)) name = 'v' + name;
|
|
@@ -134,6 +175,10 @@ class Emitter {
|
|
|
134
175
|
return candidate;
|
|
135
176
|
}
|
|
136
177
|
|
|
178
|
+
/**
|
|
179
|
+
* @param {string} base
|
|
180
|
+
* @param {string} initial
|
|
181
|
+
*/
|
|
137
182
|
addState(base, initial) {
|
|
138
183
|
const name = this.stateName(base);
|
|
139
184
|
const setter = 'set' + name[0].toUpperCase() + name.slice(1);
|
|
@@ -143,12 +188,16 @@ class Emitter {
|
|
|
143
188
|
|
|
144
189
|
// ── value → JSX prop text ────────────────────────────────────────────
|
|
145
190
|
|
|
191
|
+
/**
|
|
192
|
+
* @param {import('./xle-ast').XLEValue} value
|
|
193
|
+
* @returns {string | null}
|
|
194
|
+
*/
|
|
146
195
|
jsxValue(value) {
|
|
147
196
|
if (value === true) return null; // bare flag
|
|
148
197
|
if (value === false) return '{false}';
|
|
149
198
|
if (typeof value === 'number') return `{${value}}`;
|
|
150
199
|
if (typeof value === 'string') return `"${escapeAttr(value)}"`;
|
|
151
|
-
if (value && value
|
|
200
|
+
if (value && typeof value === 'object' && '__expr' in value) return `{${value.__expr}}`;
|
|
152
201
|
if (Array.isArray(value)) {
|
|
153
202
|
return `{[${value.map(v => (typeof v === 'string' ? `'${v}'` : String(v))).join(', ')}]}`;
|
|
154
203
|
}
|
|
@@ -161,6 +210,10 @@ class Emitter {
|
|
|
161
210
|
return `{${String(value)}}`;
|
|
162
211
|
}
|
|
163
212
|
|
|
213
|
+
/**
|
|
214
|
+
* @param {string} key
|
|
215
|
+
* @param {import('./xle-ast').XLEValue} value
|
|
216
|
+
*/
|
|
164
217
|
propText(key, value) {
|
|
165
218
|
const v = this.jsxValue(value);
|
|
166
219
|
return v === null ? key : `${key}=${v}`;
|
|
@@ -168,10 +221,14 @@ class Emitter {
|
|
|
168
221
|
|
|
169
222
|
// ── scaffolding ──────────────────────────────────────────────────────
|
|
170
223
|
|
|
224
|
+
/**
|
|
225
|
+
* @param {import('./xle-ast').RegistryProp} prop
|
|
226
|
+
* @param {import('./xle-ast').XLENode} node
|
|
227
|
+
*/
|
|
171
228
|
initialFor(prop, node) {
|
|
172
229
|
const type = (prop.type || '').trim();
|
|
173
|
-
if (node.bound
|
|
174
|
-
const tabs = node.children.filter(c => c.kind === 'node');
|
|
230
|
+
if (node.bound?.component.name === 'TabList') {
|
|
231
|
+
const tabs = /** @type {import('./xle-ast').XLENode[]} */ (node.children.filter(c => c.kind === 'node'));
|
|
175
232
|
const chosen = tabs.find(t => t.selected) || tabs[0];
|
|
176
233
|
return chosen ? `'${slugify(chosen.payload || chosen.name)}'` : `''`;
|
|
177
234
|
}
|
|
@@ -185,6 +242,11 @@ class Emitter {
|
|
|
185
242
|
return 'undefined';
|
|
186
243
|
}
|
|
187
244
|
|
|
245
|
+
/**
|
|
246
|
+
* @param {import('./xle-ast').XLENode} node
|
|
247
|
+
* @param {import('./xle-ast').RegistryComponent} component
|
|
248
|
+
* @param {Map<string, import('./xle-ast').XLEValue>} props
|
|
249
|
+
*/
|
|
188
250
|
scaffoldState(node, component, props) {
|
|
189
251
|
for (const valueKey of ['value', 'page']) {
|
|
190
252
|
const valueProp = component.props.get(valueKey);
|
|
@@ -199,6 +261,12 @@ class Emitter {
|
|
|
199
261
|
}
|
|
200
262
|
}
|
|
201
263
|
|
|
264
|
+
/**
|
|
265
|
+
* @param {import('./xle-ast').XLENode} node
|
|
266
|
+
* @param {import('./xle-ast').RegistryComponent} component
|
|
267
|
+
* @param {Map<string, import('./xle-ast').XLEValue>} props
|
|
268
|
+
* @param {Set<string>} slotKeys
|
|
269
|
+
*/
|
|
202
270
|
fillRequired(node, component, props, slotKeys) {
|
|
203
271
|
for (const prop of component.props.values()) {
|
|
204
272
|
if (!prop.required || props.has(prop.name) || slotKeys.has(prop.name)) continue;
|
|
@@ -221,7 +289,14 @@ class Emitter {
|
|
|
221
289
|
|
|
222
290
|
// ── node emission ────────────────────────────────────────────────────
|
|
223
291
|
|
|
292
|
+
/**
|
|
293
|
+
* @param {import('./xle-ast').XLEItem[]} items
|
|
294
|
+
* @param {number} depth
|
|
295
|
+
* @param {import('./xle-ast').EmitContext} [context]
|
|
296
|
+
* @returns {string[]}
|
|
297
|
+
*/
|
|
224
298
|
emitItems(items, depth, context = {}) {
|
|
299
|
+
/** @type {string[]} */
|
|
225
300
|
const lines = [];
|
|
226
301
|
for (const item of items) {
|
|
227
302
|
if (item.kind === 'group') {
|
|
@@ -237,7 +312,7 @@ class Emitter {
|
|
|
237
312
|
}
|
|
238
313
|
const count = item.repeat || 1;
|
|
239
314
|
for (let i = 1; i <= count; i++) {
|
|
240
|
-
const clone = count > 1 ? cloneItem(item) : item;
|
|
315
|
+
const clone = count > 1 ? /** @type {import('./xle-ast').XLENode} */ (cloneItem(item)) : item;
|
|
241
316
|
if (count > 1) {
|
|
242
317
|
clone.repeat = null;
|
|
243
318
|
substituteCounter(clone, i);
|
|
@@ -248,6 +323,12 @@ class Emitter {
|
|
|
248
323
|
return lines;
|
|
249
324
|
}
|
|
250
325
|
|
|
326
|
+
/**
|
|
327
|
+
* @param {import('./xle-ast').XLENode} node
|
|
328
|
+
* @param {number} depth
|
|
329
|
+
* @param {import('./xle-ast').EmitContext} [context]
|
|
330
|
+
* @returns {string[]}
|
|
331
|
+
*/
|
|
251
332
|
emitNode(node, depth, context = {}) {
|
|
252
333
|
if (!node.bound) {
|
|
253
334
|
// Anonymous block reference — emit just the block, no wrapper element.
|
|
@@ -259,6 +340,7 @@ class Emitter {
|
|
|
259
340
|
const pad = INDENT.repeat(depth);
|
|
260
341
|
|
|
261
342
|
const props = new Map(node.bound.props);
|
|
343
|
+
/** @type {string | null} */
|
|
262
344
|
let textChild = null;
|
|
263
345
|
|
|
264
346
|
// Payload → primary text prop, else text child. Required props win
|
|
@@ -273,7 +355,7 @@ class Emitter {
|
|
|
273
355
|
if (target && !props.has(target)) props.set(target, node.payload);
|
|
274
356
|
else textChild = node.payload;
|
|
275
357
|
}
|
|
276
|
-
if (node.payload2 != null && component.props.has('value') && !component.props.get('value')
|
|
358
|
+
if (node.payload2 != null && component.props.has('value') && !component.props.get('value')?.required) {
|
|
277
359
|
props.set('value', node.payload2);
|
|
278
360
|
}
|
|
279
361
|
|
|
@@ -292,9 +374,11 @@ class Emitter {
|
|
|
292
374
|
props.delete('__opens');
|
|
293
375
|
props.delete('__fill');
|
|
294
376
|
if (opens) {
|
|
295
|
-
const
|
|
377
|
+
const opensRef = /** @type {import('./xle-ast').IdRef} */ (opens);
|
|
378
|
+
const target = opensRef.idref || opens;
|
|
296
379
|
const handler = component.props.has('onClick') ? 'onClick' : 'clickAction';
|
|
297
|
-
|
|
380
|
+
const targetId = typeof target === 'object' && target != null && 'idref' in target ? target.idref : target;
|
|
381
|
+
props.set(handler, {__expr: `() => {/* TODO(xle): open #${targetId} */}`});
|
|
298
382
|
}
|
|
299
383
|
|
|
300
384
|
// Slots → element-valued props (keys collected first so required-prop
|
|
@@ -302,12 +386,14 @@ class Emitter {
|
|
|
302
386
|
const slotKeys = new Set(node.bound.slots.map(s => s.key));
|
|
303
387
|
this.fillRequired(node, component, props, slotKeys);
|
|
304
388
|
|
|
389
|
+
/** @type {Array<[string, string[]]>} */
|
|
305
390
|
const slotEntries = [];
|
|
306
391
|
for (const slot of node.bound.slots) {
|
|
307
392
|
slotEntries.push([slot.key, this.emitSlotValue(slot, depth + 1)]);
|
|
308
393
|
}
|
|
309
394
|
|
|
310
395
|
// Structural routing.
|
|
396
|
+
/** @type {import('./xle-ast').XLEItem[]} */
|
|
311
397
|
let children = node.children;
|
|
312
398
|
if (component.name === 'Layout') {
|
|
313
399
|
const routed = this.routeLayoutChildren(node, props, slotEntries, depth);
|
|
@@ -356,12 +442,21 @@ class Emitter {
|
|
|
356
442
|
return lines;
|
|
357
443
|
}
|
|
358
444
|
|
|
445
|
+
/**
|
|
446
|
+
* @param {import('./xle-ast').RegistryComponent} component
|
|
447
|
+
* @param {Map<string, import('./xle-ast').XLEValue>} props
|
|
448
|
+
* @param {Array<[string, string[]]>} slotEntries
|
|
449
|
+
* @param {string[]} bodyLines
|
|
450
|
+
* @param {number} depth
|
|
451
|
+
* @returns {string[]}
|
|
452
|
+
*/
|
|
359
453
|
renderTag(component, props, slotEntries, bodyLines, depth) {
|
|
360
454
|
const pad = INDENT.repeat(depth);
|
|
361
455
|
const propTexts = [...props.entries()].map(([k, v]) => this.propText(k, v));
|
|
362
456
|
const slotTexts = slotEntries.map(([key, valueLines]) => ({key, valueLines}));
|
|
363
457
|
const tag = component.exportName;
|
|
364
458
|
|
|
459
|
+
/** @type {string[]} */
|
|
365
460
|
const open = [];
|
|
366
461
|
const simple = slotTexts.length === 0 && propTexts.join(' ').length <= 60;
|
|
367
462
|
if (simple) {
|
|
@@ -385,6 +480,11 @@ class Emitter {
|
|
|
385
480
|
return [...open, ...bodyLines, `${pad}</${tag}>`];
|
|
386
481
|
}
|
|
387
482
|
|
|
483
|
+
/**
|
|
484
|
+
* @param {import('./xle-ast').Slot} slot
|
|
485
|
+
* @param {number} _depth
|
|
486
|
+
* @returns {string[]}
|
|
487
|
+
*/
|
|
388
488
|
emitSlotValue(slot, _depth) {
|
|
389
489
|
const value = slot.value;
|
|
390
490
|
if (value == null) {
|
|
@@ -394,17 +494,17 @@ class Emitter {
|
|
|
394
494
|
const text = this.requireComponent('Text');
|
|
395
495
|
return [text ? `<${text.exportName}>${value}</${text.exportName}>` : `<>${value}</>`];
|
|
396
496
|
}
|
|
397
|
-
if (value
|
|
497
|
+
if ('hint' in value) {
|
|
398
498
|
return [
|
|
399
499
|
'<>',
|
|
400
500
|
...this.emitHint(value.hint, 1).map(l => l.trimStart()).map(l => INDENT + l),
|
|
401
501
|
'</>',
|
|
402
502
|
];
|
|
403
503
|
}
|
|
404
|
-
if (value
|
|
504
|
+
if ('idref' in value) {
|
|
405
505
|
return [`null /* TODO(xle): reference #${value.idref} */`];
|
|
406
506
|
}
|
|
407
|
-
if (value
|
|
507
|
+
if ('subexpr' in value) {
|
|
408
508
|
const lines = this.emitItems(value.subexpr, 0, {});
|
|
409
509
|
if (value.subexpr.length > 1) return ['<>', ...lines.map(l => INDENT + l), '</>'];
|
|
410
510
|
return lines;
|
|
@@ -412,6 +512,11 @@ class Emitter {
|
|
|
412
512
|
return ['null'];
|
|
413
513
|
}
|
|
414
514
|
|
|
515
|
+
/**
|
|
516
|
+
* @param {import('./xle-ast').Hint} hint
|
|
517
|
+
* @param {number} depth
|
|
518
|
+
* @returns {string[]}
|
|
519
|
+
*/
|
|
415
520
|
emitHint(hint, depth) {
|
|
416
521
|
const pad = INDENT.repeat(depth);
|
|
417
522
|
if (hint.block) {
|
|
@@ -436,6 +541,9 @@ class Emitter {
|
|
|
436
541
|
/**
|
|
437
542
|
* Register a referenced block (import-mode app component, or splice-mode
|
|
438
543
|
* template block co-defined once) and return the JSX component name to use.
|
|
544
|
+
* @param {string} key
|
|
545
|
+
* @param {import('./xle-ast').BlockModule} mod
|
|
546
|
+
* @returns {string | null | undefined}
|
|
439
547
|
*/
|
|
440
548
|
referenceBlock(key, mod) {
|
|
441
549
|
if (this.splicedBlocks.has(key)) return this.splicedBlocks.get(key);
|
|
@@ -468,18 +576,27 @@ class Emitter {
|
|
|
468
576
|
return name;
|
|
469
577
|
}
|
|
470
578
|
|
|
579
|
+
/**
|
|
580
|
+
* @param {import('./xle-ast').XLENode} node
|
|
581
|
+
* @param {Map<string, import('./xle-ast').XLEValue>} props
|
|
582
|
+
* @param {Array<[string, string[]]>} slotEntries
|
|
583
|
+
* @param {number} depth
|
|
584
|
+
* @returns {import('./xle-ast').XLEItem[]}
|
|
585
|
+
*/
|
|
471
586
|
routeLayoutChildren(node, props, slotEntries, depth) {
|
|
587
|
+
/** @type {Record<string, string>} */
|
|
472
588
|
const family = {
|
|
473
589
|
LayoutHeader: 'header',
|
|
474
590
|
LayoutContent: 'content',
|
|
475
591
|
LayoutFooter: 'footer',
|
|
476
592
|
};
|
|
477
593
|
const assigned = new Set(slotEntries.map(([k]) => k));
|
|
594
|
+
/** @type {import('./xle-ast').XLEItem[]} */
|
|
478
595
|
const loose = [];
|
|
479
596
|
let panelCount = 0;
|
|
480
597
|
for (const child of node.children) {
|
|
481
|
-
const childName = child.bound?.component?.name;
|
|
482
|
-
let slotName = family[childName];
|
|
598
|
+
const childName = child.kind === 'node' ? child.bound?.component?.name : undefined;
|
|
599
|
+
let slotName = childName ? family[childName] : undefined;
|
|
483
600
|
if (childName === 'LayoutPanel') {
|
|
484
601
|
slotName = panelCount === 0 ? 'start' : 'end';
|
|
485
602
|
panelCount++;
|
|
@@ -493,7 +610,7 @@ class Emitter {
|
|
|
493
610
|
}
|
|
494
611
|
// Loose children auto-wrap into an implicit LayoutContent slot.
|
|
495
612
|
if (loose.length > 0 && !assigned.has('content')) {
|
|
496
|
-
const lc = this.requireComponent('LayoutContent');
|
|
613
|
+
const lc = /** @type {import('./xle-ast').RegistryComponent} */ (this.requireComponent('LayoutContent'));
|
|
497
614
|
const inner = this.emitItems(loose, 1, {});
|
|
498
615
|
slotEntries.push(['content', [`<${lc.exportName}>`, ...inner, `</${lc.exportName}>`]]);
|
|
499
616
|
} else if (loose.length > 0) {
|
|
@@ -503,8 +620,13 @@ class Emitter {
|
|
|
503
620
|
return [];
|
|
504
621
|
}
|
|
505
622
|
|
|
506
|
-
/**
|
|
623
|
+
/**
|
|
624
|
+
* Expand groups/repeats into a flat node list (clones carry repeat=null).
|
|
625
|
+
* @param {import('./xle-ast').XLEItem[]} items
|
|
626
|
+
* @returns {import('./xle-ast').XLENode[]}
|
|
627
|
+
*/
|
|
507
628
|
flattenItems(items) {
|
|
629
|
+
/** @type {import('./xle-ast').XLENode[]} */
|
|
508
630
|
const out = [];
|
|
509
631
|
for (const item of items) {
|
|
510
632
|
const count = item.repeat || 1;
|
|
@@ -521,26 +643,37 @@ class Emitter {
|
|
|
521
643
|
return out;
|
|
522
644
|
}
|
|
523
645
|
|
|
646
|
+
/**
|
|
647
|
+
* @param {import('./xle-ast').XLENode} node
|
|
648
|
+
* @returns {import('./xle-ast').XLEItem[]}
|
|
649
|
+
*/
|
|
524
650
|
partitionTableChildren(node) {
|
|
525
651
|
const flat = this.flattenItems(node.children);
|
|
526
652
|
const rows = flat.filter(c => c.kind === 'node' && c.bound?.component?.name === 'TableRow');
|
|
527
653
|
if (rows.length === 0 || rows.length !== flat.length) return node.children;
|
|
528
|
-
const isHeaderRow = (row) => {
|
|
654
|
+
const isHeaderRow = (/** @type {import('./xle-ast').XLENode} */ row) => {
|
|
529
655
|
const cells = this.flattenItems(row.children);
|
|
530
656
|
return cells.length > 0 && cells.every(c => c.bound?.component?.name === 'TableHeaderCell');
|
|
531
657
|
};
|
|
532
658
|
const headerRows = rows.filter(isHeaderRow);
|
|
533
659
|
const bodyRows = rows.filter(r => !isHeaderRow(r));
|
|
660
|
+
/**
|
|
661
|
+
* @param {string} name
|
|
662
|
+
* @param {import('./xle-ast').XLENode[]} rowNodes
|
|
663
|
+
* @returns {import('./xle-ast').XLENode}
|
|
664
|
+
*/
|
|
534
665
|
const wrap = (name, rowNodes) => {
|
|
535
666
|
const comp = this.requireComponent(name);
|
|
667
|
+
/** @type {import('./xle-ast').XLENode} */
|
|
536
668
|
const wrapper = {
|
|
537
669
|
kind: 'node', name, id: null, enumMods: [], payload: null, payload2: null,
|
|
538
670
|
attrs: [], slots: [], hint: null, repeat: null, selected: false,
|
|
539
671
|
children: rowNodes, line: node.line, col: node.col,
|
|
540
|
-
bound: {component: comp, props: new Map(), slots: [], stray: []},
|
|
672
|
+
bound: {component: /** @type {import('./xle-ast').RegistryComponent} */ (comp), props: new Map(), slots: [], stray: []},
|
|
541
673
|
};
|
|
542
674
|
return wrapper;
|
|
543
675
|
};
|
|
676
|
+
/** @type {import('./xle-ast').XLEItem[]} */
|
|
544
677
|
const out = [];
|
|
545
678
|
if (headerRows.length > 0) out.push(wrap('TableHeader', headerRows));
|
|
546
679
|
if (bodyRows.length > 0) out.push(wrap('TableBody', bodyRows));
|
|
@@ -551,9 +684,9 @@ class Emitter {
|
|
|
551
684
|
/**
|
|
552
685
|
* Expand a validated document into a complete TSX module.
|
|
553
686
|
*
|
|
554
|
-
* @param {{roots:
|
|
555
|
-
* @param {
|
|
556
|
-
* @param {{componentName?: string}} [options]
|
|
687
|
+
* @param {{roots: import('./xle-ast').XLEItem[], overlays: import('./xle-ast').XLEItem[]}} doc
|
|
688
|
+
* @param {import('./xle-ast').Registry} registry
|
|
689
|
+
* @param {{componentName?: string, blockModules?: Map<string, import('./xle-ast').BlockModule>}} [options]
|
|
557
690
|
* @returns {{code: string, componentsUsed: string[], states: number, todos: string[]}}
|
|
558
691
|
*/
|
|
559
692
|
export function expand(doc, registry, options = {}) {
|