tailwind-styled-v4 5.0.8 → 5.0.10

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 (140) hide show
  1. package/CHANGELOG.md +204 -416
  2. package/README.md +45 -15
  3. package/dist/{analyzeWorkspace-DuJKh7Ty.d.mts → analyzeWorkspace-BS5O4rhC.d.mts} +47 -2
  4. package/dist/{analyzeWorkspace-Ct_NTAWt.d.ts → analyzeWorkspace-DDOQdzzI.d.ts} +47 -2
  5. package/dist/analyzer.d.mts +5 -3
  6. package/dist/analyzer.d.ts +5 -3
  7. package/dist/analyzer.js +563 -468
  8. package/dist/analyzer.js.map +1 -1
  9. package/dist/analyzer.mjs +562 -467
  10. package/dist/analyzer.mjs.map +1 -1
  11. package/dist/animate.d.mts +4 -7
  12. package/dist/animate.d.ts +4 -7
  13. package/dist/animate.js +171 -265
  14. package/dist/animate.js.map +1 -1
  15. package/dist/animate.mjs +165 -264
  16. package/dist/animate.mjs.map +1 -1
  17. package/dist/atomic.d.mts +22 -1
  18. package/dist/atomic.d.ts +22 -1
  19. package/dist/atomic.js +221 -165
  20. package/dist/atomic.js.map +1 -1
  21. package/dist/atomic.mjs +200 -165
  22. package/dist/atomic.mjs.map +1 -1
  23. package/dist/cli.d.mts +60 -1
  24. package/dist/cli.d.ts +60 -1
  25. package/dist/cli.js +1261 -1517
  26. package/dist/cli.js.map +1 -1
  27. package/dist/cli.mjs +1238 -1513
  28. package/dist/cli.mjs.map +1 -1
  29. package/dist/compiler.d.mts +38 -7
  30. package/dist/compiler.d.ts +38 -7
  31. package/dist/compiler.js +174 -197
  32. package/dist/compiler.js.map +1 -1
  33. package/dist/compiler.mjs +151 -194
  34. package/dist/compiler.mjs.map +1 -1
  35. package/dist/devtools.js +7 -31
  36. package/dist/devtools.js.map +1 -1
  37. package/dist/devtools.mjs +7 -31
  38. package/dist/devtools.mjs.map +1 -1
  39. package/dist/engine.d.mts +134 -63
  40. package/dist/engine.d.ts +134 -63
  41. package/dist/engine.js +2863 -2482
  42. package/dist/engine.js.map +1 -1
  43. package/dist/engine.mjs +2852 -2485
  44. package/dist/engine.mjs.map +1 -1
  45. package/dist/{index-eWAocnD2.d.mts → index-NDINUhLN.d.mts} +3 -1
  46. package/dist/{index-eWAocnD2.d.ts → index-NDINUhLN.d.ts} +3 -1
  47. package/dist/index.d.mts +63 -32
  48. package/dist/index.d.ts +63 -32
  49. package/dist/index.js +335 -169
  50. package/dist/index.js.map +1 -1
  51. package/dist/index.mjs +315 -169
  52. package/dist/index.mjs.map +1 -1
  53. package/dist/{liveTokenEngine-DSUk88P6.d.ts → liveTokenEngine-CN9ian1R.d.ts} +1 -1
  54. package/dist/{liveTokenEngine-CX5_0c4q.d.mts → liveTokenEngine-DKoWRtqH.d.mts} +1 -1
  55. package/dist/next.d.mts +10 -4
  56. package/dist/next.d.ts +10 -4
  57. package/dist/next.js +32 -45
  58. package/dist/next.js.map +1 -1
  59. package/dist/next.mjs +30 -43
  60. package/dist/next.mjs.map +1 -1
  61. package/dist/plugin-api.d.mts +8 -2
  62. package/dist/plugin-api.d.ts +8 -2
  63. package/dist/plugin-api.js +14 -2
  64. package/dist/plugin-api.js.map +1 -1
  65. package/dist/plugin-api.mjs +14 -3
  66. package/dist/plugin-api.mjs.map +1 -1
  67. package/dist/plugin-registry.js +51 -11
  68. package/dist/plugin-registry.js.map +1 -1
  69. package/dist/plugin-registry.mjs +51 -11
  70. package/dist/plugin-registry.mjs.map +1 -1
  71. package/dist/plugin.d.mts +5 -7
  72. package/dist/plugin.d.ts +5 -7
  73. package/dist/plugin.js +16 -15
  74. package/dist/plugin.js.map +1 -1
  75. package/dist/plugin.mjs +16 -16
  76. package/dist/plugin.mjs.map +1 -1
  77. package/dist/rspack.js +17 -38
  78. package/dist/rspack.js.map +1 -1
  79. package/dist/rspack.mjs +15 -36
  80. package/dist/rspack.mjs.map +1 -1
  81. package/dist/runtime.d.mts +2 -2
  82. package/dist/runtime.d.ts +2 -2
  83. package/dist/scanner.d.mts +10 -1
  84. package/dist/scanner.d.ts +10 -1
  85. package/dist/scanner.js +298 -124
  86. package/dist/scanner.js.map +1 -1
  87. package/dist/scanner.mjs +296 -124
  88. package/dist/scanner.mjs.map +1 -1
  89. package/dist/shared.d.mts +1 -1
  90. package/dist/shared.d.ts +1 -1
  91. package/dist/shared.js +104 -176
  92. package/dist/shared.js.map +1 -1
  93. package/dist/shared.mjs +85 -176
  94. package/dist/shared.mjs.map +1 -1
  95. package/dist/storybook-addon.d.mts +1 -1
  96. package/dist/storybook-addon.d.ts +1 -1
  97. package/dist/svelte.d.mts +1 -1
  98. package/dist/svelte.d.ts +1 -1
  99. package/dist/svelte.js +166 -3
  100. package/dist/svelte.js.map +1 -1
  101. package/dist/svelte.mjs +143 -1
  102. package/dist/svelte.mjs.map +1 -1
  103. package/dist/syntax.js +21 -21
  104. package/dist/syntax.js.map +1 -1
  105. package/dist/syntax.mjs +21 -21
  106. package/dist/syntax.mjs.map +1 -1
  107. package/dist/testing.js +9 -1
  108. package/dist/testing.js.map +1 -1
  109. package/dist/testing.mjs +9 -1
  110. package/dist/testing.mjs.map +1 -1
  111. package/dist/theme.d.mts +2 -2
  112. package/dist/theme.d.ts +2 -2
  113. package/dist/theme.js +40 -112
  114. package/dist/theme.js.map +1 -1
  115. package/dist/theme.mjs +37 -110
  116. package/dist/theme.mjs.map +1 -1
  117. package/dist/turbopackLoader.js +84 -126
  118. package/dist/turbopackLoader.js.map +1 -1
  119. package/dist/turbopackLoader.mjs +68 -124
  120. package/dist/turbopackLoader.mjs.map +1 -1
  121. package/dist/tw.js +1256 -1517
  122. package/dist/tw.js.map +1 -1
  123. package/dist/tw.mjs +1236 -1513
  124. package/dist/tw.mjs.map +1 -1
  125. package/dist/vite.js +1783 -823
  126. package/dist/vite.js.map +1 -1
  127. package/dist/vite.mjs +1767 -821
  128. package/dist/vite.mjs.map +1 -1
  129. package/dist/vue.d.mts +1 -1
  130. package/dist/vue.d.ts +1 -1
  131. package/dist/vue.js +165 -4
  132. package/dist/vue.js.map +1 -1
  133. package/dist/vue.mjs +141 -1
  134. package/dist/vue.mjs.map +1 -1
  135. package/dist/webpackLoader.js +69 -108
  136. package/dist/webpackLoader.js.map +1 -1
  137. package/dist/webpackLoader.mjs +49 -104
  138. package/dist/webpackLoader.mjs.map +1 -1
  139. package/native/tailwind-styled-native.node +0 -0
  140. package/package.json +22 -24
package/dist/analyzer.js CHANGED
@@ -1,29 +1,25 @@
1
1
  'use strict';
2
2
 
3
- var path3 = require('path');
3
+ require('crypto');
4
+ var fs3 = require('fs');
5
+ var path5 = require('path');
4
6
  var url = require('url');
5
- var fs = require('fs');
6
7
  var module$1 = require('module');
7
8
  var worker_threads = require('worker_threads');
9
+ var os = require('os');
8
10
  var zod = require('zod');
9
11
 
10
12
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
11
13
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
12
14
 
13
- var path3__default = /*#__PURE__*/_interopDefault(path3);
14
- var fs__default = /*#__PURE__*/_interopDefault(fs);
15
+ var fs3__default = /*#__PURE__*/_interopDefault(fs3);
16
+ var path5__default = /*#__PURE__*/_interopDefault(path5);
15
17
 
16
18
  /* tailwind-styled-v4 v5.0.4 | MIT | https://github.com/dictionar32/tailwind-styled-v4 */
17
19
  var __defProp = Object.defineProperty;
18
20
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
19
21
  var __getOwnPropNames = Object.getOwnPropertyNames;
20
22
  var __hasOwnProp = Object.prototype.hasOwnProperty;
21
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
22
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
23
- }) : x)(function(x) {
24
- if (typeof require !== "undefined") return require.apply(this, arguments);
25
- throw Error('Dynamic require of "' + x + '" is not supported');
26
- });
27
23
  var __esm = (fn, res) => function __init() {
28
24
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
29
25
  };
@@ -40,41 +36,6 @@ var __copyProps = (to, from, except, desc) => {
40
36
  return to;
41
37
  };
