@wsxjs/wsx-vite-plugin 0.0.23 → 0.0.24

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/dist/index.js CHANGED
@@ -49,30 +49,40 @@ function babelPluginWSXState() {
49
49
  visitor: {
50
50
  Program: {
51
51
  enter(_path, state) {
52
- console.info(
53
- `[Babel Plugin WSX State] DEBUG: state.opts keys = ${Object.keys(state.opts || {}).join(", ")}`
54
- );
55
- console.info(
56
- `[Babel Plugin WSX State] DEBUG: state.opts = ${JSON.stringify(state.opts).substring(0, 200)}`
57
- );
58
52
  const opts = state.opts;
59
- if (opts?.originalSource) {
60
- state.originalSource = opts.originalSource;
53
+ const debug = !!opts?.debug;
54
+ state.showDebugLogs = debug;
55
+ if (debug) {
61
56
  console.info(
62
- `[Babel Plugin WSX State] \u2705 Stored original source from options (length: ${String(opts.originalSource).length})`
57
+ `[Babel Plugin WSX State] DEBUG: state.opts keys = ${Object.keys(state.opts || {}).join(", ")}`
63
58
  );
64
- } else {
65
- console.warn(
66
- `[Babel Plugin WSX State] \u26A0\uFE0F state.opts.originalSource not found, trying fallback...`
59
+ console.info(
60
+ `[Babel Plugin WSX State] DEBUG: state.opts = ${JSON.stringify(state.opts).substring(0, 200)}`
67
61
  );
62
+ }
63
+ if (opts?.originalSource) {
64
+ state.originalSource = opts.originalSource;
65
+ if (debug) {
66
+ console.info(
67
+ `[Babel Plugin WSX State] \u2705 Stored original source from options (length: ${String(opts.originalSource).length})`
68
+ );
69
+ }
70
+ } else {
71
+ if (debug) {
72
+ console.warn(
73
+ `[Babel Plugin WSX State] \u26A0\uFE0F state.opts.originalSource not found, trying fallback...`
74
+ );
75
+ }
68
76
  const file = state.file;
69
77
  if (file) {
70
78
  const sourceCode = file.code;
71
79
  if (sourceCode) {
72
80
  state.originalSource = sourceCode;
73
- console.info(
74
- `[Babel Plugin WSX State] \u2705 Stored original source from file (length: ${sourceCode.length})`
75
- );
81
+ if (debug) {
82
+ console.info(
83
+ `[Babel Plugin WSX State] \u2705 Stored original source from file (length: ${sourceCode.length})`
84
+ );
85
+ }
76
86
  } else {
77
87
  console.error(
78
88
  `[Babel Plugin WSX State] \u274C ERROR: Could not get original source code from state.opts or state.file!`
@@ -86,21 +96,29 @@ function babelPluginWSXState() {
86
96
  }
87
97
  }
88
98
  },
89
- ClassDeclaration(path) {
99
+ ClassDeclaration(path, state) {
100
+ const debug = !!state.showDebugLogs;
101
+ const logInfo = (msg) => {
102
+ if (debug) console.info(msg);
103
+ };
90
104
  const classBody = path.node.body;
91
105
  const stateProperties = [];
92
- console.info(
93
- `[Babel Plugin WSX State] Processing class ${path.node.id?.name || "anonymous"}, members: ${classBody.body.length}`
94
- );
95
- if (path.node.decorators && path.node.decorators.length > 0) {
96
- console.info(
97
- `[Babel Plugin WSX State] Class-level decorators: ${path.node.decorators.length}`
106
+ if (debug) {
107
+ logInfo(
108
+ `[Babel Plugin WSX State] Processing class ${path.node.id?.name || "anonymous"}, members: ${classBody.body.length}`
98
109
  );
110
+ if (path.node.decorators && path.node.decorators.length > 0) {
111
+ logInfo(
112
+ `[Babel Plugin WSX State] Class-level decorators: ${path.node.decorators.length}`
113
+ );
114
+ }
99
115
  }
100
116
  for (const member of classBody.body) {
101
- console.info(
102
- ` - Member type: ${member.type}, key: ${member.type === "ClassProperty" || member.type === "ClassPrivateProperty" ? member.key?.name : "N/A"}`
103
- );
117
+ if (debug) {
118
+ logInfo(
119
+ ` - Member type: ${member.type}, key: ${member.type === "ClassProperty" || member.type === "ClassPrivateProperty" ? member.key?.name : "N/A"}`
120
+ );
121
+ }
104
122
  if ((member.type === "ClassProperty" || member.type === "ClassPrivateProperty") && member.key.type === "Identifier") {
105
123
  const propertyName = member.key.name;
106
124
  const decoratorCount = member.decorators?.length || 0;
@@ -108,12 +126,14 @@ function babelPluginWSXState() {
108
126
  const isUndefined = !!(member.value && (member.value.type === "Identifier" && member.value.name === "undefined" || member.value.type === "UnaryExpression" && member.value.operator === "void"));
109
127
  const valueType = member.value ? member.value.type : "none";
110
128
  const valueName = member.value && member.value.type === "Identifier" ? member.value.name : "none";
111
- console.info(
112
- ` - Property: ${propertyName}, decorators: ${decoratorCount}, hasValue: ${hasValue}, isUndefined: ${isUndefined}, value type: ${valueType}, value name: ${valueName}`
113
- );
129
+ if (debug) {
130
+ logInfo(
131
+ ` - Property: ${propertyName}, decorators: ${decoratorCount}, hasValue: ${hasValue}, isUndefined: ${isUndefined}, value type: ${valueType}, value name: ${valueName}`
132
+ );
133
+ }
114
134
  try {
115
135
  if (isUndefined) {
116
- const originalSource2 = path.state?.originalSource;
136
+ const originalSource2 = state?.originalSource;
117
137
  if (originalSource2) {
118
138
  const escapedPropertyName = propertyName.replace(
119
139
  /[.*+?^${}()|[\]\\]/g,
@@ -150,15 +170,15 @@ Fix: Change to '@state private ${propertyName} = undefined;' or provide a real i
150
170
  }
151
171
  }
152
172
  }
153
- if (propertyName === "count") {
154
- console.info(
155
- `[Babel Plugin WSX State] DEBUG path.state keys for '${propertyName}': ${path.state ? Object.keys(path.state).join(", ") : "null"}`
173
+ if (propertyName === "count" && debug) {
174
+ logInfo(
175
+ `[Babel Plugin WSX State] DEBUG state keys for '${propertyName}': ${state ? Object.keys(state).join(", ") : "null"}`
156
176
  );
157
- console.info(
158
- `[Babel Plugin WSX State] DEBUG path.state.originalSource type: ${path.state ? typeof path.state.originalSource : "path.state is null"}`
177
+ logInfo(
178
+ `[Babel Plugin WSX State] DEBUG state.originalSource type: ${state ? typeof state.originalSource : "state is null"}`
159
179
  );
160
180
  }
161
- const originalSource = path.state?.originalSource;
181
+ const originalSource = state?.originalSource;
162
182
  if (originalSource) {
163
183
  const escapedPropertyName = propertyName.replace(
164
184
  /[.*+?^${}()|[\]\\]/g,
@@ -170,9 +190,11 @@ Fix: Change to '@state private ${propertyName} = undefined;' or provide a real i
170
190
  );
171
191
  const hasStateInSource = propertyPattern.test(originalSource);
172
192
  if (hasStateInSource) {
173
- console.info(
174
- `[Babel Plugin WSX State] Found @state in source for property '${propertyName}' (decorators array was empty: ${decoratorCount})`
175
- );
193
+ if (debug) {
194
+ logInfo(
195
+ `[Babel Plugin WSX State] Found @state in source for property '${propertyName}' (decorators array was empty: ${decoratorCount})`
196
+ );
197
+ }
176
198
  const hasInitialValueInSource = new RegExp(
177
199
  `@state\\s+(?:private|protected|public)?\\s+${escapedPropertyName}\\s*=\\s*[^;]+`,
178
200
  "m"
@@ -204,24 +226,26 @@ Fix: Change to '@state private ${propertyName} = undefined;' or provide a real i
204
226
  }
205
227
  }
206
228
  } else {
207
- if (propertyName === "count") {
229
+ if (propertyName === "count" && debug) {
208
230
  console.warn(
209
231
  `[Babel Plugin WSX State] WARNING: originalSource not available for property '${propertyName}'`
210
232
  );
211
233
  }
212
234
  }
213
235
  if (member.decorators && member.decorators.length > 0) {
214
- member.decorators.forEach((decorator) => {
215
- if (decorator.expression.type === "Identifier") {
216
- console.info(` Decorator: ${decorator.expression.name}`);
217
- } else if (decorator.expression.type === "CallExpression" && decorator.expression.callee.type === "Identifier") {
218
- console.info(
219
- ` Decorator: ${decorator.expression.callee.name}()`
220
- );
221
- } else {
222
- console.info(` Decorator: ${decorator.expression.type}`);
223
- }
224
- });
236
+ if (debug) {
237
+ member.decorators.forEach((decorator) => {
238
+ if (decorator.expression.type === "Identifier") {
239
+ logInfo(` Decorator: ${decorator.expression.name}`);
240
+ } else if (decorator.expression.type === "CallExpression" && decorator.expression.callee.type === "Identifier") {
241
+ logInfo(
242
+ ` Decorator: ${decorator.expression.callee.name}()`
243
+ );
244
+ } else {
245
+ logInfo(` Decorator: ${decorator.expression.type}`);
246
+ }
247
+ });
248
+ }
225
249
  } else {
226
250
  }
227
251
  let hasStateDecorator = false;
@@ -244,7 +268,7 @@ Fix: Change to '@state private ${propertyName} = undefined;' or provide a real i
244
268
  if (hasStateDecorator) {
245
269
  const key = member.key.name;
246
270
  const hasInitialValue = !!(member.value && !(member.value.type === "Identifier" && member.value.name === "undefined") && !(member.value.type === "UnaryExpression" && member.value.operator === "void"));
247
- if (key === "count") {
271
+ if (key === "count" && debug) {
248
272
  console.error(
249
273
  `[Babel Plugin WSX State] DEBUG: hasInitialValue for 'count' = ${hasInitialValue}, type = ${typeof hasInitialValue}`
250
274
  );
@@ -549,19 +573,23 @@ function babelPluginWSXStyle() {
549
573
  name: "babel-plugin-wsx-style",
550
574
  visitor: {
551
575
  Program(path, state) {
552
- const { cssFileExists, cssFilePath, componentName } = state.opts;
576
+ const { cssFileExists, cssFilePath, componentName, debug } = state.opts;
553
577
  if (!cssFileExists) {
554
578
  return;
555
579
  }
556
580
  if (hasStylesImport(path.node)) {
581
+ if (debug) {
582
+ console.info(
583
+ `[Babel Plugin WSX Style] Skipping ${componentName}: styles already manually imported`
584
+ );
585
+ }
586
+ return;
587
+ }
588
+ if (debug) {
557
589
  console.info(
558
- `[Babel Plugin WSX Style] Skipping ${componentName}: styles already manually imported`
590
+ `[Babel Plugin WSX Style] Injecting CSS import for ${componentName}: ${cssFilePath}`
559
591
  );
560
- return;
561
592
  }
562
- console.info(
563
- `[Babel Plugin WSX Style] Injecting CSS import for ${componentName}: ${cssFilePath}`
564
- );
565
593
  const importStatement = t.importDeclaration(
566
594
  [t.importDefaultSpecifier(t.identifier("styles"))],
567
595
  t.stringLiteral(cssFilePath)
@@ -808,7 +836,9 @@ function vitePluginWSXWithBabel(options = {}) {
808
836
  {
809
837
  cssFileExists,
810
838
  cssFilePath,
811
- componentName
839
+ componentName,
840
+ debug: options.debug
841
+ // Pass debug flag
812
842
  }
813
843
  ]
814
844
  ] : [],
@@ -823,8 +853,10 @@ function vitePluginWSXWithBabel(options = {}) {
823
853
  {
824
854
  // Pass ORIGINAL source code (before JSX import injection) to plugin
825
855
  // This ensures we can detect @state decorators even if they're removed by TypeScript preset
826
- originalSource: code
856
+ originalSource: code,
827
857
  // Use original code, not transformedCode
858
+ debug: options.debug
859
+ // Pass debug flag
828
860
  }
829
861
  ],
830
862
  // Decorator plugin runs after our custom plugins
package/dist/index.mjs CHANGED
@@ -13,30 +13,40 @@ function babelPluginWSXState() {
13
13
  visitor: {
14
14
  Program: {
15
15
  enter(_path, state) {
16
- console.info(
17
- `[Babel Plugin WSX State] DEBUG: state.opts keys = ${Object.keys(state.opts || {}).join(", ")}`
18
- );
19
- console.info(
20
- `[Babel Plugin WSX State] DEBUG: state.opts = ${JSON.stringify(state.opts).substring(0, 200)}`
21
- );
22
16
  const opts = state.opts;
23
- if (opts?.originalSource) {
24
- state.originalSource = opts.originalSource;
17
+ const debug = !!opts?.debug;
18
+ state.showDebugLogs = debug;
19
+ if (debug) {
25
20
  console.info(
26
- `[Babel Plugin WSX State] \u2705 Stored original source from options (length: ${String(opts.originalSource).length})`
21
+ `[Babel Plugin WSX State] DEBUG: state.opts keys = ${Object.keys(state.opts || {}).join(", ")}`
27
22
  );
28
- } else {
29
- console.warn(
30
- `[Babel Plugin WSX State] \u26A0\uFE0F state.opts.originalSource not found, trying fallback...`
23
+ console.info(
24
+ `[Babel Plugin WSX State] DEBUG: state.opts = ${JSON.stringify(state.opts).substring(0, 200)}`
31
25
  );
26
+ }
27
+ if (opts?.originalSource) {
28
+ state.originalSource = opts.originalSource;
29
+ if (debug) {
30
+ console.info(
31
+ `[Babel Plugin WSX State] \u2705 Stored original source from options (length: ${String(opts.originalSource).length})`
32
+ );
33
+ }
34
+ } else {
35
+ if (debug) {
36
+ console.warn(
37
+ `[Babel Plugin WSX State] \u26A0\uFE0F state.opts.originalSource not found, trying fallback...`
38
+ );
39
+ }
32
40
  const file = state.file;
33
41
  if (file) {
34
42
  const sourceCode = file.code;
35
43
  if (sourceCode) {
36
44
  state.originalSource = sourceCode;
37
- console.info(
38
- `[Babel Plugin WSX State] \u2705 Stored original source from file (length: ${sourceCode.length})`
39
- );
45
+ if (debug) {
46
+ console.info(
47
+ `[Babel Plugin WSX State] \u2705 Stored original source from file (length: ${sourceCode.length})`
48
+ );
49
+ }
40
50
  } else {
41
51
  console.error(
42
52
  `[Babel Plugin WSX State] \u274C ERROR: Could not get original source code from state.opts or state.file!`
@@ -50,21 +60,29 @@ function babelPluginWSXState() {
50
60
  }
51
61
  }
52
62
  },
53
- ClassDeclaration(path) {
63
+ ClassDeclaration(path, state) {
64
+ const debug = !!state.showDebugLogs;
65
+ const logInfo = (msg) => {
66
+ if (debug) console.info(msg);
67
+ };
54
68
  const classBody = path.node.body;
55
69
  const stateProperties = [];
56
- console.info(
57
- `[Babel Plugin WSX State] Processing class ${path.node.id?.name || "anonymous"}, members: ${classBody.body.length}`
58
- );
59
- if (path.node.decorators && path.node.decorators.length > 0) {
60
- console.info(
61
- `[Babel Plugin WSX State] Class-level decorators: ${path.node.decorators.length}`
70
+ if (debug) {
71
+ logInfo(
72
+ `[Babel Plugin WSX State] Processing class ${path.node.id?.name || "anonymous"}, members: ${classBody.body.length}`
62
73
  );
74
+ if (path.node.decorators && path.node.decorators.length > 0) {
75
+ logInfo(
76
+ `[Babel Plugin WSX State] Class-level decorators: ${path.node.decorators.length}`
77
+ );
78
+ }
63
79
  }
64
80
  for (const member of classBody.body) {
65
- console.info(
66
- ` - Member type: ${member.type}, key: ${member.type === "ClassProperty" || member.type === "ClassPrivateProperty" ? member.key?.name : "N/A"}`
67
- );
81
+ if (debug) {
82
+ logInfo(
83
+ ` - Member type: ${member.type}, key: ${member.type === "ClassProperty" || member.type === "ClassPrivateProperty" ? member.key?.name : "N/A"}`
84
+ );
85
+ }
68
86
  if ((member.type === "ClassProperty" || member.type === "ClassPrivateProperty") && member.key.type === "Identifier") {
69
87
  const propertyName = member.key.name;
70
88
  const decoratorCount = member.decorators?.length || 0;
@@ -72,12 +90,14 @@ function babelPluginWSXState() {
72
90
  const isUndefined = !!(member.value && (member.value.type === "Identifier" && member.value.name === "undefined" || member.value.type === "UnaryExpression" && member.value.operator === "void"));
73
91
  const valueType = member.value ? member.value.type : "none";
74
92
  const valueName = member.value && member.value.type === "Identifier" ? member.value.name : "none";
75
- console.info(
76
- ` - Property: ${propertyName}, decorators: ${decoratorCount}, hasValue: ${hasValue}, isUndefined: ${isUndefined}, value type: ${valueType}, value name: ${valueName}`
77
- );
93
+ if (debug) {
94
+ logInfo(
95
+ ` - Property: ${propertyName}, decorators: ${decoratorCount}, hasValue: ${hasValue}, isUndefined: ${isUndefined}, value type: ${valueType}, value name: ${valueName}`
96
+ );
97
+ }
78
98
  try {
79
99
  if (isUndefined) {
80
- const originalSource2 = path.state?.originalSource;
100
+ const originalSource2 = state?.originalSource;
81
101
  if (originalSource2) {
82
102
  const escapedPropertyName = propertyName.replace(
83
103
  /[.*+?^${}()|[\]\\]/g,
@@ -114,15 +134,15 @@ Fix: Change to '@state private ${propertyName} = undefined;' or provide a real i
114
134
  }
115
135
  }
116
136
  }
117
- if (propertyName === "count") {
118
- console.info(
119
- `[Babel Plugin WSX State] DEBUG path.state keys for '${propertyName}': ${path.state ? Object.keys(path.state).join(", ") : "null"}`
137
+ if (propertyName === "count" && debug) {
138
+ logInfo(
139
+ `[Babel Plugin WSX State] DEBUG state keys for '${propertyName}': ${state ? Object.keys(state).join(", ") : "null"}`
120
140
  );
121
- console.info(
122
- `[Babel Plugin WSX State] DEBUG path.state.originalSource type: ${path.state ? typeof path.state.originalSource : "path.state is null"}`
141
+ logInfo(
142
+ `[Babel Plugin WSX State] DEBUG state.originalSource type: ${state ? typeof state.originalSource : "state is null"}`
123
143
  );
124
144
  }
125
- const originalSource = path.state?.originalSource;
145
+ const originalSource = state?.originalSource;
126
146
  if (originalSource) {
127
147
  const escapedPropertyName = propertyName.replace(
128
148
  /[.*+?^${}()|[\]\\]/g,
@@ -134,9 +154,11 @@ Fix: Change to '@state private ${propertyName} = undefined;' or provide a real i
134
154
  );
135
155
  const hasStateInSource = propertyPattern.test(originalSource);
136
156
  if (hasStateInSource) {
137
- console.info(
138
- `[Babel Plugin WSX State] Found @state in source for property '${propertyName}' (decorators array was empty: ${decoratorCount})`
139
- );
157
+ if (debug) {
158
+ logInfo(
159
+ `[Babel Plugin WSX State] Found @state in source for property '${propertyName}' (decorators array was empty: ${decoratorCount})`
160
+ );
161
+ }
140
162
  const hasInitialValueInSource = new RegExp(
141
163
  `@state\\s+(?:private|protected|public)?\\s+${escapedPropertyName}\\s*=\\s*[^;]+`,
142
164
  "m"
@@ -168,24 +190,26 @@ Fix: Change to '@state private ${propertyName} = undefined;' or provide a real i
168
190
  }
169
191
  }
170
192
  } else {
171
- if (propertyName === "count") {
193
+ if (propertyName === "count" && debug) {
172
194
  console.warn(
173
195
  `[Babel Plugin WSX State] WARNING: originalSource not available for property '${propertyName}'`
174
196
  );
175
197
  }
176
198
  }
177
199
  if (member.decorators && member.decorators.length > 0) {
178
- member.decorators.forEach((decorator) => {
179
- if (decorator.expression.type === "Identifier") {
180
- console.info(` Decorator: ${decorator.expression.name}`);
181
- } else if (decorator.expression.type === "CallExpression" && decorator.expression.callee.type === "Identifier") {
182
- console.info(
183
- ` Decorator: ${decorator.expression.callee.name}()`
184
- );
185
- } else {
186
- console.info(` Decorator: ${decorator.expression.type}`);
187
- }
188
- });
200
+ if (debug) {
201
+ member.decorators.forEach((decorator) => {
202
+ if (decorator.expression.type === "Identifier") {
203
+ logInfo(` Decorator: ${decorator.expression.name}`);
204
+ } else if (decorator.expression.type === "CallExpression" && decorator.expression.callee.type === "Identifier") {
205
+ logInfo(
206
+ ` Decorator: ${decorator.expression.callee.name}()`
207
+ );
208
+ } else {
209
+ logInfo(` Decorator: ${decorator.expression.type}`);
210
+ }
211
+ });
212
+ }
189
213
  } else {
190
214
  }
191
215
  let hasStateDecorator = false;
@@ -208,7 +232,7 @@ Fix: Change to '@state private ${propertyName} = undefined;' or provide a real i
208
232
  if (hasStateDecorator) {
209
233
  const key = member.key.name;
210
234
  const hasInitialValue = !!(member.value && !(member.value.type === "Identifier" && member.value.name === "undefined") && !(member.value.type === "UnaryExpression" && member.value.operator === "void"));
211
- if (key === "count") {
235
+ if (key === "count" && debug) {
212
236
  console.error(
213
237
  `[Babel Plugin WSX State] DEBUG: hasInitialValue for 'count' = ${hasInitialValue}, type = ${typeof hasInitialValue}`
214
238
  );
@@ -513,19 +537,23 @@ function babelPluginWSXStyle() {
513
537
  name: "babel-plugin-wsx-style",
514
538
  visitor: {
515
539
  Program(path, state) {
516
- const { cssFileExists, cssFilePath, componentName } = state.opts;
540
+ const { cssFileExists, cssFilePath, componentName, debug } = state.opts;
517
541
  if (!cssFileExists) {
518
542
  return;
519
543
  }
520
544
  if (hasStylesImport(path.node)) {
545
+ if (debug) {
546
+ console.info(
547
+ `[Babel Plugin WSX Style] Skipping ${componentName}: styles already manually imported`
548
+ );
549
+ }
550
+ return;
551
+ }
552
+ if (debug) {
521
553
  console.info(
522
- `[Babel Plugin WSX Style] Skipping ${componentName}: styles already manually imported`
554
+ `[Babel Plugin WSX Style] Injecting CSS import for ${componentName}: ${cssFilePath}`
523
555
  );
524
- return;
525
556
  }
526
- console.info(
527
- `[Babel Plugin WSX Style] Injecting CSS import for ${componentName}: ${cssFilePath}`
528
- );
529
557
  const importStatement = t.importDeclaration(
530
558
  [t.importDefaultSpecifier(t.identifier("styles"))],
531
559
  t.stringLiteral(cssFilePath)
@@ -772,7 +800,9 @@ function vitePluginWSXWithBabel(options = {}) {
772
800
  {
773
801
  cssFileExists,
774
802
  cssFilePath,
775
- componentName
803
+ componentName,
804
+ debug: options.debug
805
+ // Pass debug flag
776
806
  }
777
807
  ]
778
808
  ] : [],
@@ -787,8 +817,10 @@ function vitePluginWSXWithBabel(options = {}) {
787
817
  {
788
818
  // Pass ORIGINAL source code (before JSX import injection) to plugin
789
819
  // This ensures we can detect @state decorators even if they're removed by TypeScript preset
790
- originalSource: code
820
+ originalSource: code,
791
821
  // Use original code, not transformedCode
822
+ debug: options.debug
823
+ // Pass debug flag
792
824
  }
793
825
  ],
794
826
  // Decorator plugin runs after our custom plugins
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wsxjs/wsx-vite-plugin",
3
- "version": "0.0.23",
3
+ "version": "0.0.24",
4
4
  "description": "Vite plugin for WSXJS",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -31,7 +31,7 @@
31
31
  "@babel/plugin-transform-class-static-block": "^7.28.0",
32
32
  "@babel/preset-typescript": "^7.28.5",
33
33
  "@babel/types": "^7.28.1",
34
- "@wsxjs/wsx-core": "0.0.23"
34
+ "@wsxjs/wsx-core": "0.0.24"
35
35
  },
36
36
  "devDependencies": {
37
37
  "@babel/traverse": "^7.28.5",
@@ -1,5 +1,6 @@
1
1
  /**
2
2
  * Babel plugin to automatically add data-wsx-key attributes to focusable elements
3
+ * for focus preservation only (RFC-0046).
3
4
  *
4
5
  * Transforms:
5
6
  * <input value={this.name} onInput={this.handleInput} />
@@ -12,6 +13,10 @@
12
13
  * />
13
14
  *
14
15
  * This enables automatic focus preservation during component rerenders.
16
+ *
17
+ * IMPORTANT: This plugin ONLY handles focus preservation. It does NOT generate
18
+ * cache keys or position IDs. The framework handles cache key generation using
19
+ * user-provided `key` prop or runtime counters (following React/Vue design).
15
20
  */
16
21
 
17
22
  import type { PluginObj, NodePath } from "@babel/core";
@@ -23,6 +23,7 @@ interface WSXStatePluginPass extends PluginPass {
23
23
  isObject: boolean;
24
24
  isArray?: boolean; // Add isArray flag
25
25
  }>;
26
+ showDebugLogs?: boolean;
26
27
  reactiveMethodName: string;
27
28
  }
28
29
 
@@ -33,26 +34,36 @@ export default function babelPluginWSXState(): PluginObj<WSXStatePluginPass> {
33
34
  visitor: {
34
35
  Program: {
35
36
  enter(_path, state) {
36
- // CRITICAL: Debug log to check state.opts
37
- console.info(
38
- `[Babel Plugin WSX State] DEBUG: state.opts keys = ${Object.keys(state.opts || {}).join(", ")}`
39
- );
40
- console.info(
41
- `[Babel Plugin WSX State] DEBUG: state.opts = ${JSON.stringify(state.opts).substring(0, 200)}`
42
- );
37
+ const opts = state.opts as Record<string, unknown> | undefined;
38
+ const debug = !!opts?.debug;
39
+ // Store debug flag in state for other visitors
40
+ (state as any).showDebugLogs = debug;
41
+
42
+ if (debug) {
43
+ // CRITICAL: Debug log to check state.opts
44
+ console.info(
45
+ `[Babel Plugin WSX State] DEBUG: state.opts keys = ${Object.keys(state.opts || {}).join(", ")}`
46
+ );
47
+ console.info(
48
+ `[Babel Plugin WSX State] DEBUG: state.opts = ${JSON.stringify(state.opts).substring(0, 200)}`
49
+ );
50
+ }
43
51
 
44
52
  // Store original source code for later checking
45
53
  // First try to get from plugin options (passed from vite plugin)
46
- const opts = state.opts as Record<string, unknown> | undefined;
47
54
  if (opts?.originalSource) {
48
55
  (state as Record<string, unknown>).originalSource = opts.originalSource;
49
- console.info(
50
- `[Babel Plugin WSX State] ✅ Stored original source from options (length: ${String(opts.originalSource).length})`
51
- );
56
+ if (debug) {
57
+ console.info(
58
+ `[Babel Plugin WSX State] ✅ Stored original source from options (length: ${String(opts.originalSource).length})`
59
+ );
60
+ }
52
61
  } else {
53
- console.warn(
54
- `[Babel Plugin WSX State] ⚠️ state.opts.originalSource not found, trying fallback...`
55
- );
62
+ if (debug) {
63
+ console.warn(
64
+ `[Babel Plugin WSX State] ⚠️ state.opts.originalSource not found, trying fallback...`
65
+ );
66
+ }
56
67
  // Fallback: try to get from file
57
68
  const file = state.file;
58
69
  if (file) {
@@ -61,9 +72,11 @@ export default function babelPluginWSXState(): PluginObj<WSXStatePluginPass> {
61
72
  | undefined;
62
73
  if (sourceCode) {
63
74
  (state as Record<string, unknown>).originalSource = sourceCode;
64
- console.info(
65
- `[Babel Plugin WSX State] ✅ Stored original source from file (length: ${sourceCode.length})`
66
- );
75
+ if (debug) {
76
+ console.info(
77
+ `[Babel Plugin WSX State] ✅ Stored original source from file (length: ${sourceCode.length})`
78
+ );
79
+ }
67
80
  } else {
68
81
  console.error(
69
82
  `[Babel Plugin WSX State] ❌ ERROR: Could not get original source code from state.opts or state.file!`
@@ -77,7 +90,11 @@ export default function babelPluginWSXState(): PluginObj<WSXStatePluginPass> {
77
90
  }
78
91
  },
79
92
  },
80
- ClassDeclaration(path) {
93
+ ClassDeclaration(path, state) {
94
+ const debug = !!(state as any).showDebugLogs;
95
+ const logInfo = (msg: string) => {
96
+ if (debug) console.info(msg);
97
+ };
81
98
  const classBody = path.node.body;
82
99
  const stateProperties: Array<{
83
100
  key: string;
@@ -88,23 +105,27 @@ export default function babelPluginWSXState(): PluginObj<WSXStatePluginPass> {
88
105
 
89
106
  // Find all @state decorated properties
90
107
  // Debug: log all class members
91
- console.info(
92
- `[Babel Plugin WSX State] Processing class ${path.node.id?.name || "anonymous"}, members: ${classBody.body.length}`
93
- );
94
-
95
- // CRITICAL: Log all decorators at class level to debug
96
- if (path.node.decorators && path.node.decorators.length > 0) {
97
- console.info(
98
- `[Babel Plugin WSX State] Class-level decorators: ${path.node.decorators.length}`
108
+ if (debug) {
109
+ logInfo(
110
+ `[Babel Plugin WSX State] Processing class ${path.node.id?.name || "anonymous"}, members: ${classBody.body.length}`
99
111
  );
112
+
113
+ // CRITICAL: Log all decorators at class level to debug
114
+ if (path.node.decorators && path.node.decorators.length > 0) {
115
+ logInfo(
116
+ `[Babel Plugin WSX State] Class-level decorators: ${path.node.decorators.length}`
117
+ );
118
+ }
100
119
  }
101
120
 
102
121
  for (const member of classBody.body) {
103
122
  // Debug: log member type
104
123
 
105
- console.info(
106
- ` - Member type: ${member.type}, key: ${member.type === "ClassProperty" || member.type === "ClassPrivateProperty" ? (member.key as any)?.name : "N/A"}`
107
- );
124
+ if (debug) {
125
+ logInfo(
126
+ ` - Member type: ${member.type}, key: ${member.type === "ClassProperty" || member.type === "ClassPrivateProperty" ? (member.key as any)?.name : "N/A"}`
127
+ );
128
+ }
108
129
 
109
130
  // Check both ClassProperty and ClassPrivateProperty
110
131
  // @babel/plugin-proposal-class-properties might convert them
@@ -143,16 +164,18 @@ export default function babelPluginWSXState(): PluginObj<WSXStatePluginPass> {
143
164
  ? (member.value as t.Identifier).name
144
165
  : "none";
145
166
 
146
- console.info(
147
- ` - Property: ${propertyName}, decorators: ${decoratorCount}, hasValue: ${hasValue}, isUndefined: ${isUndefined}, value type: ${valueType}, value name: ${valueName}`
148
- );
167
+ if (debug) {
168
+ logInfo(
169
+ ` - Property: ${propertyName}, decorators: ${decoratorCount}, hasValue: ${hasValue}, isUndefined: ${isUndefined}, value type: ${valueType}, value name: ${valueName}`
170
+ );
171
+ }
149
172
 
150
173
  // Wrap the entire detection logic in try-catch to pinpoint crash location
151
174
  try {
152
175
  // CRITICAL: If property has undefined value, check source code for @state decorator
153
176
  // This handles the case where decorator was removed but property has undefined from optional syntax
154
177
  if (isUndefined) {
155
- const originalSource = (path.state as Record<string, unknown>)
178
+ const originalSource = (state as Record<string, unknown>)
156
179
  ?.originalSource as string | undefined;
157
180
  if (originalSource) {
158
181
  // Escape special regex characters in property name
@@ -197,17 +220,17 @@ export default function babelPluginWSXState(): PluginObj<WSXStatePluginPass> {
197
220
  // Even if decorators array is empty (decorators: 0), the decorator might exist in source
198
221
  // This is the main way to detect @state when decorators are removed before our plugin runs
199
222
 
200
- // DEBUG: Check path.state structure
201
- if (propertyName === "count") {
202
- console.info(
203
- `[Babel Plugin WSX State] DEBUG path.state keys for '${propertyName}': ${path.state ? Object.keys(path.state).join(", ") : "null"}`
223
+ // DEBUG: Check state structure
224
+ if (propertyName === "count" && debug) {
225
+ logInfo(
226
+ `[Babel Plugin WSX State] DEBUG state keys for '${propertyName}': ${state ? Object.keys(state).join(", ") : "null"}`
204
227
  );
205
- console.info(
206
- `[Babel Plugin WSX State] DEBUG path.state.originalSource type: ${path.state ? typeof (path.state as any).originalSource : "path.state is null"}`
228
+ logInfo(
229
+ `[Babel Plugin WSX State] DEBUG state.originalSource type: ${state ? typeof (state as any).originalSource : "state is null"}`
207
230
  );
208
231
  }
209
232
 
210
- const originalSource = (path.state as Record<string, unknown>)
233
+ const originalSource = (state as Record<string, unknown>)
211
234
  ?.originalSource as string | undefined;
212
235
 
213
236
  if (originalSource) {
@@ -225,9 +248,11 @@ export default function babelPluginWSXState(): PluginObj<WSXStatePluginPass> {
225
248
 
226
249
  const hasStateInSource = propertyPattern.test(originalSource);
227
250
  if (hasStateInSource) {
228
- console.info(
229
- `[Babel Plugin WSX State] Found @state in source for property '${propertyName}' (decorators array was empty: ${decoratorCount})`
230
- );
251
+ if (debug) {
252
+ logInfo(
253
+ `[Babel Plugin WSX State] Found @state in source for property '${propertyName}' (decorators array was empty: ${decoratorCount})`
254
+ );
255
+ }
231
256
  // Found @state in source but decorators array is empty
232
257
  // Check if it has an initial value in source (not just undefined from TypeScript)
233
258
  // Escape special regex characters in property name (already escaped above, reuse)
@@ -265,7 +290,7 @@ export default function babelPluginWSXState(): PluginObj<WSXStatePluginPass> {
265
290
  }
266
291
  } else {
267
292
  // Log when originalSource is not available for debugging
268
- if (propertyName === "count") {
293
+ if (propertyName === "count" && debug) {
269
294
  console.warn(
270
295
  `[Babel Plugin WSX State] WARNING: originalSource not available for property '${propertyName}'`
271
296
  );
@@ -274,20 +299,22 @@ export default function babelPluginWSXState(): PluginObj<WSXStatePluginPass> {
274
299
 
275
300
  if (member.decorators && member.decorators.length > 0) {
276
301
  // Debug: log decorator names
277
- member.decorators.forEach((decorator) => {
278
- if (decorator.expression.type === "Identifier") {
279
- console.info(` Decorator: ${decorator.expression.name}`);
280
- } else if (
281
- decorator.expression.type === "CallExpression" &&
282
- decorator.expression.callee.type === "Identifier"
283
- ) {
284
- console.info(
285
- ` Decorator: ${decorator.expression.callee.name}()`
286
- );
287
- } else {
288
- console.info(` Decorator: ${decorator.expression.type}`);
289
- }
290
- });
302
+ if (debug) {
303
+ member.decorators.forEach((decorator) => {
304
+ if (decorator.expression.type === "Identifier") {
305
+ logInfo(` Decorator: ${decorator.expression.name}`);
306
+ } else if (
307
+ decorator.expression.type === "CallExpression" &&
308
+ decorator.expression.callee.type === "Identifier"
309
+ ) {
310
+ logInfo(
311
+ ` Decorator: ${decorator.expression.callee.name}()`
312
+ );
313
+ } else {
314
+ logInfo(` Decorator: ${decorator.expression.type}`);
315
+ }
316
+ });
317
+ }
291
318
  } else {
292
319
  // Check if this property might have had @state decorator but it was removed
293
320
  // This can happen if TypeScript preset or another plugin processed it first
@@ -343,7 +370,7 @@ export default function babelPluginWSXState(): PluginObj<WSXStatePluginPass> {
343
370
  );
344
371
 
345
372
  // DEBUG: Log hasInitialValue for count
346
- if (key === "count") {
373
+ if (key === "count" && debug) {
347
374
  console.error(
348
375
  `[Babel Plugin WSX State] DEBUG: hasInitialValue for 'count' = ${hasInitialValue}, type = ${typeof hasInitialValue}`
349
376
  );
@@ -21,6 +21,7 @@ interface WSXStylePluginPass extends PluginPass {
21
21
  cssFileExists: boolean;
22
22
  cssFilePath: string;
23
23
  componentName: string;
24
+ debug?: boolean;
24
25
  }
25
26
 
26
27
  /**
@@ -70,7 +71,7 @@ export default function babelPluginWSXStyle(): PluginObj<WSXStylePluginPass> {
70
71
  name: "babel-plugin-wsx-style",
71
72
  visitor: {
72
73
  Program(path, state) {
73
- const { cssFileExists, cssFilePath, componentName } =
74
+ const { cssFileExists, cssFilePath, componentName, debug } =
74
75
  state.opts as WSXStylePluginPass;
75
76
 
76
77
  // Skip if CSS file doesn't exist
@@ -80,15 +81,19 @@ export default function babelPluginWSXStyle(): PluginObj<WSXStylePluginPass> {
80
81
 
81
82
  // Check if styles are already manually imported
82
83
  if (hasStylesImport(path.node)) {
83
- console.info(
84
- `[Babel Plugin WSX Style] Skipping ${componentName}: styles already manually imported`
85
- );
84
+ if (debug) {
85
+ console.info(
86
+ `[Babel Plugin WSX Style] Skipping ${componentName}: styles already manually imported`
87
+ );
88
+ }
86
89
  return; // Skip auto-injection if manual import exists
87
90
  }
88
91
 
89
- console.info(
90
- `[Babel Plugin WSX Style] Injecting CSS import for ${componentName}: ${cssFilePath}`
91
- );
92
+ if (debug) {
93
+ console.info(
94
+ `[Babel Plugin WSX Style] Injecting CSS import for ${componentName}: ${cssFilePath}`
95
+ );
96
+ }
92
97
 
93
98
  // Add CSS import at the top of the file
94
99
  const importStatement = t.importDeclaration(
@@ -126,6 +126,7 @@ export function vitePluginWSXWithBabel(options: WSXPluginOptions = {}): Plugin {
126
126
  cssFileExists,
127
127
  cssFilePath,
128
128
  componentName,
129
+ debug: options.debug, // Pass debug flag
129
130
  },
130
131
  ],
131
132
  ]
@@ -142,6 +143,7 @@ export function vitePluginWSXWithBabel(options: WSXPluginOptions = {}): Plugin {
142
143
  // Pass ORIGINAL source code (before JSX import injection) to plugin
143
144
  // This ensures we can detect @state decorators even if they're removed by TypeScript preset
144
145
  originalSource: code, // Use original code, not transformedCode
146
+ debug: options.debug, // Pass debug flag
145
147
  },
146
148
  ],
147
149
  // Decorator plugin runs after our custom plugins