@pie-element/cli 0.1.1

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.
Files changed (255) hide show
  1. package/.compatibility/report.json +2491 -0
  2. package/.turbo/turbo-build.log +1 -0
  3. package/CHANGELOG.md +8 -0
  4. package/README.md +240 -0
  5. package/REFACTORING.md +131 -0
  6. package/bin/dev.js +5 -0
  7. package/bin/run.js +5 -0
  8. package/dist/commands/dev/demo/index.d.ts +33 -0
  9. package/dist/commands/dev/demo/index.d.ts.map +1 -0
  10. package/dist/commands/dev/demo/index.js +274 -0
  11. package/dist/commands/dev/demo/index.js.map +1 -0
  12. package/dist/commands/dev/test-bundler.d.ts +18 -0
  13. package/dist/commands/dev/test-bundler.d.ts.map +1 -0
  14. package/dist/commands/dev/test-bundler.js +284 -0
  15. package/dist/commands/dev/test-bundler.js.map +1 -0
  16. package/dist/commands/mathquill/migrate.d.ts +20 -0
  17. package/dist/commands/mathquill/migrate.d.ts.map +1 -0
  18. package/dist/commands/mathquill/migrate.js +240 -0
  19. package/dist/commands/mathquill/migrate.js.map +1 -0
  20. package/dist/commands/mathquill/status.d.ts +20 -0
  21. package/dist/commands/mathquill/status.d.ts.map +1 -0
  22. package/dist/commands/mathquill/status.js +231 -0
  23. package/dist/commands/mathquill/status.js.map +1 -0
  24. package/dist/commands/packages/create-controllers.d.ts +13 -0
  25. package/dist/commands/packages/create-controllers.d.ts.map +1 -0
  26. package/dist/commands/packages/create-controllers.js +103 -0
  27. package/dist/commands/packages/create-controllers.js.map +1 -0
  28. package/dist/commands/packages/create-lib-react.d.ts +17 -0
  29. package/dist/commands/packages/create-lib-react.d.ts.map +1 -0
  30. package/dist/commands/packages/create-lib-react.js +228 -0
  31. package/dist/commands/packages/create-lib-react.js.map +1 -0
  32. package/dist/commands/packages/create-react-elements.d.ts +16 -0
  33. package/dist/commands/packages/create-react-elements.d.ts.map +1 -0
  34. package/dist/commands/packages/create-react-elements.js +259 -0
  35. package/dist/commands/packages/create-react-elements.js.map +1 -0
  36. package/dist/commands/packages/enable-publishing.d.ts +11 -0
  37. package/dist/commands/packages/enable-publishing.d.ts.map +1 -0
  38. package/dist/commands/packages/enable-publishing.js +117 -0
  39. package/dist/commands/packages/enable-publishing.js.map +1 -0
  40. package/dist/commands/packages/init-synced-elements.d.ts +16 -0
  41. package/dist/commands/packages/init-synced-elements.d.ts.map +1 -0
  42. package/dist/commands/packages/init-synced-elements.js +204 -0
  43. package/dist/commands/packages/init-synced-elements.js.map +1 -0
  44. package/dist/commands/upstream/analyze-esm.d.ts +59 -0
  45. package/dist/commands/upstream/analyze-esm.d.ts.map +1 -0
  46. package/dist/commands/upstream/analyze-esm.js +1481 -0
  47. package/dist/commands/upstream/analyze-esm.js.map +1 -0
  48. package/dist/commands/upstream/check.d.ts +15 -0
  49. package/dist/commands/upstream/check.d.ts.map +1 -0
  50. package/dist/commands/upstream/check.js +165 -0
  51. package/dist/commands/upstream/check.js.map +1 -0
  52. package/dist/commands/upstream/deps.d.ts +15 -0
  53. package/dist/commands/upstream/deps.d.ts.map +1 -0
  54. package/dist/commands/upstream/deps.js +174 -0
  55. package/dist/commands/upstream/deps.js.map +1 -0
  56. package/dist/commands/upstream/sync-mathquill.d.ts +12 -0
  57. package/dist/commands/upstream/sync-mathquill.d.ts.map +1 -0
  58. package/dist/commands/upstream/sync-mathquill.js +97 -0
  59. package/dist/commands/upstream/sync-mathquill.js.map +1 -0
  60. package/dist/commands/upstream/sync.d.ts +25 -0
  61. package/dist/commands/upstream/sync.d.ts.map +1 -0
  62. package/dist/commands/upstream/sync.js +552 -0
  63. package/dist/commands/upstream/sync.js.map +1 -0
  64. package/dist/commands/upstream/track.d.ts +15 -0
  65. package/dist/commands/upstream/track.d.ts.map +1 -0
  66. package/dist/commands/upstream/track.js +115 -0
  67. package/dist/commands/upstream/track.js.map +1 -0
  68. package/dist/commands/upstream/update.d.ts +15 -0
  69. package/dist/commands/upstream/update.d.ts.map +1 -0
  70. package/dist/commands/upstream/update.js +98 -0
  71. package/dist/commands/upstream/update.js.map +1 -0
  72. package/dist/commands/verify/controllers.d.ts +12 -0
  73. package/dist/commands/verify/controllers.d.ts.map +1 -0
  74. package/dist/commands/verify/controllers.js +138 -0
  75. package/dist/commands/verify/controllers.js.map +1 -0
  76. package/dist/commands/verify/react-build.d.ts +13 -0
  77. package/dist/commands/verify/react-build.d.ts.map +1 -0
  78. package/dist/commands/verify/react-build.js +135 -0
  79. package/dist/commands/verify/react-build.js.map +1 -0
  80. package/dist/index.d.ts +2 -0
  81. package/dist/index.d.ts.map +1 -0
  82. package/dist/index.js +2 -0
  83. package/dist/index.js.map +1 -0
  84. package/dist/lib/mathquill/extension-generator.d.ts +9 -0
  85. package/dist/lib/mathquill/extension-generator.d.ts.map +1 -0
  86. package/dist/lib/mathquill/extension-generator.js +107 -0
  87. package/dist/lib/mathquill/extension-generator.js.map +1 -0
  88. package/dist/lib/mathquill/khan-extractor.d.ts +16 -0
  89. package/dist/lib/mathquill/khan-extractor.d.ts.map +1 -0
  90. package/dist/lib/mathquill/khan-extractor.js +148 -0
  91. package/dist/lib/mathquill/khan-extractor.js.map +1 -0
  92. package/dist/lib/mathquill/learnosity-extractor.d.ts +15 -0
  93. package/dist/lib/mathquill/learnosity-extractor.d.ts.map +1 -0
  94. package/dist/lib/mathquill/learnosity-extractor.js +170 -0
  95. package/dist/lib/mathquill/learnosity-extractor.js.map +1 -0
  96. package/dist/lib/mathquill/migration-orchestrator.d.ts +77 -0
  97. package/dist/lib/mathquill/migration-orchestrator.d.ts.map +1 -0
  98. package/dist/lib/mathquill/migration-orchestrator.js +391 -0
  99. package/dist/lib/mathquill/migration-orchestrator.js.map +1 -0
  100. package/dist/lib/mathquill/package-updater.d.ts +9 -0
  101. package/dist/lib/mathquill/package-updater.d.ts.map +1 -0
  102. package/dist/lib/mathquill/package-updater.js +103 -0
  103. package/dist/lib/mathquill/package-updater.js.map +1 -0
  104. package/dist/lib/mathquill/pie-extractor.d.ts +14 -0
  105. package/dist/lib/mathquill/pie-extractor.d.ts.map +1 -0
  106. package/dist/lib/mathquill/pie-extractor.js +167 -0
  107. package/dist/lib/mathquill/pie-extractor.js.map +1 -0
  108. package/dist/lib/upstream/repo-utils.d.ts +9 -0
  109. package/dist/lib/upstream/repo-utils.d.ts.map +1 -0
  110. package/dist/lib/upstream/repo-utils.js +10 -0
  111. package/dist/lib/upstream/repo-utils.js.map +1 -0
  112. package/dist/lib/upstream/sync-compatibility.d.ts +29 -0
  113. package/dist/lib/upstream/sync-compatibility.d.ts.map +1 -0
  114. package/dist/lib/upstream/sync-compatibility.js +70 -0
  115. package/dist/lib/upstream/sync-compatibility.js.map +1 -0
  116. package/dist/lib/upstream/sync-constants.d.ts +50 -0
  117. package/dist/lib/upstream/sync-constants.d.ts.map +1 -0
  118. package/dist/lib/upstream/sync-constants.js +66 -0
  119. package/dist/lib/upstream/sync-constants.js.map +1 -0
  120. package/dist/lib/upstream/sync-controllers-strategy.d.ts +18 -0
  121. package/dist/lib/upstream/sync-controllers-strategy.d.ts.map +1 -0
  122. package/dist/lib/upstream/sync-controllers-strategy.js +243 -0
  123. package/dist/lib/upstream/sync-controllers-strategy.js.map +1 -0
  124. package/dist/lib/upstream/sync-demo-metadata.d.ts +15 -0
  125. package/dist/lib/upstream/sync-demo-metadata.d.ts.map +1 -0
  126. package/dist/lib/upstream/sync-demo-metadata.js +165 -0
  127. package/dist/lib/upstream/sync-demo-metadata.js.map +1 -0
  128. package/dist/lib/upstream/sync-dev-exports.d.ts +13 -0
  129. package/dist/lib/upstream/sync-dev-exports.d.ts.map +1 -0
  130. package/dist/lib/upstream/sync-dev-exports.js +115 -0
  131. package/dist/lib/upstream/sync-dev-exports.js.map +1 -0
  132. package/dist/lib/upstream/sync-externals.d.ts +29 -0
  133. package/dist/lib/upstream/sync-externals.d.ts.map +1 -0
  134. package/dist/lib/upstream/sync-externals.js +164 -0
  135. package/dist/lib/upstream/sync-externals.js.map +1 -0
  136. package/dist/lib/upstream/sync-filesystem.d.ts +21 -0
  137. package/dist/lib/upstream/sync-filesystem.d.ts.map +1 -0
  138. package/dist/lib/upstream/sync-filesystem.js +64 -0
  139. package/dist/lib/upstream/sync-filesystem.js.map +1 -0
  140. package/dist/lib/upstream/sync-imports.d.ts +284 -0
  141. package/dist/lib/upstream/sync-imports.d.ts.map +1 -0
  142. package/dist/lib/upstream/sync-imports.js +816 -0
  143. package/dist/lib/upstream/sync-imports.js.map +1 -0
  144. package/dist/lib/upstream/sync-mathquill.d.ts +19 -0
  145. package/dist/lib/upstream/sync-mathquill.d.ts.map +1 -0
  146. package/dist/lib/upstream/sync-mathquill.js +160 -0
  147. package/dist/lib/upstream/sync-mathquill.js.map +1 -0
  148. package/dist/lib/upstream/sync-package-json.d.ts +28 -0
  149. package/dist/lib/upstream/sync-package-json.d.ts.map +1 -0
  150. package/dist/lib/upstream/sync-package-json.js +66 -0
  151. package/dist/lib/upstream/sync-package-json.js.map +1 -0
  152. package/dist/lib/upstream/sync-package-manager.d.ts +50 -0
  153. package/dist/lib/upstream/sync-package-manager.d.ts.map +1 -0
  154. package/dist/lib/upstream/sync-package-manager.js +570 -0
  155. package/dist/lib/upstream/sync-package-manager.js.map +1 -0
  156. package/dist/lib/upstream/sync-pielib-strategy.d.ts +26 -0
  157. package/dist/lib/upstream/sync-pielib-strategy.d.ts.map +1 -0
  158. package/dist/lib/upstream/sync-pielib-strategy.js +345 -0
  159. package/dist/lib/upstream/sync-pielib-strategy.js.map +1 -0
  160. package/dist/lib/upstream/sync-react-strategy.d.ts +54 -0
  161. package/dist/lib/upstream/sync-react-strategy.d.ts.map +1 -0
  162. package/dist/lib/upstream/sync-react-strategy.js +733 -0
  163. package/dist/lib/upstream/sync-react-strategy.js.map +1 -0
  164. package/dist/lib/upstream/sync-strategy.d.ts +49 -0
  165. package/dist/lib/upstream/sync-strategy.d.ts.map +1 -0
  166. package/dist/lib/upstream/sync-strategy.js +2 -0
  167. package/dist/lib/upstream/sync-strategy.js.map +1 -0
  168. package/dist/lib/upstream/sync-summary.d.ts +20 -0
  169. package/dist/lib/upstream/sync-summary.d.ts.map +1 -0
  170. package/dist/lib/upstream/sync-summary.js +157 -0
  171. package/dist/lib/upstream/sync-summary.js.map +1 -0
  172. package/dist/lib/upstream/sync-transforms.d.ts +60 -0
  173. package/dist/lib/upstream/sync-transforms.d.ts.map +1 -0
  174. package/dist/lib/upstream/sync-transforms.js +97 -0
  175. package/dist/lib/upstream/sync-transforms.js.map +1 -0
  176. package/dist/lib/upstream/sync-vite-config.d.ts +13 -0
  177. package/dist/lib/upstream/sync-vite-config.d.ts.map +1 -0
  178. package/dist/lib/upstream/sync-vite-config.js +231 -0
  179. package/dist/lib/upstream/sync-vite-config.js.map +1 -0
  180. package/dist/utils/compatibility.d.ts +129 -0
  181. package/dist/utils/compatibility.d.ts.map +1 -0
  182. package/dist/utils/compatibility.js +44 -0
  183. package/dist/utils/compatibility.js.map +1 -0
  184. package/dist/utils/conversion.d.ts +25 -0
  185. package/dist/utils/conversion.d.ts.map +1 -0
  186. package/dist/utils/conversion.js +123 -0
  187. package/dist/utils/conversion.js.map +1 -0
  188. package/dist/utils/git.d.ts +7 -0
  189. package/dist/utils/git.d.ts.map +1 -0
  190. package/dist/utils/git.js +63 -0
  191. package/dist/utils/git.js.map +1 -0
  192. package/dist/utils/logger.d.ts +29 -0
  193. package/dist/utils/logger.d.ts.map +1 -0
  194. package/dist/utils/logger.js +63 -0
  195. package/dist/utils/logger.js.map +1 -0
  196. package/dist/utils/package-json.d.ts +12 -0
  197. package/dist/utils/package-json.d.ts.map +1 -0
  198. package/dist/utils/package-json.js +29 -0
  199. package/dist/utils/package-json.js.map +1 -0
  200. package/package.json +59 -0
  201. package/packages/cli/bin/dev.js +5 -0
  202. package/packages/cli/bin/run.js +5 -0
  203. package/src/commands/dev/demo/index.ts +313 -0
  204. package/src/commands/dev/test-bundler.ts +345 -0
  205. package/src/commands/mathquill/migrate.ts +269 -0
  206. package/src/commands/mathquill/status.ts +267 -0
  207. package/src/commands/packages/create-controllers.ts +127 -0
  208. package/src/commands/packages/create-lib-react.ts +279 -0
  209. package/src/commands/packages/create-react-elements.ts +306 -0
  210. package/src/commands/packages/enable-publishing.ts +161 -0
  211. package/src/commands/packages/init-synced-elements.ts +259 -0
  212. package/src/commands/upstream/README.md +444 -0
  213. package/src/commands/upstream/analyze-esm.ts +1973 -0
  214. package/src/commands/upstream/check.ts +228 -0
  215. package/src/commands/upstream/deps.ts +222 -0
  216. package/src/commands/upstream/sync-mathquill.ts +108 -0
  217. package/src/commands/upstream/sync.ts +687 -0
  218. package/src/commands/upstream/track.ts +145 -0
  219. package/src/commands/upstream/update.ts +110 -0
  220. package/src/commands/verify/controllers.ts +166 -0
  221. package/src/commands/verify/react-build.ts +171 -0
  222. package/src/index.ts +1 -0
  223. package/src/lib/mathquill/extension-generator.ts +111 -0
  224. package/src/lib/mathquill/khan-extractor.ts +175 -0
  225. package/src/lib/mathquill/learnosity-extractor.ts +198 -0
  226. package/src/lib/mathquill/migration-orchestrator.ts +513 -0
  227. package/src/lib/mathquill/package-updater.ts +120 -0
  228. package/src/lib/mathquill/pie-extractor.ts +194 -0
  229. package/src/lib/upstream/repo-utils.ts +18 -0
  230. package/src/lib/upstream/sync-compatibility.ts +89 -0
  231. package/src/lib/upstream/sync-constants.ts +77 -0
  232. package/src/lib/upstream/sync-controllers-strategy.ts +291 -0
  233. package/src/lib/upstream/sync-demo-metadata.ts +199 -0
  234. package/src/lib/upstream/sync-dev-exports.ts +151 -0
  235. package/src/lib/upstream/sync-externals.ts +159 -0
  236. package/src/lib/upstream/sync-filesystem.ts +87 -0
  237. package/src/lib/upstream/sync-imports.ts +992 -0
  238. package/src/lib/upstream/sync-mathquill.ts +194 -0
  239. package/src/lib/upstream/sync-package-json.ts +86 -0
  240. package/src/lib/upstream/sync-package-manager.ts +694 -0
  241. package/src/lib/upstream/sync-pielib-strategy.ts +441 -0
  242. package/src/lib/upstream/sync-react-strategy.ts +945 -0
  243. package/src/lib/upstream/sync-strategy.ts +61 -0
  244. package/src/lib/upstream/sync-summary.ts +194 -0
  245. package/src/lib/upstream/sync-transforms.ts +154 -0
  246. package/src/lib/upstream/sync-vite-config.ts +243 -0
  247. package/src/types/es-module-lexer.d.ts +4 -0
  248. package/src/utils/compatibility.ts +182 -0
  249. package/src/utils/conversion.ts +153 -0
  250. package/src/utils/git.ts +63 -0
  251. package/src/utils/logger.ts +69 -0
  252. package/src/utils/package-json.ts +43 -0
  253. package/tests/sync-package-manager.test.ts +112 -0
  254. package/tests/transform-assign-props.test.ts +101 -0
  255. package/tsconfig.json +15 -0