42
38
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
43
-
44
- // packages/domain/shared/src/index.ts
45
- function getNodeModuleRef() {
46
- if (isBrowser) return null;
47
- if (nodeModuleRef !== null) return nodeModuleRef;
48
- try {
49
- const test = typeof __require === "function" ? __require("module") : null;
50
- nodeModuleRef = test;
51
- return test;
52
- } catch {
53
- nodeModuleRef = null;
54
- return null;
55
- }
56
- }
57
- function getNodeFs() {
58
- if (isBrowser) throw new Error("node:fs not available in browser");
59
- const nodeRequire = getNodeModuleRef();
60
- if (!nodeRequire) throw new Error("require not available");
61
- if (!_nodeFs) _nodeFs = nodeRequire.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('analyzer.js', document.baseURI).href)))("node:fs");
62
- return _nodeFs;
63
- }
64
- function getNodePath() {
65
- if (isBrowser) throw new Error("node:path not available in browser");
66
- const nodeRequire = getNodeModuleRef();
67
- if (!nodeRequire) throw new Error("require not available");
68
- if (!_nodePath) _nodePath = nodeRequire.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('analyzer.js', document.baseURI).href)))("node:path");
69
- return _nodePath;
70
- }
71
- function getNodeUrl() {
72
- if (isBrowser) throw new Error("node:url not available in browser");
73
- const nodeRequire = getNodeModuleRef();
74
- if (!nodeRequire) throw new Error("require not available");
75
- if (!_nodeUrl) _nodeUrl = nodeRequire.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('analyzer.js', document.baseURI).href)))("node:url");
76
- return _nodeUrl;
77
- }
78
39
  function createLogger(namespace) {
79
40
  const prefix = `[${namespace}]`;
80
41
  return {
@@ -104,24 +65,19 @@ function createDebugLogger(namespace, label) {
104
65
  }
105
66
  };
106
67
  }
107
- function formatIssuePath(path6) {
108
- if (!path6 || path6.length === 0) return "(root)";
109
- return path6.map(
68
+ function formatIssuePath(path8) {
69
+ if (!path8 || path8.length === 0) return "(root)";
70
+ return path8.map(
110
71
  (segment) => typeof segment === "symbol" ? segment.description ?? segment.toString() : String(segment)
111
72
  ).join(".");
112
73
  }
113
74
  function loadNativeBinding(options) {
114
- if (isBrowser) {
115
- return { binding: null, loadErrors: [{ path: "", message: "Native bindings not available in browser" }] };
116
- }
117
75
  const { runtimeDir, candidates, isValid } = options;
118
76
  const loadErrors = [];
119
- const path6 = getNodePath();
120
- const fs4 = getNodeFs();
121
77
  for (const candidate of candidates) {
122
- const candidatePath = path6.resolve(runtimeDir, candidate);
78
+ const candidatePath = path5__default.default.resolve(runtimeDir, candidate);
123
79
  try {
124
- if (!fs4.existsSync(candidatePath) && !fs4.existsSync(candidatePath + ".node")) {
80
+ if (!fs3__default.default.existsSync(candidatePath) && !fs3__default.default.existsSync(candidatePath + ".node")) {
125
81
  continue;
126
82
  }
127
83
  const mod = requireNativeModule(candidatePath);
@@ -135,72 +91,56 @@ function loadNativeBinding(options) {
135
91
  }
136
92
  return { binding: null, loadErrors };
137
93
  }
138
- function getRequire() {
139
- if (isBrowser) return (() => {
140
- throw new Error("require not available in browser");
141
- });
142
- const nodeRequire = getNodeModuleRef();
143
- if (!nodeRequire) return (() => {
144
- throw new Error("require not available");
145
- });
146
- return nodeRequire.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('analyzer.js', document.baseURI).href)));
147
- }
148
- function requireNativeModule(path6) {
149
- return _require(path6);
94
+ function requireNativeModule(p) {
95
+ return _require(p);
150
96
  }
151
97
  function resolveNativeBindingCandidates(options) {
152
- if (isBrowser) return [];
153
- const { runtimeDir, envVarNames = [], includeDefaultCandidates = true, enforceNodeExtensionForEnvPath = false } = options;
98
+ const {
99
+ envVarNames = ["TW_NATIVE_PATH", "TWS_NATIVE_PATH"],
100
+ includeDefaultCandidates = true,
101
+ enforceNodeExtensionForEnvPath = false
102
+ } = options;
103
+ const runtimeDir = options.runtimeDir || process.cwd();
154
104
  const candidates = [];
155
- const path6 = getNodePath();
156
- const fs4 = getNodeFs();
157
105
  for (const envVar of envVarNames) {
158
106
  const envPath = process.env[envVar];
159
107
  if (envPath) {
160
- if (enforceNodeExtensionForEnvPath && !envPath.endsWith(".node")) {
161
- candidates.push(envPath + ".node");
162
- } else {
163
- candidates.push(envPath);
164
- }
108
+ candidates.push(enforceNodeExtensionForEnvPath && !envPath.endsWith(".node") ? envPath + ".node" : envPath);
165
109
  }
166
110
  }
167
111
  if (!includeDefaultCandidates) return candidates;
168
- if (fs4.existsSync(runtimeDir)) {
112
+ if (fs3__default.default.existsSync(runtimeDir)) {
169
113
  try {
170
- const entries = fs4.readdirSync(runtimeDir);
171
- for (const entry of entries) {
172
- if (entry.endsWith(".node")) {
173
- candidates.push(entry);
174
- }
114
+ for (const entry of fs3__default.default.readdirSync(runtimeDir)) {
115
+ if (entry.endsWith(".node")) candidates.push(entry);
175
116
  }
176
117
  } catch {
177
118
  }
178
119
  }
179
- const platform = typeof process !== "undefined" ? process.platform : "";
180
- const ext = platform === "win32" ? ".dll" : platform === "darwin" ? ".dylib" : ".so";
181
- const defaultBindingName = `tailwind_styled_parser${ext}`;
182
- candidates.push(path6.resolve(runtimeDir, "..", "..", "..", "native", defaultBindingName));
183
- candidates.push(path6.resolve(runtimeDir, "..", "..", "..", "..", "native", defaultBindingName));
184
- candidates.push(path6.resolve(process.cwd(), "native", defaultBindingName));
120
+ const BINARY_NAMES = ["tailwind-styled-native", "tailwind_styled_parser"];
121
+ const napiPlatform = process.platform === "linux" && process.arch === "x64" ? "linux-x64-gnu" : process.platform === "linux" && process.arch === "arm64" ? "linux-arm64-gnu" : `${process.platform}-${process.arch}`;
122
+ for (const bin of BINARY_NAMES) {
123
+ candidates.push(path5__default.default.resolve(runtimeDir, `${bin}.node`));
124
+ candidates.push(path5__default.default.resolve(runtimeDir, `${bin}.${napiPlatform}.node`));
125
+ candidates.push(path5__default.default.resolve(runtimeDir, "..", "..", "..", "..", "native", `${bin}.node`));
126
+ candidates.push(path5__default.default.resolve(runtimeDir, "..", "..", "..", "..", "native", `${bin}.${napiPlatform}.node`));
127
+ candidates.push(path5__default.default.resolve(runtimeDir, "..", "..", "..", "native", `${bin}.node`));
128
+ candidates.push(path5__default.default.resolve(process.cwd(), "native", `${bin}.node`));
129
+ candidates.push(path5__default.default.resolve(process.cwd(), "native", `${bin}.${napiPlatform}.node`));
130
+ }
185
131
  return Array.from(new Set(candidates));
186
132
  }
187
133
  function resolveRuntimeDir(dir, importMetaUrl) {
188
- if (isBrowser) return "";
189
- if (dir) return getNodePath().resolve(dir);
134
+ if (dir) return path5__default.default.resolve(dir);
190
135
  try {
191
- return getNodeUrl().fileURLToPath(importMetaUrl);
136
+ return path5__default.default.dirname(url.fileURLToPath(importMetaUrl));
192
137
  } catch {
193
138
  return process.cwd();
194
139
  }
195
140
  }
196
- var isBrowser, nodeModuleRef, _nodeFs, _nodePath, _nodeUrl, TwError, _require;
141
+ var TwError, _require;
197
142
  var init_src = __esm({
198
143
  "packages/domain/shared/src/index.ts"() {
199
- isBrowser = typeof window !== "undefined" || typeof document !== "undefined";
200
- nodeModuleRef = null;
201
- _nodeFs = null;
202
- _nodePath = null;
203
- _nodeUrl = null;
204
144
  TwError = class _TwError extends Error {
205
145
  /** @deprecated Gunakan source */
206
146
  domain;
@@ -234,8 +174,8 @@ var init_src = __esm({
234
174
  /** Buat TwError dari ZodError — dukung shape Zod v3 (`errors`) dan v4 (`issues`). */
235
175
  static fromZod(err) {
236
176
  const first = err.issues?.[0] ?? err.errors?.[0];
237
- const path6 = formatIssuePath(first?.path);
238
- const message = first ? `${path6}: ${first.message}` : "Schema validation failed";
177
+ const path8 = formatIssuePath(first?.path);
178
+ const message = first ? `${path8}: ${first.message}` : "Schema validation failed";
239
179
  return new _TwError("validation", "SCHEMA_VALIDATION_FAILED", message, err);
240
180
  }
241
181
  static wrap(source, code, err) {
@@ -253,21 +193,33 @@ var init_src = __esm({
253
193
  return `[${this.source.toUpperCase()}:${this.code}] ${this.message}`;
254
194
  }
255
195
  };
256
- _require = getRequire();
196
+ _require = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('analyzer.js', document.baseURI).href)));
257
197
  }
258
198
  });
259
199
 
260
200
  // packages/domain/scanner/src/native-bridge.ts
261
201
  var native_bridge_exports = {};
262
202
  __export(native_bridge_exports, {
203
+ batchExtractClassesNative: () => batchExtractClassesNative,
263
204
  cachePriorityNative: () => cachePriorityNative,
264
205
  cacheReadNative: () => cacheReadNative,
265
206
  cacheWriteNative: () => cacheWriteNative,
207
+ collectFilesNative: () => collectFilesNative,
208
+ computeCacheStatsNative: () => computeCacheStatsNative,
266
209
  extractClassesNative: () => extractClassesNative,
210
+ generateSubComponentTypesNative: () => generateSubComponentTypesNative,
267
211
  hasNativeScannerBinding: () => hasNativeScannerBinding,
268
212
  hashContentNative: () => hashContentNative,
269
213
  isRustCacheAvailable: () => isRustCacheAvailable,
214
+ pruneStaleEntriesNative: () => pruneStaleEntriesNative,
215
+ rebuildWorkspaceResultNative: () => rebuildWorkspaceResultNative,
270
216
  resetScannerBridgeCache: () => resetScannerBridgeCache,
217
+ scanCacheGet: () => scanCacheGet,
218
+ scanCacheInvalidate: () => scanCacheInvalidate,
219
+ scanCachePut: () => scanCachePut,
220
+ scanCacheStats: () => scanCacheStats,
221
+ scanFileNative: () => scanFileNative,
222
+ scanFilesBatchNative: () => scanFilesBatchNative,
271
223
  scanWorkspaceNative: () => scanWorkspaceNative
272
224
  });
273
225
  function getDirname() {
@@ -275,7 +227,7 @@ function getDirname() {
275
227
  return __dirname;
276
228
  }
277
229
  if (typeof ({ url: (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('analyzer.js', document.baseURI).href)) }) !== "undefined" && (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('analyzer.js', document.baseURI).href))) {
278
- return path3__default.default.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('analyzer.js', document.baseURI).href))));
230
+ return path5__default.default.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('analyzer.js', document.baseURI).href))));
279
231
  }
