@volter/editor-core 0.5.57
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/BUNDLED_NOTICES +1527 -0
- package/LICENSE +686 -0
- package/LICENSE-APACHE +202 -0
- package/NOTICE +18 -0
- package/README.md +24 -0
- package/dist/build/chunk-JS4D4XZ3.js +175 -0
- package/dist/build/chunk-JS4D4XZ3.js.map +7 -0
- package/dist/build/vite-plugin-product-contributions.js +100 -0
- package/dist/build/vite-plugin-product-contributions.js.map +7 -0
- package/dist/build/vite-plugin-shared-react.js +25 -0
- package/dist/build/vite-plugin-shared-react.js.map +7 -0
- package/dist/build/vite-plugin-shared-three.js +86 -0
- package/dist/build/vite-plugin-shared-three.js.map +7 -0
- package/dist/server/chunk-KMJC7AGO.js +98 -0
- package/dist/server/chunk-KMJC7AGO.js.map +7 -0
- package/dist/server/chunk-PSILUMGS.js +46 -0
- package/dist/server/chunk-PSILUMGS.js.map +7 -0
- package/dist/server/frame-proxy.js +255 -0
- package/dist/server/frame-proxy.js.map +7 -0
- package/dist/server/open-browser.js +53 -0
- package/dist/server/open-browser.js.map +7 -0
- package/dist/server/process-shutdown.js +127 -0
- package/dist/server/process-shutdown.js.map +7 -0
- package/dist/server/session-registry.js +141 -0
- package/dist/server/session-registry.js.map +7 -0
- package/dist/server/spawn-opener.js +11 -0
- package/dist/server/spawn-opener.js.map +7 -0
- package/dist/server/worktree-identity.js +11 -0
- package/dist/server/worktree-identity.js.map +7 -0
- package/dist-server/packaged.mjs +88816 -0
- package/package.json +118 -0
- package/scripts/build-plugins.mjs +14 -0
- package/scripts/build-server.mjs +26 -0
- package/scripts/build-session.mjs +9 -0
- package/server/account-credentials.ts +60 -0
- package/server/account-service.ts +1434 -0
- package/server/adapter-region-includes.ts +47 -0
- package/server/asset-catalog-v2.ts +175 -0
- package/server/asset-history-snapshots.ts +196 -0
- package/server/asset-ledger-store.ts +195 -0
- package/server/asset-library-routes.ts +1595 -0
- package/server/blender-wasm-artifact.ts +430 -0
- package/server/boot-timings.ts +106 -0
- package/server/canonical-path.ts +50 -0
- package/server/checkout-workspace-preflight.ts +349 -0
- package/server/cloud-asset-catalog.ts +158 -0
- package/server/coding-inference-launch.ts +237 -0
- package/server/collaboration-account-client.ts +202 -0
- package/server/collaboration-attribution.ts +122 -0
- package/server/collaboration-session.ts +934 -0
- package/server/comfyui-bridge.ts +248 -0
- package/server/console-ledger.ts +499 -0
- package/server/creation-site-transform.ts +304 -0
- package/server/creation-site-write.ts +648 -0
- package/server/data-file-serialize.ts +158 -0
- package/server/editor-brand-html.ts +72 -0
- package/server/editor-control-socket.ts +366 -0
- package/server/editor-server-options.ts +190 -0
- package/server/editor-server.ts +1483 -0
- package/server/editor-sse.ts +352 -0
- package/server/engine-provenance.ts +169 -0
- package/server/engine-source-restart.ts +117 -0
- package/server/frame-bridge.ts +115 -0
- package/server/frame-proxy.ts +490 -0
- package/server/frame-workbench.ts +259 -0
- package/server/frontend-handoff.ts +229 -0
- package/server/game-globals-shadow.ts +113 -0
- package/server/gameplay-session-retention.ts +149 -0
- package/server/gameplay-sessions.ts +123 -0
- package/server/generation-jobs.ts +201 -0
- package/server/generation-reconciler.ts +137 -0
- package/server/generative-execution-context.ts +59 -0
- package/server/git-workflow.ts +612 -0
- package/server/harness-chat-caller.ts +36 -0
- package/server/harness-chat-service.ts +1681 -0
- package/server/idle-shutdown.ts +170 -0
- package/server/js-profiling-policy.ts +52 -0
- package/server/launcher-settings.ts +84 -0
- package/server/local-asset-catalog.ts +410 -0
- package/server/managed-account-defaults.ts +22 -0
- package/server/mock-control-plane.ts +540 -0
- package/server/model-import-conversion.ts +345 -0
- package/server/native-credential-store.ts +162 -0
- package/server/open-browser.ts +118 -0
- package/server/packaged.ts +1192 -0
- package/server/play-stall.ts +126 -0
- package/server/process-shutdown.ts +218 -0
- package/server/product-presets.ts +55 -0
- package/server/project-build-artifact.ts +95 -0
- package/server/project-components.ts +100 -0
- package/server/project-dependency-invalidation.ts +114 -0
- package/server/project-file-scan.ts +235 -0
- package/server/project-hmr-files.ts +215 -0
- package/server/project-install-roots.ts +210 -0
- package/server/project-kinds.ts +71 -0
- package/server/project-mcp-servers.ts +82 -0
- package/server/project-module-freshness.ts +109 -0
- package/server/project-module-instance.ts +375 -0
- package/server/project-optimize-deps-entries.ts +827 -0
- package/server/project-output-writer.ts +679 -0
- package/server/project-package-origin.ts +63 -0
- package/server/project-root-surface.ts +831 -0
- package/server/project-scratch-path.ts +47 -0
- package/server/project-script-hmr.ts +619 -0
- package/server/project-serving-plugins.ts +236 -0
- package/server/project-tools.ts +653 -0
- package/server/project-validation.ts +250 -0
- package/server/project-verbs.ts +127 -0
- package/server/project-view.ts +52 -0
- package/server/project-watch.ts +1134 -0
- package/server/project-work-coordinator.ts +288 -0
- package/server/provider-credentials.ts +331 -0
- package/server/recent-projects-store.ts +98 -0
- package/server/redact-secrets.ts +71 -0
- package/server/repository-presence.ts +267 -0
- package/server/routes/account.ts +357 -0
- package/server/routes/agents.ts +60 -0
- package/server/routes/assets.ts +154 -0
- package/server/routes/build.ts +13 -0
- package/server/routes/collaboration.ts +595 -0
- package/server/routes/configurations.ts +419 -0
- package/server/routes/context.ts +264 -0
- package/server/routes/control-plane.ts +1811 -0
- package/server/routes/logs.ts +272 -0
- package/server/routes/project-identity.ts +302 -0
- package/server/routes/project-open.ts +429 -0
- package/server/routes/project-source.ts +686 -0
- package/server/routes/project-state.ts +383 -0
- package/server/routes/relay.ts +1029 -0
- package/server/routes/route-helpers.ts +29 -0
- package/server/routes/served-modules.ts +138 -0
- package/server/routes/session-tabs.ts +196 -0
- package/server/routes/settings.ts +121 -0
- package/server/routes/share-control.ts +486 -0
- package/server/routes/themes.ts +116 -0
- package/server/routes/tools.ts +230 -0
- package/server/routes/worktrees.ts +595 -0
- package/server/scoped-game-css.ts +461 -0
- package/server/server-utils.ts +1194 -0
- package/server/session-product.ts +112 -0
- package/server/session-registry.ts +230 -0
- package/server/share-claims.ts +138 -0
- package/server/share-host.ts +526 -0
- package/server/share-session-gateway.ts +1362 -0
- package/server/share-tunnel.ts +123 -0
- package/server/spawn-opener.ts +74 -0
- package/server/support/play/log-format.ts +76 -0
- package/server/support/play/session-record.ts +199 -0
- package/server/support/project/build-discipline.ts +718 -0
- package/server/support/project/inspection-node.ts +119 -0
- package/server/support/project/log-naming.ts +54 -0
- package/server/support/project/provenance.ts +290 -0
- package/server/support/project/run-name.ts +18 -0
- package/server/support/project/session-journal.ts +830 -0
- package/server/support/project/shared.ts +327 -0
- package/server/tab-bootstrap.ts +62 -0
- package/server/tab-heartbeat.ts +477 -0
- package/server/tab-lifecycle.ts +550 -0
- package/server/tab-presence.ts +1508 -0
- package/server/team-agent-mirror.ts +95 -0
- package/server/twin-auth.ts +138 -0
- package/server/vendored-lock-recorder.ts +968 -0
- package/server/worktree-identity.ts +121 -0
- package/server/worktree-management.ts +398 -0
- package/server/worktree-retention.d.mts +13 -0
- package/server/worktree-retention.mjs +205 -0
- package/src/EditorContext.tsx +169 -0
- package/src/account.ts +333 -0
- package/src/action-registry.ts +532 -0
- package/src/active-product.ts +74 -0
- package/src/active-project.ts +155 -0
- package/src/adapter-editor-config.ts +25 -0
- package/src/adapter-observation.ts +49 -0
- package/src/animation/stage-transport.ts +379 -0
- package/src/animation/three-clips-subject.ts +172 -0
- package/src/api/asset-library-wire.ts +45 -0
- package/src/api/assets.ts +365 -0
- package/src/api/base.ts +10 -0
- package/src/api/build.ts +99 -0
- package/src/api/git-wire.ts +56 -0
- package/src/api/logs.ts +92 -0
- package/src/api/project-identity.ts +74 -0
- package/src/api/project-open.ts +355 -0
- package/src/api/project-source.ts +162 -0
- package/src/api/project-state.ts +107 -0
- package/src/api/relay.ts +268 -0
- package/src/api/settings.ts +36 -0
- package/src/api/themes.ts +45 -0
- package/src/api/worktrees.ts +257 -0
- package/src/asset-compare-core.ts +171 -0
- package/src/asset-compare.ts +294 -0
- package/src/asset-editor-context.tsx +100 -0
- package/src/asset-events.ts +97 -0
- package/src/asset-inspector-actions.ts +87 -0
- package/src/asset-preview-framing.ts +357 -0
- package/src/asset-preview.ts +2802 -0
- package/src/asset-selection-viewer-registry.ts +113 -0
- package/src/asset-selection.ts +133 -0
- package/src/asset-workflow/asset-capabilities.ts +344 -0
- package/src/asset-workflow/asset-import-jobs.ts +106 -0
- package/src/asset-workflow/asset-ledger-backend.ts +126 -0
- package/src/asset-workflow/asset-ledger.ts +156 -0
- package/src/asset-workflow/asset-materialization-report.ts +140 -0
- package/src/asset-workflow/asset-pack-manifest.ts +320 -0
- package/src/asset-workflow/asset-types.ts +142 -0
- package/src/asset-workflow/asset-workflow-quality.ts +61 -0
- package/src/asset-workflow/audio-preview-player.ts +193 -0
- package/src/asset-workflow/audio-waveform.ts +22 -0
- package/src/asset-workflow/cloud-asset-client.ts +263 -0
- package/src/asset-workflow/folder-preview.ts +345 -0
- package/src/asset-workflow/hosted-asset-materialization.ts +236 -0
- package/src/asset-workflow/image-view-scale.ts +32 -0
- package/src/asset-workflow/import-contract.ts +124 -0
- package/src/asset-workflow/ledger-write-lock.ts +244 -0
- package/src/asset-workflow/model-inspection.ts +818 -0
- package/src/asset-workflow/pixi-spritesheet.ts +197 -0
- package/src/asset-workflow/preview-resource-lifetime.ts +44 -0
- package/src/asset-workflow/project-asset-commands.ts +23 -0
- package/src/asset-workflow/project-asset-health.ts +139 -0
- package/src/asset-workflow/project-asset-operations.ts +154 -0
- package/src/asset-workflow/project-asset-roots.ts +68 -0
- package/src/asset-workflow/project-content.ts +288 -0
- package/src/asset-workflow/project-source-index.ts +550 -0
- package/src/asset-workflow/thumbnail-system.ts +256 -0
- package/src/authoring/active-adapter.ts +199 -0
- package/src/authoring/active-systems.ts +422 -0
- package/src/authoring/adapter-key.ts +18 -0
- package/src/authoring/authoring-asset-url.ts +27 -0
- package/src/authoring/bootstrap-state.ts +49 -0
- package/src/authoring/boundary-authoring-adapter.ts +184 -0
- package/src/authoring/breakpoint-state.ts +43 -0
- package/src/authoring/canvas-scene-guides.ts +76 -0
- package/src/authoring/component-instance-root.ts +171 -0
- package/src/authoring/composite-authoring-adapter.ts +2110 -0
- package/src/authoring/consumer-actions.ts +520 -0
- package/src/authoring/css-numeric-style.ts +97 -0
- package/src/authoring/design-time-layers.ts +849 -0
- package/src/authoring/design-time-mount-registry.ts +235 -0
- package/src/authoring/design-time-settle.ts +343 -0
- package/src/authoring/edit-mode-authoring.ts +619 -0
- package/src/authoring/eyedropper-session.ts +60 -0
- package/src/authoring/instance-source-menu-register.ts +13 -0
- package/src/authoring/instance-source-menu.ts +135 -0
- package/src/authoring/layered-pick.ts +183 -0
- package/src/authoring/live-gesture-lock.ts +50 -0
- package/src/authoring/live-object-transform.ts +62 -0
- package/src/authoring/mount-failure-report.ts +154 -0
- package/src/authoring/mounted-root-subjects.ts +144 -0
- package/src/authoring/no-authoring-adapter.ts +55 -0
- package/src/authoring/null-inspection-subjects.tsx +75 -0
- package/src/authoring/object3d-document-persistence.ts +106 -0
- package/src/authoring/object3d-document-session-registry.ts +120 -0
- package/src/authoring/object3d-document-session.ts +1326 -0
- package/src/authoring/object3d-gesture-controller.ts +113 -0
- package/src/authoring/panel-authoring.ts +121 -0
- package/src/authoring/prefab-instance-inspector-section.tsx +237 -0
- package/src/authoring/prefab-instance-section-model.ts +55 -0
- package/src/authoring/project-authoring-session.ts +105 -0
- package/src/authoring/provenance.ts +99 -0
- package/src/authoring/quarks-particle-systems.ts +19 -0
- package/src/authoring/react-canvas-navigation.ts +255 -0
- package/src/authoring/react-design-canvas-style.ts +20 -0
- package/src/authoring/react-story-board.ts +937 -0
- package/src/authoring/selection-scope.ts +195 -0
- package/src/authoring/shell-document-ops.ts +169 -0
- package/src/authoring/shell-object3d-document-write-policy.ts +108 -0
- package/src/authoring/shell-viewport-policy.ts +48 -0
- package/src/authoring/source-object3d-authoring-adapter.ts +526 -0
- package/src/authoring/stories-scope.ts +35 -0
- package/src/authoring/story-board-chrome-fit.ts +107 -0
- package/src/authoring/story-board-presentation.ts +111 -0
- package/src/authoring/three-projection-core.ts +226 -0
- package/src/authoring/viewport-pick-context.ts +40 -0
- package/src/authoring/viewport-raycast.ts +240 -0
- package/src/authoring/viewport-tool-context.ts +73 -0
- package/src/authoring/world-canvas-viewport-state.ts +35 -0
- package/src/authoring/world-hidden-viewport.ts +152 -0
- package/src/authoring/world-pan-state.ts +198 -0
- package/src/authoring/world-session-state.ts +101 -0
- package/src/authoring/write-pipe.ts +173 -0
- package/src/availability-tick.ts +66 -0
- package/src/bitmap-label.ts +120 -0
- package/src/blender-tab-metrics.ts +161 -0
- package/src/board-open-actions.ts +20 -0
- package/src/boot-routing.ts +391 -0
- package/src/build-identity.ts +15 -0
- package/src/bytes-codec.ts +62 -0
- package/src/camera-authoring.ts +175 -0
- package/src/cancellation-reason.ts +58 -0
- package/src/canvas-preview-frames.ts +482 -0
- package/src/capture-camera-pose.ts +77 -0
- package/src/chrome-registry.ts +159 -0
- package/src/chrome-slot-registry.ts +91 -0
- package/src/collaboration-client.ts +264 -0
- package/src/collaboration-presence.ts +41 -0
- package/src/command-dispatch.ts +19 -0
- package/src/command-listener.ts +2743 -0
- package/src/command-registry.ts +70 -0
- package/src/component-board-registry.ts +205 -0
- package/src/component-states-registry.ts +200 -0
- package/src/components/AgentPresentationNotice.tsx +75 -0
- package/src/components/AlignToolbar.tsx +204 -0
- package/src/components/AppRoot.tsx +394 -0
- package/src/components/ApplicationMenus.tsx +415 -0
- package/src/components/AssetBrowser.tsx +2843 -0
- package/src/components/AssetEditorShell.tsx +216 -0
- package/src/components/AssetInspectorToolSection.tsx +124 -0
- package/src/components/BoardRulers.tsx +354 -0
- package/src/components/CameraInfo.tsx +81 -0
- package/src/components/CanvasSceneViewport.tsx +556 -0
- package/src/components/CapabilityCoverageSection.tsx +185 -0
- package/src/components/CenterDocuments.tsx +22 -0
- package/src/components/ChromeSlot.tsx +20 -0
- package/src/components/CodeView.tsx +470 -0
- package/src/components/CollaborationHeaderControl.css +74 -0
- package/src/components/CompactInspectorCard.tsx +190 -0
- package/src/components/CompactInspectorShell.tsx +39 -0
- package/src/components/ConsolePanel.css +55 -0
- package/src/components/ConsolePanel.tsx +270 -0
- package/src/components/DefaultEditorLayout.tsx +106 -0
- package/src/components/DocumentHeaderStrip.tsx +96 -0
- package/src/components/DocumentShelfRail.tsx +45 -0
- package/src/components/DocumentThumbnail.tsx +345 -0
- package/src/components/EditorLeaseGuard.tsx +372 -0
- package/src/components/ErrorBanner.tsx +123 -0
- package/src/components/FolderPreviewTile.tsx +159 -0
- package/src/components/GameHierarchy.tsx +3842 -0
- package/src/components/GameplaySessionTimeline.tsx +295 -0
- package/src/components/InspectionProjection.tsx +968 -0
- package/src/components/Inspector.tsx +233 -0
- package/src/components/InspectorCanvasPreview.tsx +35 -0
- package/src/components/InspectorFieldsSection.tsx +290 -0
- package/src/components/InspectorObjectPreview.tsx +57 -0
- package/src/components/InspectorStoriesSection.tsx +92 -0
- package/src/components/InspectorToolSection.tsx +96 -0
- package/src/components/InspectorTransformSection.tsx +245 -0
- package/src/components/LightExplorerPanel.tsx +433 -0
- package/src/components/MediaProperties.tsx +145 -0
- package/src/components/NonThreeAuthoringBootstrap.tsx +19 -0
- package/src/components/Object3DDocumentToolbar.css +100 -0
- package/src/components/Object3DDocumentToolbar.tsx +454 -0
- package/src/components/Object3DDocumentViewport.tsx +58 -0
- package/src/components/ProjectHeader.css +617 -0
- package/src/components/ProjectHeader.tsx +328 -0
- package/src/components/ProjectLayout.tsx +249 -0
- package/src/components/ReactCanvasControls.tsx +284 -0
- package/src/components/RootSelectionOverlay.tsx +3162 -0
- package/src/components/RootTextEditor.tsx +79 -0
- package/src/components/SaveStatus.tsx +70 -0
- package/src/components/StageHost.tsx +1954 -0
- package/src/components/StageOverlays.tsx +21 -0
- package/src/components/StartupErrorScreen.tsx +76 -0
- package/src/components/StartupLoadingScreen.tsx +65 -0
- package/src/components/StatsOverlay.tsx +78 -0
- package/src/components/SurfaceStateOverlay.tsx +24 -0
- package/src/components/ToolContributionSurfaces.tsx +65 -0
- package/src/components/ToolHost.tsx +370 -0
- package/src/components/ToolObject3DPreview.tsx +39 -0
- package/src/components/Toolbar.tsx +595 -0
- package/src/components/TransientHint.tsx +44 -0
- package/src/components/TransportStrip.tsx +174 -0
- package/src/components/VersionControlSection.tsx +470 -0
- package/src/components/VgaiLogo.css +83 -0
- package/src/components/VgaiLogo.tsx +35 -0
- package/src/components/ViewportControlsHint.tsx +60 -0
- package/src/components/ViewportFurniture.tsx +401 -0
- package/src/components/ViewportOverlay.tsx +145 -0
- package/src/components/ViewportOverlaysMenu.tsx +153 -0
- package/src/components/ViewportShadingMenu.tsx +300 -0
- package/src/components/ViewportViewMenu.tsx +101 -0
- package/src/components/WorkspaceDocumentSurface.tsx +204 -0
- package/src/components/WorkspaceUtilitySurface.tsx +22 -0
- package/src/components/WorktreeSwitcher.css +239 -0
- package/src/components/WorktreeSwitcher.tsx +890 -0
- package/src/components/account-documents.tsx +1162 -0
- package/src/components/asset-documents.tsx +812 -0
- package/src/components/asset-editor-persistence.ts +216 -0
- package/src/components/asset-selection-section.tsx +535 -0
- package/src/components/asset-thumbnails.tsx +312 -0
- package/src/components/asset-viewers/AudioViewer.tsx +201 -0
- package/src/components/asset-viewers/EntityModelDocument.tsx +122 -0
- package/src/components/asset-viewers/EnvironmentAssetDocument.tsx +440 -0
- package/src/components/asset-viewers/GenericJsonViewer.tsx +102 -0
- package/src/components/asset-viewers/ImageViewer.tsx +300 -0
- package/src/components/asset-viewers/JsonAssetDocument.tsx +93 -0
- package/src/components/asset-viewers/LiveModuleDocument.tsx +417 -0
- package/src/components/asset-viewers/LutAssetDocument.tsx +444 -0
- package/src/components/asset-viewers/ModelAssetDocument.tsx +105 -0
- package/src/components/asset-viewers/Object3DPreview.tsx +359 -0
- package/src/components/asset-viewers/OnlineAssetDetail.tsx +421 -0
- package/src/components/asset-viewers/PasteboardModuleDocument.tsx +67 -0
- package/src/components/asset-viewers/QuarksAssetDocument.tsx +526 -0
- package/src/components/asset-viewers/ShaderAssetDocument.tsx +743 -0
- package/src/components/asset-viewers/SourceAssetViewer.tsx +281 -0
- package/src/components/asset-viewers/SpritesheetSpriteView.tsx +102 -0
- package/src/components/asset-viewers/VideoViewer.tsx +101 -0
- package/src/components/asset-viewers/shader-source.ts +144 -0
- package/src/components/asset-workflow.css +731 -0
- package/src/components/board-guides.ts +150 -0
- package/src/components/compact-inspector.css +539 -0
- package/src/components/core-utilities.tsx +90 -0
- package/src/components/editor-notifications.css +40 -0
- package/src/components/engine-workspace.css +274 -0
- package/src/components/inspector-preview-section.tsx +238 -0
- package/src/components/inspector-property-grouping.ts +64 -0
- package/src/components/inspector-revert-label.ts +20 -0
- package/src/components/inspector-selection.ts +42 -0
- package/src/components/inspector-stories-gating.ts +171 -0
- package/src/components/inspector-transform-subject.ts +11 -0
- package/src/components/inspector-transform.ts +75 -0
- package/src/components/kind-documents.tsx +500 -0
- package/src/components/palette-action-publisher.tsx +140 -0
- package/src/components/primitives/DraftColorInput.tsx +74 -0
- package/src/components/product-shell.css +1829 -0
- package/src/components/project-tool-documents.tsx +410 -0
- package/src/components/scene-documents.tsx +223 -0
- package/src/components/stage-keyboard.tsx +37 -0
- package/src/components/stage-overlay-set.tsx +107 -0
- package/src/components/stage-presence-markers.ts +478 -0
- package/src/components/standard-viewport-dressing.ts +417 -0
- package/src/components/status-contributions.tsx +403 -0
- package/src/components/tool-documents.tsx +309 -0
- package/src/components/tool-schema-form.tsx +262 -0
- package/src/components/use-after-paint.ts +41 -0
- package/src/components/use-project-image-assets.ts +86 -0
- package/src/components/viewport-header-controls.css +90 -0
- package/src/components/viewport-surface-status.tsx +55 -0
- package/src/components/workspace-history.ts +32 -0
- package/src/components/workspace-static-panel-registry.tsx +152 -0
- package/src/components/workspace-surfaces.css +621 -0
- package/src/components/world-documents.tsx +586 -0
- package/src/components/world-overlay-gestures.ts +1694 -0
- package/src/composite-screenshot.ts +1641 -0
- package/src/console-sync.ts +131 -0
- package/src/constraint-helper.ts +338 -0
- package/src/content-entry-source-registry.ts +184 -0
- package/src/coverage/authoring-seam-evidence.ts +300 -0
- package/src/coverage/canvas-reveal.ts +192 -0
- package/src/coverage/design-time-surfaces.ts +101 -0
- package/src/coverage/live-seam-evidence.ts +11 -0
- package/src/coverage/ontology-invariants.ts +466 -0
- package/src/coverage/session-vitals.ts +501 -0
- package/src/coverage/system-seam-evidence.ts +72 -0
- package/src/crash-null-boundary.ts +36 -0
- package/src/creation-site-edit.ts +1479 -0
- package/src/creation-site-registry.ts +160 -0
- package/src/delegate-harness-registry.ts +143 -0
- package/src/document-context-registry.ts +177 -0
- package/src/document-open-registry.ts +200 -0
- package/src/document-preview-source.ts +20 -0
- package/src/document-renderer-session.ts +138 -0
- package/src/editor-api.ts +46 -0
- package/src/editor-chrome-capture.ts +139 -0
- package/src/editor-commands.ts +164 -0
- package/src/editor-console.ts +563 -0
- package/src/editor-current-view.ts +82 -0
- package/src/editor-document-probe.ts +881 -0
- package/src/editor-git-client.ts +115 -0
- package/src/editor-host-door.ts +462 -0
- package/src/editor-hotkeys.ts +842 -0
- package/src/editor-lease-view.ts +39 -0
- package/src/editor-lease.ts +415 -0
- package/src/editor-mode.ts +19 -0
- package/src/editor-notifications.ts +140 -0
- package/src/editor-presence.ts +563 -0
- package/src/editor-presentation-activity.ts +50 -0
- package/src/editor-presentation-notice.ts +42 -0
- package/src/editor-runtime.tsx +145 -0
- package/src/editor-server-response.ts +86 -0
- package/src/editor-session-attribution.ts +75 -0
- package/src/editor-session-mode.ts +54 -0
- package/src/editor-shell-store.ts +1304 -0
- package/src/editor-state-facets.ts +74 -0
- package/src/editor-styles.css +33 -0
- package/src/editor-view-presentation.ts +810 -0
- package/src/editor-viewport.ts +5302 -0
- package/src/entity-lod.ts +31 -0
- package/src/entity-object.ts +91 -0
- package/src/files/file-provider.ts +62 -0
- package/src/files/project-files.ts +264 -0
- package/src/finders/index.ts +136 -0
- package/src/finders/scenes-from-entrypoint-selection.ts +387 -0
- package/src/frame/bridge.tsx +1408 -0
- package/src/frame/product.ts +77 -0
- package/src/gameplay-dom-recording.ts +319 -0
- package/src/gameplay-export-state.ts +14 -0
- package/src/gameplay-replay.ts +417 -0
- package/src/gameplay-session-time.ts +9 -0
- package/src/gameplay-sessions.ts +204 -0
- package/src/harness-chat-types.ts +253 -0
- package/src/hierarchy-component-marks.ts +298 -0
- package/src/hierarchy-drop.ts +91 -0
- package/src/hierarchy-expansion-state.ts +80 -0
- package/src/hierarchy-header-slot.ts +52 -0
- package/src/hierarchy-internals.ts +197 -0
- package/src/hierarchy-kind-icon.ts +217 -0
- package/src/hierarchy-mark-reader.ts +73 -0
- package/src/hierarchy-menu-registry.ts +67 -0
- package/src/hierarchy-node-rows.ts +307 -0
- package/src/hierarchy-panel-view.ts +280 -0
- package/src/hierarchy-projection.ts +76 -0
- package/src/hierarchy-row-cache.ts +243 -0
- package/src/hierarchy-row-model.ts +308 -0
- package/src/hierarchy-rows.ts +11 -0
- package/src/hierarchy-walk.ts +86 -0
- package/src/history/editor-session.ts +25 -0
- package/src/history/history-commands.ts +147 -0
- package/src/history/history-delegate.ts +163 -0
- package/src/history/history-limit-notices.ts +43 -0
- package/src/history/history-service.ts +1173 -0
- package/src/history/persistence-coordinator.ts +35 -0
- package/src/history/project-file-history.ts +386 -0
- package/src/history/project-root-history-backends.ts +139 -0
- package/src/history/resource-registry.ts +209 -0
- package/src/history/snapshot-store.ts +103 -0
- package/src/history/source-history-backend.ts +546 -0
- package/src/history/types.ts +124 -0
- package/src/hmr-registration-group.ts +67 -0
- package/src/hmr-stable-react-context.ts +23 -0
- package/src/hotkeys.ts +188 -0
- package/src/inference-diagnostics.ts +69 -0
- package/src/initial-project.ts +80 -0
- package/src/inspection/active-subject.ts +578 -0
- package/src/inspection/active-surface.ts +142 -0
- package/src/inspection/compose.ts +1064 -0
- package/src/inspection/display.ts +170 -0
- package/src/inspection/document-subject.ts +109 -0
- package/src/inspection/game-subject.ts +85 -0
- package/src/inspection/model.ts +542 -0
- package/src/inspection/null-subject.ts +115 -0
- package/src/inspection/serialize.ts +357 -0
- package/src/inspection/use-active-inspection.ts +180 -0
- package/src/inspector-presentation.ts +201 -0
- package/src/inspector-section-registry.ts +221 -0
- package/src/instance-source-actions.ts +163 -0
- package/src/instanced-presentation.ts +164 -0
- package/src/js-heap.ts +71 -0
- package/src/key-actions.ts +91 -0
- package/src/keymap-presets.ts +401 -0
- package/src/layout-policy.ts +31 -0
- package/src/learn-links.ts +73 -0
- package/src/light-explorer-model.ts +134 -0
- package/src/live-canvas-frame.ts +55 -0
- package/src/live-document.ts +279 -0
- package/src/live-module-source.ts +230 -0
- package/src/live-session-registry.ts +220 -0
- package/src/live-transition.ts +633 -0
- package/src/manifest-project.ts +107 -0
- package/src/model-thumbnail.ts +523 -0
- package/src/native-selection-style.ts +202 -0
- package/src/object3d-document-write-policy.ts +137 -0
- package/src/packaged-runtime.ts +108 -0
- package/src/palettes/maya.palette.json +57 -0
- package/src/palettes/substance.palette.json +57 -0
- package/src/pasteboard-module.ts +81 -0
- package/src/performance-profiler.ts +367 -0
- package/src/performance-sources.ts +69 -0
- package/src/play-boot-phase.ts +145 -0
- package/src/presentation-surface.ts +248 -0
- package/src/project-adapter.ts +1143 -0
- package/src/project-asset-refresh.ts +26 -0
- package/src/project-declaration-refresh.ts +31 -0
- package/src/project-local-state.ts +118 -0
- package/src/project-manager.ts +243 -0
- package/src/project-module-changes.ts +163 -0
- package/src/project-module-split.ts +266 -0
- package/src/project-provenance.ts +115 -0
- package/src/project-ready.ts +42 -0
- package/src/project-session-reset.ts +67 -0
- package/src/project-shape.ts +68 -0
- package/src/project-tool-discovery.ts +66 -0
- package/src/project-tools.ts +107 -0
- package/src/project-work-types.ts +149 -0
- package/src/projection/three.ts +898 -0
- package/src/projection/types.ts +44 -0
- package/src/readiness.ts +113 -0
- package/src/reflection-probe-helper.ts +142 -0
- package/src/reported-play-state.ts +90 -0
- package/src/resolve-relative-specifier.ts +33 -0
- package/src/scene-document-plan.ts +315 -0
- package/src/scene-framing.ts +315 -0
- package/src/scene-live-open.ts +210 -0
- package/src/scene-view-fog.ts +89 -0
- package/src/scoped-game-css.ts +152 -0
- package/src/session-orphan-record.ts +193 -0
- package/src/session-tombstone.ts +126 -0
- package/src/settings/settings-provider.ts +82 -0
- package/src/settings-store.ts +345 -0
- package/src/shared-view-restore.ts +42 -0
- package/src/shell-store-door.ts +45 -0
- package/src/source-conflict.ts +122 -0
- package/src/spatial-handle-visuals.ts +332 -0
- package/src/stage-context.ts +341 -0
- package/src/stage-store-registry.ts +63 -0
- package/src/stale-chunk-recovery.ts +34 -0
- package/src/state-report-deferral.ts +73 -0
- package/src/storage/host-files-storage.ts +97 -0
- package/src/storage/http-storage.ts +174 -0
- package/src/storage/index.ts +75 -0
- package/src/storage/mem-storage.ts +149 -0
- package/src/storage/path-lock.ts +44 -0
- package/src/storage/paths.ts +26 -0
- package/src/storage/types.ts +116 -0
- package/src/stories/StoryComponentThumbnail.tsx +184 -0
- package/src/stories/StoryPreviewMount.tsx +306 -0
- package/src/stories/component-content-source.tsx +106 -0
- package/src/stories/component-states-source.ts +78 -0
- package/src/stories/compose-project-stories.ts +255 -0
- package/src/stories/pixi-story-model.ts +30 -0
- package/src/stories/prefabs-finder.ts +54 -0
- package/src/stories/prefabs-from-stories.ts +182 -0
- package/src/stories/project-story-discovery.ts +78 -0
- package/src/stories/project-story-regions.ts +24 -0
- package/src/stories/story-actions.ts +54 -0
- package/src/stories/story-capture-command.ts +124 -0
- package/src/stories/story-capture.ts +584 -0
- package/src/stories/story-declared-medium.ts +126 -0
- package/src/stories/story-discovery.ts +176 -0
- package/src/stories/story-document-openers.ts +36 -0
- package/src/stories/story-dom-runtime.ts +78 -0
- package/src/stories/story-grouping.ts +111 -0
- package/src/stories/story-lane.ts +88 -0
- package/src/stories/story-mount-turn.ts +27 -0
- package/src/stories/story-opener.ts +260 -0
- package/src/stories/story-pixi-preview.ts +408 -0
- package/src/stories/story-presentation.ts +215 -0
- package/src/stories/story-registry.ts +517 -0
- package/src/stories/story-three-preview.ts +807 -0
- package/src/stories/three-story-model.ts +96 -0
- package/src/story-three-preview-runtime.ts +56 -0
- package/src/surface-keyboard.ts +112 -0
- package/src/surface-state.ts +124 -0
- package/src/tab-bootstrap.js +628 -0
- package/src/tab-census.ts +198 -0
- package/src/tab-lifecycle-client.ts +196 -0
- package/src/theme-library.ts +844 -0
- package/src/theme-preference.ts +378 -0
- package/src/theme.css +3437 -0
- package/src/three-viewport/bone-selection-highlight.ts +119 -0
- package/src/three-viewport/camera-fit.ts +41 -0
- package/src/three-viewport/interactive-renderer.ts +132 -0
- package/src/three-viewport/selection-brackets.ts +310 -0
- package/src/three-viewport/selection-outline.ts +183 -0
- package/src/three-viewport/skeleton-helper.ts +61 -0
- package/src/three-viewport/source-color.ts +167 -0
- package/src/three-viewport/studio-environment.ts +96 -0
- package/src/three-viewport-presentation.ts +23 -0
- package/src/tool-contribution-play.ts +74 -0
- package/src/tool-loader.ts +1798 -0
- package/src/transform-mode-request.ts +57 -0
- package/src/transient-hint.ts +78 -0
- package/src/trigger-volume-helper.ts +116 -0
- package/src/ui-source/adapter-region-includes.ts +241 -0
- package/src/ui-source/ensure-import.ts +132 -0
- package/src/ui-source/file-region-resolver.ts +302 -0
- package/src/ui-source/inspect.ts +775 -0
- package/src/ui-source/oid-transform.ts +1845 -0
- package/src/ui-source/plan-csf-story.ts +196 -0
- package/src/ui-source/plan-extract-component.ts +421 -0
- package/src/ui-source/plan-fork-component.ts +621 -0
- package/src/ui-source/plan-named-style.ts +95 -0
- package/src/ui-source/plan-source-edit.ts +353 -0
- package/src/ui-source/r3f-contract-resolver.ts +327 -0
- package/src/ui-source/r3f-diagnostic-index.ts +165 -0
- package/src/ui-source/r3f-environment-binding.ts +133 -0
- package/src/ui-source/r3f-joint-binding.ts +251 -0
- package/src/ui-source/r3f-lod-binding.ts +91 -0
- package/src/ui-source/r3f-particle-binding.ts +235 -0
- package/src/ui-source/r3f-physics-binding.ts +483 -0
- package/src/ui-source/r3f-project-contracts.ts +444 -0
- package/src/ui-source/relative-import-specifier.ts +34 -0
- package/src/ui-source/reparent-guard.ts +544 -0
- package/src/ui-source/source-edit-request.ts +97 -0
- package/src/ui-source/source-write-backend.ts +618 -0
- package/src/ui-source/syntactic-prop-specs.ts +296 -0
- package/src/ui-source/tier-source-write-backend.ts +279 -0
- package/src/ui-source/ts-ast.ts +171 -0
- package/src/ui-source/utility-class-support.ts +169 -0
- package/src/ui-source/write-component-default.ts +133 -0
- package/src/ui-source/writer.ts +1989 -0
- package/src/viewport-activation-timings.ts +840 -0
- package/src/viewport-authoring-policy.ts +186 -0
- package/src/viewport-controls-hint.ts +57 -0
- package/src/viewport-door.ts +237 -0
- package/src/viewport-shading-boundary.ts +12 -0
- package/src/vite-error-surface.ts +141 -0
- package/src/wait-until.ts +37 -0
- package/src/workspace-areas.ts +156 -0
- package/src/workspace-aux-commands.ts +11 -0
- package/src/workspace-available-documents.ts +127 -0
- package/src/workspace-core-utilities.ts +31 -0
- package/src/workspace-document-ids.ts +59 -0
- package/src/workspace-document-registry.ts +612 -0
- package/src/workspace-document-restore.ts +145 -0
- package/src/workspace-host-commands.ts +141 -0
- package/src/workspace-persistence-gate.ts +40 -0
- package/src/workspace-play-utilities.ts +44 -0
- package/src/workspace-presets.ts +425 -0
- package/src/workspace-regions.ts +294 -0
- package/src/workspace-state-persistence.ts +536 -0
- package/src/workspace-static-panels.ts +73 -0
- package/src/workspace-status-registry.ts +121 -0
- package/src/workspace-style.ts +239 -0
- package/src/workspace-utility-commands.ts +74 -0
- package/src/workspace-utility-registry.ts +263 -0
- package/src/workspace-viewport-rect.ts +97 -0
- package/src/world-adoption.ts +115 -0
- package/src/world-document-routing.ts +104 -0
- package/vite-plugin-creation-site-write.ts +184 -0
- package/vite-plugin-creation-site.ts +80 -0
- package/vite-plugin-game-static.ts +303 -0
- package/vite-plugin-module-doorways.ts +336 -0
- package/vite-plugin-product-contributions.ts +197 -0
- package/vite-plugin-project-game-static.ts +125 -0
- package/vite-plugin-project-jsx-js.ts +65 -0
- package/vite-plugin-project-root-absolute-assets.ts +359 -0
- package/vite-plugin-shared-react.ts +420 -0
- package/vite-plugin-shared-three.ts +203 -0
- package/vite-plugin-ui-oid.ts +2106 -0
|
@@ -0,0 +1,621 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `planComponentFork` — the PURE core of H7 "Fork Component…": two already-read
|
|
3
|
+
* source strings in, two exact edits out. No I/O, no hashing, no transport — the
|
|
4
|
+
* same split `plan-source-edit.ts` uses, and for the same reason (the dev server
|
|
5
|
+
* reads with `node:fs`; this module stays dependency-free so the plan is
|
|
6
|
+
* readable on its own).
|
|
7
|
+
*
|
|
8
|
+
* WHAT A FORK IS. H7's translation of Unity's Unpack into a source world:
|
|
9
|
+
* customizing ONE instance beyond the component's prop surface means COPYING the
|
|
10
|
+
* component and retargeting that callsite — never flattening the definition's
|
|
11
|
+
* JSX into the parent (a refactor no React developer performs, and the thing
|
|
12
|
+
* H7 rejects permanently). Mechanically: one new file plus one changed tag.
|
|
13
|
+
*
|
|
14
|
+
* WHY THE WHOLE MODULE IS COPIED. The copy has to COMPILE. A definition's
|
|
15
|
+
* dependencies are module-level: imports, helper functions, constants, types,
|
|
16
|
+
* the props interface. Copying the module wholesale carries all of them, and —
|
|
17
|
+
* because the copy lands as a SIBLING of the original — every relative import
|
|
18
|
+
* specifier inside it still resolves unchanged. Selective extraction (copy the
|
|
19
|
+
* function, chase what it references) is the scope-analysis machinery the
|
|
20
|
+
* reparent spec owns; this action deliberately does not have it. The price is
|
|
21
|
+
* that non-component exports are duplicated across the two modules. That is
|
|
22
|
+
* accepted for v1: nothing imports the new module except the one retargeted
|
|
23
|
+
* callsite, so a duplicate export is inert.
|
|
24
|
+
*
|
|
25
|
+
* WHY IT IS NOT "for this instance". The menu item is `Fork Component…`, not
|
|
26
|
+
* "Fork for this instance": a callsite that lives inside a component rendered
|
|
27
|
+
* many times retargets EVERY render of that callsite. One callsite is the unit
|
|
28
|
+
* of this edit, and one callsite is not always one on-screen object.
|
|
29
|
+
*
|
|
30
|
+
* REFUSALS ARE NAMED. Every rejection returns a sentence the author can act on
|
|
31
|
+
* (doctrine rule 2 — "refusal is visible and named"), and the planner refuses
|
|
32
|
+
* BEFORE anything is written; the caller writes only a plan it has in hand.
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
import ts from 'typescript';
|
|
36
|
+
import { lineColToOffset } from './oid-transform';
|
|
37
|
+
import { relativeImportSpecifier } from './relative-import-specifier';
|
|
38
|
+
import { hasModifier, parseAuthoringTsx } from './ts-ast';
|
|
39
|
+
|
|
40
|
+
/** A valid JS identifier — the gate the instance's `name` prop must pass to
|
|
41
|
+
* become the fork's component name. */
|
|
42
|
+
const IDENTIFIER_RE = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
43
|
+
|
|
44
|
+
/** `<Tag>Fork`, `<Tag>Fork2` … up to this suffix before the planner gives up. */
|
|
45
|
+
const MAX_FALLBACK_SUFFIX = 99;
|
|
46
|
+
|
|
47
|
+
const SOURCE_EXTENSION_RE = /\.(tsx|ts|jsx|js)$/;
|
|
48
|
+
|
|
49
|
+
export interface ForkComponentRequest {
|
|
50
|
+
/** The file the instance is USED in, and its current bytes. */
|
|
51
|
+
readonly callsiteFile: string;
|
|
52
|
+
readonly callsiteSource: string;
|
|
53
|
+
/** The callsite element's `OidEntry` position (1-based line, 0-based col). */
|
|
54
|
+
readonly callsiteLine: number;
|
|
55
|
+
readonly callsiteCol: number;
|
|
56
|
+
/** The file the component is WRITTEN in, and its current bytes. */
|
|
57
|
+
readonly definitionFile: string;
|
|
58
|
+
readonly definitionSource: string;
|
|
59
|
+
/** The component name as spelled AT THE CALLSITE (`OidEntry.tag`). */
|
|
60
|
+
readonly tag: string;
|
|
61
|
+
/** The instance's `name` prop — the preferred seed for the fork's name. */
|
|
62
|
+
readonly nameSeed?: string | undefined;
|
|
63
|
+
/**
|
|
64
|
+
* File NAMES (not paths) already in the definition file's directory. Two
|
|
65
|
+
* jobs: the cheap "is this export name taken" probe H7 asks for (a module's
|
|
66
|
+
* basename is a good enough proxy for the component it exports, and this
|
|
67
|
+
* planner is not allowed to read the directory itself), and the hard
|
|
68
|
+
* file-collision refusal.
|
|
69
|
+
*/
|
|
70
|
+
readonly siblingFiles?: readonly string[] | undefined;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface ForkComponentPlan {
|
|
74
|
+
/** The forked component's name inside the copy, and at the retargeted tag. */
|
|
75
|
+
readonly newName: string;
|
|
76
|
+
/** `EnemyBravo.tsx` — the caller joins it onto the definition's directory. */
|
|
77
|
+
readonly newFileName: string;
|
|
78
|
+
/** The new module's path, normalized to forward slashes. */
|
|
79
|
+
readonly newFile: string;
|
|
80
|
+
/** The complete bytes of the new module (the copy, renamed). */
|
|
81
|
+
readonly newFileSource: string;
|
|
82
|
+
readonly callsiteFile: string;
|
|
83
|
+
readonly callsitePrevSource: string;
|
|
84
|
+
readonly callsiteNewSource: string;
|
|
85
|
+
/** The specifier written into the callsite's new import. */
|
|
86
|
+
readonly importSpecifier: string;
|
|
87
|
+
/** The component name as it was spelled at the callsite before the fork. */
|
|
88
|
+
readonly tag: string;
|
|
89
|
+
/** The history label for the CALLSITE edit (the new file is outside history). */
|
|
90
|
+
readonly historyLabel: string;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export type ForkComponentPlanResult =
|
|
94
|
+
| { readonly ok: true; readonly plan: ForkComponentPlan }
|
|
95
|
+
| { readonly ok: false; readonly reason: string };
|
|
96
|
+
|
|
97
|
+
function refuse(reason: string): ForkComponentPlanResult {
|
|
98
|
+
return { ok: false, reason };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// ------------------------------------------------------------------- paths
|
|
102
|
+
|
|
103
|
+
/** Forward-slash form; a Windows path from the OID index normalizes here. */
|
|
104
|
+
function normalizePath(path: string): string {
|
|
105
|
+
return path.replace(/\\/g, '/');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function directoryOf(path: string): string {
|
|
109
|
+
const clean = normalizePath(path);
|
|
110
|
+
const cut = clean.lastIndexOf('/');
|
|
111
|
+
return cut < 0 ? '' : clean.slice(0, cut);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** `siblingOf('src/Enemy.tsx', 'Fork.tsx')` → `src/Fork.tsx`; a bare filename
|
|
115
|
+
* (no directory at all) stays bare rather than becoming root-absolute. */
|
|
116
|
+
function siblingOf(path: string, fileName: string): string {
|
|
117
|
+
const dir = directoryOf(path);
|
|
118
|
+
return dir ? `${dir}/${fileName}` : fileName;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// -------------------------------------------------------------- declarations
|
|
122
|
+
|
|
123
|
+
interface ComponentDeclaration {
|
|
124
|
+
readonly exported: boolean;
|
|
125
|
+
readonly isDefault: boolean;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* The component's own declaration in its module — a function declaration or a
|
|
130
|
+
* `const` bound to an arrow/function expression, the same two shapes
|
|
131
|
+
* `oid-transform.ts`'s `componentDefinitions` recognizes as a component. A
|
|
132
|
+
* `memo(...)`/`forwardRef(...)` wrapper is deliberately NOT matched: the fork
|
|
133
|
+
* would have to guess where the name lives, and a named refusal beats a guess.
|
|
134
|
+
*/
|
|
135
|
+
function declarationOf(sf: ts.SourceFile, name: string): ComponentDeclaration | null {
|
|
136
|
+
for (const statement of sf.statements) {
|
|
137
|
+
if (ts.isFunctionDeclaration(statement) && statement.name?.text === name && statement.body) {
|
|
138
|
+
return {
|
|
139
|
+
exported: hasModifier(statement, ts.SyntaxKind.ExportKeyword),
|
|
140
|
+
isDefault: hasModifier(statement, ts.SyntaxKind.DefaultKeyword),
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
if (!ts.isVariableStatement(statement)) continue;
|
|
144
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
145
|
+
if (
|
|
146
|
+
ts.isIdentifier(declaration.name) &&
|
|
147
|
+
declaration.name.text === name &&
|
|
148
|
+
declaration.initializer &&
|
|
149
|
+
(ts.isArrowFunction(declaration.initializer) ||
|
|
150
|
+
ts.isFunctionExpression(declaration.initializer))
|
|
151
|
+
) {
|
|
152
|
+
return {
|
|
153
|
+
exported: hasModifier(statement, ts.SyntaxKind.ExportKeyword),
|
|
154
|
+
isDefault: false,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/** How the copy will EXPORT the renamed component — which decides whether the
|
|
163
|
+
* callsite gets a named or a default import. `null` means it is not exported
|
|
164
|
+
* at all, which the fork refuses (the retargeted callsite could not import
|
|
165
|
+
* it). */
|
|
166
|
+
function exportFormOf(
|
|
167
|
+
sf: ts.SourceFile,
|
|
168
|
+
name: string,
|
|
169
|
+
declaration: ComponentDeclaration,
|
|
170
|
+
): 'named' | 'default' | null {
|
|
171
|
+
if (declaration.isDefault) return 'default';
|
|
172
|
+
if (declaration.exported) return 'named';
|
|
173
|
+
for (const statement of sf.statements) {
|
|
174
|
+
const form = exportStatementForm(statement, name);
|
|
175
|
+
if (form) return form;
|
|
176
|
+
}
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** `export default Enemy;` / `export { Enemy }` / `export { Enemy as default }`. */
|
|
181
|
+
function exportStatementForm(statement: ts.Statement, name: string): 'named' | 'default' | null {
|
|
182
|
+
if (ts.isExportAssignment(statement)) {
|
|
183
|
+
const isDefault =
|
|
184
|
+
statement.isExportEquals !== true &&
|
|
185
|
+
ts.isIdentifier(statement.expression) &&
|
|
186
|
+
statement.expression.text === name;
|
|
187
|
+
return isDefault ? 'default' : null;
|
|
188
|
+
}
|
|
189
|
+
if (!ts.isExportDeclaration(statement) || statement.moduleSpecifier) return null;
|
|
190
|
+
const clause = statement.exportClause;
|
|
191
|
+
if (!clause || !ts.isNamedExports(clause)) return null;
|
|
192
|
+
for (const element of clause.elements) {
|
|
193
|
+
if ((element.propertyName ?? element.name).text !== name) continue;
|
|
194
|
+
return element.name.text === 'default' ? 'default' : 'named';
|
|
195
|
+
}
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/** Every binding this module introduces at the top level — imports included.
|
|
200
|
+
* The fork's name must collide with none of them, in either file. */
|
|
201
|
+
function topLevelNames(sf: ts.SourceFile): Set<string> {
|
|
202
|
+
const names = new Set<string>();
|
|
203
|
+
for (const statement of sf.statements) {
|
|
204
|
+
for (const name of statementNames(statement)) names.add(name);
|
|
205
|
+
}
|
|
206
|
+
return names;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function statementNames(statement: ts.Statement): string[] {
|
|
210
|
+
if (ts.isImportDeclaration(statement)) return importedNames(statement);
|
|
211
|
+
if (ts.isVariableStatement(statement)) {
|
|
212
|
+
return statement.declarationList.declarations.flatMap((declaration) =>
|
|
213
|
+
boundNames(declaration.name),
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
if (!NAMED_DECLARATION_KINDS.has(statement.kind)) return [];
|
|
217
|
+
const named = (statement as { name?: ts.Identifier }).name;
|
|
218
|
+
return named ? [named.text] : [];
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function boundNames(node: ts.BindingName): string[] {
|
|
222
|
+
if (ts.isIdentifier(node)) return [node.text];
|
|
223
|
+
return node.elements.flatMap((element) =>
|
|
224
|
+
ts.isBindingElement(element) ? boundNames(element.name) : [],
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const NAMED_DECLARATION_KINDS: ReadonlySet<ts.SyntaxKind> = new Set([
|
|
229
|
+
ts.SyntaxKind.FunctionDeclaration,
|
|
230
|
+
ts.SyntaxKind.ClassDeclaration,
|
|
231
|
+
ts.SyntaxKind.InterfaceDeclaration,
|
|
232
|
+
ts.SyntaxKind.TypeAliasDeclaration,
|
|
233
|
+
ts.SyntaxKind.EnumDeclaration,
|
|
234
|
+
]);
|
|
235
|
+
|
|
236
|
+
function importedNames(statement: ts.ImportDeclaration): string[] {
|
|
237
|
+
const clause = statement.importClause;
|
|
238
|
+
if (!clause) return [];
|
|
239
|
+
const names = clause.name ? [clause.name.text] : [];
|
|
240
|
+
const bindings = clause.namedBindings;
|
|
241
|
+
if (!bindings) return names;
|
|
242
|
+
if (ts.isNamespaceImport(bindings)) return [...names, bindings.name.text];
|
|
243
|
+
return [...names, ...bindings.elements.map((element) => element.name.text)];
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/** The name the definition module actually declares for the tag spelled at the
|
|
247
|
+
* callsite. Usually the same string; an aliased (`import { Enemy as Foe }`) or
|
|
248
|
+
* default import makes them differ, and renaming the wrong one would produce a
|
|
249
|
+
* copy that does not compile. */
|
|
250
|
+
function resolveDeclaredName(
|
|
251
|
+
definitionSf: ts.SourceFile,
|
|
252
|
+
callsiteSf: ts.SourceFile,
|
|
253
|
+
tag: string,
|
|
254
|
+
): string | null {
|
|
255
|
+
if (declarationOf(definitionSf, tag)) return tag;
|
|
256
|
+
const imported = importedOrigin(callsiteSf, tag);
|
|
257
|
+
if (!imported) return null;
|
|
258
|
+
const original = imported === 'default' ? defaultExportName(definitionSf) : imported;
|
|
259
|
+
return original && declarationOf(definitionSf, original) ? original : null;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/** What the callsite's `tag` binding is imported AS: the exporting module's own
|
|
263
|
+
* name for it, or the sentinel `'default'`. `null` when it is not imported. */
|
|
264
|
+
function importedOrigin(callsiteSf: ts.SourceFile, tag: string): string | null {
|
|
265
|
+
for (const statement of callsiteSf.statements) {
|
|
266
|
+
if (!ts.isImportDeclaration(statement) || !statement.importClause) continue;
|
|
267
|
+
const clause = statement.importClause;
|
|
268
|
+
if (clause.name?.text === tag) return 'default';
|
|
269
|
+
const bindings = clause.namedBindings;
|
|
270
|
+
if (!bindings || !ts.isNamedImports(bindings)) continue;
|
|
271
|
+
for (const element of bindings.elements) {
|
|
272
|
+
if (element.name.text === tag) return (element.propertyName ?? element.name).text;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return null;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function defaultExportName(sf: ts.SourceFile): string | null {
|
|
279
|
+
for (const statement of sf.statements) {
|
|
280
|
+
if (
|
|
281
|
+
ts.isFunctionDeclaration(statement) &&
|
|
282
|
+
statement.name &&
|
|
283
|
+
hasModifier(statement, ts.SyntaxKind.DefaultKeyword)
|
|
284
|
+
) {
|
|
285
|
+
return statement.name.text;
|
|
286
|
+
}
|
|
287
|
+
if (
|
|
288
|
+
ts.isExportAssignment(statement) &&
|
|
289
|
+
statement.isExportEquals !== true &&
|
|
290
|
+
ts.isIdentifier(statement.expression)
|
|
291
|
+
) {
|
|
292
|
+
return statement.expression.text;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
return null;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// -------------------------------------------------------------------- naming
|
|
299
|
+
|
|
300
|
+
/** `patrol guard 2` → `PatrolGuard2`; `""`/`"2fast"` → `null` (not an
|
|
301
|
+
* identifier, so the caller falls back to `<Tag>Fork`). */
|
|
302
|
+
export function pascalCaseIdentifier(seed: string | undefined): string | null {
|
|
303
|
+
if (!seed) return null;
|
|
304
|
+
const parts = seed.split(/[^A-Za-z0-9]+/).filter(Boolean);
|
|
305
|
+
if (parts.length === 0) return null;
|
|
306
|
+
const joined = parts.map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`).join('');
|
|
307
|
+
if (!IDENTIFIER_RE.test(joined)) return null;
|
|
308
|
+
if (!/^[A-Z]/.test(joined)) return null;
|
|
309
|
+
return joined;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* The fork's name: the instance's `name` prop when it is usable and free,
|
|
314
|
+
* otherwise `<Tag>Fork`, `<Tag>Fork2`, … `null` when even the fallback series
|
|
315
|
+
* is exhausted (99 forks of one component in one directory).
|
|
316
|
+
*/
|
|
317
|
+
export function pickForkName(
|
|
318
|
+
tag: string,
|
|
319
|
+
seed: string | undefined,
|
|
320
|
+
taken: ReadonlySet<string>,
|
|
321
|
+
): string | null {
|
|
322
|
+
const fromSeed = pascalCaseIdentifier(seed);
|
|
323
|
+
if (fromSeed && !taken.has(fromSeed)) return fromSeed;
|
|
324
|
+
for (let suffix = 1; suffix <= MAX_FALLBACK_SUFFIX; suffix += 1) {
|
|
325
|
+
const candidate = `${tag}Fork${suffix === 1 ? '' : suffix}`;
|
|
326
|
+
if (!taken.has(candidate)) return candidate;
|
|
327
|
+
}
|
|
328
|
+
return null;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// --------------------------------------------------------------- the rename
|
|
332
|
+
|
|
333
|
+
interface Replacement {
|
|
334
|
+
readonly start: number;
|
|
335
|
+
readonly end: number;
|
|
336
|
+
readonly text: string;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
function applyReplacements(source: string, replacements: readonly Replacement[]): string {
|
|
340
|
+
let out = source;
|
|
341
|
+
for (const replacement of [...replacements].sort((a, b) => b.start - a.start)) {
|
|
342
|
+
out = out.slice(0, replacement.start) + replacement.text + out.slice(replacement.end);
|
|
343
|
+
}
|
|
344
|
+
return out;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Rename every reference to `name` in this module — AST-driven, never a regex.
|
|
349
|
+
*
|
|
350
|
+
* Renamed: the declaration, ordinary references, self-recursive JSX usage
|
|
351
|
+
* (`<Enemy>` inside `Enemy`'s own body), `export { Enemy }`, `export default
|
|
352
|
+
* Enemy`, type positions such as `typeof Enemy`. NOT renamed: anything that
|
|
353
|
+
* merely SPELLS the same text in a non-reference position — a property access
|
|
354
|
+
* (`registry.Enemy`), an object-literal key, a JSX attribute name, a
|
|
355
|
+
* destructuring property name, a member of a type. The props type
|
|
356
|
+
* (`EnemyProps`) is a different identifier and is deliberately untouched: H7
|
|
357
|
+
* renames the component, nothing else.
|
|
358
|
+
*
|
|
359
|
+
* A shorthand property (`{ Enemy }`) is EXPANDED to `{ Enemy: EnemyBravo }`
|
|
360
|
+
* rather than renamed, because renaming it silently changes the key.
|
|
361
|
+
*
|
|
362
|
+
* Known v1 limit, recorded rather than hidden: an inner scope that re-declares
|
|
363
|
+
* the same name would have its references renamed too. Detecting that needs a
|
|
364
|
+
* scope walk this action does not carry, and a component module shadowing its
|
|
365
|
+
* own component name is not a shape we have seen.
|
|
366
|
+
*/
|
|
367
|
+
export function renameComponentInModule(
|
|
368
|
+
file: string,
|
|
369
|
+
source: string,
|
|
370
|
+
name: string,
|
|
371
|
+
newName: string,
|
|
372
|
+
): string {
|
|
373
|
+
const sf = parseAuthoringTsx(file, source);
|
|
374
|
+
const replacements: Replacement[] = [];
|
|
375
|
+
const visit = (node: ts.Node): void => {
|
|
376
|
+
if (ts.isIdentifier(node) && node.text === name) {
|
|
377
|
+
const parent = node.parent as ts.Node | undefined;
|
|
378
|
+
if (parent && ts.isShorthandPropertyAssignment(parent) && parent.name === node) {
|
|
379
|
+
replacements.push({
|
|
380
|
+
start: node.getStart(sf),
|
|
381
|
+
end: node.getEnd(),
|
|
382
|
+
text: `${name}: ${newName}`,
|
|
383
|
+
});
|
|
384
|
+
} else if (isReferencePosition(node, parent)) {
|
|
385
|
+
replacements.push({ start: node.getStart(sf), end: node.getEnd(), text: newName });
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
ts.forEachChild(node, visit);
|
|
389
|
+
};
|
|
390
|
+
ts.forEachChild(sf, visit);
|
|
391
|
+
return applyReplacements(source, replacements);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/** Parents whose `name` child is a KEY, not a reference to a binding. */
|
|
395
|
+
const NAME_IS_A_KEY_KINDS: ReadonlySet<ts.SyntaxKind> = new Set([
|
|
396
|
+
ts.SyntaxKind.PropertyAccessExpression,
|
|
397
|
+
ts.SyntaxKind.PropertyAssignment,
|
|
398
|
+
ts.SyntaxKind.JsxAttribute,
|
|
399
|
+
ts.SyntaxKind.PropertySignature,
|
|
400
|
+
ts.SyntaxKind.PropertyDeclaration,
|
|
401
|
+
ts.SyntaxKind.MethodSignature,
|
|
402
|
+
ts.SyntaxKind.MethodDeclaration,
|
|
403
|
+
ts.SyntaxKind.EnumMember,
|
|
404
|
+
]);
|
|
405
|
+
|
|
406
|
+
function isReferencePosition(node: ts.Identifier, parent: ts.Node | undefined): boolean {
|
|
407
|
+
if (!parent) return true;
|
|
408
|
+
if (ts.isQualifiedName(parent)) return parent.right !== node;
|
|
409
|
+
if (ts.isBindingElement(parent)) return parent.propertyName !== node;
|
|
410
|
+
if (!NAME_IS_A_KEY_KINDS.has(parent.kind)) return true;
|
|
411
|
+
return (parent as { name?: ts.Node }).name !== node;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// ------------------------------------------------------------ callsite edit
|
|
415
|
+
|
|
416
|
+
interface ImportStyle {
|
|
417
|
+
readonly quote: string;
|
|
418
|
+
readonly semi: boolean;
|
|
419
|
+
readonly extension: string;
|
|
420
|
+
/** Offset the new import statement is inserted at, and what follows it. */
|
|
421
|
+
readonly insertAt: number;
|
|
422
|
+
readonly leading: string;
|
|
423
|
+
readonly trailing: string;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/** Match the file's own import spelling rather than imposing one — the fork's
|
|
427
|
+
* line should be indistinguishable from the ones already there. */
|
|
428
|
+
function importStyleOf(sf: ts.SourceFile, source: string): ImportStyle {
|
|
429
|
+
const imports = sf.statements.filter(ts.isImportDeclaration);
|
|
430
|
+
const last = imports[imports.length - 1];
|
|
431
|
+
const first = imports[0];
|
|
432
|
+
let quote = "'";
|
|
433
|
+
let extension = '';
|
|
434
|
+
if (first) {
|
|
435
|
+
const specifierStart = first.moduleSpecifier.getStart(sf);
|
|
436
|
+
if (source[specifierStart] === '"') quote = '"';
|
|
437
|
+
}
|
|
438
|
+
for (const declaration of imports) {
|
|
439
|
+
if (!ts.isStringLiteral(declaration.moduleSpecifier)) continue;
|
|
440
|
+
const text = declaration.moduleSpecifier.text;
|
|
441
|
+
if (!text.startsWith('.')) continue;
|
|
442
|
+
const match = SOURCE_EXTENSION_RE.exec(text);
|
|
443
|
+
if (match) extension = match[0];
|
|
444
|
+
break;
|
|
445
|
+
}
|
|
446
|
+
const semi = last ? source.slice(0, last.getEnd()).trimEnd().endsWith(';') : true;
|
|
447
|
+
if (last) {
|
|
448
|
+
return { quote, semi, extension, insertAt: last.getEnd(), leading: '\n', trailing: '' };
|
|
449
|
+
}
|
|
450
|
+
// No imports at all: the file's very top is the only position that cannot
|
|
451
|
+
// detach a doc comment from the statement it documents.
|
|
452
|
+
return { quote, semi, extension, insertAt: 0, leading: '', trailing: '\n' };
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
function jsxAtOffset(
|
|
456
|
+
sf: ts.SourceFile,
|
|
457
|
+
offset: number,
|
|
458
|
+
): ts.JsxOpeningElement | ts.JsxSelfClosingElement | null {
|
|
459
|
+
let found: ts.JsxOpeningElement | ts.JsxSelfClosingElement | null = null;
|
|
460
|
+
const visit = (node: ts.Node): void => {
|
|
461
|
+
if (found) return;
|
|
462
|
+
if (
|
|
463
|
+
(ts.isJsxOpeningElement(node) || ts.isJsxSelfClosingElement(node)) &&
|
|
464
|
+
node.getStart(sf) === offset
|
|
465
|
+
) {
|
|
466
|
+
found = node;
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
ts.forEachChild(node, visit);
|
|
470
|
+
};
|
|
471
|
+
ts.forEachChild(sf, visit);
|
|
472
|
+
return found;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// ------------------------------------------------------------------- the plan
|
|
476
|
+
|
|
477
|
+
/**
|
|
478
|
+
* The refusals that need no parsing at all: what the tag IS, and where the
|
|
479
|
+
* definition lives relative to the callsite.
|
|
480
|
+
*
|
|
481
|
+
* The same-file case is a real and deliberate limit. A component declared in the
|
|
482
|
+
* world file itself cannot be forked by copying its module, because the copy
|
|
483
|
+
* would carry the callsite too; extracting just the declaration is the selective
|
|
484
|
+
* scope analysis this action refuses to grow. So it says so, and names the fix.
|
|
485
|
+
*/
|
|
486
|
+
function refusedByShape(tag: string, callsiteFile: string, definitionFile: string): string | null {
|
|
487
|
+
if (!/^[A-Z]/.test(tag)) {
|
|
488
|
+
return `<${tag}> is a native element, not a component instance — there is no definition to fork.`;
|
|
489
|
+
}
|
|
490
|
+
if (tag.includes('.')) {
|
|
491
|
+
return `<${tag}> is a namespaced tag; fork can only copy a component declared as a plain module export.`;
|
|
492
|
+
}
|
|
493
|
+
if (normalizePath(callsiteFile) === normalizePath(definitionFile)) {
|
|
494
|
+
return (
|
|
495
|
+
`<${tag}> is declared in the same file as this callsite. Fork copies the component's whole ` +
|
|
496
|
+
'module, and copying this file would duplicate the callsite too — move the component into ' +
|
|
497
|
+
'its own module first.'
|
|
498
|
+
);
|
|
499
|
+
}
|
|
500
|
+
return null;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* Plan a fork: parse both files, validate everything, and return the exact
|
|
505
|
+
* bytes of BOTH edits. Nothing here writes; the caller writes the new file
|
|
506
|
+
* first and the callsite second (see the route handler), so a failure after the
|
|
507
|
+
* new file lands leaves an inert module nothing imports.
|
|
508
|
+
*/
|
|
509
|
+
export function planComponentFork(request: ForkComponentRequest): ForkComponentPlanResult {
|
|
510
|
+
const { tag, callsiteFile, callsiteSource, definitionFile, definitionSource } = request;
|
|
511
|
+
|
|
512
|
+
const shapeRefusal = refusedByShape(tag, callsiteFile, definitionFile);
|
|
513
|
+
if (shapeRefusal) return refuse(shapeRefusal);
|
|
514
|
+
|
|
515
|
+
const callsiteSf = parseAuthoringTsx(callsiteFile, callsiteSource);
|
|
516
|
+
const definitionSf = parseAuthoringTsx(definitionFile, definitionSource);
|
|
517
|
+
|
|
518
|
+
// The callsite must still BE the tag the menu was built from. An index that
|
|
519
|
+
// is one edit stale would otherwise retarget an innocent neighbouring tag.
|
|
520
|
+
const offset = lineColToOffset(callsiteSource, request.callsiteLine, request.callsiteCol);
|
|
521
|
+
const opening = jsxAtOffset(callsiteSf, offset);
|
|
522
|
+
if (!opening || opening.tagName.getText(callsiteSf) !== tag) {
|
|
523
|
+
return refuse(
|
|
524
|
+
`The callsite at ${callsiteFile}:${request.callsiteLine} is no longer <${tag}> — the source ` +
|
|
525
|
+
'changed under the editor. Reselect the instance and try again.',
|
|
526
|
+
);
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
const declaredName = resolveDeclaredName(definitionSf, callsiteSf, tag);
|
|
530
|
+
const declaration = declaredName ? declarationOf(definitionSf, declaredName) : null;
|
|
531
|
+
if (!declaredName || !declaration) {
|
|
532
|
+
return refuse(
|
|
533
|
+
`Could not find the declaration of <${tag}> in ${definitionFile}. Fork copies a component ` +
|
|
534
|
+
'written as a function declaration or a const arrow function; this one is neither.',
|
|
535
|
+
);
|
|
536
|
+
}
|
|
537
|
+
const exportForm = exportFormOf(definitionSf, declaredName, declaration);
|
|
538
|
+
if (!exportForm) {
|
|
539
|
+
return refuse(
|
|
540
|
+
`<${tag}> is not exported from ${definitionFile}, so a forked copy could not be imported here.`,
|
|
541
|
+
);
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
const siblings = request.siblingFiles ?? [];
|
|
545
|
+
const taken = new Set<string>([
|
|
546
|
+
...topLevelNames(callsiteSf),
|
|
547
|
+
...topLevelNames(definitionSf),
|
|
548
|
+
// H7's "any export of the target directory's modules you can cheaply
|
|
549
|
+
// check": a module's basename is the proxy — this planner may not read a
|
|
550
|
+
// directory, and reading every sibling's exports is not cheap.
|
|
551
|
+
...siblings.map((name) => name.replace(SOURCE_EXTENSION_RE, '')),
|
|
552
|
+
tag,
|
|
553
|
+
declaredName,
|
|
554
|
+
]);
|
|
555
|
+
const newName = pickForkName(tag, request.nameSeed, taken);
|
|
556
|
+
if (!newName) {
|
|
557
|
+
return refuse(
|
|
558
|
+
`Could not find a free name for a fork of <${tag}> — every candidate through ` +
|
|
559
|
+
`${tag}Fork${MAX_FALLBACK_SUFFIX} is already taken.`,
|
|
560
|
+
);
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
const newFileName = `${newName}.tsx`;
|
|
564
|
+
const collision = siblings.find((name) => name.toLowerCase() === newFileName.toLowerCase());
|
|
565
|
+
if (collision) {
|
|
566
|
+
return refuse(
|
|
567
|
+
`${siblingOf(definitionFile, collision)} already exists — fork will not overwrite a file.`,
|
|
568
|
+
);
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
const newFile = siblingOf(definitionFile, newFileName);
|
|
572
|
+
const newFileSource = renameComponentInModule(newFile, definitionSource, declaredName, newName);
|
|
573
|
+
|
|
574
|
+
const style = importStyleOf(callsiteSf, callsiteSource);
|
|
575
|
+
const importSpecifier = relativeImportSpecifier(callsiteFile, newFile);
|
|
576
|
+
const clause = exportForm === 'default' ? newName : `{ ${newName} }`;
|
|
577
|
+
const importText = `import ${clause} from ${style.quote}${importSpecifier}${style.quote}${
|
|
578
|
+
style.semi ? ';' : ''
|
|
579
|
+
}`;
|
|
580
|
+
|
|
581
|
+
// The OLD import may now be unused. It is left alone ON PURPOSE: pruning an
|
|
582
|
+
// import is lint's job (Biome reports it, and the same component may still be
|
|
583
|
+
// used by another tag in this file), and a fork that silently deleted a line
|
|
584
|
+
// it was not asked about would be a second, invisible edit.
|
|
585
|
+
const replacements: Replacement[] = [
|
|
586
|
+
{
|
|
587
|
+
start: opening.tagName.getStart(callsiteSf),
|
|
588
|
+
end: opening.tagName.getEnd(),
|
|
589
|
+
text: newName,
|
|
590
|
+
},
|
|
591
|
+
{
|
|
592
|
+
start: style.insertAt,
|
|
593
|
+
end: style.insertAt,
|
|
594
|
+
text: `${style.leading}${importText}${style.trailing}`,
|
|
595
|
+
},
|
|
596
|
+
];
|
|
597
|
+
const parent = opening.parent as ts.Node | undefined;
|
|
598
|
+
if (parent && ts.isJsxElement(parent) && parent.openingElement === opening) {
|
|
599
|
+
replacements.push({
|
|
600
|
+
start: parent.closingElement.tagName.getStart(callsiteSf),
|
|
601
|
+
end: parent.closingElement.tagName.getEnd(),
|
|
602
|
+
text: newName,
|
|
603
|
+
});
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
return {
|
|
607
|
+
ok: true,
|
|
608
|
+
plan: {
|
|
609
|
+
newName,
|
|
610
|
+
newFileName,
|
|
611
|
+
newFile,
|
|
612
|
+
newFileSource,
|
|
613
|
+
callsiteFile,
|
|
614
|
+
callsitePrevSource: callsiteSource,
|
|
615
|
+
callsiteNewSource: applyReplacements(callsiteSource, replacements),
|
|
616
|
+
importSpecifier,
|
|
617
|
+
tag,
|
|
618
|
+
historyLabel: `Fork ${tag} → ${newName}`,
|
|
619
|
+
},
|
|
620
|
+
};
|
|
621
|
+
}
|