@pure-ds/core 0.3.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.
Files changed (129) hide show
  1. package/CSS-INTELLISENSE-LIMITATION.md +98 -0
  2. package/CSS-INTELLISENSE-QUICK-REF.md +238 -0
  3. package/INTELLISENSE.md +384 -0
  4. package/LICENSE +15 -0
  5. package/custom-elements-manifest.config.js +30 -0
  6. package/custom-elements.json +2003 -0
  7. package/dist/types/index.d.ts +2 -0
  8. package/dist/types/packages/pds-configurator/src/figma-export.d.ts +13 -0
  9. package/dist/types/packages/pds-configurator/src/figma-export.d.ts.map +1 -0
  10. package/dist/types/packages/pds-configurator/src/pds-config-form.d.ts +2 -0
  11. package/dist/types/packages/pds-configurator/src/pds-config-form.d.ts.map +1 -0
  12. package/dist/types/packages/pds-configurator/src/pds-configurator.d.ts +2 -0
  13. package/dist/types/packages/pds-configurator/src/pds-configurator.d.ts.map +1 -0
  14. package/dist/types/packages/pds-configurator/src/pds-demo.d.ts +2 -0
  15. package/dist/types/packages/pds-configurator/src/pds-demo.d.ts.map +1 -0
  16. package/dist/types/pds.config.d.ts +13 -0
  17. package/dist/types/pds.config.d.ts.map +1 -0
  18. package/dist/types/pds.d.ts +408 -0
  19. package/dist/types/public/assets/js/app.d.ts +2 -0
  20. package/dist/types/public/assets/js/app.d.ts.map +1 -0
  21. package/dist/types/public/assets/js/pds.d.ts +23 -0
  22. package/dist/types/public/assets/js/pds.d.ts.map +1 -0
  23. package/dist/types/public/assets/pds/components/pds-calendar.d.ts +23 -0
  24. package/dist/types/public/assets/pds/components/pds-calendar.d.ts.map +1 -0
  25. package/dist/types/public/assets/pds/components/pds-drawer.d.ts +2 -0
  26. package/dist/types/public/assets/pds/components/pds-drawer.d.ts.map +1 -0
  27. package/dist/types/public/assets/pds/components/pds-icon.d.ts +53 -0
  28. package/dist/types/public/assets/pds/components/pds-icon.d.ts.map +1 -0
  29. package/dist/types/public/assets/pds/components/pds-jsonform.d.ts +104 -0
  30. package/dist/types/public/assets/pds/components/pds-jsonform.d.ts.map +1 -0
  31. package/dist/types/public/assets/pds/components/pds-richtext.d.ts +121 -0
  32. package/dist/types/public/assets/pds/components/pds-richtext.d.ts.map +1 -0
  33. package/dist/types/public/assets/pds/components/pds-scrollrow.d.ts +61 -0
  34. package/dist/types/public/assets/pds/components/pds-scrollrow.d.ts.map +1 -0
  35. package/dist/types/public/assets/pds/components/pds-splitpanel.d.ts +1 -0
  36. package/dist/types/public/assets/pds/components/pds-splitpanel.d.ts.map +1 -0
  37. package/dist/types/public/assets/pds/components/pds-tabstrip.d.ts +39 -0
  38. package/dist/types/public/assets/pds/components/pds-tabstrip.d.ts.map +1 -0
  39. package/dist/types/public/assets/pds/components/pds-toaster.d.ts +111 -0
  40. package/dist/types/public/assets/pds/components/pds-toaster.d.ts.map +1 -0
  41. package/dist/types/public/assets/pds/components/pds-upload.d.ts +83 -0
  42. package/dist/types/public/assets/pds/components/pds-upload.d.ts.map +1 -0
  43. package/dist/types/src/js/app.d.ts +2 -0
  44. package/dist/types/src/js/app.d.ts.map +1 -0
  45. package/dist/types/src/js/common/ask.d.ts +22 -0
  46. package/dist/types/src/js/common/ask.d.ts.map +1 -0
  47. package/dist/types/src/js/common/common.d.ts +3 -0
  48. package/dist/types/src/js/common/common.d.ts.map +1 -0
  49. package/dist/types/src/js/common/font-loader.d.ts +24 -0
  50. package/dist/types/src/js/common/font-loader.d.ts.map +1 -0
  51. package/dist/types/src/js/common/msg.d.ts +3 -0
  52. package/dist/types/src/js/common/msg.d.ts.map +1 -0
  53. package/dist/types/src/js/lit.d.ts +25 -0
  54. package/dist/types/src/js/lit.d.ts.map +1 -0
  55. package/dist/types/src/js/pds-configurator/figma-export.d.ts +13 -0
  56. package/dist/types/src/js/pds-configurator/figma-export.d.ts.map +1 -0
  57. package/dist/types/src/js/pds-configurator/pds-config-form.d.ts +2 -0
  58. package/dist/types/src/js/pds-configurator/pds-config-form.d.ts.map +1 -0
  59. package/dist/types/src/js/pds-configurator/pds-configurator.d.ts +2 -0
  60. package/dist/types/src/js/pds-configurator/pds-configurator.d.ts.map +1 -0
  61. package/dist/types/src/js/pds-configurator/pds-demo.d.ts +2 -0
  62. package/dist/types/src/js/pds-configurator/pds-demo.d.ts.map +1 -0
  63. package/dist/types/src/js/pds-core/pds-config.d.ts +758 -0
  64. package/dist/types/src/js/pds-core/pds-config.d.ts.map +1 -0
  65. package/dist/types/src/js/pds-core/pds-enhancer-metadata.d.ts +6 -0
  66. package/dist/types/src/js/pds-core/pds-enhancer-metadata.d.ts.map +1 -0
  67. package/dist/types/src/js/pds-core/pds-enhancers.d.ts +14 -0
  68. package/dist/types/src/js/pds-core/pds-enhancers.d.ts.map +1 -0
  69. package/dist/types/src/js/pds-core/pds-enums.d.ts +87 -0
  70. package/dist/types/src/js/pds-core/pds-enums.d.ts.map +1 -0
  71. package/dist/types/src/js/pds-core/pds-generator.d.ts +741 -0
  72. package/dist/types/src/js/pds-core/pds-generator.d.ts.map +1 -0
  73. package/dist/types/src/js/pds-core/pds-ontology.d.ts +48 -0
  74. package/dist/types/src/js/pds-core/pds-ontology.d.ts.map +1 -0
  75. package/dist/types/src/js/pds-core/pds-paths.d.ts +37 -0
  76. package/dist/types/src/js/pds-core/pds-paths.d.ts.map +1 -0
  77. package/dist/types/src/js/pds-core/pds-query.d.ts +102 -0
  78. package/dist/types/src/js/pds-core/pds-query.d.ts.map +1 -0
  79. package/dist/types/src/js/pds-core/pds-registry.d.ts +40 -0
  80. package/dist/types/src/js/pds-core/pds-registry.d.ts.map +1 -0
  81. package/dist/types/src/js/pds.d.ts +109 -0
  82. package/dist/types/src/js/pds.d.ts.map +1 -0
  83. package/dist/types/src/pds-core/pds-api.d.ts +31 -0
  84. package/dist/types/src/pds-core/pds-api.d.ts.map +1 -0
  85. package/package.json +104 -0
  86. package/packages/pds-cli/README.md +15 -0
  87. package/packages/pds-cli/bin/generate-css-data.js +565 -0
  88. package/packages/pds-cli/bin/generate-manifest.js +352 -0
  89. package/packages/pds-cli/bin/pds-build-icons.js +152 -0
  90. package/packages/pds-cli/bin/pds-dx.js +114 -0
  91. package/packages/pds-cli/bin/pds-static.js +556 -0
  92. package/packages/pds-cli/bin/pds.js +127 -0
  93. package/packages/pds-cli/bin/postinstall.js +380 -0
  94. package/packages/pds-cli/bin/sync-assets.js +252 -0
  95. package/packages/pds-cli/lib/asset-roots.js +47 -0
  96. package/packages/pds-cli/lib/fs-writer.js +75 -0
  97. package/pds.css-data.json +5 -0
  98. package/pds.html-data.json +5 -0
  99. package/public/assets/js/app.js +5719 -0
  100. package/public/assets/js/lit.js +131 -0
  101. package/public/assets/js/pds.js +3423 -0
  102. package/public/assets/pds/components/pds-calendar.js +837 -0
  103. package/public/assets/pds/components/pds-drawer.js +857 -0
  104. package/public/assets/pds/components/pds-icon.js +338 -0
  105. package/public/assets/pds/components/pds-jsonform.js +1775 -0
  106. package/public/assets/pds/components/pds-richtext.js +1035 -0
  107. package/public/assets/pds/components/pds-scrollrow.js +331 -0
  108. package/public/assets/pds/components/pds-splitpanel.js +401 -0
  109. package/public/assets/pds/components/pds-tabstrip.js +251 -0
  110. package/public/assets/pds/components/pds-toaster.js +446 -0
  111. package/public/assets/pds/components/pds-upload.js +657 -0
  112. package/public/assets/pds/custom-elements.json +2003 -0
  113. package/public/assets/pds/icons/pds-icons.svg +498 -0
  114. package/public/assets/pds/pds-css-complete.json +1861 -0
  115. package/public/assets/pds/pds.css-data.json +2152 -0
  116. package/public/assets/pds/vscode-custom-data.json +824 -0
  117. package/readme.md +1870 -0
  118. package/src/js/pds-core/pds-config.js +1162 -0
  119. package/src/js/pds-core/pds-enhancer-metadata.js +75 -0
  120. package/src/js/pds-core/pds-enhancers.js +357 -0
  121. package/src/js/pds-core/pds-enums.js +86 -0
  122. package/src/js/pds-core/pds-generator.js +5317 -0
  123. package/src/js/pds-core/pds-ontology.js +256 -0
  124. package/src/js/pds-core/pds-paths.js +109 -0
  125. package/src/js/pds-core/pds-query.js +571 -0
  126. package/src/js/pds-core/pds-registry.js +129 -0
  127. package/src/js/pds-core/pds.d.ts +129 -0
  128. package/src/js/pds.d.ts +408 -0
  129. package/src/js/pds.js +1579 -0