280
232
  return process.cwd();
281
233
  }
@@ -356,6 +308,95 @@ function cachePriorityNative(mtimeMs, size, cachedMtimeMs, cachedSize, cachedHit
356
308
  }
357
309
  return result;
358
310
  }
311
+ function batchExtractClassesNative(filePaths) {
312
+ const binding = scannerGetBinding();
313
+ if (!binding.batchExtractClasses) {
314
+ throw new Error("FATAL: Native binding 'batchExtractClasses' is required but not available.");
315
+ }
316
+ return binding.batchExtractClasses(filePaths) ?? [];
317
+ }
318
+ function scanCacheGet(filePath, contentHash) {
319
+ const binding = scannerGetBinding();
320
+ if (!binding.scanCacheGet) {
321
+ throw new Error("FATAL: Native binding 'scanCacheGet' is required but not available.");
322
+ }
323
+ return binding.scanCacheGet(filePath, contentHash) ?? null;
324
+ }
325
+ function scanCachePut(filePath, contentHash, classes, mtimeMs, size) {
326
+ const binding = scannerGetBinding();
327
+ if (!binding.scanCachePut) {
328
+ throw new Error("FATAL: Native binding 'scanCachePut' is required but not available.");
329
+ }
330
+ binding.scanCachePut(filePath, contentHash, classes, mtimeMs, size);
331
+ }
332
+ function scanCacheInvalidate(filePath) {
333
+ const binding = scannerGetBinding();
334
+ if (!binding.scanCacheInvalidate) {
335
+ throw new Error("FATAL: Native binding 'scanCacheInvalidate' is required but not available.");
336
+ }
337
+ binding.scanCacheInvalidate(filePath);
338
+ }
339
+ function scanCacheStats() {
340
+ const binding = scannerGetBinding();
341
+ if (!binding.scanCacheStats) {
342
+ throw new Error("FATAL: Native binding 'scanCacheStats' is required but not available.");
343
+ }
344
+ return binding.scanCacheStats();
345
+ }
346
+ function scanFileNative(filePath) {
347
+ const binding = scannerGetBinding();
348
+ if (!binding.scanFile) {
349
+ throw new Error("FATAL: Native binding 'scanFile' is required but not available.");
350
+ }
351
+ return binding.scanFile(filePath);
352
+ }
353
+ function collectFilesNative(root, extensions, ignoreDirs) {
354
+ const binding = scannerGetBinding();
355
+ if (!binding.collectFiles) return null;
356
+ return binding.collectFiles(root, extensions, ignoreDirs);
357
+ }
358
+ function scanFilesBatchNative(filePaths) {
359
+ const binding = scannerGetBinding();
360
+ if (!binding.scanFilesBatch) {
361
+ return filePaths.map((fp) => {
362
+ try {
363
+ const r = binding.scanFile?.(fp);
364
+ return r ? { file: r.file, classes: r.classes, hash: r.hash ?? "" } : { file: fp, classes: [], hash: "" };
365
+ } catch {
366
+ return { file: fp, classes: [], hash: "" };
367
+ }
368
+ });
369
+ }
370
+ return binding.scanFilesBatch(filePaths);
371
+ }
372
+ function generateSubComponentTypesNative(root, outputPath) {
373
+ const binding = scannerGetBinding();
374
+ if (!binding.generateSubComponentTypes) return null;
375
+ return binding.generateSubComponentTypes(root, outputPath ?? null);
376
+ }
377
+ function pruneStaleEntriesNative(entries, maxAgeMs, checkExists) {
378
+ const binding = scannerGetBinding();
379
+ if (!binding.pruneStaleEntries) return null;
380
+ return binding.pruneStaleEntries(
381
+ entries.map((e) => ({ file: e.file, lastSeenMs: e.lastSeenMs ?? 0 })),
382
+ maxAgeMs ?? null,
383
+ checkExists ?? null
384
+ );
385
+ }
386
+ function rebuildWorkspaceResultNative(files) {
387
+ const binding = scannerBridgeLoader.get();
388
+ if (!binding?.rebuildWorkspaceResult) return null;
389
+ try {
390
+ return binding.rebuildWorkspaceResult(files);
391
+ } catch {
392
+ return null;
393
+ }
394
+ }
395
+ function computeCacheStatsNative(filesClasses, sizes, top) {
396
+ const binding = scannerGetBinding();
397
+ if (!binding.computeCacheStats) return null;
398
+ return binding.computeCacheStats(filesClasses, sizes, top ?? null);
399
+ }
359
400
  var log, isValidScannerBinding, createScannerBridgeLoader, scannerBridgeLoader, scannerGetBinding, resetScannerBridgeCache;
