codeplay-common 4.10.1 → 4.10.2

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.
@@ -5,12 +5,137 @@ const fs = require('fs');
5
5
  const path = require('path');
6
6
  const plist = require('plist');
7
7
 
8
- // Preserve comments, strings, and custom tree-shaking objects/functions.
9
- // Only migrate the explicit boolean opt-out used by older Codeplay configs.
10
- const migrateViteTreeShaking = (content) => content.replace(
11
- /\/\*[\s\S]*?\*\/|\/\/[^\r\n]*|"(?:\\[\s\S]|[^"\\])*"|'(?:\\[\s\S]|[^'\\])*'|`(?:\\[\s\S]|[^`\\])*`|\btreeshake([ \t]*:[ \t]*)false\b/g,
12
- (match, separator) => separator === undefined ? match : `treeshake${separator}true`
13
- );
8
+ // Edit only build.rollupOptions.treeshake in the exported Vite config.
9
+ // Keep source formatting/comments and valid custom option objects intact.
10
+ const migrateViteTreeShaking = (content) => {
11
+ const newline = content.includes('\r\n') ? '\r\n' : '\n';
12
+ const tokens = [];
13
+ const pairs = new Map();
14
+ const stack = [];
15
+ const lexer = /\s+|\/\*[\s\S]*?\*\/|\/\/[^\r\n]*|"(?:\\[\s\S]|[^"\\])*"|'(?:\\[\s\S]|[^'\\])*'|`(?:\\[\s\S]|[^`\\])*`|=>|\.\.\.|[\w$]+|[^\s]/gy;
16
+ let match;
17
+ while ((match = lexer.exec(content))) {
18
+ const value = match[0];
19
+ if (/^\s|^\/\*|^\/\//.test(value)) continue;
20
+ // Regex literals may contain braces/commas; treat them as a single value.
21
+ if (value === '/' && (!tokens.length || /^(?:=|\(|\[|:|,|return|=>|!|\?|\||&)$/.test(tokens.at(-1).value))) {
22
+ const regex = /^\/(?:\\[^\r\n]|\[(?:\\[^\r\n]|[^\]\\\r\n])*\]|[^/\\[\r\n])+\/[a-z]*/.exec(content.slice(match.index));
23
+ if (!regex) throw new Error('Cannot safely read Vite regex literal; configuration preserved.');
24
+ lexer.lastIndex = match.index + regex[0].length;
25
+ tokens.push({ value: regex[0], start: match.index, end: lexer.lastIndex });
26
+ continue;
27
+ }
28
+ const index = tokens.length;
29
+ tokens.push({ value, start: match.index, end: lexer.lastIndex });
30
+ if (['{', '[', '('].includes(value)) stack.push(index);
31
+ else if (['}', ']', ')'].includes(value)) {
32
+ const open = stack.pop();
33
+ if (open === undefined || tokens[open].value !== ({ '}': '{', ']': '[', ')': '(' })[value]) {
34
+ throw new Error('Cannot safely read Vite configuration; file preserved.');
35
+ }
36
+ pairs.set(open, index);
37
+ }
38
+ }
39
+ if (stack.length) throw new Error('Unbalanced Vite configuration; file preserved.');
40
+ const value = index => tokens[index]?.value;
41
+ const edits = [];
42
+ const properties = open => {
43
+ const result = [];
44
+ const close = pairs.get(open);
45
+ for (let i = open + 1; i < close;) {
46
+ if (value(i) === ',') { i++; continue; }
47
+ const start = i;
48
+ let key = i;
49
+ if (value(i) === '[') {
50
+ if (pairs.get(i) !== i + 2 || !/^['"]/.test(value(i + 1))) throw new Error('Dynamic Vite property name; file preserved.');
51
+ key = i + 1;
52
+ }
53
+ const accessor = ['get', 'set'].includes(value(i)) && value(i + 2) === '(';
54
+ if (accessor) key = i + 1;
55
+ const name = value(key).replace(/^(['"])(.*)\1$/, '$2');
56
+ const afterKey = value(start) === '[' ? pairs.get(start) + 1 : key + 1;
57
+ const colon = value(afterKey) === ':';
58
+ while (i < close && value(i) !== ',') i = pairs.has(i) ? pairs.get(i) + 1 : i + 1;
59
+ if (colon || (key === start && i === start + 1) || value(afterKey) === '(') {
60
+ result.push({ name, start, first: colon ? afterKey + 1 : start, end: i, comma: value(i) === ',', colon });
61
+ }
62
+ }
63
+ return result;
64
+ };
65
+ const findConfig = (index, visited = new Set()) => {
66
+ if (visited.has(index)) throw new Error('Circular Vite configuration reference; file preserved.');
67
+ visited.add(index);
68
+ if (value(index) === 'async') return findConfig(index + 1, visited);
69
+ if (value(index) === '(') {
70
+ const close = pairs.get(index);
71
+ if (value(close + 1) === '=>') return findBody(close + 2, visited);
72
+ return findConfig(index + 1, visited);
73
+ }
74
+ if (value(index + 1) === '=>') return findBody(index + 2, visited);
75
+ if (value(index) === 'function') {
76
+ let body = index + 1;
77
+ while (body < tokens.length && value(body) !== '{') body++;
78
+ return findBody(body, visited);
79
+ }
80
+ if (value(index) === '{') return index;
81
+ if (value(index + 1) === '(') return findConfig(index + 2, visited);
82
+ const declaration = tokens.findIndex((token, i) => ['const', 'let', 'var'].includes(token.value) && value(i + 1) === value(index) && value(i + 2) === '=');
83
+ if (declaration >= 0) return findConfig(declaration + 3, visited);
84
+ throw new Error('Unsupported dynamic Vite config; cannot safely set treeshake. File preserved.');
85
+ };
86
+ const findBody = (index, visited) => {
87
+ if (value(index) !== '{') return findConfig(index, visited);
88
+ const returns = [];
89
+ for (let i = index + 1; i < pairs.get(index); i++) {
90
+ if (value(i) === 'return') returns.push(i + 1);
91
+ if (pairs.has(i)) i = pairs.get(i);
92
+ }
93
+ if (returns.length !== 1) throw new Error('Vite config must return one static object for automatic treeshake migration. File preserved.');
94
+ return findConfig(returns[0], visited);
95
+ };
96
+ const append = (open, property) => {
97
+ const close = pairs.get(open);
98
+ const last = tokens[close - 1];
99
+ const line = content.slice(content.lastIndexOf('\n', tokens[open].start) + 1, tokens[open].start);
100
+ const indent = line.match(/^[ \t]*/)[0];
101
+ const needsComma = close > open + 1 && last.value !== ',';
102
+ const inlineComma = needsComma && last.end === tokens[close].start;
103
+ if (needsComma && !inlineComma) edits.push({ start: last.end, end: last.end, text: ',' });
104
+ edits.push({ start: tokens[close].start, end: tokens[close].start, text: `${inlineComma ? ',' : ''}${newline}${indent} ${property},${newline}${indent}` });
105
+ };
106
+ let exported = tokens.findIndex((token, i) => token.value === 'export' && value(i + 1) === 'default');
107
+ if (exported >= 0) exported += 2;
108
+ else {
109
+ exported = tokens.findIndex((token, i) => token.value === 'module' && value(i + 1) === '.' && value(i + 2) === 'exports' && value(i + 3) === '=');
110
+ if (exported >= 0) exported += 4;
111
+ }
112
+ if (exported < 0) throw new Error('No supported Vite config export found; file preserved.');
113
+ const config = findConfig(exported);
114
+ const build = properties(config).filter(property => property.name === 'build').at(-1);
115
+ if (!build) append(config, 'build: { rollupOptions: { treeshake: true } }');
116
+ else {
117
+ if (value(build.first) !== '{' || pairs.get(build.first) !== build.end - 1) throw new Error('Dynamic Vite build settings; file preserved.');
118
+ const rollup = properties(build.first).filter(property => property.name === 'rollupOptions').at(-1);
119
+ if (!rollup) append(build.first, 'rollupOptions: { treeshake: true }');
120
+ else {
121
+ if (value(rollup.first) !== '{' || pairs.get(rollup.first) !== rollup.end - 1) throw new Error('Dynamic Vite rollupOptions; file preserved.');
122
+ const entries = properties(rollup.first).filter(property => property.name === 'treeshake');
123
+ if (!entries.length) append(rollup.first, 'treeshake: true');
124
+ else {
125
+ // JavaScript uses the last duplicate; retain that setting and remove earlier ones.
126
+ const keep = entries.at(-1);
127
+ for (const entry of entries.slice(0, -1)) {
128
+ edits.push({ start: tokens[entry.start].start, end: entry.comma ? tokens[entry.end].end : tokens[entry.end - 1].end, text: '' });
129
+ }
130
+ const isTrue = value(keep.first) === 'true' && keep.end === keep.first + 1;
131
+ const isObject = value(keep.first) === '{' && pairs.get(keep.first) === keep.end - 1;
132
+ if (!isTrue && !isObject) edits.push({ start: tokens[keep.first].start, end: tokens[keep.end - 1].end, text: keep.colon ? 'true' : 'treeshake: true' });
133
+ }
134
+ }
135
+ }
136
+ for (const edit of edits.sort((a, b) => b.start - a.start)) content = content.slice(0, edit.start) + edit.text + content.slice(edit.end);
137
+ return content;
138
+ };
14
139
 
15
140
 
16
141
 
@@ -2952,7 +3077,7 @@ const syncViteTreeShaking = () => {
2952
3077
  const next = migrateViteTreeShaking(current);
2953
3078
  if (next !== current) {
2954
3079
  fs.writeFileSync(configPath, next, 'utf8');
2955
- console.log('✅ Enabled Vite tree shaking for common JavaScript and other unused exports.');
3080
+ console.log('✅ Vite treeshake setting updated without duplicate entries.');
2956
3081
  }
2957
3082
  };
2958
3083
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeplay-common",
3
- "version": "4.10.1",
3
+ "version": "4.10.2",
4
4
  "description": "Common build scripts and files",
5
5
  "scripts": {
6
6
  "postinstall": "node scripts/sync-files.js",