@pie-element/cli 0.1.1 → 0.1.2-next.0
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/README.md +48 -10
- package/dist/commands/dev/demo/index.d.ts +1 -1
- package/dist/commands/dev/demo/index.js +21 -0
- package/dist/commands/dev/demo/index.js.map +1 -1
- package/dist/commands/dev/test-bundler.d.ts +0 -1
- package/dist/commands/dev/test-bundler.js +2 -10
- package/dist/commands/dev/test-bundler.js.map +1 -1
- package/dist/commands/docs/generate.d.ts +16 -0
- package/dist/commands/docs/generate.js +150 -0
- package/dist/commands/docs/generate.js.map +1 -0
- package/dist/commands/docs/verify.d.ts +12 -0
- package/dist/commands/docs/verify.js +40 -0
- package/dist/commands/docs/verify.js.map +1 -0
- package/dist/commands/packages/create-controllers.d.ts +0 -1
- package/dist/commands/packages/create-controllers.js.map +1 -1
- package/dist/commands/packages/create-lib-react.d.ts +0 -1
- package/dist/commands/packages/create-lib-react.js +1 -3
- package/dist/commands/packages/create-lib-react.js.map +1 -1
- package/dist/commands/packages/create-react-elements.d.ts +0 -1
- package/dist/commands/packages/create-react-elements.js +2 -3
- package/dist/commands/packages/create-react-elements.js.map +1 -1
- package/dist/commands/packages/enable-publishing.d.ts +0 -1
- package/dist/commands/packages/enable-publishing.js +26 -23
- package/dist/commands/packages/enable-publishing.js.map +1 -1
- package/dist/commands/packages/init-synced-elements.d.ts +0 -1
- package/dist/commands/packages/init-synced-elements.js +1 -1
- package/dist/commands/packages/init-synced-elements.js.map +1 -1
- package/dist/commands/upstream/analyze-esm.d.ts +0 -1
- package/dist/commands/upstream/analyze-esm.js +5 -1
- package/dist/commands/upstream/analyze-esm.js.map +1 -1
- package/dist/commands/upstream/check.d.ts +0 -1
- package/dist/commands/upstream/check.js.map +1 -1
- package/dist/commands/upstream/deps.d.ts +0 -1
- package/dist/commands/upstream/deps.js.map +1 -1
- package/dist/commands/upstream/sync.d.ts +11 -2
- package/dist/commands/upstream/sync.js +364 -25
- package/dist/commands/upstream/sync.js.map +1 -1
- package/dist/commands/upstream/track.d.ts +0 -1
- package/dist/commands/upstream/track.js.map +1 -1
- package/dist/commands/upstream/update.d.ts +0 -1
- package/dist/commands/upstream/update.js +37 -7
- package/dist/commands/upstream/update.js.map +1 -1
- package/dist/commands/verify/controllers.d.ts +0 -1
- package/dist/commands/verify/controllers.js +213 -59
- package/dist/commands/verify/controllers.js.map +1 -1
- package/dist/commands/verify/dependency-integrity.d.ts +18 -0
- package/dist/commands/verify/dependency-integrity.js +147 -0
- package/dist/commands/verify/dependency-integrity.js.map +1 -0
- package/dist/commands/verify/react-build.d.ts +0 -1
- package/dist/commands/verify/react-build.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/docs/contract-validator.d.ts +12 -0
- package/dist/lib/docs/contract-validator.js +38 -0
- package/dist/lib/docs/contract-validator.js.map +1 -0
- package/dist/lib/docs/contracts.d.ts +11 -0
- package/dist/lib/docs/contracts.js +241 -0
- package/dist/lib/docs/contracts.js.map +1 -0
- package/dist/lib/docs/discovery.d.ts +10 -0
- package/dist/lib/docs/discovery.js +91 -0
- package/dist/lib/docs/discovery.js.map +1 -0
- package/dist/lib/docs/generator.d.ts +14 -0
- package/dist/lib/docs/generator.js +450 -0
- package/dist/lib/docs/generator.js.map +1 -0
- package/dist/lib/docs/source-extractor.d.ts +2 -0
- package/dist/lib/docs/source-extractor.js +209 -0
- package/dist/lib/docs/source-extractor.js.map +1 -0
- package/dist/lib/docs/types.d.ts +77 -0
- package/dist/lib/docs/types.js +2 -0
- package/dist/lib/docs/types.js.map +1 -0
- package/dist/lib/upstream/repo-utils.d.ts +0 -1
- package/dist/lib/upstream/repo-utils.js.map +1 -1
- package/dist/lib/upstream/sync-compatibility.d.ts +0 -1
- package/dist/lib/upstream/sync-compatibility.js.map +1 -1
- package/dist/lib/upstream/sync-constants.d.ts +35 -7
- package/dist/lib/upstream/sync-constants.js +40 -11
- package/dist/lib/upstream/sync-constants.js.map +1 -1
- package/dist/lib/upstream/sync-controllers-strategy.d.ts +0 -1
- package/dist/lib/upstream/sync-controllers-strategy.js +14 -4
- package/dist/lib/upstream/sync-controllers-strategy.js.map +1 -1
- package/dist/lib/upstream/sync-demo-metadata.d.ts +0 -1
- package/dist/lib/upstream/sync-demo-metadata.js +1 -1
- package/dist/lib/upstream/sync-demo-metadata.js.map +1 -1
- package/dist/lib/upstream/sync-entry-discovery.d.ts +3 -0
- package/dist/lib/upstream/sync-entry-discovery.js +23 -0
- package/dist/lib/upstream/sync-entry-discovery.js.map +1 -0
- package/dist/lib/upstream/sync-externals.d.ts +7 -7
- package/dist/lib/upstream/sync-externals.js +51 -35
- package/dist/lib/upstream/sync-externals.js.map +1 -1
- package/dist/lib/upstream/sync-filesystem.d.ts +0 -1
- package/dist/lib/upstream/sync-filesystem.js.map +1 -1
- package/dist/lib/upstream/sync-imports.d.ts +82 -62
- package/dist/lib/upstream/sync-imports.js +658 -185
- package/dist/lib/upstream/sync-imports.js.map +1 -1
- package/dist/lib/upstream/sync-package-json.d.ts +0 -1
- package/dist/lib/upstream/sync-package-json.js +7 -0
- package/dist/lib/upstream/sync-package-json.js.map +1 -1
- package/dist/lib/upstream/sync-package-manager.d.ts +14 -4
- package/dist/lib/upstream/sync-package-manager.js +405 -72
- package/dist/lib/upstream/sync-package-manager.js.map +1 -1
- package/dist/lib/upstream/sync-pielib-strategy.d.ts +2 -1
- package/dist/lib/upstream/sync-pielib-strategy.js +228 -110
- package/dist/lib/upstream/sync-pielib-strategy.js.map +1 -1
- package/dist/lib/upstream/sync-presets.d.ts +52 -0
- package/dist/lib/upstream/sync-presets.js +175 -0
- package/dist/lib/upstream/sync-presets.js.map +1 -0
- package/dist/lib/upstream/sync-react-strategy.d.ts +6 -1
- package/dist/lib/upstream/sync-react-strategy.js +342 -134
- package/dist/lib/upstream/sync-react-strategy.js.map +1 -1
- package/dist/lib/upstream/sync-source-edit.d.ts +14 -0
- package/dist/lib/upstream/sync-source-edit.js +89 -0
- package/dist/lib/upstream/sync-source-edit.js.map +1 -0
- package/dist/lib/upstream/sync-source-tree.d.ts +22 -0
- package/dist/lib/upstream/sync-source-tree.js +99 -0
- package/dist/lib/upstream/sync-source-tree.js.map +1 -0
- package/dist/lib/upstream/sync-strategy.d.ts +1 -1
- package/dist/lib/upstream/sync-strategy.js.map +1 -1
- package/dist/lib/upstream/sync-summary.d.ts +0 -1
- package/dist/lib/upstream/sync-summary.js.map +1 -1
- package/dist/lib/upstream/sync-transforms.d.ts +13 -11
- package/dist/lib/upstream/sync-transforms.js +23 -17
- package/dist/lib/upstream/sync-transforms.js.map +1 -1
- package/dist/lib/upstream/sync-vite-config.d.ts +13 -1
- package/dist/lib/upstream/sync-vite-config.js +65 -46
- package/dist/lib/upstream/sync-vite-config.js.map +1 -1
- package/dist/utils/compatibility.d.ts +13 -1
- package/dist/utils/compatibility.js +143 -2
- package/dist/utils/compatibility.js.map +1 -1
- package/dist/utils/conversion.d.ts +0 -1
- package/dist/utils/conversion.js.map +1 -1
- package/dist/utils/dependency-integrity.d.ts +37 -0
- package/dist/utils/dependency-integrity.js +557 -0
- package/dist/utils/dependency-integrity.js.map +1 -0
- package/dist/utils/git.d.ts +0 -1
- package/dist/utils/git.js.map +1 -1
- package/dist/utils/logger.d.ts +0 -1
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/package-json.d.ts +0 -1
- package/dist/utils/package-json.js.map +1 -1
- package/package.json +25 -8
- package/.compatibility/report.json +0 -2491
- package/.turbo/turbo-build.log +0 -1
- package/CHANGELOG.md +0 -8
- package/REFACTORING.md +0 -131
- package/bin/dev.js +0 -5
- package/dist/commands/dev/demo/index.d.ts.map +0 -1
- package/dist/commands/dev/test-bundler.d.ts.map +0 -1
- package/dist/commands/mathquill/migrate.d.ts +0 -20
- package/dist/commands/mathquill/migrate.d.ts.map +0 -1
- package/dist/commands/mathquill/migrate.js +0 -240
- package/dist/commands/mathquill/migrate.js.map +0 -1
- package/dist/commands/mathquill/status.d.ts +0 -20
- package/dist/commands/mathquill/status.d.ts.map +0 -1
- package/dist/commands/mathquill/status.js +0 -231
- package/dist/commands/mathquill/status.js.map +0 -1
- package/dist/commands/packages/create-controllers.d.ts.map +0 -1
- package/dist/commands/packages/create-lib-react.d.ts.map +0 -1
- package/dist/commands/packages/create-react-elements.d.ts.map +0 -1
- package/dist/commands/packages/enable-publishing.d.ts.map +0 -1
- package/dist/commands/packages/init-synced-elements.d.ts.map +0 -1
- package/dist/commands/upstream/analyze-esm.d.ts.map +0 -1
- package/dist/commands/upstream/check.d.ts.map +0 -1
- package/dist/commands/upstream/deps.d.ts.map +0 -1
- package/dist/commands/upstream/sync-mathquill.d.ts +0 -12
- package/dist/commands/upstream/sync-mathquill.d.ts.map +0 -1
- package/dist/commands/upstream/sync-mathquill.js +0 -97
- package/dist/commands/upstream/sync-mathquill.js.map +0 -1
- package/dist/commands/upstream/sync.d.ts.map +0 -1
- package/dist/commands/upstream/track.d.ts.map +0 -1
- package/dist/commands/upstream/update.d.ts.map +0 -1
- package/dist/commands/verify/controllers.d.ts.map +0 -1
- package/dist/commands/verify/react-build.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/lib/mathquill/extension-generator.d.ts +0 -9
- package/dist/lib/mathquill/extension-generator.d.ts.map +0 -1
- package/dist/lib/mathquill/extension-generator.js +0 -107
- package/dist/lib/mathquill/extension-generator.js.map +0 -1
- package/dist/lib/mathquill/khan-extractor.d.ts +0 -16
- package/dist/lib/mathquill/khan-extractor.d.ts.map +0 -1
- package/dist/lib/mathquill/khan-extractor.js +0 -148
- package/dist/lib/mathquill/khan-extractor.js.map +0 -1
- package/dist/lib/mathquill/learnosity-extractor.d.ts +0 -15
- package/dist/lib/mathquill/learnosity-extractor.d.ts.map +0 -1
- package/dist/lib/mathquill/learnosity-extractor.js +0 -170
- package/dist/lib/mathquill/learnosity-extractor.js.map +0 -1
- package/dist/lib/mathquill/migration-orchestrator.d.ts +0 -77
- package/dist/lib/mathquill/migration-orchestrator.d.ts.map +0 -1
- package/dist/lib/mathquill/migration-orchestrator.js +0 -391
- package/dist/lib/mathquill/migration-orchestrator.js.map +0 -1
- package/dist/lib/mathquill/package-updater.d.ts +0 -9
- package/dist/lib/mathquill/package-updater.d.ts.map +0 -1
- package/dist/lib/mathquill/package-updater.js +0 -103
- package/dist/lib/mathquill/package-updater.js.map +0 -1
- package/dist/lib/mathquill/pie-extractor.d.ts +0 -14
- package/dist/lib/mathquill/pie-extractor.d.ts.map +0 -1
- package/dist/lib/mathquill/pie-extractor.js +0 -167
- package/dist/lib/mathquill/pie-extractor.js.map +0 -1
- package/dist/lib/upstream/repo-utils.d.ts.map +0 -1
- package/dist/lib/upstream/sync-compatibility.d.ts.map +0 -1
- package/dist/lib/upstream/sync-constants.d.ts.map +0 -1
- package/dist/lib/upstream/sync-controllers-strategy.d.ts.map +0 -1
- package/dist/lib/upstream/sync-demo-metadata.d.ts.map +0 -1
- package/dist/lib/upstream/sync-dev-exports.d.ts +0 -13
- package/dist/lib/upstream/sync-dev-exports.d.ts.map +0 -1
- package/dist/lib/upstream/sync-dev-exports.js +0 -115
- package/dist/lib/upstream/sync-dev-exports.js.map +0 -1
- package/dist/lib/upstream/sync-externals.d.ts.map +0 -1
- package/dist/lib/upstream/sync-filesystem.d.ts.map +0 -1
- package/dist/lib/upstream/sync-imports.d.ts.map +0 -1
- package/dist/lib/upstream/sync-mathquill.d.ts +0 -19
- package/dist/lib/upstream/sync-mathquill.d.ts.map +0 -1
- package/dist/lib/upstream/sync-mathquill.js +0 -160
- package/dist/lib/upstream/sync-mathquill.js.map +0 -1
- package/dist/lib/upstream/sync-package-json.d.ts.map +0 -1
- package/dist/lib/upstream/sync-package-manager.d.ts.map +0 -1
- package/dist/lib/upstream/sync-pielib-strategy.d.ts.map +0 -1
- package/dist/lib/upstream/sync-react-strategy.d.ts.map +0 -1
- package/dist/lib/upstream/sync-strategy.d.ts.map +0 -1
- package/dist/lib/upstream/sync-summary.d.ts.map +0 -1
- package/dist/lib/upstream/sync-transforms.d.ts.map +0 -1
- package/dist/lib/upstream/sync-vite-config.d.ts.map +0 -1
- package/dist/utils/compatibility.d.ts.map +0 -1
- package/dist/utils/conversion.d.ts.map +0 -1
- package/dist/utils/git.d.ts.map +0 -1
- package/dist/utils/logger.d.ts.map +0 -1
- package/dist/utils/package-json.d.ts.map +0 -1
- package/packages/cli/bin/dev.js +0 -5
- package/packages/cli/bin/run.js +0 -5
- package/src/commands/dev/demo/index.ts +0 -313
- package/src/commands/dev/test-bundler.ts +0 -345
- package/src/commands/mathquill/migrate.ts +0 -269
- package/src/commands/mathquill/status.ts +0 -267
- package/src/commands/packages/create-controllers.ts +0 -127
- package/src/commands/packages/create-lib-react.ts +0 -279
- package/src/commands/packages/create-react-elements.ts +0 -306
- package/src/commands/packages/enable-publishing.ts +0 -161
- package/src/commands/packages/init-synced-elements.ts +0 -259
- package/src/commands/upstream/README.md +0 -444
- package/src/commands/upstream/analyze-esm.ts +0 -1973
- package/src/commands/upstream/check.ts +0 -228
- package/src/commands/upstream/deps.ts +0 -222
- package/src/commands/upstream/sync-mathquill.ts +0 -108
- package/src/commands/upstream/sync.ts +0 -687
- package/src/commands/upstream/track.ts +0 -145
- package/src/commands/upstream/update.ts +0 -110
- package/src/commands/verify/controllers.ts +0 -166
- package/src/commands/verify/react-build.ts +0 -171
- package/src/index.ts +0 -1
- package/src/lib/mathquill/extension-generator.ts +0 -111
- package/src/lib/mathquill/khan-extractor.ts +0 -175
- package/src/lib/mathquill/learnosity-extractor.ts +0 -198
- package/src/lib/mathquill/migration-orchestrator.ts +0 -513
- package/src/lib/mathquill/package-updater.ts +0 -120
- package/src/lib/mathquill/pie-extractor.ts +0 -194
- package/src/lib/upstream/repo-utils.ts +0 -18
- package/src/lib/upstream/sync-compatibility.ts +0 -89
- package/src/lib/upstream/sync-constants.ts +0 -77
- package/src/lib/upstream/sync-controllers-strategy.ts +0 -291
- package/src/lib/upstream/sync-demo-metadata.ts +0 -199
- package/src/lib/upstream/sync-dev-exports.ts +0 -151
- package/src/lib/upstream/sync-externals.ts +0 -159
- package/src/lib/upstream/sync-filesystem.ts +0 -87
- package/src/lib/upstream/sync-imports.ts +0 -992
- package/src/lib/upstream/sync-mathquill.ts +0 -194
- package/src/lib/upstream/sync-package-json.ts +0 -86
- package/src/lib/upstream/sync-package-manager.ts +0 -694
- package/src/lib/upstream/sync-pielib-strategy.ts +0 -441
- package/src/lib/upstream/sync-react-strategy.ts +0 -945
- package/src/lib/upstream/sync-strategy.ts +0 -61
- package/src/lib/upstream/sync-summary.ts +0 -194
- package/src/lib/upstream/sync-transforms.ts +0 -154
- package/src/lib/upstream/sync-vite-config.ts +0 -243
- package/src/types/es-module-lexer.d.ts +0 -4
- package/src/utils/compatibility.ts +0 -182
- package/src/utils/conversion.ts +0 -153
- package/src/utils/git.ts +0 -63
- package/src/utils/logger.ts +0 -69
- package/src/utils/package-json.ts +0 -43
- package/tests/sync-package-manager.test.ts +0 -112
- package/tests/transform-assign-props.test.ts +0 -101
- package/tsconfig.json +0 -15
|
@@ -32,7 +32,21 @@
|
|
|
32
32
|
* - Student-facing UI only needs minimal fallback configuration
|
|
33
33
|
* - Inline empty defaults object to avoid the dependency
|
|
34
34
|
*/
|
|
35
|
+
import { existsSync } from 'node:fs';
|
|
35
36
|
import { readFile, writeFile } from 'node:fs/promises';
|
|
37
|
+
import { dirname, join } from 'node:path';
|
|
38
|
+
import ts from 'typescript';
|
|
39
|
+
import { PRESET_IDS, shouldTransformConfigUiMathjsSource, shouldTransformReactInputAutosizeSource, } from './sync-presets.js';
|
|
40
|
+
import { applySourceEdits, rewriteModuleSpecifiers } from './sync-source-edit.js';
|
|
41
|
+
const SOURCE_PATH_PRESET_RULES = {
|
|
42
|
+
[PRESET_IDS.transformTextSelectTokenTypesReexport]: (sourcePath) => sourcePath.includes('text-select') && sourcePath.includes('token-select/index'),
|
|
43
|
+
[PRESET_IDS.transformChartingUtilsTypeFix]: (sourcePath) => sourcePath.includes('charting') && sourcePath.includes('utils'),
|
|
44
|
+
[PRESET_IDS.transformTranslatorIndexTypeFix]: (sourcePath) => sourcePath.includes('translator') && sourcePath.includes('/src/index'),
|
|
45
|
+
[PRESET_IDS.transformRenderUiInlineMenuExport]: (sourcePath) => sourcePath.includes('render-ui/src/index.js'),
|
|
46
|
+
};
|
|
47
|
+
function sourcePathMatchesPreset(sourcePath, presetId) {
|
|
48
|
+
return !!sourcePath && SOURCE_PATH_PRESET_RULES[presetId](sourcePath);
|
|
49
|
+
}
|
|
36
50
|
/**
|
|
37
51
|
* Fix import statements in a file to handle default export conversions
|
|
38
52
|
*
|
|
@@ -62,6 +76,67 @@ export async function fixImportsInFile(filePath, defaultExportFiles) {
|
|
|
62
76
|
}
|
|
63
77
|
return modified;
|
|
64
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* Rewrite relative ESM specifiers to explicit `.js` extensions for NodeNext compatibility.
|
|
81
|
+
*
|
|
82
|
+
* This is applied after sync so TypeScript source uses runtime-valid ESM specifiers:
|
|
83
|
+
* - `./foo` -> `./foo.js`
|
|
84
|
+
* - `./bar` (directory with index file) -> `./bar/index.js`
|
|
85
|
+
*/
|
|
86
|
+
export async function rewriteRelativeSpecifiersForNodeEsm(filePath) {
|
|
87
|
+
let content = await readFile(filePath, 'utf-8');
|
|
88
|
+
let modified = false;
|
|
89
|
+
const rewriteSpecifier = (specifier) => {
|
|
90
|
+
if (!specifier.startsWith('./') && !specifier.startsWith('../')) {
|
|
91
|
+
return specifier;
|
|
92
|
+
}
|
|
93
|
+
// Keep explicit extensions as-is (css/json/svg/js/etc.).
|
|
94
|
+
if (/\.[a-z0-9]+$/i.test(specifier)) {
|
|
95
|
+
return specifier;
|
|
96
|
+
}
|
|
97
|
+
const basePath = join(dirname(filePath), specifier);
|
|
98
|
+
const moduleFileExtensions = ['.ts', '.tsx', '.mts', '.cts', '.js', '.jsx', '.mjs', '.cjs'];
|
|
99
|
+
const indexFileExtensions = moduleFileExtensions.map((ext) => `/index${ext}`);
|
|
100
|
+
const hasModuleFile = moduleFileExtensions.some((ext) => existsSync(`${basePath}${ext}`));
|
|
101
|
+
if (hasModuleFile) {
|
|
102
|
+
return `${specifier}.js`;
|
|
103
|
+
}
|
|
104
|
+
const hasIndexFile = indexFileExtensions.some((suffix) => existsSync(`${basePath}${suffix}`));
|
|
105
|
+
if (hasIndexFile) {
|
|
106
|
+
return `${specifier.replace(/\/$/, '')}/index.js`;
|
|
107
|
+
}
|
|
108
|
+
// Do not guess unresolved paths.
|
|
109
|
+
return specifier;
|
|
110
|
+
};
|
|
111
|
+
content = content.replace(/(from\s+)(['"])(\.\.?\/[^'"]+)\2/g, (match, prefix, quote, specifier) => {
|
|
112
|
+
const rewritten = rewriteSpecifier(specifier);
|
|
113
|
+
if (rewritten !== specifier) {
|
|
114
|
+
modified = true;
|
|
115
|
+
return `${prefix}${quote}${rewritten}${quote}`;
|
|
116
|
+
}
|
|
117
|
+
return match;
|
|
118
|
+
});
|
|
119
|
+
content = content.replace(/(import\(\s*)(['"])(\.\.?\/[^'"]+)\2(\s*\))/g, (match, start, quote, specifier, end) => {
|
|
120
|
+
const rewritten = rewriteSpecifier(specifier);
|
|
121
|
+
if (rewritten !== specifier) {
|
|
122
|
+
modified = true;
|
|
123
|
+
return `${start}${quote}${rewritten}${quote}${end}`;
|
|
124
|
+
}
|
|
125
|
+
return match;
|
|
126
|
+
});
|
|
127
|
+
content = content.replace(/\bimport\s+(['"])(\.\.?\/[^'"]+)\1/g, (match, quote, specifier) => {
|
|
128
|
+
const rewritten = rewriteSpecifier(specifier);
|
|
129
|
+
if (rewritten !== specifier) {
|
|
130
|
+
modified = true;
|
|
131
|
+
return `import ${quote}${rewritten}${quote}`;
|
|
132
|
+
}
|
|
133
|
+
return match;
|
|
134
|
+
});
|
|
135
|
+
if (modified) {
|
|
136
|
+
await writeFile(filePath, content, 'utf-8');
|
|
137
|
+
}
|
|
138
|
+
return modified;
|
|
139
|
+
}
|
|
65
140
|
/**
|
|
66
141
|
* Check if code contains JSX syntax
|
|
67
142
|
*/
|
|
@@ -97,7 +172,7 @@ const ${importName} = {
|
|
|
97
172
|
*/
|
|
98
173
|
export function reexportTokenTypes(code, filePath) {
|
|
99
174
|
// Only apply to text-select token-select/index file
|
|
100
|
-
if (!filePath
|
|
175
|
+
if (!sourcePathMatchesPreset(filePath, PRESET_IDS.transformTextSelectTokenTypesReexport)) {
|
|
101
176
|
return code;
|
|
102
177
|
}
|
|
103
178
|
// Check if file imports TokenTypes from ./token
|
|
@@ -202,47 +277,273 @@ export function convertModuleExportsToEsm(content) {
|
|
|
202
277
|
const esmExports = exports.join('\n\n');
|
|
203
278
|
return content.replace(fullMatch, esmExports);
|
|
204
279
|
}
|
|
280
|
+
const VENDORED_LODASH_PACKAGE = '@pie-element/shared-lodash';
|
|
281
|
+
function lodashMemberFromPath(path) {
|
|
282
|
+
return path.replace(/\.js$/i, '').split('/').pop() ?? path;
|
|
283
|
+
}
|
|
205
284
|
/**
|
|
206
|
-
* Transform lodash
|
|
285
|
+
* Transform lodash and lodash-es imports to the vendored shared lodash package.
|
|
207
286
|
*
|
|
208
|
-
*
|
|
209
|
-
*
|
|
210
|
-
*
|
|
211
|
-
|
|
212
|
-
|
|
287
|
+
* The vendored package is intentionally a narrow ESM implementation of the
|
|
288
|
+
* lodash helpers used by synced PIE sources, avoiding CDN/runtime lodash
|
|
289
|
+
* resolution while keeping import shapes tree-shakeable.
|
|
290
|
+
*/
|
|
291
|
+
export function transformLodashToVendoredLodash(content) {
|
|
292
|
+
const sourceFile = ts.createSourceFile('source.tsx', content, ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX);
|
|
293
|
+
const edits = [];
|
|
294
|
+
const dynamicDeepImportMembers = new Set();
|
|
295
|
+
const visit = (node) => {
|
|
296
|
+
if (ts.isImportDeclaration(node) && ts.isStringLiteral(node.moduleSpecifier)) {
|
|
297
|
+
const path = lodashDeepImportPath(node.moduleSpecifier.text);
|
|
298
|
+
if (path) {
|
|
299
|
+
const member = lodashMemberFromPath(path);
|
|
300
|
+
edits.push({
|
|
301
|
+
start: node.getStart(sourceFile),
|
|
302
|
+
end: node.getEnd(),
|
|
303
|
+
text: lodashImportReplacement(node, sourceFile, member),
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
else if (ts.isExportDeclaration(node) &&
|
|
308
|
+
node.moduleSpecifier &&
|
|
309
|
+
ts.isStringLiteral(node.moduleSpecifier)) {
|
|
310
|
+
const path = lodashDeepImportPath(node.moduleSpecifier.text);
|
|
311
|
+
if (path) {
|
|
312
|
+
const member = lodashMemberFromPath(path);
|
|
313
|
+
edits.push({
|
|
314
|
+
start: node.getStart(sourceFile),
|
|
315
|
+
end: node.getEnd(),
|
|
316
|
+
text: lodashExportReplacement(node, sourceFile, member),
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
else if (isDynamicStringImport(node)) {
|
|
321
|
+
const path = lodashDeepImportPath(node.arguments[0].text);
|
|
322
|
+
if (path) {
|
|
323
|
+
const member = lodashMemberFromPath(path);
|
|
324
|
+
dynamicDeepImportMembers.add(member);
|
|
325
|
+
edits.push({
|
|
326
|
+
start: node.getStart(sourceFile),
|
|
327
|
+
end: node.getEnd(),
|
|
328
|
+
text: `Promise.resolve({ default: ${member}, ${member} })`,
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
ts.forEachChild(node, visit);
|
|
333
|
+
};
|
|
334
|
+
visit(sourceFile);
|
|
335
|
+
let transformed = applySourceEdits(content, edits);
|
|
336
|
+
// Root imports keep their local import shape.
|
|
337
|
+
transformed = rewriteModuleSpecifiers(transformed, (specifier) => specifier === 'lodash' || specifier === 'lodash-es' ? VENDORED_LODASH_PACKAGE : undefined);
|
|
338
|
+
if (dynamicDeepImportMembers.size > 0) {
|
|
339
|
+
const imports = [...dynamicDeepImportMembers].sort().join(', ');
|
|
340
|
+
transformed = `import { ${imports} } from '${VENDORED_LODASH_PACKAGE}';\n${transformed}`;
|
|
341
|
+
}
|
|
342
|
+
return transformed;
|
|
343
|
+
}
|
|
344
|
+
function lodashDeepImportPath(specifier) {
|
|
345
|
+
const match = specifier.match(/^(?:lodash|lodash-es)\/(.+)$/);
|
|
346
|
+
return match?.[1] ?? null;
|
|
347
|
+
}
|
|
348
|
+
function isDynamicStringImport(node) {
|
|
349
|
+
return (ts.isCallExpression(node) &&
|
|
350
|
+
node.expression.kind === ts.SyntaxKind.ImportKeyword &&
|
|
351
|
+
node.arguments.length === 1 &&
|
|
352
|
+
ts.isStringLiteral(node.arguments[0]));
|
|
353
|
+
}
|
|
354
|
+
function quoteLike(specifier, originalText) {
|
|
355
|
+
const delimiter = originalText.startsWith('"') ? '"' : "'";
|
|
356
|
+
const escaped = specifier.replace(/\\/g, '\\\\').replaceAll(delimiter, `\\${delimiter}`);
|
|
357
|
+
return `${delimiter}${escaped}${delimiter}`;
|
|
358
|
+
}
|
|
359
|
+
function lodashImportReplacement(node, sourceFile, member) {
|
|
360
|
+
const packageSpecifier = quoteLike(VENDORED_LODASH_PACKAGE, node.moduleSpecifier.getText(sourceFile));
|
|
361
|
+
const importClause = node.importClause;
|
|
362
|
+
if (!importClause) {
|
|
363
|
+
return `import ${packageSpecifier};`;
|
|
364
|
+
}
|
|
365
|
+
if (importClause.name) {
|
|
366
|
+
return `import { ${formatLodashBinding(member, importClause.name.text)} } from ${packageSpecifier};`;
|
|
367
|
+
}
|
|
368
|
+
const namedBindings = importClause.namedBindings;
|
|
369
|
+
if (namedBindings && ts.isNamespaceImport(namedBindings)) {
|
|
370
|
+
return `import { ${formatLodashBinding(member, namedBindings.name.text)} } from ${packageSpecifier};`;
|
|
371
|
+
}
|
|
372
|
+
if (namedBindings && ts.isNamedImports(namedBindings)) {
|
|
373
|
+
const bindings = namedBindings.elements
|
|
374
|
+
.map((specifier) => lodashImportSpecifierBinding(member, specifier))
|
|
375
|
+
.join(', ');
|
|
376
|
+
const typeOnly = importClause.isTypeOnly ? 'type ' : '';
|
|
377
|
+
return `import ${typeOnly}{ ${bindings} } from ${packageSpecifier};`;
|
|
378
|
+
}
|
|
379
|
+
return `import ${packageSpecifier};`;
|
|
380
|
+
}
|
|
381
|
+
function lodashExportReplacement(node, sourceFile, member) {
|
|
382
|
+
const packageSpecifier = quoteLike(VENDORED_LODASH_PACKAGE, node.moduleSpecifier?.getText(sourceFile) ?? `'${VENDORED_LODASH_PACKAGE}'`);
|
|
383
|
+
const exportClause = node.exportClause;
|
|
384
|
+
if (!exportClause) {
|
|
385
|
+
return `export { ${member} } from ${packageSpecifier};`;
|
|
386
|
+
}
|
|
387
|
+
if (ts.isNamespaceExport(exportClause)) {
|
|
388
|
+
return `export { ${formatLodashBinding(member, exportClause.name.text)} } from ${packageSpecifier};`;
|
|
389
|
+
}
|
|
390
|
+
const bindings = exportClause.elements
|
|
391
|
+
.map((specifier) => lodashExportSpecifierBinding(member, specifier))
|
|
392
|
+
.join(', ');
|
|
393
|
+
const typeOnly = node.isTypeOnly ? 'type ' : '';
|
|
394
|
+
return `export ${typeOnly}{ ${bindings} } from ${packageSpecifier};`;
|
|
395
|
+
}
|
|
396
|
+
function lodashImportSpecifierBinding(member, specifier) {
|
|
397
|
+
const imported = specifier.propertyName?.text ?? specifier.name.text;
|
|
398
|
+
const local = specifier.name.text;
|
|
399
|
+
if (imported === 'default') {
|
|
400
|
+
return formatLodashBinding(member, local);
|
|
401
|
+
}
|
|
402
|
+
return imported === local ? imported : `${imported} as ${local}`;
|
|
403
|
+
}
|
|
404
|
+
function lodashExportSpecifierBinding(member, specifier) {
|
|
405
|
+
const exported = specifier.name.text;
|
|
406
|
+
const local = specifier.propertyName?.text ?? exported;
|
|
407
|
+
if (local === 'default') {
|
|
408
|
+
return formatLodashBinding(member, exported);
|
|
409
|
+
}
|
|
410
|
+
return local === exported ? exported : `${local} as ${exported}`;
|
|
411
|
+
}
|
|
412
|
+
function formatLodashBinding(imported, local) {
|
|
413
|
+
return imported === local ? imported : `${imported} as ${local}`;
|
|
414
|
+
}
|
|
415
|
+
export const transformLodashToLodashEs = transformLodashToVendoredLodash;
|
|
416
|
+
/**
|
|
417
|
+
* Transform classnames imports to clsx.
|
|
213
418
|
*
|
|
214
|
-
*
|
|
419
|
+
* clsx preserves the call shape used by classnames while offering a browser ESM
|
|
420
|
+
* entrypoint, so synced source should prefer it over the CommonJS-era package.
|
|
215
421
|
*/
|
|
216
|
-
export function
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
422
|
+
export function transformClassnamesToClsx(content) {
|
|
423
|
+
return rewriteModuleSpecifiers(content, (specifier) => specifier === 'classnames' ? 'clsx' : undefined);
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* Replace react-input-autosize with the local ESM autosize input component.
|
|
427
|
+
*
|
|
428
|
+
* The upstream dependency is CommonJS-era and only used by graph label inputs.
|
|
429
|
+
* Synced packages generate a tiny local component instead of carrying the
|
|
430
|
+
* dependency into browser ESM output.
|
|
431
|
+
*/
|
|
432
|
+
export function transformReactInputAutosizeToLocal(content, sourcePath) {
|
|
433
|
+
if (!shouldTransformReactInputAutosizeSource(sourcePath)) {
|
|
434
|
+
return content;
|
|
435
|
+
}
|
|
436
|
+
const sourceFile = ts.createSourceFile('source.tsx', content, ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX);
|
|
437
|
+
const edits = [];
|
|
438
|
+
const visit = (node) => {
|
|
439
|
+
if (ts.isImportDeclaration(node) &&
|
|
440
|
+
ts.isStringLiteral(node.moduleSpecifier) &&
|
|
441
|
+
node.moduleSpecifier.text === 'react-input-autosize') {
|
|
442
|
+
const importName = node.importClause?.name?.text;
|
|
443
|
+
if (importName) {
|
|
444
|
+
edits.push({
|
|
445
|
+
start: node.getStart(sourceFile),
|
|
446
|
+
end: node.getEnd(),
|
|
447
|
+
text: importName === 'AutosizeInput'
|
|
448
|
+
? "import { AutosizeInput } from './autosize-input.js';"
|
|
449
|
+
: `import { AutosizeInput as ${importName} } from './autosize-input.js';`,
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
else if (isAutosizeInputComponentAdapter(node, sourceFile)) {
|
|
454
|
+
edits.push({
|
|
455
|
+
start: node.getStart(sourceFile),
|
|
456
|
+
end: node.getEnd(),
|
|
457
|
+
text: '',
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
else if (isAutosizeInputComponentJsxTag(node)) {
|
|
461
|
+
edits.push({
|
|
462
|
+
start: node.tagName.getStart(sourceFile),
|
|
463
|
+
end: node.tagName.getEnd(),
|
|
464
|
+
text: 'AutosizeInput',
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
ts.forEachChild(node, visit);
|
|
468
|
+
};
|
|
469
|
+
visit(sourceFile);
|
|
470
|
+
return applySourceEdits(content, edits);
|
|
471
|
+
}
|
|
472
|
+
function isAutosizeInputComponentAdapter(node, sourceFile) {
|
|
473
|
+
if (!ts.isVariableStatement(node) || node.declarationList.declarations.length !== 1) {
|
|
474
|
+
return false;
|
|
475
|
+
}
|
|
476
|
+
const declaration = node.declarationList.declarations[0];
|
|
477
|
+
if (!ts.isIdentifier(declaration.name) || declaration.name.text !== 'AutosizeInputComponent') {
|
|
478
|
+
return false;
|
|
479
|
+
}
|
|
480
|
+
return (declaration.initializer?.getText(sourceFile).replace(/\s+/g, '') ===
|
|
481
|
+
'AutosizeInput?.default??AutosizeInput');
|
|
482
|
+
}
|
|
483
|
+
function isAutosizeInputComponentJsxTag(node) {
|
|
484
|
+
return ((ts.isJsxOpeningElement(node) ||
|
|
485
|
+
ts.isJsxClosingElement(node) ||
|
|
486
|
+
ts.isJsxSelfClosingElement(node)) &&
|
|
487
|
+
ts.isIdentifier(node.tagName) &&
|
|
488
|
+
node.tagName.text === 'AutosizeInputComponent');
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* Replace config-ui's tiny mathjs usage with a local fraction-to-number helper.
|
|
492
|
+
*
|
|
493
|
+
* number-text-field-custom only uses `math.number(math.fraction(value))` to
|
|
494
|
+
* compare custom fraction values. Keep mathjs for number-line where the surface
|
|
495
|
+
* includes exact rational arithmetic, comparisons, snapping, and expression
|
|
496
|
+
* parsing.
|
|
497
|
+
*/
|
|
498
|
+
export function transformConfigUiMathjsToLocalFraction(content, sourcePath) {
|
|
499
|
+
if (!shouldTransformConfigUiMathjsSource(sourcePath)) {
|
|
500
|
+
return content;
|
|
501
|
+
}
|
|
502
|
+
let transformed = content.replace(/math\.number\(\s*math\.fraction\(([^()]+?)\)\s*\)/g, 'fractionToNumber($1)');
|
|
503
|
+
if (transformed === content) {
|
|
504
|
+
return content;
|
|
505
|
+
}
|
|
506
|
+
if (!/\bmath\./.test(transformed)) {
|
|
507
|
+
transformed = transformed.replace(/import\s+\*\s+as\s+math\s+from\s+(['"])mathjs\1;?/, "import { fractionToNumber } from './fraction-to-number.js';");
|
|
508
|
+
}
|
|
509
|
+
else if (!transformed.includes("from './fraction-to-number.js'")) {
|
|
510
|
+
transformed = transformed.replace(/import\s+\*\s+as\s+math\s+from\s+(['"])mathjs\1;?/, (match) => `${match}\nimport { fractionToNumber } from './fraction-to-number.js';`);
|
|
511
|
+
}
|
|
227
512
|
return transformed;
|
|
228
513
|
}
|
|
229
514
|
/**
|
|
230
|
-
*
|
|
515
|
+
* Compatibility wrapper retained for older callers. Lodash imports now target
|
|
516
|
+
* the vendored shared package rather than lodash-es deep modules.
|
|
517
|
+
*/
|
|
518
|
+
export function transformLodashEsDeepImportsToFullySpecified(content) {
|
|
519
|
+
return transformLodashToVendoredLodash(content);
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* Ensure known strict-ESM deep imports include explicit file extensions.
|
|
523
|
+
*
|
|
524
|
+
* Webpack's fully-specified ESM resolution requires `.js` on deep imports like:
|
|
525
|
+
* - react-konva/lib/ReactKonvaCore -> react-konva/lib/ReactKonvaCore.js
|
|
526
|
+
*/
|
|
527
|
+
export function transformKnownDeepImportsToFullySpecified(content) {
|
|
528
|
+
return rewriteModuleSpecifiers(content, (specifier) => specifier === 'react-konva/lib/ReactKonvaCore' ? 'react-konva/lib/ReactKonvaCore.js' : undefined);
|
|
529
|
+
}
|
|
530
|
+
/**
|
|
531
|
+
* Transform package.json dependencies from lodash/lodash-es to the vendored package.
|
|
231
532
|
*
|
|
232
|
-
*
|
|
233
|
-
*
|
|
533
|
+
* The browser/runtime dependency is a workspace package that vendors the small
|
|
534
|
+
* lodash helper surface needed by synced sources.
|
|
234
535
|
*/
|
|
235
536
|
export function transformPackageJsonLodash(packageJson) {
|
|
236
537
|
const transformed = { ...packageJson };
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
transformed.dependencies['lodash-es'] = '^4.17.22';
|
|
538
|
+
if (transformed.dependencies?.lodash || transformed.dependencies?.['lodash-es']) {
|
|
539
|
+
transformed.dependencies[VENDORED_LODASH_PACKAGE] = 'workspace:*';
|
|
240
540
|
delete transformed.dependencies.lodash;
|
|
541
|
+
delete transformed.dependencies['lodash-es'];
|
|
241
542
|
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
transformed.devDependencies['lodash-es'] = '^4.17.22';
|
|
543
|
+
if (transformed.devDependencies?.lodash || transformed.devDependencies?.['lodash-es']) {
|
|
544
|
+
transformed.devDependencies[VENDORED_LODASH_PACKAGE] = 'workspace:*';
|
|
245
545
|
delete transformed.devDependencies.lodash;
|
|
546
|
+
delete transformed.devDependencies['lodash-es'];
|
|
246
547
|
}
|
|
247
548
|
// Remove @types/lodash if present (lodash-es has built-in types)
|
|
248
549
|
if (transformed.dependencies?.['@types/lodash']) {
|
|
@@ -261,14 +562,74 @@ export function transformPackageJsonLodash(packageJson) {
|
|
|
261
562
|
*/
|
|
262
563
|
export function transformPackageJsonRecharts(packageJson) {
|
|
263
564
|
const transformed = { ...packageJson };
|
|
264
|
-
//
|
|
565
|
+
// Keep recharts on the current ESM-capable major.
|
|
265
566
|
if (transformed.dependencies?.recharts) {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
567
|
+
transformed.dependencies.recharts = '^3.8.1';
|
|
568
|
+
}
|
|
569
|
+
return transformed;
|
|
570
|
+
}
|
|
571
|
+
/**
|
|
572
|
+
* Apply browser-ESM dependency replacements and upgrades for synced packages.
|
|
573
|
+
*
|
|
574
|
+
* This is intentionally dependency policy, not build-output patching: upstream
|
|
575
|
+
* sync rewrites package manifests toward packages that can participate in the
|
|
576
|
+
* browser ESM graph directly.
|
|
577
|
+
*/
|
|
578
|
+
export function transformPackageJsonBrowserEsmDependencies(packageJson, options = {}) {
|
|
579
|
+
const transformed = { ...packageJson };
|
|
580
|
+
const deps = transformed.dependencies;
|
|
581
|
+
if (!deps) {
|
|
582
|
+
return transformed;
|
|
583
|
+
}
|
|
584
|
+
if (deps.classnames) {
|
|
585
|
+
deps.clsx = '^2.1.1';
|
|
586
|
+
delete deps.classnames;
|
|
587
|
+
}
|
|
588
|
+
if (options.removeReactInputAutosize) {
|
|
589
|
+
delete deps['react-input-autosize'];
|
|
590
|
+
}
|
|
591
|
+
if (options.removeMathjs) {
|
|
592
|
+
delete deps.mathjs;
|
|
593
|
+
}
|
|
594
|
+
// Ranges forced onto synced packages after the copy.
|
|
595
|
+
//
|
|
596
|
+
// Only pin a dependency here when this repo has a reason upstream does not
|
|
597
|
+
// share, and state that reason. A pin silently overrides whatever upstream
|
|
598
|
+
// declares, so a pin that has outlived its reason quietly undoes upstream's
|
|
599
|
+
// decisions on every sync.
|
|
600
|
+
//
|
|
601
|
+
// mathjs is pinned to satisfy two constraints that pull in opposite
|
|
602
|
+
// directions:
|
|
603
|
+
// - This repo needs an `exports` map. mathjs 7.x (upstream's range) has
|
|
604
|
+
// none, so it resolves to its CJS `main` and reintroduces the runtime
|
|
605
|
+
// require leaks that "fix: stabilize browser ESM packaging" (481671b0)
|
|
606
|
+
// removed from the browser ESM bundles.
|
|
607
|
+
// - Upstream needs fraction.js 4. mathjs >= 14 depends on fraction.js ^5,
|
|
608
|
+
// which uses BigInt and breaks number-line bundling (PIE-926, PIE-1005).
|
|
609
|
+
// mathjs 13.2.3 is the newest release that has an `exports` map AND still
|
|
610
|
+
// depends on fraction.js ^4.3.7, so it satisfies both. Do not raise this to
|
|
611
|
+
// 14+ without resolving the BigInt problem first.
|
|
612
|
+
//
|
|
613
|
+
// react-draggable is deliberately NOT pinned: upstream moved the synced
|
|
614
|
+
// packages to ^4.7.1 and fixed the v4 drag regressions against that exact
|
|
615
|
+
// version, so a pin here would downgrade away from the code those fixes were
|
|
616
|
+
// written for.
|
|
617
|
+
const versionPins = {
|
|
618
|
+
'@types/react': '^18.2.0',
|
|
619
|
+
'@types/react-dom': '^18.2.0',
|
|
620
|
+
clsx: '^2.1.1',
|
|
621
|
+
mathjs: '^13.2.3',
|
|
622
|
+
'react-is': '^18.3.1',
|
|
623
|
+
'react-redux': '^9.3.0',
|
|
624
|
+
redux: '^5.0.1',
|
|
625
|
+
};
|
|
626
|
+
for (const [name, version] of Object.entries(versionPins)) {
|
|
627
|
+
if (deps[name]) {
|
|
628
|
+
deps[name] = version;
|
|
270
629
|
}
|
|
271
630
|
}
|
|
631
|
+
delete deps.react;
|
|
632
|
+
delete deps['react-dom'];
|
|
272
633
|
return transformed;
|
|
273
634
|
}
|
|
274
635
|
/**
|
|
@@ -279,12 +640,15 @@ export function transformPackageJsonRecharts(packageJson) {
|
|
|
279
640
|
* - @pie-framework/pie-configure-events → @pie-element/shared-configure-events
|
|
280
641
|
*/
|
|
281
642
|
export function transformPieFrameworkEventImports(content) {
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
643
|
+
return rewriteModuleSpecifiers(content, (specifier) => {
|
|
644
|
+
if (specifier === '@pie-framework/pie-player-events') {
|
|
645
|
+
return '@pie-element/shared-player-events';
|
|
646
|
+
}
|
|
647
|
+
if (specifier === '@pie-framework/pie-configure-events') {
|
|
648
|
+
return '@pie-element/shared-configure-events';
|
|
649
|
+
}
|
|
650
|
+
return undefined;
|
|
651
|
+
});
|
|
288
652
|
}
|
|
289
653
|
/**
|
|
290
654
|
* Transform @pie-lib/controller-utils imports to internal @pie-element/shared-controller-utils
|
|
@@ -296,7 +660,7 @@ export function transformPieFrameworkEventImports(content) {
|
|
|
296
660
|
* and no lodash/debug dependencies.
|
|
297
661
|
*/
|
|
298
662
|
export function transformControllerUtilsImports(content) {
|
|
299
|
-
return content
|
|
663
|
+
return rewriteModuleSpecifiers(content, (specifier) => specifier === '@pie-lib/controller-utils' ? '@pie-element/shared-controller-utils' : undefined);
|
|
300
664
|
}
|
|
301
665
|
/**
|
|
302
666
|
* Transform @pie-lib shared package imports to internal @pie-element/shared-* packages
|
|
@@ -307,24 +671,29 @@ export function transformControllerUtilsImports(content) {
|
|
|
307
671
|
* These packages have been moved to shared/ for better version control and consistency.
|
|
308
672
|
*/
|
|
309
673
|
export function transformSharedPackageImports(content) {
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
674
|
+
return rewriteModuleSpecifiers(content, (specifier) => {
|
|
675
|
+
if (specifier === '@pie-lib/math-rendering') {
|
|
676
|
+
return '@pie-element/shared-math-rendering-mathjax';
|
|
677
|
+
}
|
|
678
|
+
if (specifier === '@pie-lib/feedback') {
|
|
679
|
+
return '@pie-element/shared-feedback';
|
|
680
|
+
}
|
|
681
|
+
return undefined;
|
|
682
|
+
});
|
|
316
683
|
}
|
|
317
684
|
/**
|
|
318
|
-
*
|
|
685
|
+
* Rewrite legacy configure subpath imports to author entrypoints.
|
|
319
686
|
*
|
|
320
|
-
*
|
|
321
|
-
* - @pie-
|
|
687
|
+
* Upstream sometimes imports configure elements via:
|
|
688
|
+
* - @pie-element/<element-name>/configure/lib
|
|
322
689
|
*
|
|
323
|
-
*
|
|
324
|
-
*
|
|
690
|
+
* In this repo, configure code is synced into `src/author` and packages expose that via
|
|
691
|
+
* the `./author` export. Rewriting to `/author` preserves author-vs-delivery boundaries.
|
|
325
692
|
*/
|
|
326
|
-
export function
|
|
327
|
-
return content
|
|
693
|
+
export function transformLegacyConfigureLibImports(content) {
|
|
694
|
+
return rewriteModuleSpecifiers(content, (specifier) => /^@pie-element\/[^/]+\/configure\/lib$/.test(specifier)
|
|
695
|
+
? specifier.replace(/\/configure\/lib$/, '/author')
|
|
696
|
+
: undefined);
|
|
328
697
|
}
|
|
329
698
|
/**
|
|
330
699
|
* Transform package.json dependencies for PIE Framework event packages
|
|
@@ -396,24 +765,6 @@ export function transformPackageJsonSharedPackages(packageJson) {
|
|
|
396
765
|
}
|
|
397
766
|
return transformed;
|
|
398
767
|
}
|
|
399
|
-
/**
|
|
400
|
-
* Transform package.json dependencies for @pie-framework/mathquill
|
|
401
|
-
*
|
|
402
|
-
* Replaces @pie-framework/mathquill with internal @pie-element/shared-mathquill
|
|
403
|
-
*/
|
|
404
|
-
export function transformPackageJsonMathquill(packageJson) {
|
|
405
|
-
const transformed = { ...packageJson };
|
|
406
|
-
// Replace @pie-framework/mathquill with internal package
|
|
407
|
-
if (transformed.dependencies?.['@pie-framework/mathquill']) {
|
|
408
|
-
transformed.dependencies['@pie-element/shared-mathquill'] = 'workspace:*';
|
|
409
|
-
delete transformed.dependencies['@pie-framework/mathquill'];
|
|
410
|
-
}
|
|
411
|
-
if (transformed.devDependencies?.['@pie-framework/mathquill']) {
|
|
412
|
-
transformed.devDependencies['@pie-element/shared-mathquill'] = 'workspace:*';
|
|
413
|
-
delete transformed.devDependencies['@pie-framework/mathquill'];
|
|
414
|
-
}
|
|
415
|
-
return transformed;
|
|
416
|
-
}
|
|
417
768
|
/**
|
|
418
769
|
* Transform direct property assignment patterns to use assignProps utility
|
|
419
770
|
*
|
|
@@ -502,50 +853,22 @@ export function transformConfigureUtilsImports(content, relativePath) {
|
|
|
502
853
|
if (!configureRootFilePattern.test(relativePath)) {
|
|
503
854
|
return content;
|
|
504
855
|
}
|
|
505
|
-
// Transform '../utils' to './utils' (only exact match, not '../utils/something')
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
return transformed;
|
|
856
|
+
// Transform '../utils' to './utils.js' (only exact match, not '../utils/something')
|
|
857
|
+
// Keep explicit runtime extension for Node ESM consistency.
|
|
858
|
+
return rewriteModuleSpecifiers(content, (specifier) => specifier === '../utils' ? './utils.js' : undefined);
|
|
509
859
|
}
|
|
510
860
|
/**
|
|
511
|
-
* Transform SSR-
|
|
512
|
-
*
|
|
513
|
-
* Upstream pie-lib code uses this pattern for SSR compatibility with MathQuill:
|
|
514
|
-
*
|
|
515
|
-
* ```js
|
|
516
|
-
* // - mathquill error window not defined
|
|
517
|
-
* let EditableHtml;
|
|
518
|
-
* let StyledEditableHTML;
|
|
519
|
-
* if (typeof window !== 'undefined') {
|
|
520
|
-
* EditableHtml = require('@pie-lib/editable-html-tip-tap')['default'];
|
|
521
|
-
* StyledEditableHTML = styled(EditableHtml)(({ theme }) => ({
|
|
522
|
-
* fontFamily: theme.typography.fontFamily,
|
|
523
|
-
* }));
|
|
524
|
-
* }
|
|
525
|
-
* ```
|
|
526
|
-
*
|
|
527
|
-
* This doesn't work in browser ESM (require is not defined). Transform to:
|
|
861
|
+
* Transform legacy SSR-gated `require()` for pie-lib editors into static ESM imports.
|
|
528
862
|
*
|
|
529
|
-
*
|
|
530
|
-
*
|
|
531
|
-
*
|
|
532
|
-
*
|
|
533
|
-
* const StyledEditableHTML = styled(EditableHtml)(({ theme }) => ({
|
|
534
|
-
* fontFamily: theme.typography.fontFamily,
|
|
535
|
-
* }));
|
|
536
|
-
* ```
|
|
537
|
-
*
|
|
538
|
-
* We use direct imports instead of React.lazy because:
|
|
539
|
-
* - Simpler code (no Suspense wrapper needed)
|
|
540
|
-
* - No loading flicker
|
|
541
|
-
* - Modern bundlers handle ESM imports correctly for SSR
|
|
542
|
-
* - The component is always needed (no code-splitting benefit)
|
|
863
|
+
* Older upstream pie-lib used `typeof window` + `require()` so heavy editor code did not
|
|
864
|
+
* run under SSR. That breaks in browser ESM where `require` is undefined. When this pattern
|
|
865
|
+
* is still present in synced sources, rewrite it to a normal default import plus styled()
|
|
866
|
+
* wrapper. If upstream has already moved to ESM imports, this is a no-op.
|
|
543
867
|
*/
|
|
544
|
-
export function
|
|
868
|
+
export function transformSsrRequireToEsmImport(content) {
|
|
545
869
|
let transformed = content;
|
|
546
870
|
// Pattern 1: SSR check with require() for editable-html-tip-tap with styled wrapper
|
|
547
871
|
// Matches:
|
|
548
|
-
// // - mathquill error window not defined
|
|
549
872
|
// let EditableHtml;
|
|
550
873
|
// let StyledEditableHTML;
|
|
551
874
|
// if (typeof window !== 'undefined') {
|
|
@@ -558,7 +881,6 @@ export function transformSsrRequireToReactLazy(content) {
|
|
|
558
881
|
const match = transformed.match(ssrRequirePattern);
|
|
559
882
|
if (match) {
|
|
560
883
|
const [fullMatch, componentVar, styledVar, importPath, styleParams] = match;
|
|
561
|
-
// Generate direct import replacement (better than React.lazy - simpler, no Suspense needed)
|
|
562
884
|
const importVarName = `${componentVar}Import`;
|
|
563
885
|
const replacement = `import ${importVarName} from '${importPath}';
|
|
564
886
|
|
|
@@ -578,7 +900,6 @@ const ${styledVar} = styled(${componentVar})(${styleParams});`;
|
|
|
578
900
|
if (simpleMatch && !match) {
|
|
579
901
|
// Only apply if we didn't already match the styled pattern
|
|
580
902
|
const [fullMatch, componentVar, importPath] = simpleMatch;
|
|
581
|
-
// Generate direct import replacement (better than React.lazy - simpler, no Suspense needed)
|
|
582
903
|
const importVarName = `${componentVar}Import`;
|
|
583
904
|
const replacement = `import ${importVarName} from '${importPath}';
|
|
584
905
|
|
|
@@ -607,12 +928,11 @@ export function fixStyledComponentTypes(content) {
|
|
|
607
928
|
// Match any identifier, not just those starting with "Styled"
|
|
608
929
|
const constStyledRegex = /const (\w+) = styled\(/g;
|
|
609
930
|
transformed = transformed.replace(constStyledRegex, 'const $1: any = styled(');
|
|
610
|
-
// Pattern 3: Class
|
|
611
|
-
// Add `: any` return type to
|
|
612
|
-
//
|
|
613
|
-
//
|
|
614
|
-
|
|
615
|
-
const methodRegex = /^(\s*)(\w+)\s*=\s*\([^)]*\)\s*=>\s*\{/gm;
|
|
931
|
+
// Pattern 3: Class field arrow functions that might return styled components
|
|
932
|
+
// Add `: any` return type to class fields missing type annotations.
|
|
933
|
+
// IMPORTANT: keep this line-scoped so we do not accidentally match multiline JSX
|
|
934
|
+
// assignments such as `foo = (<Component ref={(r) => { ... }} />)`.
|
|
935
|
+
const methodRegex = /^(\s*)(\w+)\s*=\s*\([^)\n]*\)\s*=>\s*\{/gm;
|
|
616
936
|
transformed = transformed.replace(methodRegex, (match) => {
|
|
617
937
|
// Check if already has type annotation (: type = )
|
|
618
938
|
const hasTypeAnnotation = match.includes(':');
|
|
@@ -647,53 +967,27 @@ export function fixStyledComponentTypes(content) {
|
|
|
647
967
|
* @returns Transformed content with relative imports
|
|
648
968
|
*/
|
|
649
969
|
export function transformSelfReferentialImports(content, packageName, sourceFilePath) {
|
|
650
|
-
let transformed = content;
|
|
651
970
|
// Extract element name from package name (@pie-element/fraction-model → fraction-model)
|
|
652
971
|
const elementName = packageName.replace('@pie-element/', '');
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
let targetPath = '';
|
|
660
|
-
if (sourceFilePath.startsWith('configure/src/')) {
|
|
661
|
-
// Configure files reference delivery components
|
|
662
|
-
// configure/src/main.jsx → author/main.tsx
|
|
663
|
-
// Relative path from author/ to delivery/
|
|
664
|
-
targetPath = '../delivery';
|
|
665
|
-
}
|
|
666
|
-
else if (sourceFilePath.startsWith('src/')) {
|
|
667
|
-
// Main src files shouldn't self-reference, but handle it anyway
|
|
668
|
-
targetPath = '.';
|
|
669
|
-
}
|
|
670
|
-
else {
|
|
671
|
-
// Unknown structure, skip
|
|
672
|
-
continue;
|
|
673
|
-
}
|
|
674
|
-
// Strategy: Self-referential imports typically come from the package's main
|
|
675
|
-
// index file which re-exports from various locations. Rather than trying to
|
|
676
|
-
// guess individual file locations (which often fails for namespace exports
|
|
677
|
-
// and re-exports), we keep the import pointing to the index (delivery folder)
|
|
678
|
-
// which handles all re-exports correctly.
|
|
679
|
-
//
|
|
680
|
-
// Examples:
|
|
681
|
-
// - import { NumberLineComponent, dataConverter, tickUtils } from '@pie-element/number-line'
|
|
682
|
-
// → import { NumberLineComponent, dataConverter, tickUtils } from '../delivery'
|
|
683
|
-
// - import FractionModel from '@pie-element/fraction-model'
|
|
684
|
-
// → import FractionModel from '../delivery'
|
|
685
|
-
if (namedImports) {
|
|
686
|
-
// Named imports - keep them as a single import from the index
|
|
687
|
-
const replacement = `import { ${namedImports} } from '${targetPath}'`;
|
|
688
|
-
transformed = transformed.replace(fullMatch, replacement);
|
|
689
|
-
}
|
|
690
|
-
else if (defaultImport) {
|
|
691
|
-
// Default import - reference main index
|
|
692
|
-
const replacement = `import ${defaultImport} from '${targetPath}'`;
|
|
693
|
-
transformed = transformed.replace(fullMatch, replacement);
|
|
694
|
-
}
|
|
972
|
+
let targetPath = null;
|
|
973
|
+
if (sourceFilePath.startsWith('configure/src/')) {
|
|
974
|
+
// Configure files reference delivery components
|
|
975
|
+
// configure/src/main.jsx → author/main.tsx
|
|
976
|
+
// Relative path from author/ to delivery/
|
|
977
|
+
targetPath = '../delivery';
|
|
695
978
|
}
|
|
696
|
-
|
|
979
|
+
else if (sourceFilePath.startsWith('src/')) {
|
|
980
|
+
// Main src files shouldn't self-reference, but handle it anyway
|
|
981
|
+
targetPath = '.';
|
|
982
|
+
}
|
|
983
|
+
if (!targetPath) {
|
|
984
|
+
return content;
|
|
985
|
+
}
|
|
986
|
+
// Strategy: Self-referential imports typically come from the package's main
|
|
987
|
+
// index file which re-exports from various locations. Rather than trying to
|
|
988
|
+
// guess individual file locations (which often fails for namespace exports
|
|
989
|
+
// and re-exports), we keep the import pointing to the index.
|
|
990
|
+
return rewriteModuleSpecifiers(content, (specifier) => specifier === `@pie-element/${elementName}` ? `${targetPath}/index.js` : undefined);
|
|
697
991
|
}
|
|
698
992
|
/**
|
|
699
993
|
* Fix type inference errors for exported functions with complex return types
|
|
@@ -706,14 +1000,14 @@ export function transformSelfReferentialImports(content, packageName, sourceFile
|
|
|
706
1000
|
export function fixExportedFunctionTypes(content, sourcePath) {
|
|
707
1001
|
let transformed = content;
|
|
708
1002
|
// Only apply to specific files that are known to have issues
|
|
709
|
-
if (sourcePath
|
|
1003
|
+
if (sourcePathMatchesPreset(sourcePath, PRESET_IDS.transformChartingUtilsTypeFix)) {
|
|
710
1004
|
// Fix: export const dataToXBand = (...) => { ... }
|
|
711
1005
|
// Pattern: export const functionName = (params) => {
|
|
712
1006
|
transformed = transformed.replace(/export const dataToXBand = \(/g, 'export const dataToXBand: any = (');
|
|
713
1007
|
}
|
|
714
1008
|
// Fix translator package default export type inference issue
|
|
715
1009
|
// The spread operator `...i18next` causes TypeScript to require a reference to i18next types
|
|
716
|
-
if (sourcePath
|
|
1010
|
+
if (sourcePathMatchesPreset(sourcePath, PRESET_IDS.transformTranslatorIndexTypeFix)) {
|
|
717
1011
|
// Add type imports
|
|
718
1012
|
if (!transformed.includes('type i18n')) {
|
|
719
1013
|
transformed = transformed.replace(/import i18next from 'i18next';/, "import i18next, { type i18n, type TOptions } from 'i18next';");
|
|
@@ -756,21 +1050,40 @@ const translatorModule: TranslatorModule = `;
|
|
|
756
1050
|
* @returns Transformed content with Menu imports replaced
|
|
757
1051
|
*/
|
|
758
1052
|
export function transformMenuToInlineMenu(content) {
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
1053
|
+
const sourceFile = ts.createSourceFile('source.tsx', content, ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX);
|
|
1054
|
+
const edits = [];
|
|
1055
|
+
const visit = (node) => {
|
|
1056
|
+
if (ts.isImportDeclaration(node) &&
|
|
1057
|
+
ts.isStringLiteral(node.moduleSpecifier) &&
|
|
1058
|
+
node.moduleSpecifier.text === '@mui/material/Menu') {
|
|
1059
|
+
const defaultName = node.importClause?.name?.text;
|
|
1060
|
+
if (!defaultName) {
|
|
1061
|
+
return;
|
|
1062
|
+
}
|
|
1063
|
+
const namedImports = menuNamedImportsText(node, sourceFile);
|
|
1064
|
+
const replacement = [
|
|
1065
|
+
`import { InlineMenu as ${defaultName} } from '@pie-lib/render-ui';`,
|
|
1066
|
+
namedImports ? `import type { ${namedImports} } from '@mui/material/Menu';` : null,
|
|
1067
|
+
]
|
|
1068
|
+
.filter((line) => !!line)
|
|
1069
|
+
.join('\n');
|
|
1070
|
+
edits.push({
|
|
1071
|
+
start: node.getStart(sourceFile),
|
|
1072
|
+
end: node.getEnd(),
|
|
1073
|
+
text: replacement,
|
|
1074
|
+
});
|
|
1075
|
+
}
|
|
1076
|
+
ts.forEachChild(node, visit);
|
|
1077
|
+
};
|
|
1078
|
+
visit(sourceFile);
|
|
1079
|
+
return applySourceEdits(content, edits);
|
|
1080
|
+
}
|
|
1081
|
+
function menuNamedImportsText(node, sourceFile) {
|
|
1082
|
+
const namedBindings = node.importClause?.namedBindings;
|
|
1083
|
+
if (!namedBindings || !ts.isNamedImports(namedBindings)) {
|
|
1084
|
+
return null;
|
|
772
1085
|
}
|
|
773
|
-
return
|
|
1086
|
+
return namedBindings.elements.map((element) => element.getText(sourceFile)).join(', ');
|
|
774
1087
|
}
|
|
775
1088
|
/**
|
|
776
1089
|
* Add InlineMenu export to render-ui index file
|
|
@@ -789,7 +1102,7 @@ export function transformMenuToInlineMenu(content) {
|
|
|
789
1102
|
export function addInlineMenuExport(content, sourcePath) {
|
|
790
1103
|
// Only apply to render-ui root index file (not subdirectories like collapsible/index.tsx)
|
|
791
1104
|
// sourcePath format: pie-lib/packages/render-ui/src/index.js
|
|
792
|
-
if (!sourcePath
|
|
1105
|
+
if (!sourcePathMatchesPreset(sourcePath, PRESET_IDS.transformRenderUiInlineMenuExport)) {
|
|
793
1106
|
return content;
|
|
794
1107
|
}
|
|
795
1108
|
// Check if InlineMenu export already exists
|
|
@@ -801,16 +1114,176 @@ export function addInlineMenuExport(content, sourcePath) {
|
|
|
801
1114
|
return content.trimEnd() + exportStatement;
|
|
802
1115
|
}
|
|
803
1116
|
/**
|
|
804
|
-
* Transform
|
|
1117
|
+
* Transform React component imports that may resolve as module objects in IIFE builds.
|
|
805
1118
|
*
|
|
806
|
-
*
|
|
807
|
-
* which
|
|
1119
|
+
* Some libraries export React components as objects (e.g. forwardRef) or wrapped modules,
|
|
1120
|
+
* which can trigger React invariant #130 in certain bundled interop paths.
|
|
808
1121
|
*
|
|
809
|
-
*
|
|
810
|
-
*
|
|
1122
|
+
* This transform rewrites known-risk imports to pass through a small runtime unwrap helper:
|
|
1123
|
+
* - `@mdi/react` default import
|
|
1124
|
+
* - `react-konva` named imports
|
|
811
1125
|
*/
|
|
812
|
-
export function
|
|
813
|
-
|
|
814
|
-
|
|
1126
|
+
export function transformReactInteropComponentImports(content) {
|
|
1127
|
+
let transformed = content;
|
|
1128
|
+
let touched = false;
|
|
1129
|
+
// Handle default import from @mdi/react:
|
|
1130
|
+
// import Icon from '@mdi/react'
|
|
1131
|
+
// ->
|
|
1132
|
+
// import IconImport from '@mdi/react'
|
|
1133
|
+
// const Icon = unwrapReactInteropSymbol(IconImport, 'Icon');
|
|
1134
|
+
transformed = transformed.replace(/^import\s+([A-Za-z_$][\w$]*)\s+from\s+['"]@mdi\/react['"];?\s*$/m, (match, localName) => {
|
|
1135
|
+
if (localName.endsWith('Import')) {
|
|
1136
|
+
return match;
|
|
1137
|
+
}
|
|
1138
|
+
touched = true;
|
|
1139
|
+
return `import ${localName}Import from '@mdi/react';`;
|
|
1140
|
+
});
|
|
1141
|
+
const mdiMatch = transformed.match(/^import\s+([A-Za-z_$][\w$]*)Import\s+from\s+['"]@mdi\/react['"];?\s*$/m);
|
|
1142
|
+
if (mdiMatch) {
|
|
1143
|
+
const localName = mdiMatch[1];
|
|
1144
|
+
const declaration = `const ${localName} = unwrapReactInteropSymbol(${localName}Import, '${localName}');`;
|
|
1145
|
+
if (!transformed.includes(declaration)) {
|
|
1146
|
+
touched = true;
|
|
1147
|
+
transformed = transformed.replace(mdiMatch[0], `${mdiMatch[0]}\n${declaration}`);
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
// Handle named imports from react-konva:
|
|
1151
|
+
// import { Stage, Layer } from 'react-konva'
|
|
1152
|
+
// ->
|
|
1153
|
+
// import { Stage as StageImport, Layer as LayerImport } from 'react-konva'
|
|
1154
|
+
// const Stage = unwrapReactInteropSymbol(StageImport, 'Stage');
|
|
1155
|
+
// const Layer = unwrapReactInteropSymbol(LayerImport, 'Layer');
|
|
1156
|
+
const konvaImportRegex = /^import\s+\{([^}]+)\}\s+from\s+['"]react-konva['"];?\s*$/m;
|
|
1157
|
+
const konvaMatch = transformed.match(konvaImportRegex);
|
|
1158
|
+
if (konvaMatch) {
|
|
1159
|
+
const rawSpec = konvaMatch[1]
|
|
1160
|
+
.split(',')
|
|
1161
|
+
.map((s) => s.trim())
|
|
1162
|
+
.filter(Boolean);
|
|
1163
|
+
const parsed = rawSpec
|
|
1164
|
+
.map((entry) => {
|
|
1165
|
+
const aliasMatch = entry.match(/^([A-Za-z_$][\w$]*)\s+as\s+([A-Za-z_$][\w$]*)$/);
|
|
1166
|
+
if (aliasMatch) {
|
|
1167
|
+
return { exported: aliasMatch[1], local: aliasMatch[2] };
|
|
1168
|
+
}
|
|
1169
|
+
const singleMatch = entry.match(/^([A-Za-z_$][\w$]*)$/);
|
|
1170
|
+
if (singleMatch) {
|
|
1171
|
+
return { exported: singleMatch[1], local: singleMatch[1] };
|
|
1172
|
+
}
|
|
1173
|
+
return null;
|
|
1174
|
+
})
|
|
1175
|
+
.filter((v) => !!v);
|
|
1176
|
+
if (parsed.length) {
|
|
1177
|
+
const rewrittenSpecs = parsed.map(({ exported, local }) => `${exported} as ${local}Import`);
|
|
1178
|
+
const declarations = parsed.map(({ exported, local }) => `const ${local} = unwrapReactInteropSymbol(${local}Import, '${exported}');`);
|
|
1179
|
+
transformed = transformed.replace(konvaImportRegex, `import { ${rewrittenSpecs.join(', ')} } from 'react-konva';`);
|
|
1180
|
+
for (const declaration of declarations) {
|
|
1181
|
+
if (!transformed.includes(declaration)) {
|
|
1182
|
+
transformed = transformed.replace(/^import\s+\{[^}]+\}\s+from\s+['"]react-konva['"];?\s*$/m, (line) => `${line}\n${declaration}`);
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
touched = true;
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
// Handle mixed named imports from @pie-lib/render-ui where React components
|
|
1189
|
+
// may resolve through nested/default interop in IIFE bundles.
|
|
1190
|
+
// Example:
|
|
1191
|
+
// import { Collapsible, color, PreviewPrompt } from '@pie-lib/render-ui'
|
|
1192
|
+
// ->
|
|
1193
|
+
// import { Collapsible as CollapsibleImport, color, PreviewPrompt as PreviewPromptImport } from '@pie-lib/render-ui';
|
|
1194
|
+
// const Collapsible = unwrapReactInteropSymbol(CollapsibleImport, 'Collapsible');
|
|
1195
|
+
// const PreviewPrompt = unwrapReactInteropSymbol(PreviewPromptImport, 'PreviewPrompt');
|
|
1196
|
+
const renderUiImportRegex = /^import\s+\{([^}]+)\}\s+from\s+['"]@pie-lib\/render-ui['"];?\s*$/m;
|
|
1197
|
+
const renderUiMatch = transformed.match(renderUiImportRegex);
|
|
1198
|
+
if (renderUiMatch) {
|
|
1199
|
+
const rawSpec = renderUiMatch[1]
|
|
1200
|
+
.split(',')
|
|
1201
|
+
.map((s) => s.trim())
|
|
1202
|
+
.filter(Boolean);
|
|
1203
|
+
const parsed = rawSpec
|
|
1204
|
+
.map((entry) => {
|
|
1205
|
+
const aliasMatch = entry.match(/^([A-Za-z_$][\w$]*)\s+as\s+([A-Za-z_$][\w$]*)$/);
|
|
1206
|
+
if (aliasMatch) {
|
|
1207
|
+
return { exported: aliasMatch[1], local: aliasMatch[2] };
|
|
1208
|
+
}
|
|
1209
|
+
const singleMatch = entry.match(/^([A-Za-z_$][\w$]*)$/);
|
|
1210
|
+
if (singleMatch) {
|
|
1211
|
+
return { exported: singleMatch[1], local: singleMatch[1] };
|
|
1212
|
+
}
|
|
1213
|
+
return null;
|
|
1214
|
+
})
|
|
1215
|
+
.filter((v) => !!v);
|
|
1216
|
+
// Heuristic: only wrap React component-like imports (PascalCase symbols).
|
|
1217
|
+
const componentLike = parsed.filter(({ exported, local }) => /^[A-Z]/.test(exported) && /^[A-Z]/.test(local) && !local.endsWith('Import'));
|
|
1218
|
+
if (componentLike.length) {
|
|
1219
|
+
const rewrittenSpecs = parsed.map(({ exported, local }) => {
|
|
1220
|
+
const shouldWrap = componentLike.some((entry) => entry.exported === exported && entry.local === local);
|
|
1221
|
+
return shouldWrap
|
|
1222
|
+
? `${exported} as ${local}Import`
|
|
1223
|
+
: exported === local
|
|
1224
|
+
? local
|
|
1225
|
+
: `${exported} as ${local}`;
|
|
1226
|
+
});
|
|
1227
|
+
const declarations = componentLike.map(({ exported, local }) => `const ${local} = unwrapReactInteropSymbol(${local}Import, '${exported}');`);
|
|
1228
|
+
transformed = transformed.replace(renderUiImportRegex, `import { ${rewrittenSpecs.join(', ')} } from '@pie-lib/render-ui';`);
|
|
1229
|
+
// Add a namespace import so wrapped component imports can fall back to module members
|
|
1230
|
+
// when named import interop resolves unexpectedly in IIFE bundles.
|
|
1231
|
+
if (!/^import\s+\*\s+as\s+RenderUiNamespace\s+from\s+['"]@pie-lib\/render-ui['"];?\s*$/m.test(transformed)) {
|
|
1232
|
+
transformed = transformed.replace(/^import\s+\{[^}]+\}\s+from\s+['"]@pie-lib\/render-ui['"];?\s*$/m, (line) => `${line}\nimport * as RenderUiNamespace from '@pie-lib/render-ui';`);
|
|
1233
|
+
}
|
|
1234
|
+
const renderUiInteropPrelude = `const renderUiNamespaceAny = RenderUiNamespace as any;
|
|
1235
|
+
const renderUiDefaultMaybe = renderUiNamespaceAny['default'];
|
|
1236
|
+
const renderUi =
|
|
1237
|
+
renderUiDefaultMaybe && typeof renderUiDefaultMaybe === 'object'
|
|
1238
|
+
? renderUiDefaultMaybe
|
|
1239
|
+
: renderUiNamespaceAny;`;
|
|
1240
|
+
if (!transformed.includes('const renderUiNamespaceAny = RenderUiNamespace as any;')) {
|
|
1241
|
+
transformed = transformed.replace(/^import\s+\*\s+as\s+RenderUiNamespace\s+from\s+['"]@pie-lib\/render-ui['"];?\s*$/m, (line) => `${line}\n${renderUiInteropPrelude}`);
|
|
1242
|
+
}
|
|
1243
|
+
for (const declaration of declarations) {
|
|
1244
|
+
const withFallback = declaration.replace(/unwrapReactInteropSymbol\((\w+)Import, '(\w+)'\);$/, "unwrapReactInteropSymbol($1Import, '$2') || unwrapReactInteropSymbol(renderUi.$2, '$2');");
|
|
1245
|
+
if (!transformed.includes(declaration) && !transformed.includes(withFallback)) {
|
|
1246
|
+
transformed = transformed.replace(/^import\s+\{[^}]+\}\s+from\s+['"]@pie-lib\/render-ui['"];?\s*$/m, (line) => `${line}\n${withFallback}`);
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
touched = true;
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
if (!touched) {
|
|
1253
|
+
return transformed;
|
|
1254
|
+
}
|
|
1255
|
+
if (!transformed.includes('function isRenderableReactInteropType(')) {
|
|
1256
|
+
const helperBlock = `function isRenderableReactInteropType(value: any) {
|
|
1257
|
+
return (
|
|
1258
|
+
typeof value === 'function' ||
|
|
1259
|
+
(typeof value === 'object' && value !== null && typeof value.$$typeof === 'symbol')
|
|
1260
|
+
);
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
function unwrapReactInteropSymbol(maybeSymbol: any, namedExport?: string) {
|
|
1264
|
+
if (!maybeSymbol) return maybeSymbol;
|
|
1265
|
+
if (isRenderableReactInteropType(maybeSymbol)) return maybeSymbol;
|
|
1266
|
+
if (isRenderableReactInteropType(maybeSymbol.default)) return maybeSymbol.default;
|
|
1267
|
+
if (namedExport && isRenderableReactInteropType(maybeSymbol[namedExport])) {
|
|
1268
|
+
return maybeSymbol[namedExport];
|
|
1269
|
+
}
|
|
1270
|
+
if (namedExport && isRenderableReactInteropType(maybeSymbol[namedExport]?.default)) {
|
|
1271
|
+
return maybeSymbol[namedExport].default;
|
|
1272
|
+
}
|
|
1273
|
+
return maybeSymbol;
|
|
1274
|
+
}
|
|
1275
|
+
`;
|
|
1276
|
+
// Capture top-of-file import blocks, including multiline imports.
|
|
1277
|
+
const importBlockMatch = transformed.match(/^(?:(?:\s*\/\/[^\n]*\n|\s*\/\*[\s\S]*?\*\/\s*\n|\s*\n)*)((?:import[\s\S]*?;\s*\n)+)/);
|
|
1278
|
+
if (importBlockMatch) {
|
|
1279
|
+
const insertAt = importBlockMatch[0].length;
|
|
1280
|
+
transformed =
|
|
1281
|
+
transformed.slice(0, insertAt) + '\n' + helperBlock + transformed.slice(insertAt);
|
|
1282
|
+
}
|
|
1283
|
+
else {
|
|
1284
|
+
transformed = `${helperBlock}\n${transformed}`;
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
return transformed;
|
|
815
1288
|
}
|
|
816
1289
|
//# sourceMappingURL=sync-imports.js.map
|