360
401
  var init_native_bridge = __esm({
361
402
  "packages/domain/scanner/src/native-bridge.ts"() {
@@ -439,15 +480,9 @@ var init_native_bridge = __esm({
439
480
  resetScannerBridgeCache = scannerBridgeLoader.reset;
440
481
  }
441
482
  });
442
-
443
- // packages/domain/scanner/src/index.ts
444
- init_src();
445
-
446
- // packages/domain/scanner/src/cache-native.ts
447
- init_native_bridge();
448
483
  function defaultCachePath(rootDir, cacheDir) {
449
- const dir = cacheDir ? path3__default.default.resolve(rootDir, cacheDir) : path3__default.default.join(process.cwd(), ".cache", "tailwind-styled");
450
- return path3__default.default.join(dir, "scanner-cache.json");
484
+ const dir = cacheDir ? path5__default.default.resolve(rootDir, cacheDir) : path5__default.default.join(process.cwd(), ".cache", "tailwind-styled");
485
+ return path5__default.default.join(dir, "scanner-cache.json");
451
486
  }
452
487
  function readCache(rootDir, cacheDir) {
453
488
  const cachePath = defaultCachePath(rootDir, cacheDir);
@@ -483,158 +518,219 @@ function filePriority(mtimeMs, size, cached, nowMs = Date.now()) {
483
518
  nowMs
484
519
  );
485
520
  }
486
-
487
- // packages/domain/scanner/src/index.ts
488
- init_native_bridge();
489
-
490
- // packages/domain/scanner/src/schemas.ts
491
- init_src();
492
- var formatIssuePath2 = (path6) => path6.length > 0 ? path6.map(
493
- (segment) => typeof segment === "symbol" ? segment.description ?? segment.toString() : String(segment)
494
- ).join(".") : "<root>";
495
- var formatIssues = (error) => error.issues.map((issue) => {
496
- const path6 = formatIssuePath2(issue.path);
497
- return `${path6}: ${issue.message}`;
498
- }).join("; ");
499
- var parseWithSchema = (schema, data, label) => {
500
- const parsed = schema.safeParse(data);
501
- if (parsed.success) return parsed.data;
502
- const details = formatIssues(parsed.error);
503
- throw new TwError(
504
- "validation",
505
- "SCHEMA_VALIDATION_FAILED",
506
- details ? `${label}: ${details}` : label,
507
- parsed.error
508
- );
509
- };
510
- var NonNegativeIntegerSchema = zod.z.number().int().min(0);
511
- var ScanWorkspaceOptionsSchema = zod.z.object({
512
- includeExtensions: zod.z.array(zod.z.string()).optional(),
513
- ignoreDirectories: zod.z.array(zod.z.string()).optional(),
514
- useCache: zod.z.boolean().optional(),
515
- cacheDir: zod.z.string().min(1).optional(),
516
- smartInvalidation: zod.z.boolean().optional()
517
- });
518
- var ScanFileResultSchema = zod.z.object({
519
- file: zod.z.string(),
520
- classes: zod.z.array(zod.z.string()),
521
- hash: zod.z.string().optional()
522
- });
523
- var ScanWorkspaceResultSchema = zod.z.object({
524
- files: zod.z.array(ScanFileResultSchema),
525
- totalFiles: NonNegativeIntegerSchema,
526
- uniqueClasses: zod.z.array(zod.z.string())
527
- }).refine((value) => value.totalFiles === value.files.length, {
528
- message: "scan result totalFiles must match files.length",
529
- path: ["totalFiles"]
530
- });
531
- zod.z.object({
532
- rootDir: zod.z.string().min(1),
533
- options: ScanWorkspaceOptionsSchema.optional()
521
+ var init_cache_native = __esm({
522
+ "packages/domain/scanner/src/cache-native.ts"() {
523
+ init_native_bridge();
524
+ }
534
525
  });
535
- var ScannerWorkerSuccessMessageSchema = zod.z.object({
536
- ok: zod.z.literal(true),
537
- result: ScanWorkspaceResultSchema
526
+ function collectFiles(rootDir, extensions, ignoreDirs) {
527
+ const native = collectFilesNative(rootDir, extensions, ignoreDirs);
528
+ if (native !== null) return native;
529
+ const files = [];
530
+ function walk(dir) {
531
+ let entries;
532
+ try {
533
+ entries = fs3__default.default.readdirSync(dir, { withFileTypes: true });
534
+ } catch {
535
+ return;
536
+ }
537
+ for (const entry of entries) {
538
+ const fullPath = path5__default.default.join(dir, entry.name);
539
+ const rel = path5__default.default.relative(rootDir, fullPath);
540
+ if (entry.isDirectory()) {
541
+ const ignored = ignoreDirs.some((d) => entry.name === d || rel.startsWith(d + path5__default.default.sep));
542
+ if (!ignored) walk(fullPath);
543
+ } else if (isScannableFile(entry.name, extensions)) {
544
+ files.push(fullPath);
545
+ }
546
+ }
547
+ }
548
+ walk(rootDir);
549
+ return files;
550
+ }
551
+ function mergeResults(batchResults) {
552
+ const files = batchResults.map((r) => ({
553
+ file: r.file,
554
+ classes: r.classes,
555
+ hash: r.content_hash
556
+ }));
557
+ const native = rebuildWorkspaceResultNative(files);
558
+ if (native) return native;
559
+ const unique = new Set(files.flatMap((f) => f.classes));
560
+ return { files, totalFiles: files.length, uniqueClasses: Array.from(unique).sort() };
561
+ }
562
+ function runChunkInWorker(filePaths) {
563
+ return new Promise((resolve, reject) => {
564
+ const worker = new worker_threads.Worker(_workerFilename, {
565
+ workerData: { filePaths }
566
+ });
567
+ worker.once("message", (payload) => {
568
+ if (payload.ok) {
569
+ resolve(payload.results);
570
+ } else {
571
+ reject(new Error(payload.error ?? "parallel-scanner worker failed"));
572
+ }
573
+ });
574
+ worker.once("error", reject);
575
+ worker.once("exit", (code) => {
576
+ if (code !== 0) reject(new Error(`parallel-scanner worker exited with code ${code}`));
577
+ });
578
+ });
579
+ }
580
+ async function scanWorkspaceParallel(rootDir, options = {}) {
581
+ const {
582
+ extensions = DEFAULT_EXTENSIONS,
583
+ ignoreDirs = DEFAULT_IGNORES,
584
+ maxWorkers = Math.max(1, os.availableParallelism() - 1),
585
+ chunkSize = DEFAULT_CHUNK_SIZE
586
+ } = options;
587
+ const files = collectFiles(path5__default.default.resolve(rootDir), extensions, ignoreDirs);
588
+ if (files.length < PARALLEL_THRESHOLD) {
589
+ return mergeResults(batchExtractClassesNative(files));
590
+ }
591
+ const chunks = [];
592
+ for (let i = 0; i < files.length; i += chunkSize) {
593
+ chunks.push(files.slice(i, i + chunkSize));
594
+ }
595
+ const allResults = [];
596
+ for (let i = 0; i < chunks.length; i += maxWorkers) {
597
+ const batch = chunks.slice(i, i + maxWorkers);
598
+ const batchResults = await Promise.all(batch.map(runChunkInWorker));
599
+ allResults.push(...batchResults.flat());
600
+ }
601
+ return mergeResults(allResults);
602
+ }
603
+ var PARALLEL_THRESHOLD, DEFAULT_CHUNK_SIZE, _workerFilename;
604
+ var init_parallel_scanner = __esm({
605
+ "packages/domain/scanner/src/parallel-scanner.ts"() {
606
+ init_src2();
607
+ init_native_bridge();
608
+ PARALLEL_THRESHOLD = 50;
609
+ DEFAULT_CHUNK_SIZE = 150;
610
+ if (!worker_threads.isMainThread && worker_threads.parentPort) {
611
+ const { filePaths } = worker_threads.workerData;
612
+ try {
613
+ const results = batchExtractClassesNative(filePaths);
614
+ const msg = { ok: true, results };
615
+ worker_threads.parentPort.postMessage(msg);
616
+ } catch (error) {
617
+ const msg = {
618
+ ok: false,
619
+ error: error instanceof Error ? error.message : String(error)
620
+ };
621
+ worker_threads.parentPort.postMessage(msg);
622
+ }
623
+ }
624
+ _workerFilename = typeof __filename !== "undefined" ? __filename : url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('analyzer.js', document.baseURI).href)));
625
+ }
538
626
  });
539
- var ScannerWorkerErrorMessageSchema = zod.z.object({
540
- ok: zod.z.literal(false),
541
- error: zod.z.string().optional()
627
+ var formatIssuePath2, formatIssues, parseWithSchema, NonNegativeIntegerSchema, ScanWorkspaceOptionsSchema, ScanFileResultSchema, ScanWorkspaceResultSchema, ScannerWorkerSuccessMessageSchema, ScannerWorkerErrorMessageSchema, ScannerWorkerMessageSchema, parseScanWorkspaceOptions, parseScanWorkspaceResult, parseScannerWorkerMessage;
628
+ var init_schemas = __esm({
629
+ "packages/domain/scanner/src/schemas.ts"() {
630
+ init_src();
631
+ formatIssuePath2 = (path8) => path8.length > 0 ? path8.map(
632
+ (segment) => typeof segment === "symbol" ? segment.description ?? segment.toString() : String(segment)
633
+ ).join(".") : "<root>";
634
+ formatIssues = (error) => error.issues.map((issue) => {
635
+ const path8 = formatIssuePath2(issue.path);
636
+ return `${path8}: ${issue.message}`;
637
+ }).join("; ");
638
+ parseWithSchema = (schema, data, label) => {
639
+ const parsed = schema.safeParse(data);
640
+ if (parsed.success) return parsed.data;
641
+ const details = formatIssues(parsed.error);
642
+ throw new TwError(
643
+ "validation",
644
+ "SCHEMA_VALIDATION_FAILED",
645
+ details ? `${label}: ${details}` : label,
646
+ parsed.error
647
+ );
648
+ };
649
+ NonNegativeIntegerSchema = zod.z.number().int().min(0);
650
+ ScanWorkspaceOptionsSchema = zod.z.object({
651
+ includeExtensions: zod.z.array(zod.z.string()).optional(),
652
+ ignoreDirectories: zod.z.array(zod.z.string()).optional(),
653
+ useCache: zod.z.boolean().optional(),
654
+ cacheDir: zod.z.string().min(1).optional(),
655
+ smartInvalidation: zod.z.boolean().optional()
656
+ });
657
+ ScanFileResultSchema = zod.z.object({
658
+ file: zod.z.string(),
659
+ classes: zod.z.array(zod.z.string()),
660
+ hash: zod.z.string().optional()
661
+ });
662
+ ScanWorkspaceResultSchema = zod.z.object({
663
+ files: zod.z.array(ScanFileResultSchema),
664
+ totalFiles: NonNegativeIntegerSchema,
665
+ uniqueClasses: zod.z.array(zod.z.string())
666
+ }).refine((value) => value.totalFiles === value.files.length, {
667
+ message: "scan result totalFiles must match files.length",
668
+ path: ["totalFiles"]
669
+ });
670
+ zod.z.object({
671
+ rootDir: zod.z.string().min(1),
672
+ options: ScanWorkspaceOptionsSchema.optional()
673
+ });
674
+ ScannerWorkerSuccessMessageSchema = zod.z.object({
675
+ ok: zod.z.literal(true),
676
+ result: ScanWorkspaceResultSchema
677
+ });
678
+ ScannerWorkerErrorMessageSchema = zod.z.object({
679
+ ok: zod.z.literal(false),
680
+ error: zod.z.string().optional()
681
+ });
682
+ ScannerWorkerMessageSchema = zod.z.union([
683
+ ScannerWorkerSuccessMessageSchema,
684
+ ScannerWorkerErrorMessageSchema
685
+ ]);
686
+ parseScanWorkspaceOptions = (options) => parseWithSchema(ScanWorkspaceOptionsSchema, options ?? {}, "scanner options are invalid");
687
+ parseScanWorkspaceResult = (result) => parseWithSchema(ScanWorkspaceResultSchema, result, "scanner workspace result is invalid");
688
+ parseScannerWorkerMessage = (message) => parseWithSchema(ScannerWorkerMessageSchema, message, "scanner worker message is invalid");
689
+ }
542
690
  });
543
- var ScannerWorkerMessageSchema = zod.z.union([
544
- ScannerWorkerSuccessMessageSchema,
545
- ScannerWorkerErrorMessageSchema
546
- ]);
547
- var parseScanWorkspaceOptions = (options) => parseWithSchema(ScanWorkspaceOptionsSchema, options ?? {}, "scanner options are invalid");
548
- var parseScanWorkspaceResult = (result) => parseWithSchema(ScanWorkspaceResultSchema, result, "scanner workspace result is invalid");
549
- var parseScannerWorkerMessage = (message) => parseWithSchema(ScannerWorkerMessageSchema, message, "scanner worker message is invalid");
550
691
 
551
692
  // packages/domain/scanner/src/index.ts
552
- var log2 = createLogger("scanner");
553
- var SCAN_WORKER_TIMEOUT_MS = 12e4;
693
+ var src_exports = {};
694
+ __export(src_exports, {
695
+ DEFAULT_EXTENSIONS: () => DEFAULT_EXTENSIONS,
696
+ DEFAULT_IGNORES: () => DEFAULT_IGNORES,
697
+ batchExtractClassesNative: () => batchExtractClassesNative,
698
+ extractClassesNative: () => extractClassesNative,
699
+ isScannableFile: () => isScannableFile,
700
+ parseScanWorkspaceOptions: () => parseScanWorkspaceOptions,
701
+ parseScanWorkspaceResult: () => parseScanWorkspaceResult,
702
+ parseScannerWorkerMessage: () => parseScannerWorkerMessage,
703
+ scanFile: () => scanFile,
704
+ scanSource: () => scanSource,
705
+ scanWorkspace: () => scanWorkspace,
706
+ scanWorkspaceAsync: () => scanWorkspaceAsync
707
+ });
554
708
  function getRuntimeDir() {
555
709
  if (typeof __dirname !== "undefined" && __dirname.length > 0) {
556
710
  return __dirname;
557
711
  }
558
712
  if (typeof ({ url: (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('analyzer.js', document.baseURI).href)) }) !== "undefined" && (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('analyzer.js', document.baseURI).href))) {
559
- return path3__default.default.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('analyzer.js', document.baseURI).href))));
713
+ return path5__default.default.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('analyzer.js', document.baseURI).href))));
560
714
  }