@@ -0,0 +1,380 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * NPM postinstall script for @pure-ds/core
5
+ * Automatically copies PDS assets to the consuming app's web root
6
+ */
7
+
8
+ import { readFile, writeFile, mkdir, copyFile, readdir, stat, access, unlink } from 'fs/promises';
9
+ import { readFileSync } from 'fs';
10
+ import { createHash } from 'crypto';
11
+ import path from 'path';
12
+ import { fileURLToPath, pathToFileURL } from 'url';
13
+
14
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
15
+ const repoRoot = path.resolve(__dirname, '../../../');
16
+ const isWin = process.platform === 'win32';
17
+ const normalizePath = (p) => {
18
+ if (!p) return '';
19
+ const resolved = path.resolve(p).replace(/[\\/]+$/, '');
20
+ return isWin ? resolved.toLowerCase() : resolved;
21
+ };
22
+
23
+ /**
24
+ * Check if we're installing within the @pure-ds/core repo itself (not a consumer)
25
+ */
26
+ function isInstallingWithinPureDsRepo() {
27
+ try {
28
+ const cwd = process.cwd();
29
+ const initCwd = process.env.INIT_CWD || cwd;
30
+
31
+ // Check if the INIT_CWD has package.json with name "@pure-ds/core"
32
+ // This is more reliable than path comparison since repoRoot
33
+ // points to node_modules/@pure-ds/core when installed as a dependency
34
+ try {
35
+ const pkgPath = path.join(initCwd, 'package.json');
36
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
37
+ return pkg.name === '@pure-ds/core' || pkg.name === 'pure-ds';
38
+ } catch {
39
+ return false;
40
+ }
41
+ } catch (err) {
42
+ console.log('⚠️ Error checking repo location:', err.message);
43
+ return false;
44
+ }
45
+ }
46
+
47
+ function isNpmLinkInvocation() {
48
+ const truthy = (value) => {
49
+ if (value === undefined || value === null) return false;
50
+ const normalized = String(value).toLowerCase();
51
+ return normalized === 'true' || normalized === '1';
52
+ };
53
+
54
+ if (truthy(process.env.npm_config_link)) return true;
55
+ if ((process.env.npm_command || '').toLowerCase() === 'link') return true;
56
+
57
+ try {
58
+ const argvRaw = process.env.npm_config_argv;
59
+ if (!argvRaw) return false;
60
+ const argv = JSON.parse(argvRaw);
61
+ const orig = argv && (argv.original || argv.cooked || []);
62
+ if (!Array.isArray(orig)) return false;
63
+ return orig.includes('link');
64
+ } catch {
65
+ return false;
66
+ }
67
+ }
68
+
69
+ function isLinkedPackagePath(p) {
70
+ return !/[\\/]+node_modules[\\/]+/i.test(p);
71
+ }
72
+
73
+ function isGlobalInstall() {
74
+ const value = process.env.npm_config_global;
75
+ if (!value) return false;
76
+ const normalized = String(value).toLowerCase();
77
+ return normalized === 'true' || normalized === '1';
78
+ }
79
+
80
+ /**
81
+ * Find the consumer app root (directory containing the consumer's package.json)
82
+ * Prefer INIT_CWD (npm sets this to the original cwd) and fallback by walking up from the package dir
83
+ */
84
+ async function findConsumerRoot() {
85
+ const tryPaths = [];
86
+ if (process.env.INIT_CWD) tryPaths.push(process.env.INIT_CWD);
87
+ // Walk up from the package dir until we exit node_modules
88
+ let dir = repoRoot;
89
+ while (dir && path.basename(dir) !== path.dirname(dir)) {
90
+ if (path.basename(dir) === 'node_modules') {
91
+ const candidate = path.dirname(dir);
92
+ tryPaths.push(candidate);
93
+ break;
94
+ }
95
+ dir = path.dirname(dir);
96
+ }
97
+
98
+ for (const p of tryPaths) {
99
+ try {
100
+ const pkgPath = path.join(p, 'package.json');
101
+ const pkg = JSON.parse(await readFile(pkgPath, 'utf8'));
102
+ if (pkg && pkg.name && pkg.name !== 'pure-ds') {
103
+ return p;
104
+ }
105
+ } catch {}
106
+ }
107
+
108
+ // Final fallback: INIT_CWD or current working dir
109
+ return process.env.INIT_CWD || process.cwd();
110
+ }
111
+
112
+ /**
113
+ * Ensure consumer package.json contains a handy export script
114
+ */
115
+ async function ensureExportScript(consumerRoot) {
116
+ try {
117
+ const consumerPkgPath = path.join(consumerRoot, 'package.json');
118
+ const consumerPkgRaw = await readFile(consumerPkgPath, 'utf8');
119
+ const consumerPkg = JSON.parse(consumerPkgRaw);
120
+
121
+ consumerPkg.scripts = consumerPkg.scripts || {};
122
+
123
+ const desiredScriptName = 'pds:export';
124
+ const desiredScriptCmd = 'pds-export';
125
+
126
+ if (!consumerPkg.scripts[desiredScriptName]) {
127
+ consumerPkg.scripts[desiredScriptName] = desiredScriptCmd;
128
+ await writeFile(consumerPkgPath, JSON.stringify(consumerPkg, null, 2) + '\n');
129
+ console.log(`🧩 Added "${desiredScriptName}" script to consumer package.json`);
130
+ } else {
131
+ console.log(`🔧 Script "${desiredScriptName}" already present in consumer package.json`);
132
+ }
133
+ } catch (e) {
134
+ console.warn('⚠️ Could not ensure pds:export script in consumer package.json:', e.message);
135
+ }
136
+ }
137
+
138
+ /**
139
+ * Discover the web root directory using common patterns
140
+ */
141
+ async function discoverWebRoot(baseDir) {
142
+ const cwd = baseDir || process.env.INIT_CWD || process.cwd();
143
+
144
+ // Common web root patterns (in order of preference)
145
+ const candidates = [
146
+ 'public',
147
+ 'static',
148
+ 'dist',
149
+ 'build',
150
+ 'www',
151
+ 'web',
152
+ 'assets',
153
+ 'src/assets',
154
+ 'app/public',
155
+ '.' // fallback to current directory
156
+ ];
157
+
158
+ console.log('🔍 Discovering web root directory...');
159
+
160
+ for (const candidate of candidates) {
161
+ const fullPath = path.resolve(cwd, candidate);
162
+ try {
163
+ await access(fullPath);
164
+ const stats = await stat(fullPath);
165
+ if (stats.isDirectory()) {
166
+ console.log(` ✅ Found: ${candidate}/`);
167
+ return { path: fullPath, relative: candidate };
168
+ }
169
+ } catch (e) {
170
+ // Directory doesn't exist, continue
171
+ }
172
+ }
173
+
174
+ // Check package.json for hints
175
+ try {
176
+ const packagePath = path.join(cwd, 'package.json');
177
+ const pkg = JSON.parse(await readFile(packagePath, 'utf8'));
178
+
179
+ // Look for common build/output directories in scripts
180
+ const scripts = pkg.scripts || {};
181
+ const scriptText = JSON.stringify(scripts);
182
+
183
+ if (scriptText.includes('--outdir dist') || scriptText.includes('dist/')) {
184
+ const distPath = path.resolve(cwd, 'dist');
185
+ console.log(` 💡 Found "dist" in scripts, using: dist/`);
186
+ return { path: distPath, relative: 'dist' };
187
+ }
188
+
189
+ if (scriptText.includes('--outdir build') || scriptText.includes('build/')) {
190
+ const buildPath = path.resolve(cwd, 'build');
191
+ console.log(` 💡 Found "build" in scripts, using: build/`);
192
+ return { path: buildPath, relative: 'build' };
193
+ }
194
+
195
+ // Check for common framework configs
196
+ if (pkg.dependencies?.['next'] || pkg.devDependencies?.['next']) {
197
+ const publicPath = path.resolve(cwd, 'public');
198
+ console.log(` 🔧 Next.js detected, using: public/`);
199
+ return { path: publicPath, relative: 'public' };
200
+ }
201
+
202
+ if (pkg.dependencies?.['vite'] || pkg.devDependencies?.['vite']) {
203
+ const publicPath = path.resolve(cwd, 'public');
204
+ console.log(` ⚡ Vite detected, using: public/`);
205
+ return { path: publicPath, relative: 'public' };
206
+ }
207
+
208
+ } catch (e) {
209
+ // No package.json or parsing failed
210
+ }
211
+
212
+ // Ultimate fallback: create public directory
213
+ const fallbackPath = path.resolve(cwd, 'public');
214
+ console.log(` 📁 Creating fallback: public/`);
215
+ await mkdir(fallbackPath, { recursive: true });
216
+ return { path: fallbackPath, relative: 'public' };
217
+ }
218
+
219
+ /**
220
+ * Copy PDS assets to the discovered web root
221
+ */
222
+ async function copyPdsAssets() {
223
+ console.log('📦 PDS postinstall running (no automatic component copy)…');
224
+ try {
225
+ const normalizedRepoRoot = normalizePath(repoRoot);
226
+ const normalizedInitCwd = normalizePath(process.env.INIT_CWD || process.cwd());
227
+
228
+ if (isLinkedPackagePath(normalizedRepoRoot)) {
229
+ console.log('🛑 Skipping PDS postinstall (detected symlinked package path).');
230
+ return;
231
+ }
232
+
233
+ if (normalizedInitCwd === normalizedRepoRoot) {
234
+ console.log('🛑 Skipping PDS postinstall (working inside pure-ds repository root).');
235
+ return;
236
+ }
237
+
238
+ if (isNpmLinkInvocation()) {
239
+ console.log('🛑 Skipping PDS postinstall (detected npm link invocation).');
240
+ return;
241
+ }
242
+
243
+ if (isGlobalInstall()) {
244
+ console.log('🛑 Skipping PDS postinstall (global install detected).');
245
+ return;
246
+ }
247
+
248
+ const consumerRoot = await findConsumerRoot();
249
+ console.log('🧪 Consumer root:', consumerRoot);
250
+
251
+ // Allow opting out explicitly (useful for local dev / linking)
252
+ if (
253
+ process.env.PDS_SKIP_POSTINSTALL === '1' ||
254
+ process.env.PDS_SKIP_POSTINSTALL === 'true' ||
255
+ process.env.npm_config_pds_skip_postinstall === 'true'
256
+ ) {
257
+ console.log('⏭️ Skipping PDS postinstall (PDS_SKIP_POSTINSTALL set).');
258
+ return;
259
+ }
260
+
261
+ // If running inside the package repo itself (e.g., during `npm link`), skip
262
+ const inRepo = normalizePath(consumerRoot) === normalizePath(repoRoot);
263
+ const withinPureDs = isInstallingWithinPureDsRepo();
264
+
265
+ if (inRepo || withinPureDs) {
266
+ let reason = 'installing within pure-ds repository';
267
+ if (inRepo) {
268
+ reason = 'inside the package repo';
269
+ } else if (withinPureDs) {
270
+ reason = 'installing within pure-ds repository';
271
+ }
272
+ console.log(`🛑 Skipping PDS postinstall (${reason}).`);
273
+ return;
274
+ }
275
+
276
+ console.log('📦 Proceeding with asset copying...');
277
+
278
+ // Proactively add export & build-icons scripts to consumer package.json (still helpful)
279
+ await ensureExportScript(consumerRoot);
280
+ try {
281
+ const consumerPkgPath = path.join(consumerRoot, 'package.json');
282
+ const pkgRaw = await readFile(consumerPkgPath, 'utf8');
283
+ const pkgJson = JSON.parse(pkgRaw);
284
+ pkgJson.scripts = pkgJson.scripts || {};
285
+ const buildIconsName = 'pds:build-icons';
286
+ const buildIconsCmd = 'pds-build-icons';
287
+ if (!pkgJson.scripts[buildIconsName]) {
288
+ pkgJson.scripts[buildIconsName] = buildIconsCmd;
289
+ await writeFile(consumerPkgPath, JSON.stringify(pkgJson, null, 2) + '\n');
290
+ console.log(`🧩 Added "${buildIconsName}" script to consumer package.json`);
291
+ }
292
+ } catch (e) {
293
+ console.warn('⚠️ Could not ensure pds:build-icons script in consumer package.json:', e?.message || e);
294
+ }
295
+
296
+ // NEW BEHAVIOR: We no longer copy web components automatically to /auto-define/.
297
+ // Reason: static export (pds:export) is now the single source of truth for placing
298
+ // components under [static.root]/components/ (see pds.config.js). This reduces
299
+ // side-effects during npm install and avoids stale/legacy /auto-define/ layout.
300
+ console.log('🚫 Skipping legacy auto-copy of components to ./public/auto-define/.');
301
+
302
+ // Auto-run pds:export by default (can be disabled with PDS_SKIP_EXPORT)
303
+ if (
304
+ process.env.PDS_SKIP_EXPORT === '1' ||
305
+ process.env.PDS_SKIP_EXPORT === 'true' ||
306
+ process.env.npm_config_pds_skip_export === 'true'
307
+ ) {
308
+ console.log('⏭️ Skipping pds:export (PDS_SKIP_EXPORT set)');
309
+ console.log('📦 To generate static assets run: npm run pds:export');
310
+ } else {
311
+ console.log('🚀 Running pds:export automatically...');
312
+ const staticModuleUrl = pathToFileURL(path.join(__dirname, 'pds-static.js')).href;
313
+ const previousEnv = {
314
+ PDS_POSTINSTALL: process.env.PDS_POSTINSTALL,
315
+ PDS_LOG_STREAM: process.env.PDS_LOG_STREAM,
316
+ PDS_CONSUMER_ROOT: process.env.PDS_CONSUMER_ROOT,
317
+ };
318
+
319
+ try {
320
+ process.env.PDS_POSTINSTALL = '1';
321
+ process.env.PDS_LOG_STREAM = 'stderr';
322
+ process.env.PDS_CONSUMER_ROOT = consumerRoot;
323
+
324
+ const { runPdsStatic } = await import(staticModuleUrl);
325
+ await runPdsStatic({ cwd: consumerRoot });
326
+ } catch (e) {
327
+ console.error('❌ Auto-export failed:', e?.message || e);
328
+ console.log('💡 You can run it manually: npm run pds:export');
329
+ } finally {
330
+ if (previousEnv.PDS_POSTINSTALL === undefined) {
331
+ delete process.env.PDS_POSTINSTALL;
332
+ } else {
333
+ process.env.PDS_POSTINSTALL = previousEnv.PDS_POSTINSTALL;
334
+ }
335
+
336
+ if (previousEnv.PDS_LOG_STREAM === undefined) {
337
+ delete process.env.PDS_LOG_STREAM;
338
+ } else {
339
+ process.env.PDS_LOG_STREAM = previousEnv.PDS_LOG_STREAM;
340
+ }
341
+
342
+ if (previousEnv.PDS_CONSUMER_ROOT === undefined) {
343
+ delete process.env.PDS_CONSUMER_ROOT;
344
+ } else {
345
+ process.env.PDS_CONSUMER_ROOT = previousEnv.PDS_CONSUMER_ROOT;
346
+ }
347
+ }
348
+ }
349
+
350
+ console.log('🎨 (Optional) Build custom icons: npm run pds:build-icons');
351
+ console.log('ℹ️ If you previously relied on /auto-define/, update references to the new static output.');
352
+
353
+ // Tracking file for diagnostics (minimal)
354
+ try {
355
+ const webRoot = await discoverWebRoot(consumerRoot);
356
+ const trackingFile = path.join(webRoot.path, '.pds-install.json');
357
+ const tracking = {
358
+ version: '0.1.0',
359
+ installDate: new Date().toISOString(),
360
+ webRoot: webRoot.relative,
361
+ componentsCopied: 0,
362
+ mode: 'no-copy-postinstall',
363
+ };
364
+ await writeFile(trackingFile, JSON.stringify(tracking, null, 2));
365
+ } catch (e) {
366
+ console.warn('⚠️ Could not write tracking file:', e?.message || e);
367
+ }
368
+ } catch (error) {
369
+ console.error('❌ PDS postinstall failed (non-fatal):', error.message);
370
+ console.log('💡 Static export still available via: npm run pds:export');
371
+ process.exitCode = 1;
372
+ }
373
+ }
374
+
375
+ // Only run when called directly (not when imported)
376
+ if (process.argv[1].endsWith('postinstall.js')) {
377
+ copyPdsAssets().catch(console.error);
378
+ }
379
+
380
+ export { copyPdsAssets, discoverWebRoot };
@@ -0,0 +1,252 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { readFile, writeFile, mkdir, copyFile, readdir, stat } from 'fs/promises';
4
+ import { createHash } from 'crypto';
5
+ import path from 'path';
6
+ import { fileURLToPath } from 'url';
7
+
8
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
9
+
10
+ // Find the PDS package root, whether we're running from the package itself or from node_modules
11
+ async function findPdsRoot() {
12
+ const currentDir = __dirname;
13
+
14
+ // If running from the package itself (development)
15
+ if (currentDir.includes('packages/pds-cli/bin')) {
16
+ return path.resolve(currentDir, '../../../');
17
+ }
18
+
19
+ // If running from node_modules (consumer app)
20
+ // The structure would be: node_modules/@pure-ds/core/packages/pds-cli/bin
21
+ if (currentDir.includes('node_modules')) {
22
+ let dir = currentDir;
23
+ while (dir !== path.dirname(dir)) {
24
+ // Support both legacy scoped name and new unscoped name
25
+ // node_modules/@pure-ds/core/... OR node_modules/pure-ds/...
26
+ const base = path.basename(dir);
27
+ const parent = path.basename(path.dirname(dir));
28
+ if ((base === 'core' && parent === '@pure-ds') || base === 'pure-ds') {
29
+ return dir;
30
+ }
31
+ dir = path.dirname(dir);
32
+ }
33
+ }
34
+
35
+ // Fallback - navigate up to find package.json with correct name
36
+ let dir = currentDir;
37
+ while (dir !== path.dirname(dir)) {
38
+ try {
39
+ const packagePath = path.join(dir, 'package.json');
40
+ const pkg = JSON.parse(await readFile(packagePath, 'utf8'));
41
+ if (pkg.name === '@pure-ds/core' || pkg.name === 'pure-ds') {
42
+ return dir;
43
+ }
44
+ } catch (e) {
45
+ // Continue searching
46
+ }
47
+ dir = path.dirname(dir);
48
+ }
49
+
50
+ throw new Error('Could not find PDS package root');
51
+ }
52
+
53
+ /**
54
+ * Sync PDS assets to consuming app's public directory
55
+ * Copies:
56
+ * - public/pds/components/* (or legacy public/auto-define/*) -> <targetDir>/components/*
57
+ * - (icons no longer synced; static export focuses on components and styles)
58
+ *
59
+ * Usage: node node_modules/pure-ds/packages/pds-cli/bin/sync-assets.js [options]
60
+ * Options:
61
+ * --target=<path> Target directory (default: ./public)
62
+ * --force Overwrite user-modified files
63
+ * --dry-run Show what would be synced without copying
64
+ * --verbose, -v Show detailed sync information
65
+ */
66
+
67
+ async function syncAssets(options = {}) {
68
+ const {
69
+ targetDir = './public',
70
+ force = false,
71
+ dryRun = false,
72
+ verbose = false
73
+ } = options;
74
+
75
+ console.log('🔄 Syncing PDS assets...');
76
+
77
+ // Find PDS package root
78
+ const pdsRoot = await findPdsRoot();
79
+
80
+ // Prefer new packaged location; fall back to legacy paths
81
+ let autoDefineSource = path.join(pdsRoot, 'public/assets/pds/components');
82
+ try {
83
+ await stat(autoDefineSource);
84
+ } catch {
85
+ try {
86
+ autoDefineSource = path.join(pdsRoot, 'public/pds/components');
87
+ await stat(autoDefineSource);
88
+ } catch {
89
+ autoDefineSource = path.join(pdsRoot, 'public/auto-define');
90
+ }
91
+ }
92
+
93
+ // Target directories
94
+ const autoDefineTarget = path.join(process.cwd(), targetDir, 'components');
95
+
96
+ // Load or create asset tracking file
97
+ const trackingFile = path.join(process.cwd(), '.pds-assets.json');
98
+ let tracking = {};
99
+
100
+ try {
101
+ const trackingData = await readFile(trackingFile, 'utf-8');
102
+ tracking = JSON.parse(trackingData);
103
+ } catch (e) {
104
+ // First run or corrupted file
105
+ tracking = {
106
+ version: '0.1.0',
107
+ lastSync: null,
108
+ checksums: {},
109
+ userModified: {}
110
+ };
111
+ }
112
+
113
+ const newChecksums = {};
114
+ const conflicts = [];
115
+ const synced = [];
116
+
117
+ // Helper to calculate file hash
118
+ const getFileHash = async (filePath) => {
119
+ try {
120
+ const content = await readFile(filePath);
121
+ return createHash('sha256').update(content).digest('hex');
122
+ } catch (e) {
123
+ return null;
124
+ }
125
+ };
126
+
127
+ // Helper to sync a single file
128
+ const syncFile = async (sourcePath, targetPath, relativeKey) => {
129
+ try {
130
+ // Ensure target directory exists
131
+ await mkdir(path.dirname(targetPath), { recursive: true });
132
+
133
+ const sourceHash = await getFileHash(sourcePath);
134
+ const targetHash = await getFileHash(targetPath);
135
+ const knownHash = tracking.checksums[relativeKey];
136
+
137
+ newChecksums[relativeKey] = sourceHash;
138
+
139
+ // Conflict detection
140
+ if (targetHash && targetHash !== sourceHash && targetHash !== knownHash) {
141
+ conflicts.push({
142
+ file: relativeKey,
143
+ path: targetPath,
144
+ reason: 'User modified file conflicts with PDS update'
145
+ });
146
+
147
+ if (!force) {
148
+ if (verbose) {
149
+ console.log(`⚠️ Skipping ${relativeKey} (user modified)`);
150
+ }
151
+ tracking.userModified[relativeKey] = targetHash;
152
+ return;
153
+ }
154
+ }
155
+
156
+ // Copy file if needed
157
+ if (!targetHash || targetHash !== sourceHash || force) {
158
+ if (!dryRun) {
159
+ await copyFile(sourcePath, targetPath);
160
+ }
161
+ synced.push(relativeKey);
162
+
163
+ if (verbose) {
164
+ console.log(`📁 ${dryRun ? '[DRY RUN] ' : ''}Synced ${relativeKey}`);
165
+ }
166
+ }
167
+ } catch (e) {
168
+ console.warn(`⚠️ Could not sync ${relativeKey}:`, e.message);
169
+ }
170
+ };
171
+
172
+ // Helper to sync a directory
173
+ const syncDirectory = async (sourceDir, targetDir, prefix = '') => {
174
+ try {
175
+ await mkdir(targetDir, { recursive: true });
176
+ const files = await readdir(sourceDir);
177
+
178
+ for (const file of files) {
179
+ const sourcePath = path.join(sourceDir, file);
180
+ const targetPath = path.join(targetDir, file);
181
+ const relativeKey = `${prefix}${file}`;
182
+
183
+ const sourceStat = await stat(sourcePath);
184
+ if (sourceStat.isDirectory()) {
185
+ await syncDirectory(sourcePath, targetPath, `${relativeKey}/`);
186
+ continue;
187
+ }
188
+
189
+ await syncFile(sourcePath, targetPath, relativeKey);
190
+ }
191
+ } catch (e) {
192
+ console.warn(`⚠️ Could not sync ${sourceDir}:`, e.message);
193
+ }
194
+ };
195
+
196
+ // Sync components directory
197
+ if (verbose) {
198
+ console.log('📁 Syncing components...');
199
+ }
200
+ await syncDirectory(autoDefineSource, autoDefineTarget, 'components/');
201
+
202
+ // Note: icons are not synced in this flow; use pds:export if needed
203
+
204
+ // Update tracking file
205
+ if (!dryRun) {
206
+ tracking.checksums = { ...tracking.checksums, ...newChecksums };
207
+ tracking.lastSync = new Date().toISOString();
208
+ await writeFile(trackingFile, JSON.stringify(tracking, null, 2));
209
+ }
210
+
211
+ // Report results
212
+ console.log(`✅ Sync complete: ${synced.length} files updated`);
213
+
214
+ if (conflicts.length > 0) {
215
+ console.log(`⚠️ ${conflicts.length} conflicts detected:`);
216
+ conflicts.forEach(c => {
217
+ console.log(` - ${c.file}: ${c.reason}`);
218
+ });
219
+ console.log(' Use --force to overwrite user modifications');
220
+ }
221
+
222
+ if (verbose) {
223
+ console.log(`📊 Tracking file: ${trackingFile}`);
224
+ console.log(`📁 Components: ${autoDefineTarget}`);
225
+ }
226
+
227
+ return {
228
+ synced: synced.length,
229
+ conflicts: conflicts.length,
230
+ tracking
231
+ };
232
+ }
233
+
234
+ // CLI interface
235
+ if (import.meta.url === `file://${process.argv[1]}`) {
236
+ const args = process.argv.slice(2);
237
+ const options = {
238
+ force: args.includes('--force'),
239
+ dryRun: args.includes('--dry-run'),
240
+ verbose: args.includes('--verbose') || args.includes('-v'),
241
+ targetDir: args.find(arg => arg.startsWith('--target='))?.split('=')[1] || './public'
242
+ };
243
+
244
+ try {
245
+ await syncAssets(options);
246
+ } catch (error) {
247
+ console.error('❌ Sync failed:', error.message);
248
+ process.exit(1);
249
+ }
250
+ }
251
+
252
+ export { syncAssets };
@@ -0,0 +1,47 @@
1
+ import path from 'path';
2
+ import { resolvePublicAssetURL, getPublicRootCandidate, __internal } from '../../../src/js/pds-core/pds-paths.js';
3
+
4
+ const URL_PATTERN = __internal.URL_PATTERN;
5
+ const PDS_SEGMENT = __internal.DEFAULT_SEGMENT;
6
+
7
+ function trimTrailingSeparators(value) {
8
+ return value.replace(/[\\/]+$/, '');
9
+ }
10
+
11
+ export function ensurePdsPath(input) {
12
+ if (!input || typeof input !== 'string') return input;
13
+ let target = trimTrailingSeparators(input);
14
+ if (/[\\/]pds$/i.test(target)) {
15
+ return target;
16
+ }
17
+ return path.join(target, PDS_SEGMENT);
18
+ }
19
+
20
+ export function resolvePublicAssetDirectory(config, options = {}) {
21
+ const webRootPath = options.webRootPath;
22
+ const cwd = options.cwd || process.cwd();
23
+ const overrideRoot = options.overrideRoot;
24
+ const candidate = (overrideRoot ?? getPublicRootCandidate(config)) || '';
25
+
26
+ if (candidate && typeof candidate === 'string' && !URL_PATTERN.test(candidate.trim())) {
27
+ let target = candidate.trim();
28
+ if (target) {
29
+ if (!path.isAbsolute(target)) {
30
+ target = path.resolve(cwd, target);
31
+ }
32
+ return ensurePdsPath(target);
33
+ }
34
+ }
35
+
36
+ if (webRootPath) {
37
+ return ensurePdsPath(path.join(webRootPath, 'assets'));
38
+ }
39
+
40
+ return ensurePdsPath(path.resolve(cwd, 'public', 'assets'));
41
+ }
42
+
43
+ export function isUrlLike(value) {
44
+ return typeof value === 'string' && URL_PATTERN.test(value.trim());
45
+ }
46
+
47
+ export { resolvePublicAssetURL, getPublicRootCandidate };