@fynixorg/ui 1.0.11 → 1.0.12

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 (127) hide show
  1. package/LICENSE +21 -0
  2. package/dist/README.md +36 -0
  3. package/dist/context/context.d.ts +19 -0
  4. package/dist/context/context.d.ts.map +1 -0
  5. package/dist/context/context.js +3 -11
  6. package/dist/context/context.js.map +3 -3
  7. package/dist/custom/button.d.ts +2 -0
  8. package/dist/custom/button.d.ts.map +1 -0
  9. package/dist/custom/button.js +2 -9
  10. package/dist/custom/button.js.map +3 -3
  11. package/dist/custom/index.d.ts +3 -0
  12. package/dist/custom/index.d.ts.map +1 -0
  13. package/dist/custom/index.js +2 -7
  14. package/dist/custom/index.js.map +3 -3
  15. package/dist/custom/path.d.ts +14 -0
  16. package/dist/custom/path.d.ts.map +1 -0
  17. package/dist/custom/path.js +17 -34
  18. package/dist/custom/path.js.map +3 -3
  19. package/dist/error/errorOverlay.d.ts +3 -0
  20. package/dist/error/errorOverlay.d.ts.map +1 -0
  21. package/dist/error/errorOverlay.js +82 -91
  22. package/dist/error/errorOverlay.js.map +3 -3
  23. package/dist/fynix/index.d.ts +5 -0
  24. package/dist/fynix/index.d.ts.map +1 -0
  25. package/dist/fynix/index.js +2 -7
  26. package/dist/fynix/index.js.map +3 -3
  27. package/dist/hooks/nixAsync.d.ts +14 -0
  28. package/dist/hooks/nixAsync.d.ts.map +1 -0
  29. package/dist/hooks/nixAsync.js +38 -43
  30. package/dist/hooks/nixAsync.js.map +3 -3
  31. package/dist/hooks/nixAsyncCache.d.ts +14 -0
  32. package/dist/hooks/nixAsyncCache.d.ts.map +1 -0
  33. package/dist/hooks/nixAsyncCache.js +57 -59
  34. package/dist/hooks/nixAsyncCache.js.map +3 -3
  35. package/dist/hooks/nixAsyncDebounce.d.ts +22 -0
  36. package/dist/hooks/nixAsyncDebounce.d.ts.map +1 -0
  37. package/dist/hooks/nixAsyncDebounce.js +74 -85
  38. package/dist/hooks/nixAsyncDebounce.js.map +3 -3
  39. package/dist/hooks/nixAsyncQuery.d.ts +16 -0
  40. package/dist/hooks/nixAsyncQuery.d.ts.map +1 -0
  41. package/dist/hooks/nixAsyncQuery.js +85 -79
  42. package/dist/hooks/nixAsyncQuery.js.map +3 -3
  43. package/dist/hooks/nixCallback.d.ts +2 -0
  44. package/dist/hooks/nixCallback.d.ts.map +1 -0
  45. package/dist/hooks/nixCallback.js +30 -40
  46. package/dist/hooks/nixCallback.js.map +3 -3
  47. package/dist/hooks/nixComputed.d.ts +16 -0
  48. package/dist/hooks/nixComputed.d.ts.map +1 -0
  49. package/dist/hooks/nixComputed.js +166 -198
  50. package/dist/hooks/nixComputed.js.map +4 -4
  51. package/dist/hooks/nixDebounce.d.ts +11 -0
  52. package/dist/hooks/nixDebounce.d.ts.map +1 -0
  53. package/dist/hooks/nixDebounce.js +53 -58
  54. package/dist/hooks/nixDebounce.js.map +3 -3
  55. package/dist/hooks/nixEffect.d.ts +4 -0
  56. package/dist/hooks/nixEffect.d.ts.map +1 -0
  57. package/dist/hooks/nixEffect.js +65 -75
  58. package/dist/hooks/nixEffect.js.map +3 -3
  59. package/dist/hooks/nixForm.d.ts +33 -0
  60. package/dist/hooks/nixForm.d.ts.map +1 -0
  61. package/dist/hooks/nixForm.js +110 -120
  62. package/dist/hooks/nixForm.js.map +3 -3
  63. package/dist/hooks/nixFormAsync.d.ts +42 -0
  64. package/dist/hooks/nixFormAsync.d.ts.map +1 -0
  65. package/dist/hooks/nixFormAsync.js +158 -167
  66. package/dist/hooks/nixFormAsync.js.map +3 -3
  67. package/dist/hooks/nixInterval.d.ts +2 -0
  68. package/dist/hooks/nixInterval.d.ts.map +1 -0
  69. package/dist/hooks/nixInterval.js +21 -27
  70. package/dist/hooks/nixInterval.js.map +3 -3
  71. package/dist/hooks/nixLazy.d.ts +8 -0
  72. package/dist/hooks/nixLazy.d.ts.map +1 -0
  73. package/dist/hooks/nixLazy.js +53 -58
  74. package/dist/hooks/nixLazy.js.map +3 -3
  75. package/dist/hooks/nixLazyAsync.d.ts +10 -0
  76. package/dist/hooks/nixLazyAsync.d.ts.map +1 -0
  77. package/dist/hooks/nixLazyAsync.js +65 -71
  78. package/dist/hooks/nixLazyAsync.js.map +3 -3
  79. package/dist/hooks/nixLazyFormAsync.d.ts +50 -0
  80. package/dist/hooks/nixLazyFormAsync.d.ts.map +1 -0
  81. package/dist/hooks/nixLazyFormAsync.js +209 -213
  82. package/dist/hooks/nixLazyFormAsync.js.map +3 -3
  83. package/dist/hooks/nixLocalStorage.d.ts +5 -0
  84. package/dist/hooks/nixLocalStorage.d.ts.map +1 -0
  85. package/dist/hooks/nixLocalStorage.js +21 -25
  86. package/dist/hooks/nixLocalStorage.js.map +3 -3
  87. package/dist/hooks/nixMemo.d.ts +2 -0
  88. package/dist/hooks/nixMemo.d.ts.map +1 -0
  89. package/dist/hooks/nixMemo.js +27 -31
  90. package/dist/hooks/nixMemo.js.map +3 -3
  91. package/dist/hooks/nixPrevious.d.ts +2 -0
  92. package/dist/hooks/nixPrevious.d.ts.map +1 -0
  93. package/dist/hooks/nixPrevious.js +13 -19
  94. package/dist/hooks/nixPrevious.js.map +3 -3
  95. package/dist/hooks/nixRef.d.ts +4 -0
  96. package/dist/hooks/nixRef.d.ts.map +1 -0
  97. package/dist/hooks/nixRef.js +14 -20
  98. package/dist/hooks/nixRef.js.map +3 -3
  99. package/dist/hooks/nixState.d.ts +15 -0
  100. package/dist/hooks/nixState.d.ts.map +1 -0
  101. package/dist/hooks/nixState.js +120 -173
  102. package/dist/hooks/nixState.js.map +3 -3
  103. package/dist/hooks/nixStore.d.ts +7 -0
  104. package/dist/hooks/nixStore.d.ts.map +1 -0
  105. package/dist/hooks/nixStore.js +48 -54
  106. package/dist/hooks/nixStore.js.map +3 -3
  107. package/dist/package.json +213 -0
  108. package/dist/plugins/vite-plugin-res.d.ts +41 -0
  109. package/dist/plugins/vite-plugin-res.d.ts.map +1 -0
  110. package/dist/plugins/vite-plugin-res.js +620 -36
  111. package/dist/plugins/vite-plugin-res.js.map +4 -4
  112. package/dist/router/router.d.ts +35 -0
  113. package/dist/router/router.d.ts.map +1 -0
  114. package/dist/router/router.js +520 -486
  115. package/dist/router/router.js.map +3 -3
  116. package/dist/runtime.d.ts +62 -0
  117. package/dist/runtime.d.ts.map +1 -0
  118. package/dist/runtime.js +833 -820
  119. package/dist/runtime.js.map +4 -4
  120. package/package.json +227 -44
  121. package/types/fnx.d.ts +72 -0
  122. package/types/fynix-ui.d.ts +323 -0
  123. package/types/global.d.ts +46 -6
  124. package/types/index.d.ts +37 -0
  125. package/types/vite-env.d.ts +553 -0
  126. package/runtime.d.ts +0 -83
  127. package/types/jsx.d.ts +0 -692