561
715
  return process.cwd();
562
716
  }
563
- var createNativeParserLoader = () => {
564
- const _state = {
565
- binding: void 0,
566
- initError: null
567
- };
568
- const debugNative = (message) => {
569
- log2.debug(`[native] ${message}`);
570
- };
571
- const loadNativeParserBinding = () => {
572
- if (_state.binding !== void 0) return _state.binding;
573
- const runtimeDir = getRuntimeDir();
574
- const req = module$1.createRequire(path3__default.default.join(runtimeDir, "noop.cjs"));
575
- const candidates = [
576
- path3__default.default.resolve(process.cwd(), "native/tailwind_styled_parser.node"),
577
- path3__default.default.resolve(process.cwd(), "native/build/Release/tailwind_styled_parser.node"),
578
- path3__default.default.resolve(runtimeDir, "..", "..", "..", "native", "tailwind_styled_parser.node"),
579
- path3__default.default.resolve(
580
- runtimeDir,
581
- "..",
582
- "..",
583
- "..",
584
- "native",
585
- "build",
586
- "Release",
587
- "tailwind_styled_parser.node"
588
- )
589
- ];
590
- for (const fullPath of candidates) {
591
- if (!fs__default.default.existsSync(fullPath)) continue;
592
- try {
593
- const required = req(fullPath);
594
- if (required && (typeof required.extractClassesFromSource === "function" || typeof required.parseClasses === "function" || typeof required.parse_classes === "function")) {
595
- _state.binding = required;
596
- debugNative(`using native parser from ${fullPath}`);
597
- return _state.binding;
598
- }
599
- } catch (error) {
600
- _state.initError = error instanceof Error ? error.message : String(error);
601
- }
602
- }
603
- _state.binding = null;
604
- if (!_state.initError) {
605
- _state.initError = "native .node binding not found";
606
- }
607
- debugNative(`native binding not available: ${_state.initError}`);
608
- return _state.binding;
609
- };
610
- return {
611
- get: loadNativeParserBinding,
612
- reset: () => {
613
- _state.binding = void 0;
614
- _state.initError = null;
615
- }
616
- };
617
- };
618
- var nativeParserLoader = createNativeParserLoader();
619
- var DEFAULT_EXTENSIONS = [".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs"];
620
- var DEFAULT_IGNORES = ["node_modules", ".git", ".next", "dist", "out", ".turbo", ".cache"];
621
717
  function resolveScannerWorkerModulePath() {
622
718
  const runtimeDir = (() => {
623
719
  if (typeof __dirname !== "undefined" && __dirname.length > 0) {
624
720
  return __dirname;
625
721
  }
626
722
  if (typeof ({ url: (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('analyzer.js', document.baseURI).href)) }) !== "undefined" && (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('analyzer.js', document.baseURI).href))) {
627
- return path3__default.default.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('analyzer.js', document.baseURI).href))));
723
+ return path5__default.default.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('analyzer.js', document.baseURI).href))));
628
724
  }
629
725
  return process.cwd();
630
726
  })();
631
727
  const candidates = [
632
- path3__default.default.resolve(runtimeDir, "worker.cjs"),
633
- path3__default.default.resolve(runtimeDir, "worker.js"),
634
- path3__default.default.resolve(runtimeDir, "worker.ts")
728
+ path5__default.default.resolve(runtimeDir, "worker.cjs"),
729
+ path5__default.default.resolve(runtimeDir, "worker.js"),
730
+ path5__default.default.resolve(runtimeDir, "worker.ts")
635
731
  ];
636
732
  for (const candidate of candidates) {
637
- if (fs__default.default.existsSync(candidate)) return candidate;
733
+ if (fs3__default.default.existsSync(candidate)) return candidate;
638
734
  }
639
735
  return null;
640
736
  }
@@ -691,19 +787,19 @@ function collectCandidates(rootDir, ignoreDirectories, extensionSet) {
691
787
  if (!currentDir) continue;
692
788
  const entries = (() => {
693
789
  try {
694
- return fs__default.default.readdirSync(currentDir, { withFileTypes: true });
790
+ return fs3__default.default.readdirSync(currentDir, { withFileTypes: true });
695
791
  } catch {
696
792
  return [];
697
793
  }
698
794
  })();
699
795
  for (const entry of entries) {
700
- const fullPath = path3__default.default.join(currentDir, entry.name);
796
+ const fullPath = path5__default.default.join(currentDir, entry.name);
701
797
  if (entry.isDirectory()) {
702
798
  if (!ignoreDirectories.has(entry.name)) directories.push(fullPath);
703
799
  continue;
704
800
  }
705
801
  if (!entry.isFile()) continue;
706
- if (!extensionSet.has(path3__default.default.extname(entry.name))) continue;
802
+ if (!extensionSet.has(path5__default.default.extname(entry.name))) continue;
707
803
  candidates.push(fullPath);
708
804
  }
709
805
  }