@@ -0,0 +1,199 @@
1
+ /**
2
+ * Generate demo metadata for SvelteKit demo app
3
+ *
4
+ * This module generates:
5
+ * 1. Element registry (lib/elements/registry.ts)
6
+ * 2. Sample configs converted to JSON from each element
7
+ * 3. Sample sessions converted to JSON from each element
8
+ */
9
+ import { mkdir, writeFile } from 'node:fs/promises';
10
+ import { join, dirname } from 'node:path';
11
+ import { fileURLToPath } from 'node:url';
12
+
13
+ const __dirname = dirname(fileURLToPath(import.meta.url));
14
+ const REPO_ROOT = join(__dirname, '../../../../..');
15
+ const DEMO_APP_PATH = join(REPO_ROOT, 'apps/element-demo');
16
+ const ELEMENTS_REACT_PATH = join(REPO_ROOT, 'packages/elements-react');
17
+
18
+ export interface ElementMetadata {
19
+ name: string;
20
+ title: string;
21
+ packageName: string;
22
+ hasAuthor: boolean;
23
+ hasPrint: boolean;
24
+ hasConfig: boolean;
25
+ hasSession: boolean;
26
+ demoCount: number;
27
+ }
28
+
29
+ /**
30
+ * Scan elements-react directory for all elements
31
+ */
32
+ async function scanReactElements(): Promise<ElementMetadata[]> {
33
+ const { readdirSync, existsSync: fsExistsSync, statSync } = await import('node:fs');
34
+
35
+ if (!fsExistsSync(ELEMENTS_REACT_PATH)) {
36
+ console.log('[demo-metadata] elements-react directory not found, skipping');
37
+ return [];
38
+ }
39
+
40
+ const elements: ElementMetadata[] = [];
41
+ const dirs = readdirSync(ELEMENTS_REACT_PATH);
42
+
43
+ for (const dir of dirs) {
44
+ const elementPath = join(ELEMENTS_REACT_PATH, dir);
45
+ const stat = statSync(elementPath);
46
+
47
+ if (!stat.isDirectory()) continue;
48
+
49
+ // Check for required structure
50
+ const srcPath = join(elementPath, 'src');
51
+ const deliveryPath = join(srcPath, 'delivery');
52
+ if (!fsExistsSync(deliveryPath)) continue;
53
+
54
+ // Check for author and print
55
+ const hasAuthor = fsExistsSync(join(srcPath, 'author'));
56
+ const hasPrint = fsExistsSync(join(srcPath, 'print'));
57
+
58
+ // Check for demo files
59
+ const docsPath = join(elementPath, 'docs/demo');
60
+ const hasConfig = fsExistsSync(join(docsPath, 'config.mjs'));
61
+ const hasSession = fsExistsSync(join(docsPath, 'session.mjs'));
62
+
63
+ // Generate title from name (e.g., "multiple-choice" -> "Multiple Choice")
64
+ const title = dir
65
+ .split('-')
66
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
67
+ .join(' ');
68
+
69
+ elements.push({
70
+ name: dir,
71
+ title,
72
+ packageName: `@pie-element/${dir}`,
73
+ hasAuthor,
74
+ hasPrint,
75
+ hasConfig,
76
+ hasSession,
77
+ demoCount: 0, // Will be updated in copySampleConfigs
78
+ });
79
+ }
80
+
81
+ return elements;
82
+ }
83
+
84
+ /**
85
+ * Generate registry.ts file
86
+ */
87
+ async function generateRegistry(elements: ElementMetadata[]): Promise<void> {
88
+ const registryPath = join(DEMO_APP_PATH, 'src/lib/elements/registry.ts');
89
+
90
+ const content = `/**
91
+ * Element Registry
92
+ *
93
+ * AUTO-GENERATED by upstream:sync command.
94
+ * DO NOT EDIT MANUALLY - changes will be overwritten.
95
+ *
96
+ * Generated: ${new Date().toISOString()}
97
+ */
98
+
99
+ export interface ElementMetadata {
100
+ name: string;
101
+ title: string;
102
+ packageName: string;
103
+ hasAuthor: boolean;
104
+ hasPrint: boolean;
105
+ hasConfig: boolean;
106
+ hasSession: boolean;
107
+ demoCount: number;
108
+ }
109
+
110
+ export const ELEMENT_REGISTRY: readonly ElementMetadata[] = ${JSON.stringify(elements, null, 2)};
111
+
112
+ export function getElement(name: string): ElementMetadata | undefined {
113
+ return ELEMENT_REGISTRY.find((el) => el.name === name);
114
+ }
115
+
116
+ export function getAllElements(): ElementMetadata[] {
117
+ return ELEMENT_REGISTRY;
118
+ }
119
+ `;
120
+
121
+ await mkdir(dirname(registryPath), { recursive: true });
122
+ await writeFile(registryPath, content, 'utf-8');
123
+ console.log(`[demo-metadata] Generated registry with ${elements.length} elements`);
124
+ }
125
+
126
+ /**
127
+ * Convert and copy sample configs for an element as JSON
128
+ */
129
+ async function copySampleConfigs(elements: ElementMetadata[]): Promise<void> {
130
+ for (const element of elements) {
131
+ const sourcePath = join(ELEMENTS_REACT_PATH, element.name, 'docs/demo');
132
+ const targetDir = join(DEMO_APP_PATH, 'src/lib/data/sample-configs/react');
133
+ await mkdir(targetDir, { recursive: true });
134
+
135
+ // Convert config.mjs to JSON
136
+ if (element.hasConfig) {
137
+ const sourceConfig = join(sourcePath, 'config.mjs');
138
+ const targetConfig = join(targetDir, `${element.name}.json`);
139
+ try {
140
+ // Dynamic import the .mjs file
141
+ const configModule = await import(`file://${sourceConfig}`);
142
+ let configData = configModule.default;
143
+
144
+ // Convert old format (models array) to new format (demos array)
145
+ if (configData?.models && !configData?.demos) {
146
+ console.log(`[demo-metadata] Converting ${element.name} from old format to new format`);
147
+ configData = {
148
+ demos: configData.models.map((model: any, index: number) => ({
149
+ id: index === 0 ? 'default' : `demo-${index + 1}`,
150
+ title: index === 0 ? 'Default Demo' : `Demo ${index + 1}`,
151
+ description: 'Default configuration',
152
+ tags: [],
153
+ model: model,
154
+ session: { value: [] },
155
+ })),
156
+ };
157
+ }
158
+
159
+ // Count demos (now all in 'demos' format)
160
+ if (configData?.demos && Array.isArray(configData.demos)) {
161
+ element.demoCount = configData.demos.length;
162
+ } else {
163
+ element.demoCount = 0;
164
+ }
165
+
166
+ // Write as JSON
167
+ await writeFile(targetConfig, JSON.stringify(configData, null, 2) + '\n', 'utf-8');
168
+ } catch (e) {
169
+ console.warn(`[demo-metadata] Failed to convert config for ${element.name}:`, e);
170
+ }
171
+ }
172
+
173
+ // Note: session.mjs files are no longer copied as separate files.
174
+ // Sessions are now embedded within each demo object in the config.
175
+ // Old format session files are automatically converted during config import above.
176
+ }
177
+
178
+ console.log(`[demo-metadata] Converted sample configs to JSON for ${elements.length} elements`);
179
+ }
180
+
181
+ /**
182
+ * Main entry point
183
+ */
184
+ export async function generateDemoMetadata(): Promise<void> {
185
+ console.log('[demo-metadata] Scanning elements...');
186
+
187
+ const reactElements = await scanReactElements();
188
+ const allElements = [...reactElements].sort((a, b) => a.name.localeCompare(b.name));
189
+
190
+ console.log(`[demo-metadata] Found ${reactElements.length} React elements`);
191
+
192
+ // Copy sample configs first so demoCount gets populated
193
+ await copySampleConfigs(allElements);
194
+
195
+ // Then generate registry with updated demoCount values
196
+ await generateRegistry(allElements);
197
+
198
+ console.log('[demo-metadata] ✓ Demo metadata generation complete');
199
+ }
@@ -0,0 +1,151 @@
1
+ import { readFileSync, writeFileSync, existsSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import type { Logger } from '../../utils/logger.js';
4
+
5
+ /**
6
+ * Map of export paths to their likely source file extensions.
7
+ * This determines which source files to look for when adding development export conditions.
8
+ */
9
+ const SOURCE_EXTENSIONS: Record<string, string[]> = {
10
+ '.': ['index.ts', 'index.tsx', 'index.js'],
11
+ './delivery': ['delivery/index.ts', 'delivery/index.tsx', 'delivery/index.js'],
12
+ './author': ['author/index.tsx', 'author/index.ts', 'author/index.js'],
13
+ './controller': ['controller/index.ts', 'controller/index.js'],
14
+ './print': ['print/index.tsx', 'print/index.ts', 'print/index.js'],
15
+ './configure': ['configure/index.tsx', 'configure/index.ts', 'configure/index.js'],
16
+ };
17
+
18
+ /**
19
+ * Find the source file for a given export path in an element package.
20
+ */
21
+ function findSourceFile(elementPath: string, exportPath: string): string | null {
22
+ const possibleFiles = SOURCE_EXTENSIONS[exportPath] || [];
23
+
24
+ for (const file of possibleFiles) {
25
+ const fullPath = join(elementPath, 'src', file);
26
+ if (existsSync(fullPath)) {
27
+ return `./src/${file}`;
28
+ }
29
+ }
30
+
31
+ return null;
32
+ }
33
+
34
+ interface PackageExports {
35
+ [key: string]: string | { [condition: string]: string };
36
+ }
37
+
38
+ interface PackageJson {
39
+ name?: string;
40
+ exports?: PackageExports;
41
+ [key: string]: unknown;
42
+ }
43
+
44
+ /**
45
+ * Add development export conditions to a package.json file.
46
+ * Returns true if the file was modified, false otherwise.
47
+ */
48
+ function updatePackageJson(pkgPath: string, logger: Logger): boolean {
49
+ const pkgJsonPath = join(pkgPath, 'package.json');
50
+
51
+ if (!existsSync(pkgJsonPath)) {
52
+ return false;
53
+ }
54
+
55
+ const content = readFileSync(pkgJsonPath, 'utf-8');
56
+ const pkg: PackageJson = JSON.parse(content);
57
+
58
+ if (!pkg.exports || typeof pkg.exports !== 'object') {
59
+ logger.debug(` ⚠️ No exports field found in ${pkg.name || pkgPath}`);
60
+ return false;
61
+ }
62
+
63
+ let modified = false;
64
+
65
+ for (const [exportPath, exportConfig] of Object.entries(pkg.exports)) {
66
+ // Skip if not an object (string exports)
67
+ if (typeof exportConfig !== 'object') {
68
+ continue;
69
+ }
70
+
71
+ // Skip if already has development condition
72
+ if ('development' in exportConfig) {
73
+ continue;
74
+ }
75
+
76
+ // Find the source file
77
+ const sourceFile = findSourceFile(pkgPath, exportPath);
78
+
79
+ if (sourceFile) {
80
+ // Add development condition as the first entry
81
+ pkg.exports[exportPath] = {
82
+ development: sourceFile,
83
+ ...exportConfig,
84
+ };
85
+ modified = true;
86
+ logger.debug(` ✓ Added development export for ${exportPath} -> ${sourceFile}`);
87
+ } else {
88
+ logger.debug(` ⚠️ Could not find source file for ${exportPath}`);
89
+ }
90
+ }
91
+
92
+ if (modified) {
93
+ // Write back with proper formatting
94
+ writeFileSync(pkgJsonPath, JSON.stringify(pkg, null, 2) + '\n', 'utf-8');
95
+ return true;
96
+ }
97
+
98
+ return false;
99
+ }
100
+
101
+ /**
102
+ * Add development export conditions to element packages.
103
+ * This allows Vite to resolve directly to src/ files in development mode
104
+ * for Hot Module Reload (HMR) without needing a custom plugin.
105
+ *
106
+ * @param elementsDir - Path to the elements-react directory
107
+ * @param packageNames - Optional array of specific package names to process (e.g., ['multiple-choice'])
108
+ * @param logger - Logger instance for output
109
+ * @returns Number of packages updated
110
+ */
111
+ export async function addDevelopmentExports(
112
+ elementsDir: string,
113
+ packageNames: string[] | undefined,
114
+ logger: Logger
115
+ ): Promise<number> {
116
+ if (!existsSync(elementsDir)) {
117
+ logger.warn(`Elements directory not found: ${elementsDir}`);
118
+ return 0;
119
+ }
120
+
121
+ let updated = 0;
122
+ const packagesToProcess = packageNames || [];
123
+
124
+ // If no specific packages provided, we don't process anything
125
+ // (this function is meant to be called with specific packages after sync)
126
+ if (packagesToProcess.length === 0) {
127
+ return 0;
128
+ }
129
+
130
+ for (const pkgName of packagesToProcess) {
131
+ const elementPath = join(elementsDir, pkgName);
132
+
133
+ if (!existsSync(elementPath)) {
134
+ logger.debug(` Package not found: ${pkgName}`);
135
+ continue;
136
+ }
137
+
138
+ logger.debug(` Processing ${pkgName}...`);
139
+
140
+ const wasUpdated = updatePackageJson(elementPath, logger);
141
+
142
+ if (wasUpdated) {
143
+ updated++;
144
+ logger.debug(` ✓ Updated\n`);
145
+ } else {
146
+ logger.debug(` → Skipped (no changes needed)\n`);
147
+ }
148
+ }
149
+
150
+ return updated;
151
+ }
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Shared external dependency configuration for Vite builds
3
+ *
4
+ * These dependencies should NOT be bundled into library outputs.
5
+ * Instead, they are resolved at runtime from the consuming application.
6
+ */
7
+
8
+ /**
9
+ * Check if a module ID should be treated as external (not bundled)
10
+ *
11
+ * Categories of externals:
12
+ * 1. Framework peer dependencies (React, MUI, Emotion) - MUST be external to avoid duplicate instances
13
+ * 2. Internal monorepo packages (@pie-lib, @pie-element, @pie-element) - External for separate resolution
14
+ * 3. Utility libraries (prop-types, classnames, debug) - External to reduce duplication across packages
15
+ * 4. Specialized UI libraries (@dnd-kit, react-transition-group, styled-components) - External to avoid version conflicts
16
+ * 5. Lodash variants (lodash/lodash-es) - External for runtime resolution via import maps
17
+ * 6. D3 modules - External as they're commonly shared
18
+ */
19
+ export function isExternal(id: string, variant: 'element' | 'pielib'): boolean {
20
+ // React and React DOM - always external (peer dependencies)
21
+ if (/^react($|\/)/.test(id)) return true;
22
+ if (/^react-dom($|\/)/.test(id)) return true;
23
+
24
+ // Internal monorepo packages - always external
25
+ if (/^@pie-lib\//.test(id)) return true;
26
+ if (/^@pie-element\//.test(id)) return true;
27
+ if (/^@pie-element\//.test(id)) return true;
28
+ if (/^@pie-framework\//.test(id)) return true;
29
+
30
+ // UI framework packages - always external (peer dependencies)
31
+ if (/^@mui\//.test(id)) return true;
32
+ if (/^@emotion\//.test(id)) return true;
33
+
34
+ // D3 visualization modules - always external
35
+ if (/^d3-/.test(id)) return true;
36
+
37
+ // Recharts charting library - external for fraction-model
38
+ if (id === 'recharts' || /^recharts\//.test(id)) return true;
39
+
40
+ // Testing libraries - always external
41
+ if (/^@testing-library\//.test(id)) return true;
42
+
43
+ // Lodash - variant-specific (elements use lodash, pie-lib uses lodash-es)
44
+ if (variant === 'element') {
45
+ if (id === 'lodash') return true;
46
+ if (/^lodash\//.test(id)) return true;
47
+ } else {
48
+ if (id === 'lodash-es') return true;
49
+ if (/^lodash-es\//.test(id)) return true;
50
+ }
51
+
52
+ // Styled-components - external to avoid multiple instances
53
+ if (/^styled-components/.test(id)) return true;
54
+
55
+ // Konva visualization library - external for hotspot/drawing-response
56
+ if (id === 'konva' || id.startsWith('konva/')) return true;
57
+ if (id === 'react-konva' || id.startsWith('react-konva/')) return true;
58
+
59
+ // DnD Kit libraries - external for drag and drop functionality
60
+ if (/^@dnd-kit\//.test(id)) return true;
61
+
62
+ // Common utility and UI libraries - always external
63
+ const commonExternals = [
64
+ 'prop-types', // React prop validation
65
+ 'classnames', // CSS class utility
66
+ 'debug', // Debug logging
67
+ 'i18next', // Internationalization
68
+ 'humps', // String case conversion
69
+ 'mathjs', // Math expression evaluation
70
+ 'react-jss', // JSS styling for React
71
+ 'js-combinatorics', // Combinatorics library
72
+ '@mapbox/point-geometry', // Graphing utils dependency
73
+ '@dnd-kit/core', // Drag and drop
74
+ 'react-transition-group', // Animations
75
+ 'nested-property', // Object property access (placement-ordering)
76
+ 'pluralize', // Word pluralization (placement-ordering)
77
+ 'decimal.js', // Decimal math (placement-ordering)
78
+ ];
79
+
80
+ return commonExternals.includes(id);
81
+ }
82
+
83
+ /**
84
+ * Generate external function for Vite rollupOptions
85
+ * Use this in vite.config.ts generation
86
+ */
87
+ export function createExternalFunction(variant: 'element' | 'pielib'): string {
88
+ const lodashCheck =
89
+ variant === 'element'
90
+ ? `id === 'lodash' ||
91
+ /^lodash\\//.test(id) ||`
92
+ : `id === 'lodash-es' ||
93
+ /^lodash-es\\//.test(id) ||`;
94
+
95
+ return `(id) => {
96
+ return (
97
+ /^react($|\\/)/.test(id) ||
98
+ /^react-dom($|\\/)/.test(id) ||
99
+ /^@pie-lib\\//.test(id) ||
100
+ /^@pie-element\\//.test(id) ||
101
+ /^@pie-element\\//.test(id) ||
102
+ /^@pie-framework\\//.test(id) ||
103
+ /^@mui\\//.test(id) ||
104
+ /^@emotion\\//.test(id) ||
105
+ /^d3-/.test(id) ||
106
+ /^@testing-library\\//.test(id) ||
107
+ ${lodashCheck}
108
+ /^styled-components/.test(id) ||
109
+ id === 'konva' || /^konva\\//.test(id) ||
110
+ id === 'react-konva' || /^react-konva\\//.test(id) ||
111
+ /^@dnd-kit\\//.test(id) ||
112
+ id === '@mdi/react' || /^@mdi\\/react\\//.test(id) ||
113
+ id === '@mdi/js' || /^@mdi\\/js\\//.test(id) ||
114
+ id === 'recharts' || /^recharts\\//.test(id) ||
115
+ ['prop-types', 'classnames', 'debug', 'i18next', 'humps', 'mathjs', 'react-jss', 'js-combinatorics', '@mapbox/point-geometry', 'react-transition-group', 'nested-property', 'pluralize', 'decimal.js'].includes(id)
116
+ );
117
+ }`;
118
+ }
119
+
120
+ /**
121
+ * Generate external function for Konva-based elements (preserveModules: false)
122
+ * These bundle konva, react-konva, scheduler, and react-reconciler to avoid runtime resolution issues
123
+ */
124
+ export function createKonvaExternalFunction(): string {
125
+ return `(id) => {
126
+ // Bundle konva, react-konva, scheduler, and react-reconciler
127
+ // Check these FIRST before other react checks
128
+ if (id === 'konva' || id.startsWith('konva/')) return false;
129
+ if (id === 'react-konva' || id.startsWith('react-konva/')) return false;
130
+ if (id === 'scheduler' || id.startsWith('scheduler/')) return false;
131
+ if (id === 'react-reconciler' || id.startsWith('react-reconciler/')) return false;
132
+
133
+ // Always external: base package names
134
+ if (id === 'react' || id.startsWith('react/')) return true;
135
+ if (id === 'react-dom' || id.startsWith('react-dom/')) return true;
136
+ if (id.startsWith('@pie-lib/')) return true;
137
+ if (id.startsWith('@pie-element/')) return true;
138
+ if (id.startsWith('@pie-element/')) return true;
139
+ if (id.startsWith('@pie-framework/')) return true;
140
+ if (id.startsWith('@mui/')) return true;
141
+ if (id.startsWith('@emotion/')) return true;
142
+ if (id.startsWith('d3-')) return true;
143
+ // Keep recharts external
144
+ if (id === 'recharts' || id.startsWith('recharts/')) return true;
145
+ // Keep lodash external even with preserveModules: false
146
+ // It will be resolved via import map in demo HTML
147
+ if (id === 'lodash' || id.startsWith('lodash/')) return true;
148
+ if (id === 'styled-components' || id.startsWith('styled-components/')) return true;
149
+ // DnD Kit libraries
150
+ if (id.startsWith('@dnd-kit/')) return true;
151
+ // Material Design Icons for drawing-response
152
+ if (id === '@mdi/react' || id.startsWith('@mdi/react/')) return true;
153
+ if (id === '@mdi/js' || id.startsWith('@mdi/js/')) return true;
154
+ if (['prop-types', 'classnames', 'debug', 'i18next', 'humps', 'mathjs', 'react-jss', 'js-combinatorics', '@mapbox/point-geometry', 'react-transition-group', 'nested-property', 'pluralize', 'decimal.js'].includes(id)) return true;
155
+
156
+ // Everything else gets bundled (including dependencies of konva/react-konva)
157
+ return false;
158
+ }`;
159
+ }
@@ -0,0 +1,87 @@
1
+ /**
2
+ * File system utilities for sync operations
3
+ */
4
+ import { existsSync } from 'node:fs';
5
+ import { readdir as fsReaddir, rm as fsRm } from 'node:fs/promises';
6
+ import { join } from 'node:path';
7
+
8
+ export interface CleanOptions {
9
+ dryRun?: boolean;
10
+ verbose?: boolean;
11
+ preserve?: string[];
12
+ }
13
+
14
+ export interface Logger {
15
+ info(message: string): void;
16
+ }
17
+
18
+ /**
19
+ * Clean a directory, optionally preserving subdirectories
20
+ */
21
+ export async function cleanDirectory(
22
+ targetDir: string,
23
+ label: string,
24
+ options: CleanOptions = {},
25
+ logger?: Logger
26
+ ): Promise<void> {
27
+ const { dryRun = false, verbose = false, preserve = [] } = options;
28
+
29
+ if (!existsSync(targetDir)) {
30
+ return;
31
+ }
32
+
33
+ if (dryRun) {
34
+ if (verbose && logger) {
35
+ const preserveMsg = preserve.length > 0 ? ` (preserving: ${preserve.join(', ')})` : '';
36
+ logger.info(` 🧹 Would clean ${label}${preserveMsg}`);
37
+ }
38
+ return;
39
+ }
40
+
41
+ // If no directories to preserve, delete everything
42
+ if (preserve.length === 0) {
43
+ await fsRm(targetDir, { recursive: true, force: true });
44
+ if (verbose && logger) {
45
+ logger.info(` 🧹 Cleaned ${label}`);
46
+ }
47
+ return;
48
+ }
49
+
50
+ // Selectively delete entries, preserving specified directories
51
+ const entries = await fsReaddir(targetDir);
52
+
53
+ for (const entry of entries) {
54
+ if (preserve.includes(entry)) {
55
+ continue;
56
+ }
57
+
58
+ const entryPath = join(targetDir, entry);
59
+ await fsRm(entryPath, { recursive: true, force: true });
60
+ }
61
+
62
+ if (verbose && logger) {
63
+ logger.info(` 🧹 Cleaned ${label} (preserved: ${preserve.join(', ')})`);
64
+ }
65
+ }
66
+
67
+ /**
68
+ * Check if any of the given paths exist
69
+ */
70
+ export function existsAny(paths: string[]): boolean {
71
+ return paths.some((p) => existsSync(p));
72
+ }
73
+
74
+ /**
75
+ * Safe wrapper around readdir that sorts results
76
+ */
77
+ export async function readdir(path: string): Promise<string[]> {
78
+ try {
79
+ const entries = await fsReaddir(path);
80
+ return entries.sort();
81
+ } catch (error: unknown) {
82
+ if (error && typeof error === 'object' && 'code' in error && error.code === 'ENOENT') {
83
+ return [];
84
+ }
85
+ throw error;
86
+ }
87
+ }