@@ -1,38 +1,622 @@
1
- var __defProp = Object.defineProperty;
2
- var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
1
  import { transform } from "esbuild";
4
- function fynix() {
5
- return {
6
- name: "vite-plugin-res",
7
- enforce: "pre",
8
- async transform(code, id) {
9
- if (!id.includes("/src/"))
10
- return null;
11
- if (!id.endsWith(".ts") && !id.endsWith(".js") && !id.endsWith(".fnx"))
12
- return null;
13
- this.addWatchFile(id);
14
- const result = await transform(code, {
15
- loader: "jsx",
16
- jsxFactory: "Fynix",
17
- jsxFragment: "Fynix.Fragment",
18
- sourcemap: true,
19
- sourcefile: id
20
- });
21
- return {
22
- code: result.code,
23
- map: result.map
24
- };
25
- },
26
- handleHotUpdate({ file, server }) {
27
- if (file.endsWith(".ts") || file.endsWith(".js") || file.endsWith(".fnx")) {
28
- server.ws.send({ type: "full-reload" });
29
- return [];
30
- }
31
- }
32
- };
33
- }
34
- __name(fynix, "fynix");
35
- export {
36
- fynix as default
2
+ import { normalizePath } from "vite";
3
+ import * as ts from "typescript";
4
+ const colors = {
5
+ reset: "\x1b[0m",
6
+ red: "\x1b[31m",
7
+ green: "\x1b[32m",
8
+ yellow: "\x1b[33m",
9
+ blue: "\x1b[34m",
10
+ magenta: "\x1b[35m",
11
+ cyan: "\x1b[36m",
12
+ gray: "\x1b[90m",
13
+ bold: "\x1b[1m",
37
14
  };
38
- //# sourceMappingURL=vite-plugin-res.js.map
15
+ function parseSFC(source) {
16
+ const result = {
17
+ logic: "",
18
+ view: "",
19
+ style: "",
20
+ logicLang: "ts",
21
+ hasLogic: false,
22
+ hasView: false,
23
+ hasStyle: false,
24
+ isStyleScoped: false,
25
+ imports: [],
26
+ exports: [],
27
+ };
28
+ const logicMatch = source.match(/<logic\s+setup\s*=\s*["']?(ts|js)["']?\s*>([\s\S]*?)<\/logic>/i);
29
+ if (logicMatch && logicMatch[1] && logicMatch[2] !== undefined) {
30
+ result.hasLogic = true;
31
+ result.logicLang = logicMatch[1].toLowerCase();
32
+ const rawLogic = logicMatch[2].trim();
33
+ const logicLines = rawLogic.split("\n");
34
+ const imports = [];
35
+ const exports = [];
36
+ const otherLogic = [];
37
+ let inExportBlock = false;
38
+ let exportBuffer = [];
39
+ let exportBraceDepth = 0;
40
+ for (let i = 0; i < logicLines.length; i++) {
41
+ const line = logicLines[i] ?? "";
42
+ const trimmed = line.trim();
43
+ if (inExportBlock) {
44
+ exportBuffer.push(line);
45
+ const openBraces = ((line && line.match(/{/g)) || []).length;
46
+ const closeBraces = ((line && line.match(/}/g)) || []).length;
47
+ exportBraceDepth += openBraces - closeBraces;
48
+ if (exportBraceDepth <= 0) {
49
+ exports.push(exportBuffer.join("\n"));
50
+ exportBuffer = [];
51
+ inExportBlock = false;
52
+ exportBraceDepth = 0;
53
+ }
54
+ continue;
55
+ }
56
+ if (trimmed.startsWith("import ")) {
57
+ imports.push(line ?? "");
58
+ }
59
+ else if (trimmed.startsWith("export ")) {
60
+ if (/export\s+\w+\s*=\s*{/.test(trimmed) || trimmed.endsWith("{")) {
61
+ inExportBlock = true;
62
+ exportBuffer = [line];
63
+ exportBraceDepth =
64
+ ((line && line.match(/{/g)) || []).length -
65
+ ((line && line.match(/}/g)) || []).length;
66
+ if (exportBraceDepth <= 0) {
67
+ exports.push(exportBuffer.join("\n"));
68
+ exportBuffer = [];
69
+ inExportBlock = false;
70
+ exportBraceDepth = 0;
71
+ }
72
+ }
73
+ else {
74
+ exports.push(line ?? "");
75
+ }
76
+ }
77
+ else if (trimmed) {
78
+ otherLogic.push(line ?? "");
79
+ }
80
+ }
81
+ if (exportBuffer.length > 0) {
82
+ exports.push(exportBuffer.join("\n"));
83
+ }
84
+ result.imports = imports;
85
+ result.exports = exports;
86
+ result.logic = otherLogic.join("\n");
87
+ }
88
+ const viewMatch = source.match(/<view\s*>([\s\S]*?)<\/view>/i);
89
+ if (viewMatch && viewMatch[1] !== undefined) {
90
+ result.hasView = true;
91
+ result.view = viewMatch[1].trim();
92
+ }
93
+ const styleMatch = source.match(/<style(\s+scoped)?\s*>([\s\S]*?)<\/style>/i);
94
+ if (styleMatch && styleMatch[2] !== undefined) {
95
+ result.hasStyle = true;
96
+ result.isStyleScoped = !!styleMatch[1];
97
+ result.style = styleMatch[2].trim();
98
+ }
99
+ return result;
100
+ }
101
+ function generateStyleId(filePath) {
102
+ let hash = 0;
103
+ for (let i = 0; i < filePath.length; i++) {
104
+ const char = filePath.charCodeAt(i);
105
+ hash = (hash << 5) - hash + char;
106
+ hash = hash & hash;
107
+ }
108
+ return `fynix-${Math.abs(hash).toString(36)}`;
109
+ }
110
+ function scopeStyles(css, scopeId) {
111
+ const dataAttr = `[data-${scopeId}]`;
112
+ const keyframeMap = new Map();
113
+ const keyframes = [];
114
+ css = css.replace(/@keyframes\s+([a-zA-Z0-9_-]+)\s*\{[\s\S]*?\}/g, (block, name) => {
115
+ const scopedName = `${name}-${scopeId}`;
116
+ keyframeMap.set(name, scopedName);
117
+ const renamed = block.replace(new RegExp(`@keyframes\\s+${name}`), `@keyframes ${scopedName}`);
118
+ const index = keyframes.push(renamed) - 1;
119
+ return `__KEYFRAMES_${index}__`;
120
+ });
121
+ keyframeMap.forEach((scoped, original) => {
122
+ const re = new RegExp(`(animation(?:-name)?\\s*:[^;]*?)\\b${original}\\b`, "g");
123
+ css = css.replace(re, `$1${scoped}`);
124
+ });
125
+ let rootClass = null;
126
+ try {
127
+ const viewMatch = css.match(/\.(\w+)[^{]*\{/);
128
+ if (viewMatch) {
129
+ rootClass = viewMatch[1];
130
+ }
131
+ }
132
+ catch { }
133
+ css = css.replace(/([^{}]+)\{([^{}]*)\}/g, (match, selector, rules) => {
134
+ if (selector.trim().startsWith("@"))
135
+ return match;
136
+ const scopedSelectors = selector
137
+ .split(",")
138
+ .map((s) => {
139
+ const sel = s.trim();
140
+ if (rootClass) {
141
+ const rootRe = new RegExp(`^\\.${rootClass}((:[\\w-]+)*|(::[\\w-]+)*)?$`);
142
+ const pseudo = sel.replace(new RegExp(`^\\.${rootClass}`), "");
143
+ if (rootRe.test(sel)) {
144
+ return `${dataAttr}${pseudo}`;
145
+ }
146
+ }
147
+ return `${dataAttr} ${sel}`;
148
+ })
149
+ .join(", ");
150
+ return `${scopedSelectors}{${rules}}`;
151
+ });
152
+ keyframes.forEach((kf, i) => {
153
+ css = css.replace(`__KEYFRAMES_${i}__`, kf);
154
+ });
155
+ return css;
156
+ }
157
+ function transformSFC(parsed, filePath, jsxFactory) {
158
+ const styleId = generateStyleId(filePath);
159
+ const lines = [];
160
+ lines.push(`import { ${jsxFactory} } from '@fynixorg/ui';`);
161
+ if (parsed.imports.length > 0) {
162
+ parsed.imports.forEach((importLine) => {
163
+ lines.push(importLine);
164
+ });
165
+ }
166
+ lines.push("");
167
+ if (parsed.hasStyle) {
168
+ let processedStyle = parsed.style;
169
+ if (parsed.isStyleScoped) {
170
+ processedStyle = scopeStyles(parsed.style, styleId);
171
+ }
172
+ lines.push(`// Inject styles`);
173
+ lines.push(`if (typeof document !== 'undefined') {`);
174
+ lines.push(` const styleId = '${styleId}';`);
175
+ lines.push(` if (!document.getElementById(styleId)) {`);
176
+ lines.push(` const styleEl = document.createElement('style');`);
177
+ lines.push(` styleEl.id = styleId;`);
178
+ lines.push(` styleEl.textContent = ${JSON.stringify(processedStyle)};`);
179
+ lines.push(` document.head.appendChild(styleEl);`);
180
+ lines.push(` }`);
181
+ lines.push(`}`);
182
+ lines.push("");
183
+ }
184
+ if (parsed.exports.length > 0) {
185
+ parsed.exports.forEach((exportLine) => {
186
+ lines.push(exportLine);
187
+ });
188
+ lines.push("");
189
+ }
190
+ let propsType = "any";
191
+ const propsInterfaceRegex = /interface\s+Props\s*{[\s\S]*?}/m;
192
+ if (propsInterfaceRegex.test(parsed.logic)) {
193
+ propsType = "Props";
194
+ }
195
+ lines.push(`function FynixComponent(props: ${propsType} = {}) {`);
196
+ if (parsed.hasLogic && parsed.logic.trim()) {
197
+ lines.push(` // Component logic`);
198
+ const logicLines = parsed.logic.split("\n");
199
+ logicLines.forEach((line) => {
200
+ if (line.trim()) {
201
+ lines.push(` ${line}`);
202
+ }
203
+ });
204
+ lines.push("");
205
+ }
206
+ if (parsed.exports.some((e) => e.trim().startsWith("export const meta"))) {
207
+ lines.push(` if (typeof document !== "undefined" && typeof meta !== "undefined") {`);
208
+ lines.push(` if (meta.title) document.title = meta.title;`);
209
+ lines.push(` const _meta = meta as any;`);
210
+ lines.push(` const metaTags = [`);
211
+ lines.push(` _meta.description ? { name: "description", content: _meta.description } : null,`);
212
+ lines.push(` _meta.keywords ? { name: "keywords", content: _meta.keywords } : null,`);
213
+ lines.push(` _meta.ogTitle ? { property: "og:title", content: _meta.ogTitle } : null,`);
214
+ lines.push(` _meta.ogDescription ? { property: "og:description", content: _meta.ogDescription } : null,`);
215
+ lines.push(` _meta.ogImage ? { property: "og:image", content: _meta.ogImage } : null,`);
216
+ lines.push(` ].filter(Boolean);`);
217
+ lines.push(` metaTags.forEach((tagObj) => {`);
218
+ lines.push(` if (!tagObj) return;`);
219
+ lines.push(` const { name, property, content } = tagObj;`);
220
+ lines.push(` if (!content) return;`);
221
+ lines.push(` let tag;`);
222
+ lines.push(` if (name) {`);
223
+ lines.push(" tag = document.querySelector(`meta[name='${name}']`);");
224
+ lines.push(` if (!tag) {`);
225
+ lines.push(` tag = document.createElement("meta");`);
226
+ lines.push(` tag.setAttribute("name", name);`);
227
+ lines.push(` document.head.appendChild(tag);`);
228
+ lines.push(` }`);
229
+ lines.push(` } else if (property) {`);
230
+ lines.push(" tag = document.querySelector(`meta[property='${property}']`);");
231
+ lines.push(` if (!tag) {`);
232
+ lines.push(` tag = document.createElement("meta");`);
233
+ lines.push(` tag.setAttribute("property", property);`);
234
+ lines.push(` document.head.appendChild(tag);`);
235
+ lines.push(` }`);
236
+ lines.push(` }`);
237
+ lines.push(` if (tag) tag.setAttribute("content", content);`);
238
+ lines.push(` });`);
239
+ lines.push(` }`);
240
+ lines.push("");
241
+ }
242
+ if (parsed.hasView) {
243
+ lines.push(` // Component view`);
244
+ if (parsed.isStyleScoped) {
245
+ let viewContent = parsed.view.trim();
246
+ const showGeneratedCode = typeof globalThis !== "undefined" &&
247
+ globalThis.fynixShowGeneratedCode !== undefined
248
+ ? globalThis.fynixShowGeneratedCode
249
+ : false;
250
+ if (showGeneratedCode) {
251
+ console.log(`${colors.magenta}[DEBUG] Original view content:${colors.reset}`);
252
+ console.log(viewContent.substring(0, 200));
253
+ }
254
+ const tagMatch = viewContent.match(/^(<\w+)((?:\s+[^>]*?)?)(\s*>)/s);
255
+ if (tagMatch) {
256
+ const openTag = tagMatch[1];
257
+ const attributes = tagMatch[2];
258
+ const closingBracket = tagMatch[3];
259
+ if (showGeneratedCode) {
260
+ console.log(`${colors.magenta}[DEBUG] Matched tag:${colors.reset} ${openTag}`);
261
+ console.log(`${colors.magenta}[DEBUG] Attributes:${colors.reset} ${attributes}`);
262
+ }
263
+ const modifiedStart = `${openTag}${attributes} data-${styleId}=""${closingBracket}`;
264
+ const restOfView = viewContent.substring(tagMatch[0].length);
265
+ const modifiedView = modifiedStart + restOfView;
266
+ if (showGeneratedCode) {
267
+ console.log(`${colors.magenta}[DEBUG] Modified first line:${colors.reset}`);
268
+ console.log(modifiedView.split("\n")[0]);
269
+ }
270
+ lines.push(` return (`);
271
+ const viewLines = modifiedView.split("\n");
272
+ viewLines.forEach((line) => {
273
+ lines.push(` ${line}`);
274
+ });
275
+ lines.push(` );`);
276
+ }
277
+ else {
278
+ lines.push(` return (`);
279
+ lines.push(` <div data-${styleId}="">`);
280
+ const viewLines = parsed.view.split("\n");
281
+ viewLines.forEach((line) => {
282
+ lines.push(` ${line}`);
283
+ });
284
+ lines.push(` </div>`);
285
+ lines.push(` );`);
286
+ }
287
+ }
288
+ else {
289
+ lines.push(` return (`);
290
+ const viewLines = parsed.view.split("\n");
291
+ viewLines.forEach((line) => {
292
+ lines.push(` ${line}`);
293
+ });
294
+ lines.push(` );`);
295
+ }
296
+ }
297
+ else {
298
+ lines.push(` return null;`);
299
+ }
300
+ lines.push(`}`);
301
+ lines.push("");
302
+ lines.push(`export default FynixComponent;`);
303
+ return lines.join("\n");
304
+ }
305
+ function validateSFC(parsed, filePath) {
306
+ if (!parsed.hasView) {
307
+ throw new Error(`${colors.red}[Fynix SFC]${colors.reset} Missing <view> block in ${colors.cyan}${filePath}${colors.reset}. Every .fnx file must have a <view> section.`);
308
+ }
309
+ if (parsed.hasLogic && !["ts", "js"].includes(parsed.logicLang)) {
310
+ throw new Error(`${colors.red}[Fynix SFC]${colors.reset} Invalid setup attribute in <logic> block in ${colors.cyan}${filePath}${colors.reset}. Must be "ts" or "js".`);
311
+ }
312
+ if (parsed.hasLogic && parsed.logicLang === "js") {
313
+ const tsPatterns = [
314
+ { pattern: /\binterface\s+\w+/, name: "interface declaration" },
315
+ { pattern: /\btype\s+\w+\s*=/, name: "type alias" },
316
+ { pattern: /:\s*\w+(\[\]|<[^>]+>)?\s*[;,=)]/, name: "type annotation" },
317
+ { pattern: /<\w+>(?!\s*<)/, name: "generic type" },
318
+ { pattern: /\benum\s+\w+/, name: "enum declaration" },
319
+ { pattern: /\bas\s+\w+/, name: "type assertion" },
320
+ { pattern: /\bnamespace\s+\w+/, name: "namespace" },
321
+ { pattern: /\babstract\s+class/, name: "abstract class" },
322
+ {
323
+ pattern: /\bpublic\s+|private\s+|protected\s+/,
324
+ name: "access modifier",
325
+ },
326
+ ];
327
+ const allCode = parsed.logic + "\n" + parsed.imports.join("\n");
328
+ for (const { pattern, name } of tsPatterns) {
329
+ if (pattern.test(allCode)) {
330
+ throw new Error(`${colors.red}[Fynix SFC]${colors.reset} TypeScript syntax detected ${colors.yellow}(${name})${colors.reset} in ${colors.cyan}${filePath}${colors.reset} with ${colors.yellow}setup="js"${colors.reset}.\n` +
331
+ `${colors.gray}Either change to setup="ts" or remove TypeScript-specific syntax.${colors.reset}`);
332
+ }
333
+ }
334
+ }
335
+ }
336
+ class TypeScriptChecker {
337
+ constructor(customOptions) {
338
+ this.virtualFiles = new Map();
339
+ this.program = null;
340
+ this.compilerOptions = {
341
+ noEmit: true,
342
+ strict: true,
343
+ target: ts.ScriptTarget.ESNext,
344
+ module: ts.ModuleKind.ESNext,
345
+ jsx: ts.JsxEmit.Preserve,
346
+ lib: ["lib.es2023.d.ts", "lib.dom.d.ts"],
347
+ moduleResolution: ts.ModuleResolutionKind.Bundler,
348
+ esModuleInterop: true,
349
+ skipLibCheck: true,
350
+ allowSyntheticDefaultImports: true,
351
+ strictNullChecks: true,
352
+ strictFunctionTypes: true,
353
+ noImplicitAny: false,
354
+ allowJs: true,
355
+ checkJs: false,
356
+ resolveJsonModule: true,
357
+ isolatedModules: true,
358
+ ...customOptions,
359
+ };
360
+ }
361
+ addFile(fileName, content) {
362
+ this.virtualFiles.set(fileName, content);
363
+ this.program = null;
364
+ }
365
+ createCompilerHost() {
366
+ const defaultHost = ts.createCompilerHost(this.compilerOptions);
367
+ return {
368
+ ...defaultHost,
369
+ getSourceFile: (fileName, languageVersion) => {
370
+ if (this.virtualFiles.has(fileName)) {
371
+ const content = this.virtualFiles.get(fileName);
372
+ if (content === undefined)
373
+ return undefined;
374
+ return ts.createSourceFile(fileName, content, languageVersion, true);
375
+ }
376
+ try {
377
+ if (ts.sys.fileExists(fileName)) {
378
+ const content = ts.sys.readFile(fileName);
379
+ if (content !== undefined) {
380
+ return ts.createSourceFile(fileName, content, languageVersion, true);
381
+ }
382
+ }
383
+ }
384
+ catch (err) {
385
+ }
386
+ return undefined;
387
+ },
388
+ fileExists: (fileName) => {
389
+ if (this.virtualFiles.has(fileName))
390
+ return true;
391
+ return ts.sys.fileExists(fileName);
392
+ },
393
+ readFile: (fileName) => {
394
+ if (this.virtualFiles.has(fileName)) {
395
+ const content = this.virtualFiles.get(fileName);
396
+ return content === undefined ? undefined : content;
397
+ }
398
+ const sysContent = ts.sys.readFile(fileName);
399
+ return sysContent === undefined ? undefined : sysContent;
400
+ },
401
+ writeFile: () => { },
402
+ };
403
+ }
404
+ checkFile(fileName) {
405
+ const errors = [];
406
+ try {
407
+ if (!this.virtualFiles.has(fileName)) {
408
+ return ["File not found in virtual file system"];
409
+ }
410
+ const compilerHost = this.createCompilerHost();
411
+ if (!this.program) {
412
+ this.program = ts.createProgram([fileName], this.compilerOptions, compilerHost);
413
+ }
414
+ const sourceFile = this.program.getSourceFile(fileName);
415
+ if (!sourceFile) {
416
+ return [`Could not get source file for ${fileName}`];
417
+ }
418
+ const diagnostics = [
419
+ ...this.program.getSyntacticDiagnostics(sourceFile),
420
+ ...this.program.getSemanticDiagnostics(sourceFile),
421
+ ];
422
+ const skipCodes = new Set([
423
+ 2307,
424
+ 2792,
425
+ 7016,
426
+ 7026,
427
+ ]);
428
+ diagnostics.forEach((diagnostic) => {
429
+ if (skipCodes.has(diagnostic.code)) {
430
+ return;
431
+ }
432
+ if (diagnostic.file && diagnostic.start !== undefined) {
433
+ const pos = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
434
+ const line = pos?.line ?? 0;
435
+ const character = pos?.character ?? 0;
436
+ const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n");
437
+ errors.push(`${colors.yellow}Line ${line + 1}:${character + 1}${colors.reset} - ${message} ${colors.gray}(TS${diagnostic.code})${colors.reset}`);
438
+ }
439
+ else {
440
+ const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n");
441
+ errors.push(`${message} ${colors.gray}(TS${diagnostic.code})${colors.reset}`);
442
+ }
443
+ });
444
+ }
445
+ catch (error) {
446
+ errors.push(`${colors.red}Type checking error:${colors.reset} ${error instanceof Error ? error.message : String(error)}`);
447
+ }
448
+ return errors;
449
+ }
450
+ clear() {
451
+ this.virtualFiles.clear();
452
+ this.program = null;
453
+ }
454
+ }
455
+ export default function fynixPlugin(options = {}) {
456
+ const { jsxFactory = "Fynix", jsxFragment = "Fynix.Fragment", include = [".ts", ".js", ".jsx", ".tsx", ".fnx"], exclude = ["node_modules"], sourcemap = true, esbuildOptions = {}, enableSFC = true, showGeneratedCode = false, typeCheck = false, tsConfig, } = options;
457
+ let typeChecker = null;
458
+ if (typeCheck) {
459
+ typeChecker = new TypeScriptChecker(tsConfig);
460
+ }
461
+ return {
462
+ name: "vite-plugin-fynix-sfc",
463
+ enforce: "pre",
464
+ async transform(code, id) {
465
+ const normalizedId = normalizePath(id);
466
+ const shouldExclude = exclude.some((pattern) => normalizedId.includes(pattern));
467
+ if (shouldExclude)
468
+ return null;
469
+ const shouldInclude = include.some((ext) => normalizedId.endsWith(ext));
470
+ if (!shouldInclude)
471
+ return null;
472
+ const ctx = this;
473
+ if (typeof ctx.addWatchFile === "function") {
474
+ ctx.addWatchFile(id);
475
+ }
476
+ try {
477
+ let codeToTransform = code;
478
+ let loader = "tsx";
479
+ let shouldTypeCheck = false;
480
+ if (normalizedId.endsWith(".fnx") && enableSFC) {
481
+ const parsed = parseSFC(code);
482
+ validateSFC(parsed, normalizedId);
483
+ codeToTransform = transformSFC(parsed, normalizedId, jsxFactory);
484
+ if (showGeneratedCode) {
485
+ console.log(`\n${colors.cyan}${"=".repeat(80)}${colors.reset}`);
486
+ console.log(`${colors.cyan}[Fynix SFC]${colors.reset} Generated code for: ${colors.gray}${normalizedId}${colors.reset}`);
487
+ console.log(`${colors.cyan}${"=".repeat(80)}${colors.reset}`);
488
+ console.log(codeToTransform);
489
+ console.log(`${colors.cyan}${"=".repeat(80)}${colors.reset}\n`);
490
+ }
491
+ shouldTypeCheck = typeCheck && parsed.logicLang === "ts";
492
+ if (shouldTypeCheck && typeChecker) {
493
+ const virtualFileName = normalizedId.replace(/\.fnx$/, ".virtual.tsx");
494
+ typeChecker.addFile(virtualFileName, codeToTransform);
495
+ const typeErrors = typeChecker.checkFile(virtualFileName);
496
+ if (typeErrors.length > 0) {
497
+ console.error(`\n${colors.red}${colors.bold}[Fynix SFC] TypeScript Errors${colors.reset} in ${colors.cyan}${normalizedId}${colors.reset}:`);
498
+ typeErrors.forEach((error) => console.error(` ${error}`));
499
+ console.error("");
500
+ if (process.env.NODE_ENV === "production") {
501
+ throw new Error(`TypeScript errors in ${normalizedId}`);
502
+ }
503
+ }
504
+ shouldTypeCheck = false;
505
+ }
506
+ }
507
+ else {
508
+ if (normalizedId.endsWith(".ts")) {
509
+ loader = "ts";
510
+ shouldTypeCheck = typeCheck;
511
+ }
512
+ else if (normalizedId.endsWith(".tsx")) {
513
+ loader = "tsx";
514
+ shouldTypeCheck = typeCheck;
515
+ }
516
+ else if (normalizedId.endsWith(".jsx")) {
517
+ loader = "jsx";
518
+ }
519
+ else if (normalizedId.endsWith(".js")) {
520
+ loader = "js";
521
+ }
522
+ }
523
+ if (shouldTypeCheck && typeChecker) {
524
+ typeChecker.addFile(normalizedId, codeToTransform);
525
+ const typeErrors = typeChecker.checkFile(normalizedId);
526
+ if (typeErrors.length > 0) {
527
+ console.error(`\n${colors.red}${colors.bold}[Fynix SFC] TypeScript Errors${colors.reset} in ${colors.cyan}${normalizedId}${colors.reset}:`);
528
+ typeErrors.forEach((error) => console.error(` ${error}`));
529
+ console.error("");
530
+ if (process.env.NODE_ENV === "production") {
531
+ throw new Error(`TypeScript errors in ${normalizedId}`);
532
+ }
533
+ }
534
+ }
535
+ const result = await transform(codeToTransform, {
536
+ loader,
537
+ jsxFactory,
538
+ jsxFragment,
539
+ sourcemap,
540
+ sourcefile: id,
541
+ target: "esnext",
542
+ format: "esm",
543
+ ...esbuildOptions,
544
+ });
545
+ return {
546
+ code: result.code,
547
+ map: result.map || null,
548
+ };
549
+ }
550
+ catch (error) {
551
+ const err = error;
552
+ console.error(`\n${colors.red}${colors.bold}[Fynix SFC] Transform Error${colors.reset} in ${colors.cyan}${id}${colors.reset}:`);
553
+ console.error(` ${colors.red}${err.message}${colors.reset}\n`);
554
+ const ctx = this;
555
+ if (typeof ctx.error === "function") {
556
+ ctx.error({
557
+ message: `Failed to transform ${id}: ${err.message}`,
558
+ stack: err.stack,
559
+ id,
560
+ });
561
+ }
562
+ else {
563
+ throw err;
564
+ }
565
+ return null;
566
+ }
567
+ },
568
+ handleHotUpdate(ctx) {
569
+ const { file, server } = ctx;
570
+ const normalizedFile = normalizePath(file);
571
+ const shouldReload = include.some((ext) => normalizedFile.endsWith(ext));
572
+ if (shouldReload) {
573
+ console.log(`${colors.green}[HMR]${colors.reset} ${colors.gray}${normalizedFile}${colors.reset}`);
574
+ if (typeChecker) {
575
+ typeChecker.clear();
576
+ }
577
+ server.ws.send({
578
+ type: "full-reload",
579
+ path: "*",
580
+ });
581
+ return [];
582
+ }
583
+ return undefined;
584
+ },
585
+ config() {
586
+ const config = {
587
+ esbuild: {
588
+ jsxFactory,
589
+ jsxFragment,
590
+ jsxInject: `import { ${jsxFactory} } from '@fynixorg/ui'`,
591
+ },
592
+ optimizeDeps: {
593
+ include: ["@fynixorg/ui"],
594
+ esbuildOptions: {
595
+ jsx: "transform",
596
+ jsxFactory,
597
+ jsxFragment,
598
+ },
599
+ },
600
+ resolve: {
601
+ extensions: [".fnx", ".ts", ".tsx", ".js", ".jsx", ".json"],
602
+ },
603
+ };
604
+ return config;
605
+ },
606
+ buildStart() {
607
+ console.log(`${colors.cyan}[vite-plugin-fynix-sfc]${colors.reset} Initialized`);
608
+ if (enableSFC) {
609
+ console.log(`${colors.cyan}[vite-plugin-fynix-sfc]${colors.reset} SFC support: ${colors.green}enabled${colors.reset}`);
610
+ }
611
+ if (typeCheck) {
612
+ console.log(`${colors.cyan}[vite-plugin-fynix-sfc]${colors.reset} Type checking: ${colors.green}enabled${colors.reset}`);
613
+ }
614
+ },
615
+ buildEnd() {
616
+ if (typeChecker) {
617
+ typeChecker.clear();
618
+ }
619
+ },
620
+ };
621
+ }
622
+ export { fynixPlugin, TypeScriptChecker };