@@ -717,22 +813,31 @@ function toCacheSize(size) {
717
813
  function scanSource(source) {
718
814
  const nativeBinding = nativeParserLoader.get();
719
815
  if (nativeBinding?.extractClassesFromSource) {
720
- const classes = nativeBinding.extractClassesFromSource(source);
721
- if (Array.isArray(classes)) {
722
- return Array.from(new Set(classes.filter(Boolean)));
816
+ const result = nativeBinding.extractClassesFromSource(source);
817
+ if (Array.isArray(result)) {
818
+ return Array.from(new Set(result.filter(Boolean)));
819
+ }
820
+ if (result !== null && result !== void 0 && Array.isArray(result.classes)) {
821
+ return Array.from(new Set(result.classes.filter(Boolean)));
723
822
  }
724
823
  }
725
824
  throw new Error(
726
825
  "FATAL: Native parser binding is required but not available.\nThis package requires native Rust bindings.\n\nResolution steps:\n1. Build the native Rust module: npm run build:rust"
727
826
  );
728
827
  }
828
+ function isScannableFile(filePath, includeExtensions = DEFAULT_EXTENSIONS) {
829
+ return includeExtensions.includes(path5__default.default.extname(filePath));
830
+ }
729
831
  function scanFile(filePath) {
730
- const source = fs__default.default.readFileSync(filePath, "utf8");
731
- const hash = hashContentNative(source) ?? void 0;
832
+ const { scanFileNative: scanFileNative2 } = (init_native_bridge(), __toCommonJS(native_bridge_exports));
833
+ const result = scanFileNative2(filePath);
834
+ if (!result.ok) {
835
+ throw new Error(`scanFile failed for ${filePath}: ${result.error ?? "unknown error"}`);
836
+ }
732
837
  return {
733
- file: filePath,
734
- classes: scanSource(source),
735
- ...hash ? { hash } : {}
838
+ file: result.file,
839
+ classes: result.classes,
840
+ ...result.hash ? { hash: result.hash } : {}
736
841
  };
737
842
  }
738
843
  function scanWorkspace(rootDir, options = {}) {
@@ -781,7 +886,7 @@ function scanWorkspace(rootDir, options = {}) {
781
886
  for (const filePath of candidates) {
782
887
  const stat = (() => {
783
888
  try {
784
- return fs__default.default.statSync(filePath);
889
+ return fs3__default.default.statSync(filePath);
785
890
  } catch {
786
891
  return null;
787
892
  }
@@ -807,7 +912,7 @@ function scanWorkspace(rootDir, options = {}) {
807
912
  for (const { filePath, stat, size, cached } of ranked) {
808
913
  const content = (() => {
809
914
  try {
810
- return fs__default.default.readFileSync(filePath, "utf8");
915
+ return fs3__default.default.readFileSync(filePath, "utf8");
811
916
  } catch {
812
917
  return null;
813
918
  }
@@ -869,18 +974,113 @@ function scanWorkspace(rootDir, options = {}) {
869
974
  }
870
975
  async function scanWorkspaceAsync(rootDir, options = {}) {
871
976
  const normalizedOptions = parseScanWorkspaceOptions(options);
872
- if (process.env.TWS_DISABLE_SCANNER_WORKER === "1") {
873
- return scanWorkspace(rootDir, normalizedOptions);
977
+ try {
978
+ return await scanWorkspaceParallel(rootDir, {
979
+ extensions: normalizedOptions.includeExtensions,
980
+ ignoreDirs: normalizedOptions.ignoreDirectories
981
+ });
982
+ } catch (parallelError) {
983
+ log2.debug(
984
+ `parallel scan failed, retrying with single worker: ${parallelError instanceof Error ? parallelError.message : String(parallelError)}`
985
+ );
874
986
  }
875
987
  try {
876
988
  return await scanWorkspaceInWorker(rootDir, normalizedOptions);
877
989
  } catch (error) {
878
990
  log2.debug(
879
- `worker scan failed, falling back to sync scanner: ${error instanceof Error ? error.message : String(error)}`
991
+ `worker scan failed, retrying with sync native scanner: ${error instanceof Error ? error.message : String(error)}`
880
992
  );
881
993
  return scanWorkspace(rootDir, normalizedOptions);
882
994
  }
883
995
  }
996
+ var log2, SCAN_WORKER_TIMEOUT_MS, createNativeParserLoader, nativeParserLoader, DEFAULT_EXTENSIONS, DEFAULT_IGNORES;
997
+ var init_src2 = __esm({
998
+ "packages/domain/scanner/src/index.ts"() {
999
+ init_src();
1000
+ init_cache_native();
1001
+ init_native_bridge();
1002
+ init_parallel_scanner();
1003
+ init_schemas();
1004
+ init_schemas();
1005
+ init_native_bridge();
1006
+ log2 = createLogger("scanner");
1007
+ SCAN_WORKER_TIMEOUT_MS = 12e4;
1008
+ createNativeParserLoader = () => {
1009
+ const _state = {
1010
+ binding: void 0,
1011
+ initError: null
1012
+ };
1013
+ const debugNative = (message) => {
1014
+ log2.debug(`[native] ${message}`);
1015
+ };
1016
+ const loadNativeParserBinding = () => {
1017
+ if (_state.binding !== void 0) return _state.binding;
1018
+ const runtimeDir = getRuntimeDir();
1019
+ const req = module$1.createRequire(path5__default.default.join(runtimeDir, "noop.cjs"));
1020
+ const candidates = [
1021
+ // ── binaryName baru: tailwind-styled-native (napi-rs naming) ──
1022
+ // cwd = repo root saat run dari root, atau package dir saat workspaces
1023
+ path5__default.default.resolve(process.cwd(), "native", "tailwind-styled-native.node"),
1024
+ path5__default.default.resolve(process.cwd(), "native", `tailwind-styled-native.${process.platform}-${process.arch}.node`),
1025
+ path5__default.default.resolve(process.cwd(), "native", `tailwind-styled-native.${process.platform}-${process.arch}-gnu.node`),
1026
+ // runtimeDir = dist/ → naik 4 level ke repo root
1027
+ path5__default.default.resolve(runtimeDir, "..", "..", "..", "..", "native", "tailwind-styled-native.node"),
1028
+ path5__default.default.resolve(runtimeDir, "..", "..", "..", "..", "native", `tailwind-styled-native.${process.platform}-${process.arch}-gnu.node`),
1029
+ // 3 level fallback (jika package di-nest lebih dangkal)
1030
+ path5__default.default.resolve(runtimeDir, "..", "..", "..", "native", "tailwind-styled-native.node"),
1031
+ path5__default.default.resolve(runtimeDir, "..", "..", "..", "native", `tailwind-styled-native.${process.platform}-${process.arch}-gnu.node`),
1032
+ // ── binaryName lama: tailwind_styled_parser (backward compat) ──
1033
+ path5__default.default.resolve(process.cwd(), "native/tailwind_styled_parser.node"),
1034
+ path5__default.default.resolve(process.cwd(), "native/build/Release/tailwind_styled_parser.node"),
1035
+ path5__default.default.resolve(runtimeDir, "..", "..", "..", "..", "native", "tailwind_styled_parser.node"),
1036
+ path5__default.default.resolve(runtimeDir, "..", "..", "..", "native", "tailwind_styled_parser.node"),
1037
+ path5__default.default.resolve(
1038
+ runtimeDir,
1039
+ "..",
1040
+ "..",
1041
+ "..",
1042
+ "native",
1043
+ "build",
1044
+ "Release",
1045
+ "tailwind_styled_parser.node"
1046
+ )
1047
+ ];
1048
+ for (const fullPath of candidates) {
1049
+ if (!fs3__default.default.existsSync(fullPath)) continue;
1050
+ try {
1051
+ const required = req(fullPath);
1052
+ if (required && (typeof required.extractClassesFromSource === "function" || typeof required.parseClasses === "function" || typeof required.parse_classes === "function")) {
1053
+ _state.binding = required;
1054
+ debugNative(`using native parser from ${fullPath}`);
1055
+ return _state.binding;
1056
+ }
1057
+ } catch (error) {
1058
+ _state.initError = error instanceof Error ? error.message : String(error);
1059
+ }
1060
+ }
1061
+ _state.binding = null;
1062
+ if (!_state.initError) {
1063
+ _state.initError = "native .node binding not found";
1064
+ }
1065
+ debugNative(`native binding not available: ${_state.initError}`);
1066
+ return _state.binding;
1067
+ };
1068
+ return {
1069
+ get: loadNativeParserBinding,
1070
+ reset: () => {
1071
+ _state.binding = void 0;
1072
+ _state.initError = null;
1073
+ }
1074
+ };
1075
+ };
1076
+ nativeParserLoader = createNativeParserLoader();
1077
+ DEFAULT_EXTENSIONS = [".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs"];
1078
+ DEFAULT_IGNORES = ["node_modules", ".git", ".next", "dist", "out", ".turbo", ".cache"];
1079
+ }
1080
+ });
1081
+
1082
+ // packages/domain/analyzer/src/analyzeWorkspace.ts
1083
+ init_src2();
884
1084
 
885
1085
  // packages/domain/analyzer/src/binding.ts
886
1086
  init_src();
@@ -900,7 +1100,7 @@ function isRecord(value) {
900
1100
  }
901
1101
  async function pathExists(filePath) {
902
1102
  try {
903
- await fs__default.default.promises.access(filePath, fs__default.default.constants.F_OK);
1103
+ await fs3__default.default.promises.access(filePath, fs3__default.default.constants.F_OK);
904
1104
  return true;
905
1105
  } catch {
906
1106
  return false;
@@ -963,6 +1163,9 @@ var createAnalyzerBindingLoader = () => {
963
1163
  };
964
1164
  };
965
1165
  var analyzerBindingLoader = createAnalyzerBindingLoader();
1166
+ async function getNativeBinding() {
1167
+ return analyzerBindingLoader.get();
1168
+ }
966
1169
  async function requireNativeBinding() {
967
1170
  const binding = await analyzerBindingLoader.get();
968
1171
  if (binding?.analyzeClasses) return binding;
@@ -1001,7 +1204,7 @@ async function requireNativeCssCompiler() {
1001
1204
 
1002
1205
  // packages/domain/analyzer/src/schemas.ts
1003
1206
  init_src();
1004
- var formatIssuePath3 = (path6) => path6.length > 0 ? path6.map(
1207
+ var formatIssuePath3 = (path8) => path8.length > 0 ? path8.map(
1005
1208
  (segment) => typeof segment === "symbol" ? segment.description ?? segment.toString() : String(segment)
1006
1209
  ).join(".") : "<root>";
1007
1210
  var isPlainObject = (value) => {
@@ -1010,8 +1213,8 @@ var isPlainObject = (value) => {
1010
1213
  return proto === Object.prototype || proto === null;
1011
1214
  };
1012
1215
  var formatIssues2 = (error) => error.issues.map((issue) => {
1013
- const path6 = formatIssuePath3(issue.path);
1014
- return `${path6}: ${issue.message}`;
1216
+ const path8 = formatIssuePath3(issue.path);
1217
+ return `${path8}: ${issue.message}`;
1015
1218
  }).join("; ");
1016
1219
  var parseWithSchema2 = (schema, data, label) => {
1017
1220
  const parsed = schema.safeParse(data);
@@ -1106,112 +1309,6 @@ var parseNativeCssCompileResult = (result, className) => parseWithSchema2(
1106
1309
  );
1107
1310
  var parseClassToCssOptions = (options) => parseWithSchema2(ClassToCssOptionsSchema, options ?? {}, "classToCss options are invalid");
1108
1311
  var SUPPORTED_TAILWIND_CONFIG_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".js", ".cjs", ".mjs"]);
1109
- var KNOWN_UTILITY_PREFIXES = /* @__PURE__ */ new Set([
1110
- "absolute",
1111
- "align",
1112
- "animate",
1113
- "arbitrary",
1114
- "aspect",
1115
- "backdrop",
1116
- "basis",
1117
- "bg",
1118
- "block",
1119
- "border",
1120
- "bottom",
1121
- "col",
1122
- "container",
1123
- "contents",
1124
- "cursor",
1125
- "dark",
1126
- "display",
1127
- "divide",
1128
- "fill",
1129
- "fixed",
1130
- "flex",
1131
- "float",
1132
- "font",
1133
- "from",
1134
- "gap",
1135
- "grid",
1136
- "grow",
1137
- "h",
1138
- "hidden",
1139
- "inset",
1140
- "inline",
1141
- "isolate",
1142
- "items",
1143
- "justify",
1144
- "left",
1145
- "leading",
1146
- "line",
1147
- "list",
1148
- "m",
1149
- "max-h",
1150
- "max-w",
1151
- "mb",
1152
- "min-h",
1153
- "min-w",
1154
- "ml",
1155
- "mr",
1156
- "mt",
1157
- "mx",
1158
- "my",
1159
- "object",
1160
- "opacity",
1161
- "order",
1162
- "origin",
1163
- "outline",
1164
- "overflow",
1165
- "overscroll",
1166
- "p",
1167
- "pb",
1168
- "pe",
1169
- "perspective",
1170
- "place",
1171
- "pl",
1172
- "pointer",
1173
- "position",
1174
- "pr",
1175
- "ps",
1176
- "pt",
1177
- "px",
1178
- "py",
1179
- "relative",
1180
- "right",
1181
- "ring",
1182
- "rotate",
1183
- "rounded",
1184
- "row",
1185
- "scale",
1186
- "shadow",
1187
- "shrink",
1188
- "size",
1189
- "skew",
1190
- "snap",
1191
- "space-x",
1192
- "space-y",
1193
- "sr",
1194
- "start",
1195
- "static",
1196
- "sticky",
1197
- "stroke",
1198
- "table",
1199
- "text",
1200
- "to",
1201
- "top",
1202
- "touch",
1203
- "tracking",
1204
- "transform",
1205
- "transition",
1206
- "translate",
1207
- "truncate",
1208
- "underline",
1209
- "via",
1210
- "visible",
1211
- "w",
1212
- "whitespace",
1213
- "z"
1214
- ]);
1215
1312
  var tailwindConfigCache = /* @__PURE__ */ new Map();
1216
1313
  var splitVariantAndBase = (className) => {
1217
1314
  const parts = className.split(":");
@@ -1241,48 +1338,28 @@ var resolveConflictGroup = (base) => {
1241
1338
  if (base.startsWith("m-") || base.startsWith("mx-") || base.startsWith("my-")) return "margin";
1242
1339
  return null;
1243
1340
  };
1244
- var detectConflicts = (usages) => {
1245
- const buckets = /* @__PURE__ */ new Map();
1246
- for (const usage of usages) {
1247
- const { variantKey, base } = splitVariantAndBase(usage.name);
1248
- const group = resolveConflictGroup(base);
1249
- if (!group) continue;
1250
- const key = `${variantKey}::${group}`;
1251
- const bucket = buckets.get(key) ?? {
1252
- variantKey,
1253
- group,
1254
- classes: /* @__PURE__ */ new Set()
1255
- };
1256
- bucket.classes.add(usage.name);
1257
- buckets.set(key, bucket);
1258
- }
1259
- const conflicts = [];
1260
- const conflictedClassNames = /* @__PURE__ */ new Set();
1261
- for (const bucket of buckets.values()) {
1262
- if (bucket.classes.size <= 1) continue;
1263
- const classes = Array.from(bucket.classes).sort();
1264
- for (const className of classes) conflictedClassNames.add(className);
1265
- const variantLabel = bucket.variantKey.length > 0 ? bucket.variantKey : "base";
1266
- conflicts.push({
1267
- className: bucket.group,
1268
- variants: bucket.variantKey.length > 0 ? bucket.variantKey.split(":") : [],
1269
- classes,
1270
- message: `Multiple ${bucket.group} utilities detected for "${variantLabel}".`
1271
- });
1341
+ var detectConflicts = async (usages) => {
1342
+ const native = await getNativeBinding();
1343
+ if (!native?.detectClassConflicts) {
1344
+ throw new Error("FATAL: Native binding 'detectClassConflicts' is required but not available.");
1272
1345
  }
1273
- conflicts.sort((left, right) => {
1274
- if (right.classes.length !== left.classes.length)
1275
- return right.classes.length - left.classes.length;
1276
- return left.className.localeCompare(right.className);
1277
- });
1278
- return { conflicts, conflictedClassNames };
1346
+ const result = native.detectClassConflicts(JSON.stringify(usages.map((u) => ({ name: u.name, count: u.count }))));
1347
+ return {
1348
+ conflicts: result.conflicts.map((c) => ({
1349
+ className: c.group,
1350
+ variants: c.variantKey.length > 0 ? c.variantKey.split(":") : [],
1351
+ classes: c.classes,
1352
+ message: c.message
1353
+ })),
1354
+ conflictedClassNames: new Set(result.conflictedClassNames)
1355
+ };
1279
1356
  };
1280
1357
  var isSupportedTailwindConfigPath = (configPath) => {
1281
- return SUPPORTED_TAILWIND_CONFIG_EXTENSIONS.has(path3__default.default.extname(configPath).toLowerCase());
1358
+ return SUPPORTED_TAILWIND_CONFIG_EXTENSIONS.has(path5__default.default.extname(configPath).toLowerCase());
1282
1359
  };
1283
1360
  var resolveTailwindConfigPath = async (root, explicitPath) => {
1284
1361
  if (explicitPath) {
1285
- const resolved = path3__default.default.resolve(root, explicitPath);
1362
+ const resolved = path5__default.default.resolve(root, explicitPath);
1286
1363
  if (!await pathExists(resolved)) return null;
1287
1364
  return resolved;
1288
1365
  }
@@ -1293,7 +1370,7 @@ var resolveTailwindConfigPath = async (root, explicitPath) => {
1293
1370
  "tailwind.config.mjs"
1294
1371
  ];
1295
1372
  for (const candidate of candidates) {
1296
- const fullPath = path3__default.default.resolve(root, candidate);
1373
+ const fullPath = path5__default.default.resolve(root, candidate);
1297
1374
  if (await pathExists(fullPath)) return fullPath;
1298
1375
  }
1299
1376
  return null;
@@ -1347,15 +1424,19 @@ var collectCustomUtilities = (config) => {
1347
1424
  return out;
1348
1425
  };
1349
1426
  var collectSafelistFromSource = async (configPath) => {
1350
- const source = await fs__default.default.promises.readFile(configPath, "utf8");
1351
- const safelistBlock = source.match(/safelist\s*:\s*\[([\s\S]*?)\]/m)?.[1];
1352
- if (!safelistBlock) return [];
1353
- const out = /* @__PURE__ */ new Set();
1354
- for (const token of safelistBlock.matchAll(/["'`]([^"'`]+)["'`]/g)) {
1427
+ const source = await fs3__default.default.promises.readFile(configPath, "utf8");
1428
+ const { extractClassesNative: extractClassesNative2 } = await Promise.resolve().then(() => (init_src2(), src_exports));
1429
+ const allTokens = extractClassesNative2(source);
1430
+ const hasSafelist = source.includes("safelist");
1431
+ if (!hasSafelist) return [];
1432
+ const safelistMatch = source.match(/safelist\s*:\s*\[([\s\S]*?)\]/m)?.[1];
1433
+ if (!safelistMatch) return [];
1434
+ const safelistSet = /* @__PURE__ */ new Set();
1435
+ for (const token of safelistMatch.matchAll(/["'`]([^"'`]+)["'`]/g)) {
1355
1436
  const value = token[1].trim();
1356
- if (value.length > 0) out.add(value);
1437
+ if (value.length > 0) safelistSet.add(value);
1357
1438
  }
1358
- return Array.from(out);
1439
+ return allTokens.filter((t) => safelistSet.has(t));
1359
1440
  };
1360
1441
  var loadTailwindConfig = async (root, semanticOption) => {
1361
1442
  const startMs = Date.now();
@@ -1370,7 +1451,7 @@ var loadTailwindConfig = async (root, semanticOption) => {
1370
1451
  customUtilities: /* @__PURE__ */ new Set()
1371
1452
  };
1372
1453
  }
1373
- const configStat = await fs__default.default.promises.stat(configPath).catch(() => null);
1454
+ const configStat = await fs3__default.default.promises.stat(configPath).catch(() => null);
1374
1455
  if (configStat) {
1375
1456
  const cached = tailwindConfigCache.get(configPath);
1376
1457
  if (cached && cached.mtimeMs === configStat.mtimeMs && cached.size === configStat.size) {
@@ -1456,21 +1537,27 @@ var utilityPrefix = (baseClass) => {
1456
1537
  if (hyphen < 0) return normalized;
1457
1538
  return normalized.slice(0, hyphen);
1458
1539
  };
1459
- var isKnownTailwindClass = (className, safelist, customUtilities) => {
1460
- if (safelist.has(className) || customUtilities.has(className)) return true;
1461
- const { base } = splitVariantAndBase(className);
1462
- if (customUtilities.has(base)) return true;
1463
- const prefix = utilityPrefix(base);
1464
- return KNOWN_UTILITY_PREFIXES.has(prefix);
1465
- };
1466
1540
  var buildSemanticReport = async (usages, root, semanticOption) => {
1467
1541
  const loadedConfig = await loadTailwindConfig(root, semanticOption);
1468
1542
  const safelist = loadedConfig?.safelist ?? /* @__PURE__ */ new Set();
1469
1543
  const customUtilities = loadedConfig?.customUtilities ?? /* @__PURE__ */ new Set();
1470
1544
  const usageNames = new Set(usages.map((usage) => usage.name));
1471
1545
  const unusedClasses = Array.from(safelist).filter((className) => !usageNames.has(className)).sort().map((className) => ({ name: className, count: 0, isUnused: true }));
1472
- const unknownClasses = usages.filter((usage) => !isKnownTailwindClass(usage.name, safelist, customUtilities)).map((usage) => ({ ...usage, isUnused: true }));
1473
- const { conflicts } = detectConflicts(usages);
1546
+ const native = await getNativeBinding();
1547
+ if (!native?.classifyKnownClasses) {
1548
+ throw new Error("FATAL: Native binding 'classifyKnownClasses' is required but not available.");
1549
+ }
1550
+ const classNames = usages.map((u) => u.name);
1551
+ const results = native.classifyKnownClasses(
1552
+ classNames,
1553
+ Array.from(safelist),
1554
+ Array.from(customUtilities)
1555
+ );
1556
+ const unknownSet = new Set(
1557
+ results.filter((r) => !r.isKnown).map((r) => r.className)
1558
+ );
1559
+ const unknownClasses = usages.filter((usage) => unknownSet.has(usage.name)).map((usage) => ({ ...usage, isUnused: true }));
1560
+ const { conflicts } = await detectConflicts(usages);
1474
1561
  return {
1475
1562
  unusedClasses,
1476
1563
  unknownClasses,
@@ -1506,13 +1593,17 @@ function normalizeScan(scan, includeClass) {
1506
1593
  uniqueClasses: Array.from(unique).sort()
1507
1594
  };
1508
1595
  }
1509
- function collectClassCounts(scan) {
1510
- const counts = /* @__PURE__ */ new Map();
1511
- for (const file of scan.files) {
1512
- for (const className of file.classes) {
1513
- counts.set(className, (counts.get(className) ?? 0) + 1);
1514
- }
1596
+ async function collectClassCounts(scan) {
1597
+ const native = await requireNativeBinding();
1598
+ if (!native?.collectClassCounts) {
1599
+ throw new Error("FATAL: Native binding 'collectClassCounts' is required but not available.");
1515
1600
  }
1601
+ const filesJson = JSON.stringify(
1602
+ scan.files.map((f) => ({ file: f.file ?? "", classes: f.classes }))
1603
+ );
1604
+ const result = native.collectClassCounts(filesJson);
1605
+ const counts = /* @__PURE__ */ new Map();
1606
+ for (const entry of result) counts.set(entry.name, entry.count);
1516
1607
  return counts;
1517
1608
  }
1518
1609
  function buildClassUsage(counts) {
@@ -1521,29 +1612,24 @@ function buildClassUsage(counts) {
1521
1612
  return left.name.localeCompare(right.name);
1522
1613
  });
1523
1614
  }
1524
- function buildDistribution(usages) {
1525
- const distribution = {
1526
- "1": 0,
1527
- "2-3": 0,
1528
- "4-7": 0,
1529
- "8+": 0
1530
- };
1531
- for (const usage of usages) {
1532
- if (usage.count === 1) {
1533
- distribution["1"] += 1;
1534
- } else if (usage.count <= 3) {
1535
- distribution["2-3"] += 1;
1536
- } else if (usage.count <= 7) {
1537
- distribution["4-7"] += 1;
1538
- } else {
1539
- distribution["8+"] += 1;
1540
- }
1615
+ async function buildDistribution(usages, native) {
1616
+ const binding = native ?? await requireNativeBinding();
1617
+ if (!binding?.buildDistribution) {
1618
+ throw new Error("FATAL: Native binding 'buildDistribution' is required but not available.");
1541
1619
  }
1542
- return distribution;
1620
+ const result = binding.buildDistribution(
1621
+ JSON.stringify(usages.map((u) => ({ name: u.name, count: u.count })))
1622
+ );
1623
+ return {
1624
+ "1": result.once,
1625
+ "2-3": result.few,
1626
+ "4-7": result.moderate,
1627
+ "8+": result.frequent
1628
+ };
1543
1629
  }
1544
1630
  async function analyzeWorkspace(root, options = {}) {
1545
1631
  const startedAtMs = Date.now();
1546
- const resolvedRoot = path3__default.default.resolve(root);
1632
+ const resolvedRoot = path5__default.default.resolve(root);
1547
1633
  const normalizedOptions = parseAnalyzerOptions(options);
1548
1634
  const scan = await (async () => {
1549
1635
  const scanStartedAtMs = Date.now();
@@ -1587,7 +1673,7 @@ async function analyzeWorkspace(root, options = {}) {
1587
1673
  );
1588
1674
  }
1589
1675
  })();
1590
- const counts = collectClassCounts(normalizedScan);
1676
+ const counts = await collectClassCounts(normalizedScan);
1591
1677
  const baseAll = buildClassUsage(counts);
1592
1678
  const { all, semanticReport } = await (async () => {
1593
1679
  if (!normalizedOptions.semantic) {
@@ -1613,13 +1699,19 @@ async function analyzeWorkspace(root, options = {}) {
1613
1699
  );
1614
1700
  }
1615
1701
  })();
1616
- const top = all.slice(0, topLimit);
1617
- const frequent = all.filter((usage) => usage.count >= frequentThreshold).slice(0, topLimit);
1618
- const unique = all.filter((usage) => usage.count === 1);
1619
- const totalClassOccurrences = all.reduce((sum, usage) => sum + usage.count, 0);
1702
+ const classStatsNative = binding?.computeClassStats?.(
1703
+ JSON.stringify(all),
1704
+ topLimit,
1705
+ frequentThreshold
1706
+ );
1707
+ const top = classStatsNative ? JSON.parse(classStatsNative.topJson) : all.slice(0, topLimit);
1708
+ const frequent = classStatsNative ? JSON.parse(classStatsNative.frequentJson) : all.filter((usage) => usage.count >= frequentThreshold).slice(0, topLimit);
1709
+ const unique = classStatsNative ? JSON.parse(classStatsNative.uniqueJson) : all.filter((usage) => usage.count === 1);
1710
+ const totalClassOccurrences = classStatsNative ? classStatsNative.totalClassOccurrences : all.reduce((sum, usage) => sum + usage.count, 0);
1620
1711
  debugLog(
1621
1712
  `analyzeWorkspace completed in ${Date.now() - startedAtMs}ms (files=${normalizedScan.totalFiles}, uniqueClasses=${all.length})`
1622
1713
  );
1714
+ const distribution = await buildDistribution(all, binding);
1623
1715
  return {
1624
1716
  root: nativeReport.root || resolvedRoot,
1625
1717
  totalFiles: nativeReport.totalFiles,
@@ -1630,16 +1722,21 @@ async function analyzeWorkspace(root, options = {}) {
1630
1722
  top,
1631
1723
  frequent,
1632
1724
  unique,
1633
- distribution: buildDistribution(all)
1725
+ distribution
1634
1726
  },
1727
+ // topClasses — alias for classStats.top (test contract & backward compat)
1728
+ topClasses: top,
1635
1729
  safelist: all.map((usage) => usage.name),
1636
1730
  ...semanticReport ? { semantic: semanticReport } : {}
1637
1731
  };
1638
1732
  }
1639
1733
 
1640
1734
  // packages/domain/analyzer/src/classToCss.ts
1641
- var normalizeClassInput = (input) => {
1735
+ var normalizeClassInput = (input, _binding) => {
1642
1736
  if (typeof input === "string") {
1737
+ if (_binding?.normalizeClassInput) {
1738
+ return _binding.normalizeClassInput(input);
1739
+ }
1643
1740
  return input.split(/\s+/).map((item) => item.trim()).filter((item) => item.length > 0);
1644
1741
  }
1645
1742
  if (!Array.isArray(input)) {
@@ -1661,27 +1758,26 @@ var normalizeClassToCssOptions = (options) => {
1661
1758
  const prefix = parsed.prefix ?? null;
1662
1759
  return { prefix, strict };
1663
1760
  };
1664
- var mergeDeclarationMap = (target, css) => {
1665
- for (const ruleMatch of css.matchAll(/\{([^}]*)\}/g)) {
1666
- const body = ruleMatch[1];
1667
- for (const raw of body.split(";")) {
1668
- const declaration = raw.trim();
1669
- if (declaration.length === 0) continue;
1670
- const colonIndex = declaration.indexOf(":");
1671
- if (colonIndex <= 0) continue;
1672
- const property = declaration.slice(0, colonIndex).trim();
1673
- const value = declaration.slice(colonIndex + 1).trim();
1674
- if (property.length === 0 || value.length === 0) continue;
1675
- if (target.has(property)) target.delete(property);
1676
- target.set(property, value);
1677
- }
1761
+ var mergeDeclarationMap = (target, css, binding) => {
1762
+ if (!binding.parseCssRules) {
1763
+ throw new Error("FATAL: Native binding 'parseCssRules' is required but not available.");
1764
+ }
1765
+ const rules = binding.parseCssRules(css);
1766
+ for (const rule of rules) {
1767
+ if (target.has(rule.property)) target.delete(rule.property);
1768
+ target.set(rule.property, rule.isImportant ? `${rule.value} !important` : rule.value);
1678
1769
  }
1679
1770
  };
1680
- var declarationMapToString = (declarationMap) => {
1681
- return Array.from(declarationMap.entries()).map(([property, value]) => `${property}: ${value}`).join("; ");
1771
+ var declarationMapToString = (declarationMap, binding) => {
1772
+ const entries = Array.from(declarationMap.entries()).map(([property, value]) => ({ property, value }));
1773
+ if (binding?.declarationMapToString) {
1774
+ return binding.declarationMapToString(entries);
1775
+ }
1776
+ return entries.map(({ property, value }) => `${property}: ${value}`).join("; ");
1682
1777
  };
1683
1778
  var classToCss = async (input, options = {}) => {
1684
- const inputClasses = normalizeClassInput(input);
1779
+ const binding = await requireNativeCssCompiler();
1780
+ const inputClasses = normalizeClassInput(input, binding);
1685
1781
  const normalizedOptions = normalizeClassToCssOptions(options);
1686
1782
  if (inputClasses.length === 0) {
1687
1783
  return {
@@ -1693,7 +1789,6 @@ var classToCss = async (input, options = {}) => {
1693
1789
  sizeBytes: 0
1694
1790
  };
1695
1791
  }
1696
- const binding = await requireNativeCssCompiler();
1697
1792
  const prefix = normalizedOptions.prefix;
1698
1793
  const results = await Promise.all(
1699
1794
  inputClasses.map(async (className) => {
@@ -1726,7 +1821,7 @@ var classToCss = async (input, options = {}) => {
1726
1821
  const sizeBytes = results.reduce((sum, r) => sum + r.sizeBytes, 0);
1727
1822
  const declarationMap = /* @__PURE__ */ new Map();
1728
1823
  for (const result of results) {
1729
- mergeDeclarationMap(declarationMap, result.css);
1824
+ mergeDeclarationMap(declarationMap, result.css, binding);
1730
1825
  }
1731
1826
  const uniqueUnknown = Array.from(new Set(unknownClasses));
1732
1827
  if (normalizedOptions.strict && uniqueUnknown.length > 0) {
@@ -1735,7 +1830,7 @@ var classToCss = async (input, options = {}) => {
1735
1830
  return {
1736
1831
  inputClasses,
1737
1832
  css: cssChunks.filter((chunk) => chunk.length > 0).join("\n"),
1738
- declarations: declarationMapToString(declarationMap),
1833
+ declarations: declarationMapToString(declarationMap, binding),
1739
1834
  resolvedClasses: Array.from(new Set(resolvedClasses)),
1740
1835
  unknownClasses: uniqueUnknown,
1741
1836
  sizeBytes