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/cli.mjs CHANGED
@@ -1,10 +1,14 @@
1
- import path3, { join, extname } from 'path';
2
- import { pathToFileURL, fileURLToPath } from 'url';
3
- import { z } from 'zod';
4
- import fs8, { readFileSync, readdirSync } from 'fs';
5
1
  import { createRequire } from 'module';
6
- import { Worker } from 'worker_threads';
7
- import fs4 from 'fs/promises';
2
+ import * as fs11 from 'fs';
3
+ import fs11__default, { readFileSync, readdirSync } from 'fs';
4
+ import * as path6 from 'path';
5
+ import path6__default, { join, extname } from 'path';
6
+ import 'crypto';
7
+ import { fileURLToPath, pathToFileURL } from 'url';
8
+ import { Worker, isMainThread, parentPort, workerData } from 'worker_threads';
9
+ import { availableParallelism } from 'os';
10
+ import { z } from 'zod';
11
+ import fs7 from 'fs/promises';
8
12
  import { isTTY, spinner, note, outro, intro, text, isCancel, select, confirm } from '@clack/prompts';
9
13
  import { parseArgs } from 'util';
10
14
  import { spawn } from 'child_process';
@@ -983,8 +987,8 @@ var require_command = __commonJS({
983
987
  "packages/infrastructure/cli/node_modules/commander/lib/command.js"(exports$1) {
984
988
  var EventEmitter = __require("events").EventEmitter;
985
989
  var childProcess = __require("child_process");
986
- var path26 = __require("path");
987
- var fs12 = __require("fs");
990
+ var path29 = __require("path");
991
+ var fs15 = __require("fs");
988
992
  var process2 = __require("process");
989
993
  var { Argument: Argument2, humanReadableArgName } = require_argument();
990
994
  var { CommanderError: CommanderError2 } = require_error();
@@ -1915,11 +1919,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
1915
1919
  let launchWithNode = false;
1916
1920
  const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
1917
1921
  function findFile(baseDir, baseName) {
1918
- const localBin = path26.resolve(baseDir, baseName);
1919
- if (fs12.existsSync(localBin)) return localBin;
1920
- if (sourceExt.includes(path26.extname(baseName))) return void 0;
1922
+ const localBin = path29.resolve(baseDir, baseName);
1923
+ if (fs15.existsSync(localBin)) return localBin;
1924
+ if (sourceExt.includes(path29.extname(baseName))) return void 0;
1921
1925
  const foundExt = sourceExt.find(
1922
- (ext) => fs12.existsSync(`${localBin}${ext}`)
1926
+ (ext) => fs15.existsSync(`${localBin}${ext}`)
1923
1927
  );
1924
1928
  if (foundExt) return `${localBin}${foundExt}`;
1925
1929
  return void 0;
@@ -1931,21 +1935,21 @@ Expecting one of '${allowedValues.join("', '")}'`);
1931
1935
  if (this._scriptPath) {
1932
1936
  let resolvedScriptPath;
1933
1937
  try {
1934
- resolvedScriptPath = fs12.realpathSync(this._scriptPath);
1938
+ resolvedScriptPath = fs15.realpathSync(this._scriptPath);
1935
1939
  } catch (err) {
1936
1940
  resolvedScriptPath = this._scriptPath;
1937
1941
  }
1938
- executableDir = path26.resolve(
1939
- path26.dirname(resolvedScriptPath),
1942
+ executableDir = path29.resolve(
1943
+ path29.dirname(resolvedScriptPath),
1940
1944
  executableDir
1941
1945
  );
1942
1946
  }
1943
1947
  if (executableDir) {
1944
1948
  let localFile = findFile(executableDir, executableFile);
1945
1949
  if (!localFile && !subcommand._executableFile && this._scriptPath) {
1946
- const legacyName = path26.basename(
1950
+ const legacyName = path29.basename(
1947
1951
  this._scriptPath,
1948
- path26.extname(this._scriptPath)
1952
+ path29.extname(this._scriptPath)
1949
1953
  );
1950
1954
  if (legacyName !== this._name) {
1951
1955
  localFile = findFile(
@@ -1956,7 +1960,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1956
1960
  }
1957
1961
  executableFile = localFile || executableFile;
1958
1962
  }
1959
- launchWithNode = sourceExt.includes(path26.extname(executableFile));
1963
+ launchWithNode = sourceExt.includes(path29.extname(executableFile));
1960
1964
  let proc;
1961
1965
  if (process2.platform !== "win32") {
1962
1966
  if (launchWithNode) {
@@ -2796,7 +2800,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
2796
2800
  * @return {Command}
2797
2801
  */
2798
2802
  nameFromFilename(filename) {
2799
- this._name = path26.basename(filename, path26.extname(filename));
2803
+ this._name = path29.basename(filename, path29.extname(filename));
2800
2804
  return this;
2801
2805
  }
2802
2806
  /**
@@ -2810,9 +2814,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
2810
2814
  * @param {string} [path]
2811
2815
  * @return {(string|null|Command)}
2812
2816
  */
2813
- executableDir(path27) {
2814
- if (path27 === void 0) return this._executableDir;
2815
- this._executableDir = path27;
2817
+ executableDir(path30) {
2818
+ if (path30 === void 0) return this._executableDir;
2819
+ this._executableDir = path30;
2816
2820
  return this;
2817
2821
  }
2818
2822
  /**
@@ -3152,45 +3156,6 @@ var init_esmHelpers = __esm({
3152
3156
  _nodeUrl = null;
3153
3157
  }
3154
3158
  });
3155
-
3156
- // packages/domain/shared/src/native-resolution.ts
3157
- function getNodeModuleRef2() {
3158
- if (isBrowser2) return null;
3159
- if (nodeModuleRef2 !== null) return nodeModuleRef2;
3160
- try {
3161
- const test = typeof __require === "function" ? __require("module") : null;
3162
- nodeModuleRef2 = test;
3163
- return test;
3164
- } catch {
3165
- nodeModuleRef2 = null;
3166
- return null;
3167
- }
3168
- }
3169
- function getNodeFs() {
3170
- if (isBrowser2) return { existsSync: () => false };
3171
- const nodeRequire = getNodeModuleRef2();
3172
- if (!nodeRequire) return { existsSync: () => false };
3173
- if (!_nodeFs) _nodeFs = nodeRequire.createRequire(import.meta.url)("node:fs");
3174
- return _nodeFs;
3175
- }
3176
- function getNodePath2() {
3177
- if (isBrowser2) return { resolve: () => "", dirname: "" };
3178
- const nodeRequire = getNodeModuleRef2();
3179
- if (!nodeRequire) return { resolve: () => "", dirname: "" };
3180
- if (!_nodePath2) _nodePath2 = nodeRequire.createRequire(import.meta.url)("node:path");
3181
- return _nodePath2;
3182
- }
3183
- function getRequire(_importMetaUrl) {
3184
- if (isBrowser2) return () => {
3185
- throw new Error("node:module not available");
3186
- };
3187
- const nodeRequire = getNodeModuleRef2();
3188
- if (!nodeRequire) return () => {
3189
- throw new Error("require not available");
3190
- };
3191
- if (!_require) _require = nodeRequire.createRequire(_importMetaUrl);
3192
- return _require;
3193
- }
3194
3159
  function platformKey() {
3195
3160
  if (isBrowser2) return "browser";
3196
3161
  return `${process.platform}-${process.arch}`;
@@ -3201,24 +3166,21 @@ function resolveNativeBinary(runtimeDir) {
3201
3166
  if (isBrowser2) {
3202
3167
  return { path: null, source: "not-found", platform, tried: ["not available in browser"] };
3203
3168
  }
3204
- const fs12 = getNodeFs();
3205
- const path26 = getNodePath2();
3206
- const _req = getRequire(import.meta.url);
3169
+ if (process.env.TWS_DISABLE_NATIVE === "1") {
3170
+ return { path: null, source: "not-found", platform, tried: [] };
3171
+ }
3207
3172
  const envPath = process.env.TW_NATIVE_PATH?.trim();
3208
3173
  if (envPath) {
3209
- if (fs12.existsSync(envPath)) {
3174
+ if (fs11.existsSync(envPath)) {
3210
3175
  return { path: envPath, source: "env", platform, tried };
3211
3176
  }
3212
3177
  tried.push(`env:${envPath} (not found)`);
3213
3178
  }
3214
- if (process.env.TWS_NO_NATIVE === "1" || process.env.TWS_NO_RUST === "1" || process.env.TWS_DISABLE_NATIVE === "1") {
3215
- return { path: null, source: "not-found", platform, tried: ["disabled by env"] };
3216
- }
3217
3179
  const prebuiltPkgs = PLATFORM_MAP[platform] ?? [];
3218
3180
  for (const pkg of prebuiltPkgs) {
3219
3181
  try {
3220
- const candidate = _req.resolve(`${pkg}/tailwind_styled_parser.node`);
3221
- if (fs12.existsSync(candidate)) {
3182
+ const candidate = _require.resolve(`${pkg}/tailwind_styled_parser.node`);
3183
+ if (fs11.existsSync(candidate)) {
3222
3184
  return { path: candidate, source: "prebuilt", platform, tried };
3223
3185
  }
3224
3186
  tried.push(`prebuilt:${pkg} (resolved but missing)`);
@@ -3228,30 +3190,43 @@ function resolveNativeBinary(runtimeDir) {
3228
3190
  }
3229
3191
  const cwd2 = process.cwd();
3230
3192
  const base = runtimeDir ?? cwd2;
3231
- const localCandidates = [
3232
- path26.resolve(base, "tailwind_styled_parser.node"),
3233
- path26.resolve(base, "..", "tailwind_styled_parser.node"),
3234
- path26.resolve(cwd2, "native", "tailwind_styled_parser.node"),
3235
- path26.resolve(cwd2, "native", "target", "release", "tailwind_styled_parser.node"),
3236
- // napi-rs conventional output
3237
- path26.resolve(base, `tailwind_styled_parser.${platform}.node`)
3238
- ];
3193
+ const napiPlatform = platform === "linux-x64" ? "linux-x64-gnu" : platform === "linux-arm64" ? "linux-arm64-gnu" : platform;
3194
+ const BINARY_NAMES = ["tailwind-styled-native", "tailwind_styled_parser"];
3195
+ const localCandidates = [];
3196
+ for (const bin of BINARY_NAMES) {
3197
+ localCandidates.push(path6.resolve(base, `${bin}.node`));
3198
+ localCandidates.push(path6.resolve(base, "..", `${bin}.node`));
3199
+ localCandidates.push(path6.resolve(base, `${bin}.${platform}.node`));
3200
+ localCandidates.push(path6.resolve(base, `${bin}.${napiPlatform}.node`));
3201
+ }
3202
+ for (const startDir of [cwd2, base]) {
3203
+ let dir = startDir;
3204
+ for (let i = 0; i < 6; i++) {
3205
+ const nativeDir = path6.resolve(dir, "native");
3206
+ for (const bin of BINARY_NAMES) {
3207
+ localCandidates.push(path6.resolve(nativeDir, `${bin}.node`));
3208
+ localCandidates.push(path6.resolve(nativeDir, `${bin}.${platform}.node`));
3209
+ localCandidates.push(path6.resolve(nativeDir, `${bin}.${napiPlatform}.node`));
3210
+ localCandidates.push(path6.resolve(nativeDir, "target", "release", `${bin}.node`));
3211
+ }
3212
+ const parent = path6.resolve(dir, "..");
3213
+ if (parent === dir) break;
3214
+ dir = parent;
3215
+ }
3216
+ }
3239
3217
  for (const candidate of localCandidates) {
3240
3218
  tried.push(`local:${candidate}`);
3241
- if (fs12.existsSync(candidate)) {
3219
+ if (fs11.existsSync(candidate)) {
3242
3220
  return { path: candidate, source: "local", platform, tried };
3243
3221
  }
3244
3222
  }
3245
3223
  return { path: null, source: "not-found", platform, tried };
3246
3224
  }
3247
- var isBrowser2, nodeModuleRef2, _nodeFs, _nodePath2, _require, PLATFORM_MAP;
3225
+ var isBrowser2, _require, PLATFORM_MAP;
3248
3226
  var init_native_resolution = __esm({
3249
3227
  "packages/domain/shared/src/native-resolution.ts"() {
3250
3228
  isBrowser2 = typeof window !== "undefined" || typeof document !== "undefined";
3251
- nodeModuleRef2 = null;
3252
- _nodeFs = null;
3253
- _nodePath2 = null;
3254
- _require = null;
3229
+ _require = typeof __require !== "undefined" ? __require : createRequire(import.meta.url);
3255
3230
  PLATFORM_MAP = {
3256
3231
  "linux-x64": ["@tailwind-styled/native-linux-x64"],
3257
3232
  "linux-arm64": ["@tailwind-styled/native-linux-arm64"],
@@ -3262,41 +3237,6 @@ var init_native_resolution = __esm({
3262
3237
  };
3263
3238
  }
3264
3239
  });
3265
-
3266
- // packages/domain/shared/src/index.ts
3267
- function getNodeModuleRef3() {
3268
- if (isBrowser3) return null;
3269
- if (nodeModuleRef3 !== null) return nodeModuleRef3;
3270
- try {
3271
- const test = typeof __require === "function" ? __require("module") : null;
3272
- nodeModuleRef3 = test;
3273
- return test;
3274
- } catch {
3275
- nodeModuleRef3 = null;
3276
- return null;
3277
- }
3278
- }
3279
- function getNodeFs2() {
3280
- if (isBrowser3) throw new Error("node:fs not available in browser");
3281
- const nodeRequire = getNodeModuleRef3();
3282
- if (!nodeRequire) throw new Error("require not available");
3283
- if (!_nodeFs2) _nodeFs2 = nodeRequire.createRequire(import.meta.url)("node:fs");
3284
- return _nodeFs2;
3285
- }
3286
- function getNodePath3() {
3287
- if (isBrowser3) throw new Error("node:path not available in browser");
3288
- const nodeRequire = getNodeModuleRef3();
3289
- if (!nodeRequire) throw new Error("require not available");
3290
- if (!_nodePath3) _nodePath3 = nodeRequire.createRequire(import.meta.url)("node:path");
3291
- return _nodePath3;
3292
- }
3293
- function getNodeUrl2() {
3294
- if (isBrowser3) throw new Error("node:url not available in browser");
3295
- const nodeRequire = getNodeModuleRef3();
3296
- if (!nodeRequire) throw new Error("require not available");
3297
- if (!_nodeUrl2) _nodeUrl2 = nodeRequire.createRequire(import.meta.url)("node:url");
3298
- return _nodeUrl2;
3299
- }
3300
3240
  function createLogger(namespace) {
3301
3241
  const prefix = `[${namespace}]`;
3302
3242
  return {
@@ -3326,9 +3266,9 @@ function createDebugLogger(namespace, label) {
3326
3266
  }
3327
3267
  };
3328
3268
  }
3329
- function formatIssuePath(path26) {
3330
- if (!path26 || path26.length === 0) return "(root)";
3331
- return path26.map(
3269
+ function formatIssuePath(path29) {
3270
+ if (!path29 || path29.length === 0) return "(root)";
3271
+ return path29.map(
3332
3272
  (segment) => typeof segment === "symbol" ? segment.description ?? segment.toString() : String(segment)
3333
3273
  ).join(".");
3334
3274
  }
@@ -3336,17 +3276,12 @@ function wrapUnknownError(domain, code, error) {
3336
3276
  return TwError.wrap(domain, code, error);
3337
3277
  }
3338
3278
  function loadNativeBinding(options) {
3339
- if (isBrowser3) {
3340
- return { binding: null, loadErrors: [{ path: "", message: "Native bindings not available in browser" }] };
3341
- }
3342
3279
  const { runtimeDir, candidates, isValid } = options;
3343
3280
  const loadErrors = [];
3344
- const path26 = getNodePath3();
3345
- const fs12 = getNodeFs2();
3346
3281
  for (const candidate of candidates) {
3347
- const candidatePath = path26.resolve(runtimeDir, candidate);
3282
+ const candidatePath = path6__default.resolve(runtimeDir, candidate);
3348
3283
  try {
3349
- if (!fs12.existsSync(candidatePath) && !fs12.existsSync(candidatePath + ".node")) {
3284
+ if (!fs11__default.existsSync(candidatePath) && !fs11__default.existsSync(candidatePath + ".node")) {
3350
3285
  continue;
3351
3286
  }
3352
3287
  const mod = requireNativeModule(candidatePath);
@@ -3360,74 +3295,58 @@ function loadNativeBinding(options) {
3360
3295
  }
3361
3296
  return { binding: null, loadErrors };
3362
3297
  }
3363
- function getRequire2() {
3364
- if (isBrowser3) return (() => {
3365
- throw new Error("require not available in browser");
3366
- });
3367
- const nodeRequire = getNodeModuleRef3();
3368
- if (!nodeRequire) return (() => {
3369
- throw new Error("require not available");
3370
- });
3371
- return nodeRequire.createRequire(import.meta.url);
3372
- }
3373
- function requireNativeModule(path26) {
3374
- return _require2(path26);
3298
+ function requireNativeModule(p) {
3299
+ return _require2(p);
3375
3300
  }
3376
3301
  function resolveNativeBindingCandidates(options) {
3377
- if (isBrowser3) return [];
3378
- const { runtimeDir, envVarNames = [], includeDefaultCandidates = true, enforceNodeExtensionForEnvPath = false } = options;
3302
+ const {
3303
+ envVarNames = ["TW_NATIVE_PATH", "TWS_NATIVE_PATH"],
3304
+ includeDefaultCandidates = true,
3305
+ enforceNodeExtensionForEnvPath = false
3306
+ } = options;
3307
+ const runtimeDir = options.runtimeDir || process.cwd();
3379
3308
  const candidates = [];
3380
- const path26 = getNodePath3();
3381
- const fs12 = getNodeFs2();
3382
3309
  for (const envVar of envVarNames) {
3383
3310
  const envPath = process.env[envVar];
3384
3311
  if (envPath) {
3385
- if (enforceNodeExtensionForEnvPath && !envPath.endsWith(".node")) {
3386
- candidates.push(envPath + ".node");
3387
- } else {
3388
- candidates.push(envPath);
3389
- }
3312
+ candidates.push(enforceNodeExtensionForEnvPath && !envPath.endsWith(".node") ? envPath + ".node" : envPath);
3390
3313
  }
3391
3314
  }
3392
3315
  if (!includeDefaultCandidates) return candidates;
3393
- if (fs12.existsSync(runtimeDir)) {
3316
+ if (fs11__default.existsSync(runtimeDir)) {
3394
3317
  try {
3395
- const entries = fs12.readdirSync(runtimeDir);
3396
- for (const entry of entries) {
3397
- if (entry.endsWith(".node")) {
3398
- candidates.push(entry);
3399
- }
3318
+ for (const entry of fs11__default.readdirSync(runtimeDir)) {
3319
+ if (entry.endsWith(".node")) candidates.push(entry);
3400
3320
  }
3401
3321
  } catch {
3402
3322
  }
3403
3323
  }
3404
- const platform = typeof process !== "undefined" ? process.platform : "";
3405
- const ext = platform === "win32" ? ".dll" : platform === "darwin" ? ".dylib" : ".so";
3406
- const defaultBindingName = `tailwind_styled_parser${ext}`;
3407
- candidates.push(path26.resolve(runtimeDir, "..", "..", "..", "native", defaultBindingName));
3408
- candidates.push(path26.resolve(runtimeDir, "..", "..", "..", "..", "native", defaultBindingName));
3409
- candidates.push(path26.resolve(process.cwd(), "native", defaultBindingName));
3324
+ const BINARY_NAMES = ["tailwind-styled-native", "tailwind_styled_parser"];
3325
+ const napiPlatform = process.platform === "linux" && process.arch === "x64" ? "linux-x64-gnu" : process.platform === "linux" && process.arch === "arm64" ? "linux-arm64-gnu" : `${process.platform}-${process.arch}`;
3326
+ for (const bin of BINARY_NAMES) {
3327
+ candidates.push(path6__default.resolve(runtimeDir, `${bin}.node`));
3328
+ candidates.push(path6__default.resolve(runtimeDir, `${bin}.${napiPlatform}.node`));
3329
+ candidates.push(path6__default.resolve(runtimeDir, "..", "..", "..", "..", "native", `${bin}.node`));
3330
+ candidates.push(path6__default.resolve(runtimeDir, "..", "..", "..", "..", "native", `${bin}.${napiPlatform}.node`));
3331
+ candidates.push(path6__default.resolve(runtimeDir, "..", "..", "..", "native", `${bin}.node`));
3332
+ candidates.push(path6__default.resolve(process.cwd(), "native", `${bin}.node`));
3333
+ candidates.push(path6__default.resolve(process.cwd(), "native", `${bin}.${napiPlatform}.node`));
3334
+ }
3410
3335
  return Array.from(new Set(candidates));
3411
3336
  }
3412
3337
  function resolveRuntimeDir(dir, importMetaUrl) {
3413
- if (isBrowser3) return "";
3414
- if (dir) return getNodePath3().resolve(dir);
3338
+ if (dir) return path6__default.resolve(dir);
3415
3339
  try {
3416
- return getNodeUrl2().fileURLToPath(importMetaUrl);
3340
+ return path6__default.dirname(fileURLToPath(importMetaUrl));
3417
3341
  } catch {
3418
3342
  return process.cwd();
3419
3343
  }
3420
3344
  }
3421
- var isBrowser3, nodeModuleRef3, _nodeFs2, _nodePath3, _nodeUrl2, TwError, _require2;
3345
+ var TwError, _require2;
3422
3346
  var init_src = __esm({
3423
3347
  "packages/domain/shared/src/index.ts"() {
3424
3348
  init_esmHelpers();
3425
3349
  init_native_resolution();
3426
- isBrowser3 = typeof window !== "undefined" || typeof document !== "undefined";
3427
- nodeModuleRef3 = null;
3428
- _nodeFs2 = null;
3429
- _nodePath3 = null;
3430
- _nodeUrl2 = null;
3431
3350
  TwError = class _TwError extends Error {
3432
3351
  /** @deprecated Gunakan source */
3433
3352
  domain;
@@ -3461,8 +3380,8 @@ var init_src = __esm({
3461
3380
  /** Buat TwError dari ZodError — dukung shape Zod v3 (`errors`) dan v4 (`issues`). */
3462
3381
  static fromZod(err) {
3463
3382
  const first = err.issues?.[0] ?? err.errors?.[0];
3464
- const path26 = formatIssuePath(first?.path);
3465
- const message = first ? `${path26}: ${first.message}` : "Schema validation failed";
3383
+ const path29 = formatIssuePath(first?.path);
3384
+ const message = first ? `${path29}: ${first.message}` : "Schema validation failed";
3466
3385
  return new _TwError("validation", "SCHEMA_VALIDATION_FAILED", message, err);
3467
3386
  }
3468
3387
  static wrap(source, code, err) {
@@ -3480,21 +3399,33 @@ var init_src = __esm({
3480
3399
  return `[${this.source.toUpperCase()}:${this.code}] ${this.message}`;
3481
3400
  }
3482
3401
  };
3483
- _require2 = getRequire2();
3402
+ _require2 = createRequire(import.meta.url);
3484
3403
  }
3485
3404
  });
3486
3405
 
3487
3406
  // packages/domain/scanner/src/native-bridge.ts
3488
3407
  var native_bridge_exports = {};
3489
3408
  __export(native_bridge_exports, {
3409
+ batchExtractClassesNative: () => batchExtractClassesNative,
3490
3410
  cachePriorityNative: () => cachePriorityNative,
3491
3411
  cacheReadNative: () => cacheReadNative,
3492
3412
  cacheWriteNative: () => cacheWriteNative,
3413
+ collectFilesNative: () => collectFilesNative,
3414
+ computeCacheStatsNative: () => computeCacheStatsNative,
3493
3415
  extractClassesNative: () => extractClassesNative,
3416
+ generateSubComponentTypesNative: () => generateSubComponentTypesNative,
3494
3417
  hasNativeScannerBinding: () => hasNativeScannerBinding,
3495
3418
  hashContentNative: () => hashContentNative,
3496
3419
  isRustCacheAvailable: () => isRustCacheAvailable,
3420
+ pruneStaleEntriesNative: () => pruneStaleEntriesNative,
3421
+ rebuildWorkspaceResultNative: () => rebuildWorkspaceResultNative,
3497
3422
  resetScannerBridgeCache: () => resetScannerBridgeCache,
3423
+ scanCacheGet: () => scanCacheGet,
3424
+ scanCacheInvalidate: () => scanCacheInvalidate,
3425
+ scanCachePut: () => scanCachePut,
3426
+ scanCacheStats: () => scanCacheStats,
3427
+ scanFileNative: () => scanFileNative,
3428
+ scanFilesBatchNative: () => scanFilesBatchNative,
3498
3429
  scanWorkspaceNative: () => scanWorkspaceNative
3499
3430
  });
3500
3431
  function getDirname2() {
@@ -3502,7 +3433,7 @@ function getDirname2() {
3502
3433
  return __dirname;
3503
3434
  }
3504
3435
  if (typeof import.meta !== "undefined" && import.meta.url) {
3505
- return path3.dirname(fileURLToPath(import.meta.url));
3436
+ return path6__default.dirname(fileURLToPath(import.meta.url));
3506
3437
  }
3507
3438
  return process.cwd();
3508
3439
  }
@@ -3583,6 +3514,95 @@ function cachePriorityNative(mtimeMs, size, cachedMtimeMs, cachedSize, cachedHit
3583
3514
  }
3584
3515
  return result;
3585
3516
  }
3517
+ function batchExtractClassesNative(filePaths) {
3518
+ const binding = scannerGetBinding();
3519
+ if (!binding.batchExtractClasses) {
3520
+ throw new Error("FATAL: Native binding 'batchExtractClasses' is required but not available.");
3521
+ }
3522
+ return binding.batchExtractClasses(filePaths) ?? [];
3523
+ }
3524
+ function scanCacheGet(filePath, contentHash) {
3525
+ const binding = scannerGetBinding();
3526
+ if (!binding.scanCacheGet) {
3527
+ throw new Error("FATAL: Native binding 'scanCacheGet' is required but not available.");
3528
+ }
3529
+ return binding.scanCacheGet(filePath, contentHash) ?? null;
3530
+ }
3531
+ function scanCachePut(filePath, contentHash, classes, mtimeMs, size) {
3532
+ const binding = scannerGetBinding();
3533
+ if (!binding.scanCachePut) {
3534
+ throw new Error("FATAL: Native binding 'scanCachePut' is required but not available.");
3535
+ }
3536
+ binding.scanCachePut(filePath, contentHash, classes, mtimeMs, size);
3537
+ }
3538
+ function scanCacheInvalidate(filePath) {
3539
+ const binding = scannerGetBinding();
3540
+ if (!binding.scanCacheInvalidate) {
3541
+ throw new Error("FATAL: Native binding 'scanCacheInvalidate' is required but not available.");
3542
+ }
3543
+ binding.scanCacheInvalidate(filePath);
3544
+ }
3545
+ function scanCacheStats() {
3546
+ const binding = scannerGetBinding();
3547
+ if (!binding.scanCacheStats) {
3548
+ throw new Error("FATAL: Native binding 'scanCacheStats' is required but not available.");
3549
+ }
3550
+ return binding.scanCacheStats();
3551
+ }
3552
+ function scanFileNative(filePath) {
3553
+ const binding = scannerGetBinding();
3554
+ if (!binding.scanFile) {
3555
+ throw new Error("FATAL: Native binding 'scanFile' is required but not available.");
3556
+ }
3557
+ return binding.scanFile(filePath);
3558
+ }
3559
+ function collectFilesNative(root, extensions, ignoreDirs) {
3560
+ const binding = scannerGetBinding();
3561
+ if (!binding.collectFiles) return null;
3562
+ return binding.collectFiles(root, extensions, ignoreDirs);
3563
+ }
3564
+ function scanFilesBatchNative(filePaths) {
3565
+ const binding = scannerGetBinding();
3566
+ if (!binding.scanFilesBatch) {
3567
+ return filePaths.map((fp) => {
3568
+ try {
3569
+ const r = binding.scanFile?.(fp);
3570
+ return r ? { file: r.file, classes: r.classes, hash: r.hash ?? "" } : { file: fp, classes: [], hash: "" };
3571
+ } catch {
3572
+ return { file: fp, classes: [], hash: "" };
3573
+ }
3574
+ });
3575
+ }
3576
+ return binding.scanFilesBatch(filePaths);
3577
+ }
3578
+ function generateSubComponentTypesNative(root, outputPath) {
3579
+ const binding = scannerGetBinding();
3580
+ if (!binding.generateSubComponentTypes) return null;
3581
+ return binding.generateSubComponentTypes(root, outputPath ?? null);
3582
+ }
3583
+ function pruneStaleEntriesNative(entries, maxAgeMs, checkExists) {
3584
+ const binding = scannerGetBinding();
3585
+ if (!binding.pruneStaleEntries) return null;
3586
+ return binding.pruneStaleEntries(
3587
+ entries.map((e) => ({ file: e.file, lastSeenMs: e.lastSeenMs ?? 0 })),
3588
+ maxAgeMs ?? null,
3589
+ checkExists ?? null
3590
+ );
3591
+ }
3592
+ function rebuildWorkspaceResultNative(files) {
3593
+ const binding = scannerBridgeLoader.get();
3594
+ if (!binding?.rebuildWorkspaceResult) return null;
3595
+ try {
3596
+ return binding.rebuildWorkspaceResult(files);
3597
+ } catch {
3598
+ return null;
3599
+ }
3600
+ }
3601
+ function computeCacheStatsNative(filesClasses, sizes, top) {
3602
+ const binding = scannerGetBinding();
3603
+ if (!binding.computeCacheStats) return null;
3604
+ return binding.computeCacheStats(filesClasses, sizes, top ?? null);
3605
+ }
3586
3606
  var log, isValidScannerBinding, createScannerBridgeLoader, scannerBridgeLoader, scannerGetBinding, resetScannerBridgeCache;
3587
3607
  var init_native_bridge = __esm({
3588
3608
  "packages/domain/scanner/src/native-bridge.ts"() {
@@ -3667,8 +3687,8 @@ var init_native_bridge = __esm({
3667
3687
  }
3668
3688
  });
3669
3689
  function defaultCachePath(rootDir, cacheDir) {
3670
- const dir = cacheDir ? path3.resolve(rootDir, cacheDir) : path3.join(process.cwd(), ".cache", "tailwind-styled");
3671
- return path3.join(dir, "scanner-cache.json");
3690
+ const dir = cacheDir ? path6__default.resolve(rootDir, cacheDir) : path6__default.join(process.cwd(), ".cache", "tailwind-styled");
3691
+ return path6__default.join(dir, "scanner-cache.json");
3672
3692
  }
3673
3693
  function readCache(rootDir, cacheDir) {
3674
3694
  const cachePath = defaultCachePath(rootDir, cacheDir);
@@ -3709,16 +3729,117 @@ var init_cache_native = __esm({
3709
3729
  init_native_bridge();
3710
3730
  }
3711
3731
  });
3732
+ function collectFiles(rootDir, extensions, ignoreDirs) {
3733
+ const native = collectFilesNative(rootDir, extensions, ignoreDirs);
3734
+ if (native !== null) return native;
3735
+ const files = [];
3736
+ function walk(dir) {
3737
+ let entries;
3738
+ try {
3739
+ entries = fs11__default.readdirSync(dir, { withFileTypes: true });
3740
+ } catch {
3741
+ return;
3742
+ }
3743
+ for (const entry of entries) {
3744
+ const fullPath = path6__default.join(dir, entry.name);
3745
+ const rel = path6__default.relative(rootDir, fullPath);
3746
+ if (entry.isDirectory()) {
3747
+ const ignored = ignoreDirs.some((d) => entry.name === d || rel.startsWith(d + path6__default.sep));
3748
+ if (!ignored) walk(fullPath);
3749
+ } else if (isScannableFile(entry.name, extensions)) {
3750
+ files.push(fullPath);
3751
+ }
3752
+ }
3753
+ }
3754
+ walk(rootDir);
3755
+ return files;
3756
+ }
3757
+ function mergeResults(batchResults) {
3758
+ const files = batchResults.map((r) => ({
3759
+ file: r.file,
3760
+ classes: r.classes,
3761
+ hash: r.content_hash
3762
+ }));
3763
+ const native = rebuildWorkspaceResultNative(files);
3764
+ if (native) return native;
3765
+ const unique = new Set(files.flatMap((f) => f.classes));
3766
+ return { files, totalFiles: files.length, uniqueClasses: Array.from(unique).sort() };
3767
+ }
3768
+ function runChunkInWorker(filePaths) {
3769
+ return new Promise((resolve2, reject) => {
3770
+ const worker = new Worker(_workerFilename, {
3771
+ workerData: { filePaths }
3772
+ });
3773
+ worker.once("message", (payload) => {
3774
+ if (payload.ok) {
3775
+ resolve2(payload.results);
3776
+ } else {
3777
+ reject(new Error(payload.error ?? "parallel-scanner worker failed"));
3778
+ }
3779
+ });
3780
+ worker.once("error", reject);
3781
+ worker.once("exit", (code) => {
3782
+ if (code !== 0) reject(new Error(`parallel-scanner worker exited with code ${code}`));
3783
+ });
3784
+ });
3785
+ }
3786
+ async function scanWorkspaceParallel(rootDir, options = {}) {
3787
+ const {
3788
+ extensions = DEFAULT_EXTENSIONS,
3789
+ ignoreDirs = DEFAULT_IGNORES,
3790
+ maxWorkers = Math.max(1, availableParallelism() - 1),
3791
+ chunkSize = DEFAULT_CHUNK_SIZE
3792
+ } = options;
3793
+ const files = collectFiles(path6__default.resolve(rootDir), extensions, ignoreDirs);
3794
+ if (files.length < PARALLEL_THRESHOLD) {
3795
+ return mergeResults(batchExtractClassesNative(files));
3796
+ }
3797
+ const chunks = [];
3798
+ for (let i = 0; i < files.length; i += chunkSize) {
3799
+ chunks.push(files.slice(i, i + chunkSize));
3800
+ }
3801
+ const allResults = [];
3802
+ for (let i = 0; i < chunks.length; i += maxWorkers) {
3803
+ const batch = chunks.slice(i, i + maxWorkers);
3804
+ const batchResults = await Promise.all(batch.map(runChunkInWorker));
3805
+ allResults.push(...batchResults.flat());
3806
+ }
3807
+ return mergeResults(allResults);
3808
+ }
3809
+ var PARALLEL_THRESHOLD, DEFAULT_CHUNK_SIZE, _workerFilename;
3810
+ var init_parallel_scanner = __esm({
3811
+ "packages/domain/scanner/src/parallel-scanner.ts"() {
3812
+ init_src2();
3813
+ init_native_bridge();
3814
+ PARALLEL_THRESHOLD = 50;
3815
+ DEFAULT_CHUNK_SIZE = 150;
3816
+ if (!isMainThread && parentPort) {
3817
+ const { filePaths } = workerData;
3818
+ try {
3819
+ const results = batchExtractClassesNative(filePaths);
3820
+ const msg = { ok: true, results };
3821
+ parentPort.postMessage(msg);
3822
+ } catch (error) {
3823
+ const msg = {
3824
+ ok: false,
3825
+ error: error instanceof Error ? error.message : String(error)
3826
+ };
3827
+ parentPort.postMessage(msg);
3828
+ }
3829
+ }
3830
+ _workerFilename = typeof __filename !== "undefined" ? __filename : fileURLToPath(import.meta.url);
3831
+ }
3832
+ });
3712
3833
  var formatIssuePath2, formatIssues, parseWithSchema, NonNegativeIntegerSchema, ScanWorkspaceOptionsSchema, ScanFileResultSchema, ScanWorkspaceResultSchema, ScannerWorkerSuccessMessageSchema, ScannerWorkerErrorMessageSchema, ScannerWorkerMessageSchema, parseScanWorkspaceOptions, parseScanWorkspaceResult, parseScannerWorkerMessage;
3713
3834
  var init_schemas = __esm({
3714
3835
  "packages/domain/scanner/src/schemas.ts"() {
3715
3836
  init_src();
3716
- formatIssuePath2 = (path26) => path26.length > 0 ? path26.map(
3837
+ formatIssuePath2 = (path29) => path29.length > 0 ? path29.map(
3717
3838
  (segment) => typeof segment === "symbol" ? segment.description ?? segment.toString() : String(segment)
3718
3839
  ).join(".") : "<root>";
3719
3840
  formatIssues = (error) => error.issues.map((issue) => {
3720
- const path26 = formatIssuePath2(issue.path);
3721
- return `${path26}: ${issue.message}`;
3841
+ const path29 = formatIssuePath2(issue.path);
3842
+ return `${path29}: ${issue.message}`;
3722
3843
  }).join("; ");
3723
3844
  parseWithSchema = (schema, data, label) => {
3724
3845
  const parsed = schema.safeParse(data);
@@ -3773,12 +3894,29 @@ var init_schemas = __esm({
3773
3894
  parseScannerWorkerMessage = (message) => parseWithSchema(ScannerWorkerMessageSchema, message, "scanner worker message is invalid");
3774
3895
  }
3775
3896
  });
3897
+
3898
+ // packages/domain/scanner/src/index.ts
3899
+ var src_exports = {};
3900
+ __export(src_exports, {
3901
+ DEFAULT_EXTENSIONS: () => DEFAULT_EXTENSIONS,
3902
+ DEFAULT_IGNORES: () => DEFAULT_IGNORES,
3903
+ batchExtractClassesNative: () => batchExtractClassesNative,
3904
+ extractClassesNative: () => extractClassesNative,
3905
+ isScannableFile: () => isScannableFile,
3906
+ parseScanWorkspaceOptions: () => parseScanWorkspaceOptions,
3907
+ parseScanWorkspaceResult: () => parseScanWorkspaceResult,
3908
+ parseScannerWorkerMessage: () => parseScannerWorkerMessage,
3909
+ scanFile: () => scanFile,
3910
+ scanSource: () => scanSource,
3911
+ scanWorkspace: () => scanWorkspace,
3912
+ scanWorkspaceAsync: () => scanWorkspaceAsync
3913
+ });
3776
3914
  function getRuntimeDir() {
3777
3915
  if (typeof __dirname !== "undefined" && __dirname.length > 0) {
3778
3916
  return __dirname;
3779
3917
  }
3780
3918
  if (typeof import.meta !== "undefined" && import.meta.url) {
3781
- return path3.dirname(fileURLToPath(import.meta.url));
3919
+ return path6__default.dirname(fileURLToPath(import.meta.url));
3782
3920
  }
3783
3921
  return process.cwd();
3784
3922
  }
@@ -3788,17 +3926,17 @@ function resolveScannerWorkerModulePath() {
3788
3926
  return __dirname;
3789
3927
  }
3790
3928
  if (typeof import.meta !== "undefined" && import.meta.url) {
3791
- return path3.dirname(fileURLToPath(import.meta.url));
3929
+ return path6__default.dirname(fileURLToPath(import.meta.url));
3792
3930
  }
3793
3931
  return process.cwd();
3794
3932
  })();
3795
3933
  const candidates = [
3796
- path3.resolve(runtimeDir, "worker.cjs"),
3797
- path3.resolve(runtimeDir, "worker.js"),
3798
- path3.resolve(runtimeDir, "worker.ts")
3934
+ path6__default.resolve(runtimeDir, "worker.cjs"),
3935
+ path6__default.resolve(runtimeDir, "worker.js"),
3936
+ path6__default.resolve(runtimeDir, "worker.ts")
3799
3937
  ];
3800
3938
  for (const candidate of candidates) {
3801
- if (fs8.existsSync(candidate)) return candidate;
3939
+ if (fs11__default.existsSync(candidate)) return candidate;
3802
3940
  }
3803
3941
  return null;
3804
3942
  }
@@ -3808,7 +3946,7 @@ function scanWorkspaceInWorker(rootDir, options) {
3808
3946
  if (!modulePath) {
3809
3947
  return Promise.reject(new Error("scanner worker module path could not be resolved"));
3810
3948
  }
3811
- return new Promise((resolve, reject) => {
3949
+ return new Promise((resolve2, reject) => {
3812
3950
  const settleState = { settled: false };
3813
3951
  const worker = new Worker(modulePath, { workerData: { rootDir, options: normalizedOptions } });
3814
3952
  const timeout = setTimeout(() => {
@@ -3828,7 +3966,7 @@ function scanWorkspaceInWorker(rootDir, options) {
3828
3966
  const message = parseScannerWorkerMessage(payload);
3829
3967
  finish(() => {
3830
3968
  if (message?.ok) {
3831
- resolve(parseScanWorkspaceResult(message.result));
3969
+ resolve2(parseScanWorkspaceResult(message.result));
3832
3970
  return;
3833
3971
  }
3834
3972
  reject(new Error(message?.error ?? "scanner worker failed without an error message"));
@@ -3855,19 +3993,19 @@ function collectCandidates(rootDir, ignoreDirectories, extensionSet) {
3855
3993
  if (!currentDir) continue;
3856
3994
  const entries = (() => {
3857
3995
  try {
3858
- return fs8.readdirSync(currentDir, { withFileTypes: true });
3996
+ return fs11__default.readdirSync(currentDir, { withFileTypes: true });
3859
3997
  } catch {
3860
3998
  return [];
3861
3999
  }
3862
4000
  })();
3863
4001
  for (const entry of entries) {
3864
- const fullPath = path3.join(currentDir, entry.name);
4002
+ const fullPath = path6__default.join(currentDir, entry.name);
3865
4003
  if (entry.isDirectory()) {
3866
4004
  if (!ignoreDirectories.has(entry.name)) directories.push(fullPath);
3867
4005
  continue;
3868
4006
  }
3869
4007
  if (!entry.isFile()) continue;
3870
- if (!extensionSet.has(path3.extname(entry.name))) continue;
4008
+ if (!extensionSet.has(path6__default.extname(entry.name))) continue;
3871
4009
  candidates.push(fullPath);
3872
4010
  }
3873
4011
  }
@@ -3881,9 +4019,12 @@ function toCacheSize(size) {
3881
4019
  function scanSource(source) {
3882
4020
  const nativeBinding = nativeParserLoader.get();
3883
4021
  if (nativeBinding?.extractClassesFromSource) {
3884
- const classes = nativeBinding.extractClassesFromSource(source);
3885
- if (Array.isArray(classes)) {
3886
- return Array.from(new Set(classes.filter(Boolean)));
4022
+ const result = nativeBinding.extractClassesFromSource(source);
4023
+ if (Array.isArray(result)) {
4024
+ return Array.from(new Set(result.filter(Boolean)));
4025
+ }
4026
+ if (result !== null && result !== void 0 && Array.isArray(result.classes)) {
4027
+ return Array.from(new Set(result.classes.filter(Boolean)));
3887
4028
  }
3888
4029
  }
3889
4030
  throw new Error(
@@ -3891,15 +4032,18 @@ function scanSource(source) {
3891
4032
  );
3892
4033
  }
3893
4034
  function isScannableFile(filePath, includeExtensions = DEFAULT_EXTENSIONS) {
3894
- return includeExtensions.includes(path3.extname(filePath));
4035
+ return includeExtensions.includes(path6__default.extname(filePath));
3895
4036
  }
3896
4037
  function scanFile(filePath) {
3897
- const source = fs8.readFileSync(filePath, "utf8");
3898
- const hash = hashContentNative(source) ?? void 0;
4038
+ const { scanFileNative: scanFileNative2 } = (init_native_bridge(), __toCommonJS(native_bridge_exports));
4039
+ const result = scanFileNative2(filePath);
4040
+ if (!result.ok) {
4041
+ throw new Error(`scanFile failed for ${filePath}: ${result.error ?? "unknown error"}`);
4042
+ }
3899
4043
  return {
3900
- file: filePath,
3901
- classes: scanSource(source),
3902
- ...hash ? { hash } : {}
4044
+ file: result.file,
4045
+ classes: result.classes,
4046
+ ...result.hash ? { hash: result.hash } : {}
3903
4047
  };
3904
4048
  }
3905
4049
  function scanWorkspace(rootDir, options = {}) {
@@ -3948,7 +4092,7 @@ function scanWorkspace(rootDir, options = {}) {
3948
4092
  for (const filePath of candidates) {
3949
4093
  const stat = (() => {
3950
4094
  try {
3951
- return fs8.statSync(filePath);
4095
+ return fs11__default.statSync(filePath);
3952
4096
  } catch {
3953
4097
  return null;
3954
4098
  }
@@ -3974,7 +4118,7 @@ function scanWorkspace(rootDir, options = {}) {
3974
4118
  for (const { filePath, stat, size, cached } of ranked) {
3975
4119
  const content = (() => {
3976
4120
  try {
3977
- return fs8.readFileSync(filePath, "utf8");
4121
+ return fs11__default.readFileSync(filePath, "utf8");
3978
4122
  } catch {
3979
4123
  return null;
3980
4124
  }
@@ -4036,14 +4180,21 @@ function scanWorkspace(rootDir, options = {}) {
4036
4180
  }
4037
4181
  async function scanWorkspaceAsync(rootDir, options = {}) {
4038
4182
  const normalizedOptions = parseScanWorkspaceOptions(options);
4039
- if (process.env.TWS_DISABLE_SCANNER_WORKER === "1") {
4040
- return scanWorkspace(rootDir, normalizedOptions);
4183
+ try {
4184
+ return await scanWorkspaceParallel(rootDir, {
4185
+ extensions: normalizedOptions.includeExtensions,
4186
+ ignoreDirs: normalizedOptions.ignoreDirectories
4187
+ });
4188
+ } catch (parallelError) {
4189
+ log2.debug(
4190
+ `parallel scan failed, retrying with single worker: ${parallelError instanceof Error ? parallelError.message : String(parallelError)}`
4191
+ );
4041
4192
  }
4042
4193
  try {
4043
4194
  return await scanWorkspaceInWorker(rootDir, normalizedOptions);
4044
4195
  } catch (error) {
4045
4196
  log2.debug(
4046
- `worker scan failed, falling back to sync scanner: ${error instanceof Error ? error.message : String(error)}`
4197
+ `worker scan failed, retrying with sync native scanner: ${error instanceof Error ? error.message : String(error)}`
4047
4198
  );
4048
4199
  return scanWorkspace(rootDir, normalizedOptions);
4049
4200
  }
@@ -4054,7 +4205,10 @@ var init_src2 = __esm({
4054
4205
  init_src();
4055
4206
  init_cache_native();
4056
4207
  init_native_bridge();
4208
+ init_parallel_scanner();
4057
4209
  init_schemas();
4210
+ init_schemas();
4211
+ init_native_bridge();
4058
4212
  log2 = createLogger("scanner");
4059
4213
  SCAN_WORKER_TIMEOUT_MS = 12e4;
4060
4214
  createNativeParserLoader = () => {
@@ -4068,12 +4222,25 @@ var init_src2 = __esm({
4068
4222
  const loadNativeParserBinding = () => {
4069
4223
  if (_state.binding !== void 0) return _state.binding;
4070
4224
  const runtimeDir = getRuntimeDir();
4071
- const req = createRequire(path3.join(runtimeDir, "noop.cjs"));
4225
+ const req = createRequire(path6__default.join(runtimeDir, "noop.cjs"));
4072
4226
  const candidates = [
4073
- path3.resolve(process.cwd(), "native/tailwind_styled_parser.node"),
4074
- path3.resolve(process.cwd(), "native/build/Release/tailwind_styled_parser.node"),
4075
- path3.resolve(runtimeDir, "..", "..", "..", "native", "tailwind_styled_parser.node"),
4076
- path3.resolve(
4227
+ // ── binaryName baru: tailwind-styled-native (napi-rs naming) ──
4228
+ // cwd = repo root saat run dari root, atau package dir saat workspaces
4229
+ path6__default.resolve(process.cwd(), "native", "tailwind-styled-native.node"),
4230
+ path6__default.resolve(process.cwd(), "native", `tailwind-styled-native.${process.platform}-${process.arch}.node`),
4231
+ path6__default.resolve(process.cwd(), "native", `tailwind-styled-native.${process.platform}-${process.arch}-gnu.node`),
4232
+ // runtimeDir = dist/ → naik 4 level ke repo root
4233
+ path6__default.resolve(runtimeDir, "..", "..", "..", "..", "native", "tailwind-styled-native.node"),
4234
+ path6__default.resolve(runtimeDir, "..", "..", "..", "..", "native", `tailwind-styled-native.${process.platform}-${process.arch}-gnu.node`),
4235
+ // 3 level fallback (jika package di-nest lebih dangkal)
4236
+ path6__default.resolve(runtimeDir, "..", "..", "..", "native", "tailwind-styled-native.node"),
4237
+ path6__default.resolve(runtimeDir, "..", "..", "..", "native", `tailwind-styled-native.${process.platform}-${process.arch}-gnu.node`),
4238
+ // ── binaryName lama: tailwind_styled_parser (backward compat) ──
4239
+ path6__default.resolve(process.cwd(), "native/tailwind_styled_parser.node"),
4240
+ path6__default.resolve(process.cwd(), "native/build/Release/tailwind_styled_parser.node"),
4241
+ path6__default.resolve(runtimeDir, "..", "..", "..", "..", "native", "tailwind_styled_parser.node"),
4242
+ path6__default.resolve(runtimeDir, "..", "..", "..", "native", "tailwind_styled_parser.node"),
4243
+ path6__default.resolve(
4077
4244
  runtimeDir,
4078
4245
  "..",
4079
4246
  "..",
@@ -4085,7 +4252,7 @@ var init_src2 = __esm({
4085
4252
  )
4086
4253
  ];
4087
4254
  for (const fullPath of candidates) {
4088
- if (!fs8.existsSync(fullPath)) continue;
4255
+ if (!fs11__default.existsSync(fullPath)) continue;
4089
4256
  try {
4090
4257
  const required = req(fullPath);
4091
4258
  if (required && (typeof required.extractClassesFromSource === "function" || typeof required.parseClasses === "function" || typeof required.parse_classes === "function")) {
@@ -4127,7 +4294,7 @@ function isRecord(value) {
4127
4294
  }
4128
4295
  async function pathExists(filePath) {
4129
4296
  try {
4130
- await fs8.promises.access(filePath, fs8.constants.F_OK);
4297
+ await fs11__default.promises.access(filePath, fs11__default.constants.F_OK);
4131
4298
  return true;
4132
4299
  } catch {
4133
4300
  return false;
@@ -4153,6 +4320,9 @@ var init_utils = __esm({
4153
4320
  });
4154
4321
 
4155
4322
  // packages/domain/analyzer/src/binding.ts
4323
+ async function getNativeBinding() {
4324
+ return analyzerBindingLoader.get();
4325
+ }
4156
4326
  async function requireNativeBinding() {
4157
4327
  const binding = await analyzerBindingLoader.get();
4158
4328
  if (binding?.analyzeClasses) return binding;
@@ -4245,7 +4415,7 @@ var formatIssuePath3, isPlainObject, formatIssues2, parseWithSchema2, CountSchem
4245
4415
  var init_schemas2 = __esm({
4246
4416
  "packages/domain/analyzer/src/schemas.ts"() {
4247
4417
  init_src();
4248
- formatIssuePath3 = (path26) => path26.length > 0 ? path26.map(
4418
+ formatIssuePath3 = (path29) => path29.length > 0 ? path29.map(
4249
4419
  (segment) => typeof segment === "symbol" ? segment.description ?? segment.toString() : String(segment)
4250
4420
  ).join(".") : "<root>";
4251
4421
  isPlainObject = (value) => {
@@ -4254,8 +4424,8 @@ var init_schemas2 = __esm({
4254
4424
  return proto === Object.prototype || proto === null;
4255
4425
  };
4256
4426
  formatIssues2 = (error) => error.issues.map((issue) => {
4257
- const path26 = formatIssuePath3(issue.path);
4258
- return `${path26}: ${issue.message}`;
4427
+ const path29 = formatIssuePath3(issue.path);
4428
+ return `${path29}: ${issue.message}`;
4259
4429
  }).join("; ");
4260
4430
  parseWithSchema2 = (schema, data, label) => {
4261
4431
  const parsed = schema.safeParse(data);
@@ -4351,117 +4521,12 @@ var init_schemas2 = __esm({
4351
4521
  parseClassToCssOptions = (options) => parseWithSchema2(ClassToCssOptionsSchema, options ?? {}, "classToCss options are invalid");
4352
4522
  }
4353
4523
  });
4354
- var SUPPORTED_TAILWIND_CONFIG_EXTENSIONS, KNOWN_UTILITY_PREFIXES, tailwindConfigCache, splitVariantAndBase, isArbitraryUtility, resolveConflictGroup, detectConflicts, isSupportedTailwindConfigPath, resolveTailwindConfigPath, collectSafelistFromConfig, collectCustomUtilities, collectSafelistFromSource, loadTailwindConfig, utilityPrefix, isKnownTailwindClass, buildSemanticReport;
4524
+ var SUPPORTED_TAILWIND_CONFIG_EXTENSIONS, tailwindConfigCache, splitVariantAndBase, isArbitraryUtility, resolveConflictGroup, detectConflicts, isSupportedTailwindConfigPath, resolveTailwindConfigPath, collectSafelistFromConfig, collectCustomUtilities, collectSafelistFromSource, loadTailwindConfig, utilityPrefix, buildSemanticReport;
4355
4525
  var init_semantic = __esm({
4356
4526
  "packages/domain/analyzer/src/semantic.ts"() {
4527
+ init_binding();
4357
4528
  init_utils();
4358
4529
  SUPPORTED_TAILWIND_CONFIG_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".js", ".cjs", ".mjs"]);
4359
- KNOWN_UTILITY_PREFIXES = /* @__PURE__ */ new Set([
4360
- "absolute",
4361
- "align",
4362
- "animate",
4363
- "arbitrary",
4364
- "aspect",
4365
- "backdrop",
4366
- "basis",
4367
- "bg",
4368
- "block",
4369
- "border",
4370
- "bottom",
4371
- "col",
4372
- "container",
4373
- "contents",
4374
- "cursor",
4375
- "dark",
4376
- "display",
4377
- "divide",
4378
- "fill",
4379
- "fixed",
4380
- "flex",
4381
- "float",
4382
- "font",
4383
- "from",
4384
- "gap",
4385
- "grid",
4386
- "grow",
4387
- "h",
4388
- "hidden",
4389
- "inset",
4390
- "inline",
4391
- "isolate",
4392
- "items",
4393
- "justify",
4394
- "left",
4395
- "leading",
4396
- "line",
4397
- "list",
4398
- "m",
4399
- "max-h",
4400
- "max-w",
4401
- "mb",
4402
- "min-h",
4403
- "min-w",
4404
- "ml",
4405
- "mr",
4406
- "mt",
4407
- "mx",
4408
- "my",
4409
- "object",
4410
- "opacity",
4411
- "order",
4412
- "origin",
4413
- "outline",
4414
- "overflow",
4415
- "overscroll",
4416
- "p",
4417
- "pb",
4418
- "pe",
4419
- "perspective",
4420
- "place",
4421
- "pl",
4422
- "pointer",
4423
- "position",
4424
- "pr",
4425
- "ps",
4426
- "pt",
4427
- "px",
4428
- "py",
4429
- "relative",
4430
- "right",
4431
- "ring",
4432
- "rotate",
4433
- "rounded",
4434
- "row",
4435
- "scale",
4436
- "shadow",
4437
- "shrink",
4438
- "size",
4439
- "skew",
4440
- "snap",
4441
- "space-x",
4442
- "space-y",
4443
- "sr",
4444
- "start",
4445
- "static",
4446
- "sticky",
4447
- "stroke",
4448
- "table",
4449
- "text",
4450
- "to",
4451
- "top",
4452
- "touch",
4453
- "tracking",
4454
- "transform",
4455
- "transition",
4456
- "translate",
4457
- "truncate",
4458
- "underline",
4459
- "via",
4460
- "visible",
4461
- "w",
4462
- "whitespace",
4463
- "z"
4464
- ]);
4465
4530
  tailwindConfigCache = /* @__PURE__ */ new Map();
4466
4531
  splitVariantAndBase = (className) => {
4467
4532
  const parts = className.split(":");
@@ -4491,48 +4556,28 @@ var init_semantic = __esm({
4491
4556
  if (base.startsWith("m-") || base.startsWith("mx-") || base.startsWith("my-")) return "margin";
4492
4557
  return null;
4493
4558
  };
4494
- detectConflicts = (usages) => {
4495
- const buckets = /* @__PURE__ */ new Map();
4496
- for (const usage of usages) {
4497
- const { variantKey, base } = splitVariantAndBase(usage.name);
4498
- const group = resolveConflictGroup(base);
4499
- if (!group) continue;
4500
- const key = `${variantKey}::${group}`;
4501
- const bucket = buckets.get(key) ?? {
4502
- variantKey,
4503
- group,
4504
- classes: /* @__PURE__ */ new Set()
4505
- };
4506
- bucket.classes.add(usage.name);
4507
- buckets.set(key, bucket);
4508
- }
4509
- const conflicts = [];
4510
- const conflictedClassNames = /* @__PURE__ */ new Set();
4511
- for (const bucket of buckets.values()) {
4512
- if (bucket.classes.size <= 1) continue;
4513
- const classes = Array.from(bucket.classes).sort();
4514
- for (const className of classes) conflictedClassNames.add(className);
4515
- const variantLabel = bucket.variantKey.length > 0 ? bucket.variantKey : "base";
4516
- conflicts.push({
4517
- className: bucket.group,
4518
- variants: bucket.variantKey.length > 0 ? bucket.variantKey.split(":") : [],
4519
- classes,
4520
- message: `Multiple ${bucket.group} utilities detected for "${variantLabel}".`
4521
- });
4559
+ detectConflicts = async (usages) => {
4560
+ const native = await getNativeBinding();
4561
+ if (!native?.detectClassConflicts) {
4562
+ throw new Error("FATAL: Native binding 'detectClassConflicts' is required but not available.");
4522
4563
  }
4523
- conflicts.sort((left, right) => {
4524
- if (right.classes.length !== left.classes.length)
4525
- return right.classes.length - left.classes.length;
4526
- return left.className.localeCompare(right.className);
4527
- });
4528
- return { conflicts, conflictedClassNames };
4564
+ const result = native.detectClassConflicts(JSON.stringify(usages.map((u) => ({ name: u.name, count: u.count }))));
4565
+ return {
4566
+ conflicts: result.conflicts.map((c) => ({
4567
+ className: c.group,
4568
+ variants: c.variantKey.length > 0 ? c.variantKey.split(":") : [],
4569
+ classes: c.classes,
4570
+ message: c.message
4571
+ })),
4572
+ conflictedClassNames: new Set(result.conflictedClassNames)
4573
+ };
4529
4574
  };
4530
4575
  isSupportedTailwindConfigPath = (configPath) => {
4531
- return SUPPORTED_TAILWIND_CONFIG_EXTENSIONS.has(path3.extname(configPath).toLowerCase());
4576
+ return SUPPORTED_TAILWIND_CONFIG_EXTENSIONS.has(path6__default.extname(configPath).toLowerCase());
4532
4577
  };
4533
4578
  resolveTailwindConfigPath = async (root, explicitPath) => {
4534
4579
  if (explicitPath) {
4535
- const resolved = path3.resolve(root, explicitPath);
4580
+ const resolved = path6__default.resolve(root, explicitPath);
4536
4581
  if (!await pathExists(resolved)) return null;
4537
4582
  return resolved;
4538
4583
  }
@@ -4543,7 +4588,7 @@ var init_semantic = __esm({
4543
4588
  "tailwind.config.mjs"
4544
4589
  ];
4545
4590
  for (const candidate of candidates) {
4546
- const fullPath = path3.resolve(root, candidate);
4591
+ const fullPath = path6__default.resolve(root, candidate);
4547
4592
  if (await pathExists(fullPath)) return fullPath;
4548
4593
  }
4549
4594
  return null;
@@ -4597,15 +4642,19 @@ var init_semantic = __esm({
4597
4642
  return out;
4598
4643
  };
4599
4644
  collectSafelistFromSource = async (configPath) => {
4600
- const source = await fs8.promises.readFile(configPath, "utf8");
4601
- const safelistBlock = source.match(/safelist\s*:\s*\[([\s\S]*?)\]/m)?.[1];
4602
- if (!safelistBlock) return [];
4603
- const out = /* @__PURE__ */ new Set();
4604
- for (const token of safelistBlock.matchAll(/["'`]([^"'`]+)["'`]/g)) {
4645
+ const source = await fs11__default.promises.readFile(configPath, "utf8");
4646
+ const { extractClassesNative: extractClassesNative2 } = await Promise.resolve().then(() => (init_src2(), src_exports));
4647
+ const allTokens = extractClassesNative2(source);
4648
+ const hasSafelist = source.includes("safelist");
4649
+ if (!hasSafelist) return [];
4650
+ const safelistMatch = source.match(/safelist\s*:\s*\[([\s\S]*?)\]/m)?.[1];
4651
+ if (!safelistMatch) return [];
4652
+ const safelistSet = /* @__PURE__ */ new Set();
4653
+ for (const token of safelistMatch.matchAll(/["'`]([^"'`]+)["'`]/g)) {
4605
4654
  const value = token[1].trim();
4606
- if (value.length > 0) out.add(value);
4655
+ if (value.length > 0) safelistSet.add(value);
4607
4656
  }
4608
- return Array.from(out);
4657
+ return allTokens.filter((t) => safelistSet.has(t));
4609
4658
  };
4610
4659
  loadTailwindConfig = async (root, semanticOption) => {
4611
4660
  const startMs = Date.now();
@@ -4620,7 +4669,7 @@ var init_semantic = __esm({
4620
4669
  customUtilities: /* @__PURE__ */ new Set()
4621
4670
  };
4622
4671
  }
4623
- const configStat = await fs8.promises.stat(configPath).catch(() => null);
4672
+ const configStat = await fs11__default.promises.stat(configPath).catch(() => null);
4624
4673
  if (configStat) {
4625
4674
  const cached = tailwindConfigCache.get(configPath);
4626
4675
  if (cached && cached.mtimeMs === configStat.mtimeMs && cached.size === configStat.size) {
@@ -4706,21 +4755,27 @@ var init_semantic = __esm({
4706
4755
  if (hyphen < 0) return normalized;
4707
4756
  return normalized.slice(0, hyphen);
4708
4757
  };
4709
- isKnownTailwindClass = (className, safelist, customUtilities) => {
4710
- if (safelist.has(className) || customUtilities.has(className)) return true;
4711
- const { base } = splitVariantAndBase(className);
4712
- if (customUtilities.has(base)) return true;
4713
- const prefix = utilityPrefix(base);
4714
- return KNOWN_UTILITY_PREFIXES.has(prefix);
4715
- };
4716
4758
  buildSemanticReport = async (usages, root, semanticOption) => {
4717
4759
  const loadedConfig = await loadTailwindConfig(root, semanticOption);
4718
4760
  const safelist = loadedConfig?.safelist ?? /* @__PURE__ */ new Set();
4719
4761
  const customUtilities = loadedConfig?.customUtilities ?? /* @__PURE__ */ new Set();
4720
4762
  const usageNames = new Set(usages.map((usage) => usage.name));
4721
4763
  const unusedClasses = Array.from(safelist).filter((className) => !usageNames.has(className)).sort().map((className) => ({ name: className, count: 0, isUnused: true }));
4722
- const unknownClasses = usages.filter((usage) => !isKnownTailwindClass(usage.name, safelist, customUtilities)).map((usage) => ({ ...usage, isUnused: true }));
4723
- const { conflicts } = detectConflicts(usages);
4764
+ const native = await getNativeBinding();
4765
+ if (!native?.classifyKnownClasses) {
4766
+ throw new Error("FATAL: Native binding 'classifyKnownClasses' is required but not available.");
4767
+ }
4768
+ const classNames = usages.map((u) => u.name);
4769
+ const results = native.classifyKnownClasses(
4770
+ classNames,
4771
+ Array.from(safelist),
4772
+ Array.from(customUtilities)
4773
+ );
4774
+ const unknownSet = new Set(
4775
+ results.filter((r) => !r.isKnown).map((r) => r.className)
4776
+ );
4777
+ const unknownClasses = usages.filter((usage) => unknownSet.has(usage.name)).map((usage) => ({ ...usage, isUnused: true }));
4778
+ const { conflicts } = await detectConflicts(usages);
4724
4779
  return {
4725
4780
  unusedClasses,
4726
4781
  unknownClasses,
@@ -4756,13 +4811,17 @@ function normalizeScan(scan, includeClass) {
4756
4811
  uniqueClasses: Array.from(unique).sort()
4757
4812
  };
4758
4813
  }
4759
- function collectClassCounts(scan) {
4760
- const counts = /* @__PURE__ */ new Map();
4761
- for (const file of scan.files) {
4762
- for (const className of file.classes) {
4763
- counts.set(className, (counts.get(className) ?? 0) + 1);
4764
- }
4814
+ async function collectClassCounts(scan) {
4815
+ const native = await requireNativeBinding();
4816
+ if (!native?.collectClassCounts) {
4817
+ throw new Error("FATAL: Native binding 'collectClassCounts' is required but not available.");
4765
4818
  }
4819
+ const filesJson = JSON.stringify(
4820
+ scan.files.map((f) => ({ file: f.file ?? "", classes: f.classes }))
4821
+ );
4822
+ const result = native.collectClassCounts(filesJson);
4823
+ const counts = /* @__PURE__ */ new Map();
4824
+ for (const entry of result) counts.set(entry.name, entry.count);
4766
4825
  return counts;
4767
4826
  }
4768
4827
  function buildClassUsage(counts) {
@@ -4771,29 +4830,24 @@ function buildClassUsage(counts) {
4771
4830
  return left.name.localeCompare(right.name);
4772
4831
  });
4773
4832
  }
4774
- function buildDistribution(usages) {
4775
- const distribution = {
4776
- "1": 0,
4777
- "2-3": 0,
4778
- "4-7": 0,
4779
- "8+": 0
4780
- };
4781
- for (const usage of usages) {
4782
- if (usage.count === 1) {
4783
- distribution["1"] += 1;
4784
- } else if (usage.count <= 3) {
4785
- distribution["2-3"] += 1;
4786
- } else if (usage.count <= 7) {
4787
- distribution["4-7"] += 1;
4788
- } else {
4789
- distribution["8+"] += 1;
4790
- }
4833
+ async function buildDistribution(usages, native) {
4834
+ const binding = native ?? await requireNativeBinding();
4835
+ if (!binding?.buildDistribution) {
4836
+ throw new Error("FATAL: Native binding 'buildDistribution' is required but not available.");
4791
4837
  }
4792
- return distribution;
4838
+ const result = binding.buildDistribution(
4839
+ JSON.stringify(usages.map((u) => ({ name: u.name, count: u.count })))
4840
+ );
4841
+ return {
4842
+ "1": result.once,
4843
+ "2-3": result.few,
4844
+ "4-7": result.moderate,
4845
+ "8+": result.frequent
4846
+ };
4793
4847
  }
4794
4848
  async function analyzeWorkspace(root, options = {}) {
4795
4849
  const startedAtMs = Date.now();
4796
- const resolvedRoot = path3.resolve(root);
4850
+ const resolvedRoot = path6__default.resolve(root);
4797
4851
  const normalizedOptions = parseAnalyzerOptions(options);
4798
4852
  const scan = await (async () => {
4799
4853
  const scanStartedAtMs = Date.now();
@@ -4837,7 +4891,7 @@ async function analyzeWorkspace(root, options = {}) {
4837
4891
  );
4838
4892
  }
4839
4893
  })();
4840
- const counts = collectClassCounts(normalizedScan);
4894
+ const counts = await collectClassCounts(normalizedScan);
4841
4895
  const baseAll = buildClassUsage(counts);
4842
4896
  const { all, semanticReport } = await (async () => {
4843
4897
  if (!normalizedOptions.semantic) {
@@ -4863,13 +4917,19 @@ async function analyzeWorkspace(root, options = {}) {
4863
4917
  );
4864
4918
  }
4865
4919
  })();
4866
- const top = all.slice(0, topLimit);
4867
- const frequent = all.filter((usage) => usage.count >= frequentThreshold).slice(0, topLimit);
4868
- const unique = all.filter((usage) => usage.count === 1);
4869
- const totalClassOccurrences = all.reduce((sum, usage) => sum + usage.count, 0);
4920
+ const classStatsNative = binding?.computeClassStats?.(
4921
+ JSON.stringify(all),
4922
+ topLimit,
4923
+ frequentThreshold
4924
+ );
4925
+ const top = classStatsNative ? JSON.parse(classStatsNative.topJson) : all.slice(0, topLimit);
4926
+ const frequent = classStatsNative ? JSON.parse(classStatsNative.frequentJson) : all.filter((usage) => usage.count >= frequentThreshold).slice(0, topLimit);
4927
+ const unique = classStatsNative ? JSON.parse(classStatsNative.uniqueJson) : all.filter((usage) => usage.count === 1);
4928
+ const totalClassOccurrences = classStatsNative ? classStatsNative.totalClassOccurrences : all.reduce((sum, usage) => sum + usage.count, 0);
4870
4929
  debugLog(
4871
4930
  `analyzeWorkspace completed in ${Date.now() - startedAtMs}ms (files=${normalizedScan.totalFiles}, uniqueClasses=${all.length})`
4872
4931
  );
4932
+ const distribution = await buildDistribution(all, binding);
4873
4933
  return {
4874
4934
  root: nativeReport.root || resolvedRoot,
4875
4935
  totalFiles: nativeReport.totalFiles,
@@ -4880,8 +4940,10 @@ async function analyzeWorkspace(root, options = {}) {
4880
4940
  top,
4881
4941
  frequent,
4882
4942
  unique,
4883
- distribution: buildDistribution(all)
4943
+ distribution
4884
4944
  },
4945
+ // topClasses — alias for classStats.top (test contract & backward compat)
4946
+ topClasses: top,
4885
4947
  safelist: all.map((usage) => usage.name),
4886
4948
  ...semanticReport ? { semantic: semanticReport } : {}
4887
4949
  };
@@ -4903,8 +4965,11 @@ var init_classToCss = __esm({
4903
4965
  init_binding();
4904
4966
  init_schemas2();
4905
4967
  init_utils();
4906
- normalizeClassInput = (input) => {
4968
+ normalizeClassInput = (input, _binding) => {
4907
4969
  if (typeof input === "string") {
4970
+ if (_binding?.normalizeClassInput) {
4971
+ return _binding.normalizeClassInput(input);
4972
+ }
4908
4973
  return input.split(/\s+/).map((item) => item.trim()).filter((item) => item.length > 0);
4909
4974
  }
4910
4975
  if (!Array.isArray(input)) {
@@ -4926,27 +4991,26 @@ var init_classToCss = __esm({
4926
4991
  const prefix = parsed.prefix ?? null;
4927
4992
  return { prefix, strict };
4928
4993
  };
4929
- mergeDeclarationMap = (target, css) => {
4930
- for (const ruleMatch of css.matchAll(/\{([^}]*)\}/g)) {
4931
- const body = ruleMatch[1];
4932
- for (const raw of body.split(";")) {
4933
- const declaration = raw.trim();
4934
- if (declaration.length === 0) continue;
4935
- const colonIndex = declaration.indexOf(":");
4936
- if (colonIndex <= 0) continue;
4937
- const property = declaration.slice(0, colonIndex).trim();
4938
- const value = declaration.slice(colonIndex + 1).trim();
4939
- if (property.length === 0 || value.length === 0) continue;
4940
- if (target.has(property)) target.delete(property);
4941
- target.set(property, value);
4942
- }
4994
+ mergeDeclarationMap = (target, css, binding) => {
4995
+ if (!binding.parseCssRules) {
4996
+ throw new Error("FATAL: Native binding 'parseCssRules' is required but not available.");
4997
+ }
4998
+ const rules = binding.parseCssRules(css);
4999
+ for (const rule of rules) {
5000
+ if (target.has(rule.property)) target.delete(rule.property);
5001
+ target.set(rule.property, rule.isImportant ? `${rule.value} !important` : rule.value);
4943
5002
  }
4944
5003
  };
4945
- declarationMapToString = (declarationMap) => {
4946
- return Array.from(declarationMap.entries()).map(([property, value]) => `${property}: ${value}`).join("; ");
5004
+ declarationMapToString = (declarationMap, binding) => {
5005
+ const entries = Array.from(declarationMap.entries()).map(([property, value]) => ({ property, value }));
5006
+ if (binding?.declarationMapToString) {
5007
+ return binding.declarationMapToString(entries);
5008
+ }
5009
+ return entries.map(({ property, value }) => `${property}: ${value}`).join("; ");
4947
5010
  };
4948
5011
  classToCss = async (input, options = {}) => {
4949
- const inputClasses = normalizeClassInput(input);
5012
+ const binding = await requireNativeCssCompiler();
5013
+ const inputClasses = normalizeClassInput(input, binding);
4950
5014
  const normalizedOptions = normalizeClassToCssOptions(options);
4951
5015
  if (inputClasses.length === 0) {
4952
5016
  return {
@@ -4958,7 +5022,6 @@ var init_classToCss = __esm({
4958
5022
  sizeBytes: 0
4959
5023
  };
4960
5024
  }
4961
- const binding = await requireNativeCssCompiler();
4962
5025
  const prefix = normalizedOptions.prefix;
4963
5026
  const results = await Promise.all(
4964
5027
  inputClasses.map(async (className) => {
@@ -4991,7 +5054,7 @@ var init_classToCss = __esm({
4991
5054
  const sizeBytes = results.reduce((sum, r) => sum + r.sizeBytes, 0);
4992
5055
  const declarationMap = /* @__PURE__ */ new Map();
4993
5056
  for (const result of results) {
4994
- mergeDeclarationMap(declarationMap, result.css);
5057
+ mergeDeclarationMap(declarationMap, result.css, binding);
4995
5058
  }
4996
5059
  const uniqueUnknown = Array.from(new Set(unknownClasses));
4997
5060
  if (normalizedOptions.strict && uniqueUnknown.length > 0) {
@@ -5000,7 +5063,7 @@ var init_classToCss = __esm({
5000
5063
  return {
5001
5064
  inputClasses,
5002
5065
  css: cssChunks.filter((chunk) => chunk.length > 0).join("\n"),
5003
- declarations: declarationMapToString(declarationMap),
5066
+ declarations: declarationMapToString(declarationMap, binding),
5004
5067
  resolvedClasses: Array.from(new Set(resolvedClasses)),
5005
5068
  unknownClasses: uniqueUnknown,
5006
5069
  sizeBytes
@@ -5010,8 +5073,8 @@ var init_classToCss = __esm({
5010
5073
  });
5011
5074
 
5012
5075
  // packages/domain/analyzer/src/index.ts
5013
- var src_exports = {};
5014
- __export(src_exports, {
5076
+ var src_exports2 = {};
5077
+ __export(src_exports2, {
5015
5078
  __internal: () => __internal,
5016
5079
  analyzeWorkspace: () => analyzeWorkspace,
5017
5080
  classToCss: () => classToCss
@@ -5039,7 +5102,7 @@ var init_src3 = __esm({
5039
5102
  });
5040
5103
  async function pathExists2(filePath) {
5041
5104
  try {
5042
- await fs4.access(filePath);
5105
+ await fs7.access(filePath);
5043
5106
  return true;
5044
5107
  } catch {
5045
5108
  return false;
@@ -5047,7 +5110,7 @@ async function pathExists2(filePath) {
5047
5110
  }
5048
5111
  async function readFileSafe(filePath) {
5049
5112
  try {
5050
- return await fs4.readFile(filePath, "utf8");
5113
+ return await fs7.readFile(filePath, "utf8");
5051
5114
  } catch {
5052
5115
  return null;
5053
5116
  }
@@ -5066,8 +5129,8 @@ async function writeFileSafe(filePath, content, options = {}) {
5066
5129
  options.onDryRun?.(`write ${filePath}`);
5067
5130
  return;
5068
5131
  }
5069
- await fs4.mkdir(path3.dirname(filePath), { recursive: true });
5070
- await fs4.writeFile(filePath, content, "utf8");
5132
+ await fs7.mkdir(path6__default.dirname(filePath), { recursive: true });
5133
+ await fs7.writeFile(filePath, content, "utf8");
5071
5134
  }
5072
5135
  async function ensureFileSafe(filePath, content, options = {}) {
5073
5136
  if (await pathExists2(filePath)) return "skipped";
@@ -5355,11 +5418,11 @@ var init_args = __esm({
5355
5418
  });
5356
5419
  function runtimeDirFromImportMeta(importMetaUrl) {
5357
5420
  const filename = fileURLToPath(importMetaUrl);
5358
- return path3.dirname(filename);
5421
+ return path6__default.dirname(filename);
5359
5422
  }
5360
5423
  async function resolveMonorepoPath(runtimeDir, relativeToRepoRoot) {
5361
- const fromRuntime = path3.resolve(runtimeDir, "..", "..", "..", relativeToRepoRoot);
5362
- const fromCwd = path3.resolve(process.cwd(), relativeToRepoRoot);
5424
+ const fromRuntime = path6__default.resolve(runtimeDir, "..", "..", "..", relativeToRepoRoot);
5425
+ const fromCwd = path6__default.resolve(process.cwd(), relativeToRepoRoot);
5363
5426
  return await pathExists2(fromRuntime) ? fromRuntime : fromCwd;
5364
5427
  }
5365
5428
  async function firstExistingPath(paths) {
@@ -5435,7 +5498,8 @@ async function runCliMain(options) {
5435
5498
  await program2.parseAsync(argv);
5436
5499
  } catch (error) {
5437
5500
  const isHelpError = isHelpExit(error);
5438
- if (isHelpError) return;
5501
+ const isVersionError = isVersionExit(error);
5502
+ if (isHelpError || isVersionError) return;
5439
5503
  const normalized = normalizeCliError(error);
5440
5504
  const isJson = input.json;
5441
5505
  if (isJson) {
@@ -5450,7 +5514,7 @@ async function runCliMain(options) {
5450
5514
  process.exitCode = errorExitCode(normalized);
5451
5515
  }
5452
5516
  }
5453
- var isCommanderLikeError, isHelpExit, normalizeCliError, findCommandByPath, resolveCommandHelp, resolveHelpPath, walkCommands;
5517
+ var isCommanderLikeError, isHelpExit, isVersionExit, normalizeCliError, findCommandByPath, resolveCommandHelp, resolveHelpPath, walkCommands;
5454
5518
  var init_runtime = __esm({
5455
5519
  "packages/infrastructure/cli/src/utils/runtime.ts"() {
5456
5520
  init_args();
@@ -5463,6 +5527,9 @@ var init_runtime = __esm({
5463
5527
  isHelpExit = (error) => {
5464
5528
  return isCommanderLikeError(error) && error.code === "commander.helpDisplayed";
5465
5529
  };
5530
+ isVersionExit = (error) => {
5531
+ return isCommanderLikeError(error) && error.code === "commander.version";
5532
+ };
5466
5533
  normalizeCliError = (error) => {
5467
5534
  if (!isCommanderLikeError(error)) return error;
5468
5535
  if (!error.code?.startsWith("commander.")) return error;
@@ -5543,7 +5610,7 @@ async function resolveCreateInput(options) {
5543
5610
  return { name: resolvedName, template: templateValue };
5544
5611
  }
5545
5612
  async function writeProjectFile(context, relativePath, content) {
5546
- const filePath = path3.join(context.projectDir, relativePath);
5613
+ const filePath = path6__default.join(context.projectDir, relativePath);
5547
5614
  await writeFileSafe(filePath, content, { dryRun: context.dryRun });
5548
5615
  context.writtenFiles.push(relativePath.replaceAll("\\", "/"));
5549
5616
  }
@@ -5662,7 +5729,6 @@ async function createViteVueApp(context) {
5662
5729
  scripts: { dev: "vite", build: "vite build", preview: "vite preview" },
5663
5730
  dependencies: {
5664
5731
  vue: "^3.4.0",
5665
- "tailwind-merge": "^3.5.0",
5666
5732
  "tailwind-styled-v4/vue": "^5.0.0"
5667
5733
  },
5668
5734
  devDependencies: {
@@ -5759,7 +5825,7 @@ async function createViteSvelteApp(context) {
5759
5825
  private: true,
5760
5826
  type: "module",
5761
5827
  scripts: { dev: "vite", build: "vite build", preview: "vite preview" },
5762
- dependencies: { "tailwind-merge": "^3.5.0", "tailwind-styled-v4/svelte": "^5.0.0" },
5828
+ dependencies: { "tailwind-styled-v4/svelte": "^5.0.0" },
5763
5829
  devDependencies: {
5764
5830
  svelte: "^5.0.0",
5765
5831
  "@sveltejs/vite-plugin-svelte": "^3.0.0",
@@ -5860,7 +5926,7 @@ async function createSimpleApp(context) {
5860
5926
  }
5861
5927
  async function createProject(options, output) {
5862
5928
  const { name, template } = await resolveCreateInput(options);
5863
- const projectDir = path3.resolve(process.cwd(), name);
5929
+ const projectDir = path6__default.resolve(process.cwd(), name);
5864
5930
  if (await pathExists2(projectDir)) {
5865
5931
  throw new CliUsageError(`Directory ${name} already exists.`);
5866
5932
  }
@@ -5931,10 +5997,13 @@ var init_createApp = __esm({
5931
5997
  };
5932
5998
  }
5933
5999
  });
5934
- var log3, NATIVE_UNAVAILABLE_MESSAGE, nativeBridge, bridgeLoadAttempted, bridgeLoadError, isValidNativeBridge, getNativeBridge;
6000
+
6001
+ // packages/domain/compiler/src/nativeBridge.ts
6002
+ var _loadNative, log3, NATIVE_UNAVAILABLE_MESSAGE, nativeBridge, bridgeLoadAttempted, bridgeLoadError, isValidNativeBridge, getNativeBridge;
5935
6003
  var init_nativeBridge = __esm({
5936
6004
  "packages/domain/compiler/src/nativeBridge.ts"() {
5937
6005
  init_src();
6006
+ _loadNative = (path29) => __require(path29);
5938
6007
  log3 = (...args) => {
5939
6008
  if (process.env.DEBUG?.includes("compiler:native")) {
5940
6009
  console.log("[compiler:native]", ...args);
@@ -5961,11 +6030,10 @@ var init_nativeBridge = __esm({
5961
6030
  bridgeLoadAttempted = true;
5962
6031
  try {
5963
6032
  const runtimeDir = resolveRuntimeDir(void 0, import.meta.url);
5964
- const require2 = createRequire(import.meta.url);
5965
6033
  const result = resolveNativeBinary(runtimeDir);
5966
6034
  if (result.path && result.path.endsWith(".node")) {
5967
6035
  try {
5968
- const binding = require2(result.path);
6036
+ const binding = _loadNative(result.path);
5969
6037
  if (isValidNativeBridge(binding)) {
5970
6038
  nativeBridge = binding;
5971
6039
  log3("Native bridge loaded successfully from:", result.path);
@@ -6000,7 +6068,7 @@ init_esm();
6000
6068
  init_errors();
6001
6069
  async function loadAnalyzerModule() {
6002
6070
  try {
6003
- const mod = await Promise.resolve().then(() => (init_src3(), src_exports));
6071
+ const mod = await Promise.resolve().then(() => (init_src3(), src_exports2));
6004
6072
  if (typeof mod.analyzeWorkspace !== "function") {
6005
6073
  throw new Error("analyzeWorkspace export not found");
6006
6074
  }
@@ -6067,7 +6135,7 @@ async function runAnalyzeCli(args) {
6067
6135
  verbose: process.env.TWS_VERBOSE === "1" || process.env.VERBOSE === "1"
6068
6136
  });
6069
6137
  const dirArg = parsed.positionals[0] ?? ".";
6070
- const dir = path3.resolve(process.cwd(), dirArg);
6138
+ const dir = path6__default.resolve(process.cwd(), dirArg);
6071
6139
  if (!await pathExists2(dir)) {
6072
6140
  throw new CliUsageError(`Directory not found: ${dir}`);
6073
6141
  }
@@ -6123,7 +6191,7 @@ async function runExtractCli(args) {
6123
6191
  const parsedMin = parseInt(minRaw, 10);
6124
6192
  const minCount = Number.isFinite(parsedMin) && parsedMin > 0 ? parsedMin : 2;
6125
6193
  const dirArg = parsed.positionals[0] ?? ".";
6126
- const dir = path3.resolve(process.cwd(), dirArg);
6194
+ const dir = path6__default.resolve(process.cwd(), dirArg);
6127
6195
  if (!await pathExists2(dir)) {
6128
6196
  throw new CliUsageError(`Directory not found: ${dir}`);
6129
6197
  }
@@ -6196,15 +6264,15 @@ async function runInitCli(rawArgs) {
6196
6264
  verbose: process.env.TWS_VERBOSE === "1" || process.env.VERBOSE === "1"
6197
6265
  });
6198
6266
  const target = rawArgs.find((arg) => !arg.startsWith("-")) ?? ".";
6199
- const root = path3.resolve(process.cwd(), target);
6267
+ const root = path6__default.resolve(process.cwd(), target);
6200
6268
  const report = { created: [], skipped: [] };
6201
6269
  await ensureFile(
6202
- path3.join(root, "src", "tailwind.css"),
6270
+ path6__default.join(root, "src", "tailwind.css"),
6203
6271
  '@import "tailwindcss";\n\n@theme {\n --color-primary: #3b82f6;\n --spacing-section: 3rem;\n}\n',
6204
6272
  report
6205
6273
  );
6206
6274
  await ensureFile(
6207
- path3.join(root, "tailwind-styled.config.json"),
6275
+ path6__default.join(root, "tailwind-styled.config.json"),
6208
6276
  `${JSON.stringify(
6209
6277
  {
6210
6278
  version: 1,
@@ -6223,12 +6291,12 @@ async function runInitCli(rawArgs) {
6223
6291
  output.writeText("\nInit complete");
6224
6292
  output.writeText(`Created: ${report.created.length}`);
6225
6293
  for (const filePath of report.created) {
6226
- output.writeText(` + ${path3.relative(root, filePath)}`);
6294
+ output.writeText(` + ${path6__default.relative(root, filePath)}`);
6227
6295
  }
6228
6296
  if (report.skipped.length > 0) {
6229
6297
  output.writeText(`Skipped: ${report.skipped.length}`);
6230
6298
  for (const filePath of report.skipped) {
6231
- output.writeText(` - ${path3.relative(root, filePath)} (exists)`);
6299
+ output.writeText(` - ${path6__default.relative(root, filePath)} (exists)`);
6232
6300
  }
6233
6301
  }
6234
6302
  }
@@ -6289,15 +6357,15 @@ async function findSourceFiles(dir) {
6289
6357
  const out = [];
6290
6358
  async function walk(currentDir) {
6291
6359
  if (!await pathExists2(currentDir)) return;
6292
- const entries = await fs4.readdir(currentDir, { withFileTypes: true });
6360
+ const entries = await fs7.readdir(currentDir, { withFileTypes: true });
6293
6361
  for (const entry of entries) {
6294
- const fullPath = path3.join(currentDir, entry.name);
6362
+ const fullPath = path6__default.join(currentDir, entry.name);
6295
6363
  if (entry.isDirectory()) {
6296
6364
  if (IGNORED_DIRS.has(entry.name)) continue;
6297
6365
  await walk(fullPath);
6298
6366
  continue;
6299
6367
  }
6300
- if (SOURCE_EXTENSIONS.has(path3.extname(entry.name))) {
6368
+ if (SOURCE_EXTENSIONS.has(path6__default.extname(entry.name))) {
6301
6369
  out.push(fullPath);
6302
6370
  }
6303
6371
  }
@@ -6318,7 +6386,7 @@ function migrateSource(source, options) {
6318
6386
  return { output, classRenames: 0, importRenames };
6319
6387
  }
6320
6388
  async function migrateConfig(root, dryRun) {
6321
- const cssPath = path3.join(root, "src", "tailwind.css");
6389
+ const cssPath = path6__default.join(root, "src", "tailwind.css");
6322
6390
  if (await pathExists2(cssPath)) return 0;
6323
6391
  await writeFileSafe(cssPath, DEFAULT_TAILWIND_CSS, { dryRun });
6324
6392
  return 1;
@@ -6331,7 +6399,7 @@ async function runMigrateCli(rawArgs) {
6331
6399
  verbose: process.env.TWS_VERBOSE === "1" || process.env.VERBOSE === "1"
6332
6400
  });
6333
6401
  const target = firstPositional(rawArgs) ?? ".";
6334
- const root = path3.resolve(process.cwd(), target);
6402
+ const root = path6__default.resolve(process.cwd(), target);
6335
6403
  const dryRunFlag = hasFlag("dry-run", rawArgs);
6336
6404
  const wizardOptions = hasFlag("wizard", rawArgs) ? await runMigrationWizard() : null;
6337
6405
  const { dryRun, includeConfig, includeClasses, includeImports } = wizardOptions ? {
@@ -6355,12 +6423,12 @@ async function runMigrateCli(rawArgs) {
6355
6423
  report.configWrites += await migrateConfig(root, dryRun);
6356
6424
  }
6357
6425
  for (const filePath of files) {
6358
- const source = await fs4.readFile(filePath, "utf8");
6426
+ const source = await fs7.readFile(filePath, "utf8");
6359
6427
  const migrated = migrateSource(source, { includeImports, includeClasses });
6360
6428
  if (migrated.output !== source) {
6361
6429
  report.updatedFiles++;
6362
6430
  if (!dryRun) {
6363
- await fs4.writeFile(filePath, migrated.output, "utf8");
6431
+ await fs7.writeFile(filePath, migrated.output, "utf8");
6364
6432
  }
6365
6433
  }
6366
6434
  report.classRenames += migrated.classRenames;
@@ -6424,10 +6492,10 @@ function buildClassNames(files, uniqueClasses) {
6424
6492
  });
6425
6493
  }
6426
6494
  function writeScanCache(root, cacheData) {
6427
- const cacheDir = path3.join(root, ".tailwind-styled");
6428
- const cachePath = path3.join(cacheDir, "scan-cache.json");
6429
- fs8.mkdirSync(cacheDir, { recursive: true });
6430
- fs8.writeFileSync(cachePath, JSON.stringify(cacheData, null, 2), "utf-8");
6495
+ const cacheDir = path6__default.join(root, ".tailwind-styled");
6496
+ const cachePath = path6__default.join(cacheDir, "scan-cache.json");
6497
+ fs11__default.mkdirSync(cacheDir, { recursive: true });
6498
+ fs11__default.writeFileSync(cachePath, JSON.stringify(cacheData, null, 2), "utf-8");
6431
6499
  return cachePath;
6432
6500
  }
6433
6501
  async function runScanCli(rawArgs) {
@@ -6439,7 +6507,7 @@ async function runScanCli(rawArgs) {
6439
6507
  debug: process.env.TWS_DEBUG === "1" || process.env.DEBUG === "1",
6440
6508
  verbose: process.env.TWS_VERBOSE === "1" || process.env.VERBOSE === "1"
6441
6509
  });
6442
- const root = path3.resolve(process.cwd(), target);
6510
+ const root = path6__default.resolve(process.cwd(), target);
6443
6511
  const spinner = output.spinner();
6444
6512
  spinner.start(`Scanning ${root}`);
6445
6513
  const scanned = await scanWorkspaceAsync(root);
@@ -6729,7 +6797,7 @@ var writeVerboseLine = (binary, args) => {
6729
6797
  console.error(` [verbose] $ ${formatCommand(binary, args)}`);
6730
6798
  };
6731
6799
  var runCommand = async (binary, args, options = {}) => {
6732
- return new Promise((resolve, reject) => {
6800
+ return new Promise((resolve2, reject) => {
6733
6801
  if (isVerboseEnabled(options)) {
6734
6802
  writeVerboseLine(binary, args);
6735
6803
  }
@@ -6756,7 +6824,7 @@ var runCommand = async (binary, args, options = {}) => {
6756
6824
  );
6757
6825
  return;
6758
6826
  }
6759
- resolve(exitCode);
6827
+ resolve2(exitCode);
6760
6828
  });
6761
6829
  });
6762
6830
  };
@@ -6785,7 +6853,7 @@ var formatCommandFailureOutput = (stdout, stderr) => {
6785
6853
  return "Command failed with no output.";
6786
6854
  };
6787
6855
  var runCommandCapture = async (binary, args, options = {}) => {
6788
- return new Promise((resolve, reject) => {
6856
+ return new Promise((resolve2, reject) => {
6789
6857
  if (isVerboseEnabled(options)) {
6790
6858
  writeVerboseLine(binary, args);
6791
6859
  }
@@ -6828,7 +6896,7 @@ ${formatCommandFailureOutput(stdout, stderr)}`,
6828
6896
  );
6829
6897
  return;
6830
6898
  }
6831
- resolve({
6899
+ resolve2({
6832
6900
  exitCode,
6833
6901
  stdout,
6834
6902
  stderr
@@ -6866,12 +6934,12 @@ function configureSetupFlags(rawArgs) {
6866
6934
  };
6867
6935
  }
6868
6936
  async function readPackageJson(cwd2) {
6869
- return readJsonSafe(path3.join(cwd2, "package.json"));
6937
+ return readJsonSafe(path6__default.join(cwd2, "package.json"));
6870
6938
  }
6871
6939
  async function detectPm(cwd2) {
6872
- if (await pathExists2(path3.join(cwd2, "bun.lockb"))) return "bun";
6873
- if (await pathExists2(path3.join(cwd2, "pnpm-lock.yaml"))) return "pnpm";
6874
- if (await pathExists2(path3.join(cwd2, "yarn.lock"))) return "yarn";
6940
+ if (await pathExists2(path6__default.join(cwd2, "bun.lockb"))) return "bun";
6941
+ if (await pathExists2(path6__default.join(cwd2, "pnpm-lock.yaml"))) return "pnpm";
6942
+ if (await pathExists2(path6__default.join(cwd2, "yarn.lock"))) return "yarn";
6875
6943
  return "npm";
6876
6944
  }
6877
6945
  async function detectBundler(cwd2) {
@@ -6892,7 +6960,7 @@ async function alreadyInstalled(cwd2, pkgName) {
6892
6960
  }
6893
6961
  async function findExisting(cwd2, names) {
6894
6962
  for (const name of names) {
6895
- const resolved = path3.join(cwd2, name);
6963
+ const resolved = path6__default.join(cwd2, name);
6896
6964
  if (await pathExists2(resolved)) return resolved;
6897
6965
  }
6898
6966
  return null;
@@ -7032,16 +7100,10 @@ var runSetupCli = async (rawArgs) => {
7032
7100
  output.writeText(import_picocolors3.default.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
7033
7101
  output.writeText("");
7034
7102
  output.writeText(import_picocolors3.default.bold(" [1/4]") + import_picocolors3.default.cyan(" packages"));
7035
- const [hasCorePkg, hasMergePkg] = await Promise.all([
7036
- alreadyInstalled(cwd, "tailwind-styled-v4"),
7037
- alreadyInstalled(cwd, "tailwind-merge")
7038
- ]);
7039
- const toInstall = [
7040
- hasCorePkg ? null : "tailwind-styled-v4",
7041
- hasMergePkg ? null : "tailwind-merge"
7042
- ].filter(Boolean);
7103
+ const hasCorePkg = await alreadyInstalled(cwd, "tailwind-styled-v4");
7104
+ const toInstall = hasCorePkg ? [] : ["tailwind-styled-v4"];
7043
7105
  if (toInstall.length > 0) await installPackages(cwd, pm, toInstall, false, setupFlags, logger);
7044
- else logger.skip("tailwind-styled-v4 + tailwind-merge sudah terpasang");
7106
+ else logger.skip("tailwind-styled-v4 sudah terpasang");
7045
7107
  output.writeText("\n" + import_picocolors3.default.bold(" [2/4]") + import_picocolors3.default.cyan(" bundler config"));
7046
7108
  const bundlerConfigMap = {
7047
7109
  next: {
@@ -7064,7 +7126,7 @@ var runSetupCli = async (rawArgs) => {
7064
7126
  if (bundlerConfig) {
7065
7127
  const cfg = await findExisting(cwd, bundlerConfig.files);
7066
7128
  if (cfg)
7067
- await patchFileWithDryRun(cfg, bundlerConfig.patcher, path3.basename(cfg), setupFlags, logger);
7129
+ await patchFileWithDryRun(cfg, bundlerConfig.patcher, path6__default.basename(cfg), setupFlags, logger);
7068
7130
  else logger.warn(bundlerConfig.warnMsg);
7069
7131
  } else {
7070
7132
  logger.skip("React tanpa bundler - tidak ada bundler config yang di-patch");
@@ -7083,8 +7145,8 @@ var runSetupCli = async (rawArgs) => {
7083
7145
  if (cssFile) {
7084
7146
  await patchFileWithDryRun(
7085
7147
  cssFile,
7086
- (src) => patchTailwindCss(src, bundler, path3.relative(cwd, cssFile), cwd),
7087
- path3.relative(cwd, cssFile),
7148
+ (src) => patchTailwindCss(src, bundler, path6__default.relative(cwd, cssFile), cwd),
7149
+ path6__default.relative(cwd, cssFile),
7088
7150
  setupFlags,
7089
7151
  logger
7090
7152
  );
@@ -7092,7 +7154,7 @@ var runSetupCli = async (rawArgs) => {
7092
7154
  logger.warn('CSS entry tidak ditemukan \u2014 tambahkan @import "tailwindcss" manual ke globals.css');
7093
7155
  }
7094
7156
  output.writeText("\n" + import_picocolors3.default.bold(" [4/4]") + import_picocolors3.default.cyan(" tsconfig.json"));
7095
- const tsCfg = path3.join(cwd, "tsconfig.json");
7157
+ const tsCfg = path6__default.join(cwd, "tsconfig.json");
7096
7158
  const hasTsConfig = await findExisting(cwd, ["tsconfig.json"]);
7097
7159
  if (hasTsConfig) {
7098
7160
  await patchFileWithDryRun(tsCfg, patchTsConfig, "tsconfig.json", setupFlags, logger);
@@ -7158,7 +7220,7 @@ async function runStatsCli(args) {
7158
7220
  verbose: process.env.TWS_VERBOSE === "1" || process.env.VERBOSE === "1"
7159
7221
  });
7160
7222
  const dirArg = parsed.positionals[0] ?? ".";
7161
- const dir = path3.resolve(process.cwd(), dirArg);
7223
+ const dir = path6__default.resolve(process.cwd(), dirArg);
7162
7224
  if (!await pathExists2(dir)) {
7163
7225
  throw new CliUsageError(`Directory not found: ${dir}`);
7164
7226
  }
@@ -7370,7 +7432,7 @@ function enumerateVariantProps(matrix) {
7370
7432
  }
7371
7433
  async function resolveScript(context, relativeToRepoRoot) {
7372
7434
  const fromRuntime = await resolveMonorepoPath(context.runtimeDir, relativeToRepoRoot);
7373
- const fromCwd = path3.resolve(process.cwd(), relativeToRepoRoot);
7435
+ const fromCwd = path6__default.resolve(process.cwd(), relativeToRepoRoot);
7374
7436
  const resolved = await firstExistingPath([fromRuntime, fromCwd]);
7375
7437
  if (!resolved) {
7376
7438
  throw new CliUsageError(`Required script not found: ${relativeToRepoRoot}`);
@@ -7384,13 +7446,13 @@ async function loadRegistry(context) {
7384
7446
  );
7385
7447
  const candidates = [
7386
7448
  runtimeRegistryPath,
7387
- path3.resolve(process.cwd(), "packages/domain/plugin-registry/registry.json")
7449
+ path6__default.resolve(process.cwd(), "packages/domain/plugin-registry/registry.json")
7388
7450
  ];
7389
7451
  const registryPath = await firstExistingPath(candidates);
7390
7452
  if (!registryPath) {
7391
7453
  throw new CliUsageError("Plugin registry file not found.");
7392
7454
  }
7393
- const raw = await fs4.readFile(registryPath, "utf8");
7455
+ const raw = await fs7.readFile(registryPath, "utf8");
7394
7456
  const data = JSON.parse(raw);
7395
7457
  return [
7396
7458
  ...data.official.map((item) => ({ ...item, official: true })),
@@ -7440,7 +7502,7 @@ init_json();
7440
7502
  var postJson = async (url, body, token) => {
7441
7503
  const { default: https } = await import('https');
7442
7504
  const { default: http } = await import('http');
7443
- return new Promise((resolve, reject) => {
7505
+ return new Promise((resolve2, reject) => {
7444
7506
  const client = url.protocol === "https:" ? https : http;
7445
7507
  const req = client.request(
7446
7508
  url,
@@ -7458,9 +7520,9 @@ var postJson = async (url, body, token) => {
7458
7520
  res.on("end", () => {
7459
7521
  const raw = Buffer.concat(chunks).toString("utf8");
7460
7522
  try {
7461
- resolve({ status: res.statusCode, body: JSON.parse(raw) });
7523
+ resolve2({ status: res.statusCode, body: JSON.parse(raw) });
7462
7524
  } catch {
7463
- resolve({ status: res.statusCode, body: raw });
7525
+ resolve2({ status: res.statusCode, body: raw });
7464
7526
  }
7465
7527
  });
7466
7528
  }
@@ -7489,7 +7551,7 @@ var deployCommand = {
7489
7551
  const version = typeof parsed.values.version === "string" ? parsed.values.version : "0.1.0";
7490
7552
  const tag = typeof parsed.values.tag === "string" ? parsed.values.tag : "latest";
7491
7553
  const registryUrl = typeof parsed.values.registry === "string" ? parsed.values.registry : process.env.TW_REGISTRY_URL ?? null;
7492
- const pkgPath = path3.join(process.cwd(), "package.json");
7554
+ const pkgPath = path6__default.join(process.cwd(), "package.json");
7493
7555
  if (!await pathExists2(pkgPath)) {
7494
7556
  throw new CliUsageError("[tw deploy] No package.json found in current directory");
7495
7557
  }
@@ -7524,10 +7586,10 @@ var deployCommand = {
7524
7586
  }
7525
7587
  return;
7526
7588
  }
7527
- const cacheDir = path3.join(process.cwd(), ".tw-cache");
7528
- await fs4.mkdir(cacheDir, { recursive: true });
7529
- await fs4.writeFile(
7530
- path3.join(cacheDir, "deploy-manifest.json"),
7589
+ const cacheDir = path6__default.join(process.cwd(), ".tw-cache");
7590
+ await fs7.mkdir(cacheDir, { recursive: true });
7591
+ await fs7.writeFile(
7592
+ path6__default.join(cacheDir, "deploy-manifest.json"),
7531
7593
  JSON.stringify(manifest, null, 2)
7532
7594
  );
7533
7595
  if (!registryUrl) {
@@ -7627,24 +7689,24 @@ function addIssue(issues, severity, type, message, suggestion, location) {
7627
7689
  issues.push({ severity, type, message, suggestion, location });
7628
7690
  }
7629
7691
  function readJsonFile(filePath) {
7630
- if (!fs8.existsSync(filePath)) return null;
7692
+ if (!fs11__default.existsSync(filePath)) return null;
7631
7693
  try {
7632
- return JSON.parse(fs8.readFileSync(filePath, "utf8"));
7694
+ return JSON.parse(fs11__default.readFileSync(filePath, "utf8"));
7633
7695
  } catch {
7634
7696
  return null;
7635
7697
  }
7636
7698
  }
7637
7699
  function findWorkspacePackageJsonFiles(root) {
7638
- const packagesDir = path3.join(root, "packages");
7639
- if (!fs8.existsSync(packagesDir)) return [];
7640
- return fs8.readdirSync(packagesDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => path3.join(packagesDir, entry.name, "package.json")).filter((filePath) => fs8.existsSync(filePath));
7700
+ const packagesDir = path6__default.join(root, "packages");
7701
+ if (!fs11__default.existsSync(packagesDir)) return [];
7702
+ return fs11__default.readdirSync(packagesDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => path6__default.join(packagesDir, entry.name, "package.json")).filter((filePath) => fs11__default.existsSync(filePath));
7641
7703
  }
7642
7704
  function findFiles(dir, ext) {
7643
7705
  const files = [];
7644
7706
  try {
7645
- const entries = fs8.readdirSync(dir, { withFileTypes: true });
7707
+ const entries = fs11__default.readdirSync(dir, { withFileTypes: true });
7646
7708
  for (const entry of entries) {
7647
- const fullPath = path3.join(dir, entry.name);
7709
+ const fullPath = path6__default.join(dir, entry.name);
7648
7710
  if (entry.isDirectory() && !entry.name.startsWith(".") && entry.name !== "node_modules") {
7649
7711
  files.push(...findFiles(fullPath, ext));
7650
7712
  } else if (entry.isFile() && entry.name.endsWith(ext)) {
@@ -7657,7 +7719,7 @@ function findFiles(dir, ext) {
7657
7719
  return files;
7658
7720
  }
7659
7721
  function runWorkspaceDiagnostics(root, issues, checks) {
7660
- const rootPackageJsonPath = path3.join(root, "package.json");
7722
+ const rootPackageJsonPath = path6__default.join(root, "package.json");
7661
7723
  const rootPackageJson = readJsonFile(rootPackageJsonPath);
7662
7724
  if (!rootPackageJson) {
7663
7725
  addCheck(
@@ -7710,7 +7772,7 @@ function runWorkspaceDiagnostics(root, issues, checks) {
7710
7772
  const scripts = typeof manifest.scripts === "object" && manifest.scripts !== null ? manifest.scripts : {};
7711
7773
  const missing = requiredScripts.filter((name) => typeof scripts[name] !== "string");
7712
7774
  if (missing.length === 0) return [];
7713
- const packageName = typeof manifest.name === "string" && manifest.name.length > 0 ? manifest.name : path3.basename(path3.dirname(filePath));
7775
+ const packageName = typeof manifest.name === "string" && manifest.name.length > 0 ? manifest.name : path6__default.basename(path6__default.dirname(filePath));
7714
7776
  return [{ packageName, missing }];
7715
7777
  });
7716
7778
  if (missingScripts.length === 0) {
@@ -7745,7 +7807,7 @@ function runWorkspaceDiagnostics(root, issues, checks) {
7745
7807
  );
7746
7808
  }
7747
7809
  function runTailwindProjectDiagnostics(root, issues, checks) {
7748
- const packageJsonPath = path3.join(root, "package.json");
7810
+ const packageJsonPath = path6__default.join(root, "package.json");
7749
7811
  const packageJson = readJsonFile(packageJsonPath);
7750
7812
  if (!packageJson) {
7751
7813
  addCheck(
@@ -7804,7 +7866,7 @@ function runTailwindProjectDiagnostics(root, issues, checks) {
7804
7866
  const cssFiles = findFiles(root, ".css");
7805
7867
  const hasTailwindImport = cssFiles.slice(0, 10).some((filePath) => {
7806
7868
  try {
7807
- const content = fs8.readFileSync(filePath, "utf8");
7869
+ const content = fs11__default.readFileSync(filePath, "utf8");
7808
7870
  return content.includes("@tailwind") || content.includes('@import "tailwindcss"');
7809
7871
  } catch {
7810
7872
  return false;
@@ -7828,7 +7890,7 @@ function runTailwindProjectDiagnostics(root, issues, checks) {
7828
7890
  );
7829
7891
  }
7830
7892
  const configFiles = ["tailwind.config.js", "tailwind.config.ts", "tailwind.config.mjs"];
7831
- const hasConfig = configFiles.some((name) => fs8.existsSync(path3.join(root, name)));
7893
+ const hasConfig = configFiles.some((name) => fs11__default.existsSync(path6__default.join(root, name)));
7832
7894
  addCheck(
7833
7895
  checks,
7834
7896
  "tailwind",
@@ -7837,7 +7899,7 @@ function runTailwindProjectDiagnostics(root, issues, checks) {
7837
7899
  "info",
7838
7900
  hasConfig ? "Tailwind config file detected." : "No tailwind.config file found."
7839
7901
  );
7840
- const tsconfig = readJsonFile(path3.join(root, "tsconfig.json"));
7902
+ const tsconfig = readJsonFile(path6__default.join(root, "tsconfig.json"));
7841
7903
  const jsx = tsconfig?.compilerOptions?.jsx;
7842
7904
  addCheck(
7843
7905
  checks,
@@ -8003,7 +8065,7 @@ async function runAnalysisDiagnostics(root, issues, checks, verbose) {
8003
8065
  }
8004
8066
  }
8005
8067
  var runDiagnostics = async (options = {}) => {
8006
- const root = path3.resolve(options.root ?? process.cwd());
8068
+ const root = path6__default.resolve(options.root ?? process.cwd());
8007
8069
  const includes = parseIncludes(options.include);
8008
8070
  const issues = [];
8009
8071
  const checks = [];
@@ -8153,7 +8215,7 @@ var shareCommand = {
8153
8215
  name: "share",
8154
8216
  async run(args, context) {
8155
8217
  const name = args.find((arg) => !arg.startsWith("-")) ?? "component-name";
8156
- const manifestPath = path3.join(process.cwd(), ".tw-cache", "deploy-manifest.json");
8218
+ const manifestPath = path6__default.join(process.cwd(), ".tw-cache", "deploy-manifest.json");
8157
8219
  const defaultManifest = {
8158
8220
  name,
8159
8221
  version: "0.1.0"
@@ -8239,14 +8301,14 @@ var isVersionOutdated = (currentVersion, latestVersion) => {
8239
8301
  };
8240
8302
  var resolveCurrentCliVersion = async (context) => {
8241
8303
  const candidates = [
8242
- path3.resolve(context.runtimeDir, "..", "package.json"),
8243
- path3.resolve(process.cwd(), "packages", "cli", "package.json"),
8244
- path3.resolve(process.cwd(), "package.json")
8304
+ path6__default.resolve(context.runtimeDir, "..", "package.json"),
8305
+ path6__default.resolve(process.cwd(), "packages", "cli", "package.json"),
8306
+ path6__default.resolve(process.cwd(), "package.json")
8245
8307
  ];
8246
8308
  for (const candidate of candidates) {
8247
8309
  if (!await pathExists2(candidate)) continue;
8248
8310
  const pkg = await readJsonSafe(candidate);
8249
- const isCliPackage = pkg?.version && (pkg.name === CLI_PACKAGE_NAME || candidate.includes(`${path3.sep}packages${path3.sep}cli${path3.sep}`));
8311
+ const isCliPackage = pkg?.version && (pkg.name === CLI_PACKAGE_NAME || candidate.includes(`${path6__default.sep}packages${path6__default.sep}cli${path6__default.sep}`));
8250
8312
  if (isCliPackage) return pkg.version ?? "0.0.0";
8251
8313
  }
8252
8314
  return "0.0.0";
@@ -8519,7 +8581,7 @@ function resolveCliEntry(scriptPath) {
8519
8581
  async function hasTailwindCssImport(cwd2) {
8520
8582
  const cssFiles = ["src/app/globals.css", "src/index.css", "src/style.css", "app/globals.css"];
8521
8583
  for (const file of cssFiles) {
8522
- const raw = await readFileSafe(path3.join(cwd2, file));
8584
+ const raw = await readFileSafe(path6__default.join(cwd2, file));
8523
8585
  if (raw?.includes("tailwindcss")) return true;
8524
8586
  }
8525
8587
  return false;
@@ -8535,7 +8597,7 @@ async function hasSafelistSource(cwd2) {
8535
8597
  "app/globals.css"
8536
8598
  ];
8537
8599
  for (const file of cssFiles) {
8538
- const raw = await readFileSafe(path3.join(cwd2, file));
8600
+ const raw = await readFileSafe(path6__default.join(cwd2, file));
8539
8601
  if (raw === null) continue;
8540
8602
  if (raw.includes("tw-classes")) return { found: true, cssFile: file };
8541
8603
  if (raw.includes("tailwindcss")) return { found: false, cssFile: file };
@@ -8543,8 +8605,8 @@ async function hasSafelistSource(cwd2) {
8543
8605
  return { found: false, cssFile: null };
8544
8606
  }
8545
8607
  async function applyTailwindInit(cwd2) {
8546
- await ensureFileSafe(path3.join(cwd2, "src", "tailwind.css"), DEFAULT_TAILWIND_CSS2);
8547
- await ensureFileSafe(path3.join(cwd2, "tailwind-styled.config.json"), DEFAULT_TW_CONFIG);
8608
+ await ensureFileSafe(path6__default.join(cwd2, "src", "tailwind.css"), DEFAULT_TAILWIND_CSS2);
8609
+ await ensureFileSafe(path6__default.join(cwd2, "tailwind-styled.config.json"), DEFAULT_TW_CONFIG);
8548
8610
  }
8549
8611
  function check(results, id, label, pass, message, fix) {
8550
8612
  results.push({ id, label, pass, message, fix });
@@ -8566,7 +8628,7 @@ async function runPreflightCli(rawArgs) {
8566
8628
  node.major >= 20 ? `Node ${node.full} OK` : `Node ${node.full} - requires >=20. Download: https://nodejs.org`,
8567
8629
  node.major < 20 ? "Install Node.js 20 LTS or newer from https://nodejs.org" : void 0
8568
8630
  );
8569
- const pkg = await readJsonSafe(path3.join(cwd2, "package.json"));
8631
+ const pkg = await readJsonSafe(path6__default.join(cwd2, "package.json"));
8570
8632
  check(
8571
8633
  results,
8572
8634
  "package-json",
@@ -8597,19 +8659,10 @@ async function runPreflightCli(rawArgs) {
8597
8659
  hasBundler ? `${bundlerName} detected OK` : "No supported bundler (Vite/Next.js/Rspack) found",
8598
8660
  "Install a bundler: npm install vite @vitejs/plugin-react OR npx create-next-app"
8599
8661
  );
8600
- const hasMerge = pkgHasDep(pkg, "tailwind-merge");
8601
- check(
8602
- results,
8603
- "tailwind-merge",
8604
- "tailwind-merge installed",
8605
- hasMerge,
8606
- hasMerge ? "tailwind-merge found OK" : "Missing peer dep - run: npm install tailwind-merge",
8607
- "npm install tailwind-merge"
8608
- );
8609
8662
  }
8610
8663
  const twConfigFiles = ["tailwind.config.ts", "tailwind.config.js", "tailwind.config.mjs"];
8611
8664
  const twConfigChecks = await Promise.all(
8612
- twConfigFiles.map(async (file) => ({ file, exists: await pathExists2(path3.join(cwd2, file)) }))
8665
+ twConfigFiles.map(async (file) => ({ file, exists: await pathExists2(path6__default.join(cwd2, file)) }))
8613
8666
  );
8614
8667
  const foundTwConfig = twConfigChecks.find((item) => item.exists)?.file ?? null;
8615
8668
  const hasCssConfig = await hasTailwindCssImport(cwd2);
@@ -8621,7 +8674,7 @@ async function runPreflightCli(rawArgs) {
8621
8674
  foundTwConfig ? `${foundTwConfig} found OK` : hasCssConfig ? "@import tailwindcss found in CSS OK" : "No Tailwind config found - run: tw init",
8622
8675
  "tw init"
8623
8676
  );
8624
- const oldConfig = await readJsonSafe(path3.join(cwd2, "tailwind.config.js")) ?? await readJsonSafe(path3.join(cwd2, "tailwind.config.ts"));
8677
+ const oldConfig = await readJsonSafe(path6__default.join(cwd2, "tailwind.config.js")) ?? await readJsonSafe(path6__default.join(cwd2, "tailwind.config.ts"));
8625
8678
  if (oldConfig) {
8626
8679
  const hasOldJit = oldConfig.mode === "jit";
8627
8680
  const hasOldPurge = "purge" in oldConfig;
@@ -8635,7 +8688,7 @@ async function runPreflightCli(rawArgs) {
8635
8688
  "Run: tw migrate --dry-run to see migration steps"
8636
8689
  );
8637
8690
  }
8638
- const hasTsConfig = await pathExists2(path3.join(cwd2, "tsconfig.json"));
8691
+ const hasTsConfig = await pathExists2(path6__default.join(cwd2, "tsconfig.json"));
8639
8692
  check(
8640
8693
  results,
8641
8694
  "typescript",
@@ -9029,7 +9082,7 @@ var storybookCommand = {
9029
9082
  context.output.writeText(
9030
9083
  `[tw storybook] Tip: use --variants='{"size":["sm","lg"]}' to enumerate variant combinations`
9031
9084
  );
9032
- const localBin = path3.join(
9085
+ const localBin = path6__default.join(
9033
9086
  process.cwd(),
9034
9087
  "node_modules",
9035
9088
  ".bin",
@@ -9226,418 +9279,269 @@ function getNativeEngineBinding() {
9226
9279
  // packages/domain/engine/src/bundleAnalyzer.ts
9227
9280
  var BundleAnalyzer = class {
9228
9281
  analyzeClass(className, scanResult, css) {
9229
- if (!className || className.trim() === "") {
9230
- throw new Error("Class name cannot be empty");
9231
- }
9232
- if (!scanResult) {
9233
- throw new Error("Scan result is required for analysis");
9282
+ if (!className || className.trim() === "") throw new Error("Class name cannot be empty");
9283
+ if (!scanResult) throw new Error("Scan result is required for analysis");
9284
+ if (typeof css !== "string") throw new Error("CSS string is required for analysis");
9285
+ const normalizedClass = className.startsWith(".") ? className.slice(1) : className;
9286
+ const native = getNativeEngineBinding();
9287
+ if (!native.analyzeClassUsage) {
9288
+ throw new Error("FATAL: Native binding 'analyzeClassUsage' is required but not available.");
9234
9289
  }
9235
- if (typeof css !== "string") {
9236
- throw new Error("CSS string is required for analysis");
9290
+ if (!native.buildDependencyChain) {
9291
+ throw new Error("FATAL: Native binding 'buildDependencyChain' is required but not available.");
9237
9292
  }
9238
- const normalizedClass = className.startsWith(".") ? className.slice(1) : className;
9239
- const usageCount = this.countClassUsage(normalizedClass, scanResult);
9240
- const files = this.getFilesUsingClass(normalizedClass, scanResult);
9241
- const bundleSize = this.calculateBundleContribution(normalizedClass, css);
9242
- const variantChains = this.extractVariantChains(normalizedClass, css);
9243
- const dependencies = this.extractDependencies(normalizedClass, css);
9244
- const isDeadCode = this.checkIsDeadCode(normalizedClass, scanResult, css);
9293
+ const results = native.analyzeClassUsage(
9294
+ [normalizedClass],
9295
+ JSON.stringify(scanResult),
9296
+ css
9297
+ );
9298
+ const info = results[0];
9299
+ const files = info ? JSON.parse(info.filesJson).map((f) => ({ file: f, line: 1, column: 1 })) : [];
9300
+ const dependencies = native.buildDependencyChain(normalizedClass);
9245
9301
  return {
9246
9302
  className: normalizedClass,
9247
- totalUsage: usageCount,
9303
+ totalUsage: info?.usageCount ?? 0,
9248
9304
  files,
9249
- bundleSizeBytes: bundleSize,
9250
- variantChains,
9251
- isDeadCode,
9305
+ bundleSizeBytes: info?.bundleSizeBytes ?? 0,
9306
+ variantChains: [],
9307
+ isDeadCode: info?.isDeadCode ?? true,
9252
9308
  dependencies
9253
9309
  };
9254
9310
  }
9255
9311
  analyzeAll(scanResult, css) {
9256
- if (!scanResult) {
9257
- throw new Error("Scan result is required for analysis");
9258
- }
9259
- if (typeof css !== "string") {
9260
- throw new Error("CSS string is required for analysis");
9261
- }
9262
- const results = /* @__PURE__ */ new Map();
9263
- const allClasses = new Set(scanResult.uniqueClasses);
9264
- const cssClasses = this.extractClassesFromCss(css);
9265
- for (const cssClass of cssClasses) {
9266
- allClasses.add(cssClass);
9267
- }
9268
- for (const className of allClasses) {
9269
- try {
9270
- const result = this.analyzeClass(className, scanResult, css);
9271
- results.set(className, result);
9272
- } catch (error) {
9273
- console.warn(`Failed to analyze class "${className}":`, error);
9274
- }
9312
+ if (!scanResult) throw new Error("Scan result is required for analysis");
9313
+ if (typeof css !== "string") throw new Error("CSS string is required for analysis");
9314
+ const native = getNativeEngineBinding();
9315
+ if (!native.analyzeClassUsage) {
9316
+ throw new Error("FATAL: Native binding 'analyzeClassUsage' is required but not available.");
9317
+ }
9318
+ if (!native.buildDependencyChain) {
9319
+ throw new Error("FATAL: Native binding 'buildDependencyChain' is required but not available.");
9320
+ }
9321
+ const allClasses = Array.from(/* @__PURE__ */ new Set([
9322
+ ...scanResult.uniqueClasses,
9323
+ ...native.extractAllClasses ? native.extractAllClasses(css) : []
9324
+ ]));
9325
+ const results = native.analyzeClassUsage(
9326
+ allClasses,
9327
+ JSON.stringify(scanResult),
9328
+ css
9329
+ );
9330
+ const map = /* @__PURE__ */ new Map();
9331
+ for (const info of results) {
9332
+ const files = JSON.parse(info.filesJson).map((f) => ({
9333
+ file: f,
9334
+ line: 1,
9335
+ column: 1
9336
+ }));
9337
+ const dependencies = native.buildDependencyChain ? native.buildDependencyChain(info.className) : [];
9338
+ map.set(info.className, {
9339
+ className: info.className,
9340
+ totalUsage: info.usageCount,
9341
+ files,
9342
+ bundleSizeBytes: info.bundleSizeBytes,
9343
+ variantChains: [],
9344
+ isDeadCode: info.isDeadCode,
9345
+ dependencies
9346
+ });
9275
9347
  }
9276
- return results;
9348
+ return map;
9277
9349
  }
9278
9350
  calculateBundleContribution(className, css) {
9279
9351
  if (!className || className.trim() === "") throw new Error("Class name cannot be empty");
9280
9352
  if (typeof css !== "string") throw new Error("CSS string is required");
9281
- try {
9282
- const native = (() => {
9283
- try {
9284
- return getNativeEngineBinding();
9285
- } catch {
9286
- return null;
9287
- }
9288
- })();
9289
- if (native?.calculateBundleContributionsNative) {
9290
- const r = native.calculateBundleContributionsNative([className], css);
9291
- return r?.[0]?.sizeBytes ?? 0;
9292
- }
9293
- } catch (err) {
9353
+ const native = getNativeEngineBinding();
9354
+ if (!native.calculateBundleContributions) {
9355
+ throw new Error("FATAL: Native binding 'calculateBundleContributions' is required but not available.");
9294
9356
  }
9295
- const normalizedClass = className.startsWith(".") ? className.slice(1) : className;
9296
- const escapedClass = normalizedClass.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
9297
- const selectorPattern = new RegExp(`\\.${escapedClass}([\\s:{]|$)`, "g");
9298
- if (!css.match(selectorPattern)) return 0;
9299
- const classSelector = `.${normalizedClass}`;
9300
- return css.split("\n").filter((l) => l.includes(classSelector)).reduce((sum, l) => {
9301
- const s = l.indexOf("{");
9302
- return s !== -1 ? sum + l.substring(s).length + 1 : sum;
9303
- }, 0);
9357
+ const r = native.calculateBundleContributions([className], css);
9358
+ return r?.[0]?.sizeBytes ?? 0;
9304
9359
  }
9305
9360
  detectDeadCode(scanResult, css) {
9306
9361
  if (!scanResult) throw new Error("Scan result is required for dead code detection");
9307
9362
  if (typeof css !== "string") throw new Error("CSS string is required for dead code detection");
9308
- try {
9309
- const native = (() => {
9310
- try {
9311
- return getNativeEngineBinding();
9312
- } catch {
9313
- return null;
9314
- }
9315
- })();
9316
- if (native?.detectDeadCodeNative) {
9317
- const r = native.detectDeadCodeNative(JSON.stringify(scanResult), css);
9318
- return r?.deadInCss ?? [];
9319
- }
9320
- } catch (err) {
9321
- }
9322
- const cssClasses = this.extractClassesFromCss(css);
9323
- const usedClasses = new Set(scanResult.uniqueClasses);
9324
- return cssClasses.filter((c) => !usedClasses.has(c));
9325
- }
9326
- countClassUsage(className, scanResult) {
9327
- const normalizedClass = className.startsWith(".") ? className.slice(1) : className;
9328
- const count = scanResult.files.reduce((sum, file) => {
9329
- return sum + file.classes.filter((fileClass) => {
9330
- const normalizedFileClass = fileClass.startsWith(".") ? fileClass.slice(1) : fileClass;
9331
- return normalizedFileClass === normalizedClass;
9332
- }).length;
9333
- }, 0);
9334
- return count;
9335
- }
9336
- getFilesUsingClass(className, scanResult) {
9337
- const files = [];
9338
- const normalizedClass = className.startsWith(".") ? className.slice(1) : className;
9339
- for (const file of scanResult.files) {
9340
- for (const fileClass of file.classes) {
9341
- const normalizedFileClass = fileClass.startsWith(".") ? fileClass.slice(1) : fileClass;
9342
- if (normalizedFileClass === normalizedClass) {
9343
- files.push({
9344
- file: file.file,
9345
- line: 1,
9346
- column: 1
9347
- });
9348
- break;
9349
- }
9350
- }
9351
- }
9352
- return files;
9353
- }
9354
- extractVariantChains(className, css) {
9355
- const normalizedClass = className.startsWith(".") ? className.slice(1) : className;
9356
- const variantChains = [];
9357
- const escapedClass = normalizedClass.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
9358
- const variantPattern = new RegExp(`([\\w-]+:${escapedClass}|${escapedClass})`, "g");
9359
- const lines = css.split("\n");
9360
- for (const line of lines) {
9361
- const matches = line.match(variantPattern);
9362
- if (matches) {
9363
- for (const match of matches) {
9364
- if (match.includes(":")) {
9365
- variantChains.push(match);
9366
- }
9367
- }
9368
- }
9369
- }
9370
- return [...new Set(variantChains)];
9371
- }
9372
- extractDependencies(className, _css) {
9373
- const normalizedClass = className.startsWith(".") ? className.slice(1) : className;
9374
- const parts = normalizedClass.split(":");
9375
- const dependencies = parts.slice(0, -1).map((_, i) => parts.slice(0, i + 1).join(":"));
9376
- return dependencies;
9377
- }
9378
- checkIsDeadCode(className, scanResult, css) {
9379
- const normalizedClass = className.startsWith(".") ? className.slice(1) : className;
9380
- const cssClasses = this.extractClassesFromCss(css);
9381
- if (!cssClasses.includes(normalizedClass)) {
9382
- return true;
9383
- }
9384
- const usageCount = this.countClassUsage(normalizedClass, scanResult);
9385
- return usageCount === 0;
9386
- }
9387
- extractClassesFromCss(css) {
9388
- const classes = [];
9389
- const classPattern = /\.([a-zA-Z0-9_-]+(?::[a-zA-Z0-9_-]+)*)/g;
9390
- for (const match of css.matchAll(classPattern)) {
9391
- const className = match[1];
9392
- if (!classes.includes(className)) {
9393
- classes.push(className);
9394
- }
9363
+ const native = getNativeEngineBinding();
9364
+ if (!native.detectDeadCode) {
9365
+ throw new Error("FATAL: Native binding 'detectDeadCode' is required but not available.");
9395
9366
  }
9396
- return classes;
9367
+ const r = native.detectDeadCode(JSON.stringify(scanResult), css);
9368
+ return r?.deadInCss ?? [];
9397
9369
  }
9398
9370
  };
9399
9371
 
9400
9372
  // packages/domain/engine/src/impactTracker.ts
9401
9373
  var ImpactTracker = class {
9402
9374
  bundleAnalyzer;
9403
- criticalPatterns = [
9404
- "fixed",
9405
- "absolute",
9406
- "sticky",
9407
- "z-50",
9408
- "z-index",
9409
- "top-0",
9410
- "right-0",
9411
- "bottom-0",
9412
- "left-0",
9413
- "w-full",
9414
- "h-full",
9415
- "min-h-screen",
9416
- "flex",
9417
- "grid",
9418
- "block",
9419
- "inline",
9420
- "hidden",
9421
- "visible",
9422
- "opacity",
9423
- "pointer-events",
9424
- "cursor"
9425
- ];
9426
9375
  constructor() {
9427
9376
  this.bundleAnalyzer = new BundleAnalyzer();
9428
9377
  }
9429
- /**
9430
- * Analisis impact sebuah class menggunakan BundleAnalyzer untuk dapat
9431
- * data akurat tentang bundle size contribution.
9432
- *
9433
- * @param className - Tailwind class yang ingin dianalisis
9434
- * @param scanResult - Hasil scan workspace
9435
- * @param css - CSS string dari build output (opsional — jika tidak ada, gunakan estimasi)
9436
- */
9437
9378
  analyzeWithBundle(className, scanResult, css = "") {
9438
9379
  const normalizedClass = className.startsWith(".") ? className.slice(1) : className;
9439
- let bundleAnalysis = null;
9440
- try {
9441
- if (scanResult && css) {
9442
- bundleAnalysis = this.bundleAnalyzer.analyzeClass(normalizedClass, scanResult, css);
9443
- }
9444
- } catch {
9445
- }
9446
- const resolvedBundleAnalysis = bundleAnalysis ?? (() => {
9447
- const usedIn = (scanResult?.files ?? []).filter(
9448
- (f) => f.classes?.includes(normalizedClass)
9449
- );
9450
- return {
9451
- className: normalizedClass,
9452
- totalUsage: usedIn.length,
9453
- files: usedIn.map((f) => ({
9454
- file: f.file,
9455
- line: 1,
9456
- column: 1
9457
- })),
9458
- bundleSizeBytes: 0,
9459
- variantChains: [],
9460
- isDeadCode: usedIn.length === 0,
9461
- dependencies: []
9462
- };
9463
- })();
9464
- return this.calculateImpact(normalizedClass, resolvedBundleAnalysis, scanResult);
9380
+ const native = getNativeEngineBinding();
9381
+ if (!native?.calculateImpactScores) {
9382
+ throw new Error("FATAL: Native binding 'calculateImpactScores' is required but not available.");
9383
+ }
9384
+ const scores = native.calculateImpactScores(
9385
+ [normalizedClass],
9386
+ JSON.stringify(scanResult),
9387
+ css,
9388
+ 0.6,
9389
+ 0.4
9390
+ );
9391
+ const score = scores[0];
9392
+ const bundleAnalysis = {
9393
+ className: normalizedClass,
9394
+ totalUsage: score?.usageCount ?? 0,
9395
+ files: [],
9396
+ bundleSizeBytes: score?.sizeBytes ?? 0,
9397
+ variantChains: [],
9398
+ isDeadCode: (score?.usageCount ?? 0) === 0,
9399
+ dependencies: []
9400
+ };
9401
+ return this.calculateImpact(normalizedClass, bundleAnalysis, scanResult, score);
9465
9402
  }
9466
- /**
9467
- * Analisis semua class dalam workspace sekaligus.
9468
- */
9469
9403
  analyzeAll(scanResult, css = "") {
9470
- const results = /* @__PURE__ */ new Map();
9404
+ const native = getNativeEngineBinding();
9405
+ if (!native?.calculateImpactScores) {
9406
+ throw new Error("FATAL: Native binding 'calculateImpactScores' is required but not available.");
9407
+ }
9471
9408
  const classes = scanResult?.uniqueClasses ?? [];
9409
+ const scores = native.calculateImpactScores(
9410
+ classes,
9411
+ JSON.stringify(scanResult),
9412
+ css,
9413
+ 0.6,
9414
+ 0.4
9415
+ );
9416
+ const scoreMap = new Map(scores.map((s) => [s.className, s]));
9417
+ const results = /* @__PURE__ */ new Map();
9472
9418
  for (const cls of classes) {
9473
- try {
9474
- results.set(cls, this.analyzeWithBundle(cls, scanResult, css));
9475
- } catch {
9476
- }
9419
+ const score = scoreMap.get(cls);
9420
+ const bundleAnalysis = {
9421
+ className: cls,
9422
+ totalUsage: score?.usageCount ?? 0,
9423
+ files: [],
9424
+ bundleSizeBytes: score?.sizeBytes ?? 0,
9425
+ variantChains: [],
9426
+ isDeadCode: (score?.usageCount ?? 0) === 0,
9427
+ dependencies: []
9428
+ };
9429
+ results.set(cls, this.calculateImpact(cls, bundleAnalysis, scanResult, score));
9477
9430
  }
9478
9431
  return results;
9479
9432
  }
9480
- calculateImpact(className, bundleAnalysis, scanResult) {
9481
- if (!className || className.trim() === "") {
9482
- return this.createEmptyReport(className);
9483
- }
9484
- if (!bundleAnalysis) {
9485
- return this.createEmptyReport(className);
9486
- }
9433
+ calculateImpact(className, bundleAnalysis, scanResult, nativeScore) {
9434
+ if (!className || className.trim() === "") return this.createEmptyReport(className);
9435
+ if (!bundleAnalysis) return this.createEmptyReport(className);
9487
9436
  const normalizedClass = className.startsWith(".") ? className.slice(1) : className;
9488
- const affectedComponents = this.findAffectedComponents(normalizedClass, scanResult);
9489
- const directUsage = affectedComponents.filter((c) => c.usageType === "direct").length;
9490
- const indirectUsage = affectedComponents.filter((c) => c.usageType !== "direct").length;
9491
- const totalComponents = affectedComponents.length;
9437
+ const totalComponents = nativeScore?.usageCount ?? bundleAnalysis.totalUsage ?? 0;
9438
+ const directUsage = totalComponents;
9439
+ const indirectUsage = 0;
9492
9440
  const bundleSizeBytes = bundleAnalysis.bundleSizeBytes || 0;
9493
- const estimatedSavings = this.calculateSavings(bundleSizeBytes, totalComponents);
9494
- const impactReport = {
9495
- className: normalizedClass,
9496
- totalComponents,
9497
- directUsage,
9498
- indirectUsage,
9499
- bundleSizeBytes,
9500
- estimatedSavings,
9501
- riskLevel: "low",
9502
- suggestions: []
9503
- };
9504
- impactReport.riskLevel = this.calculateRisk(normalizedClass, impactReport);
9505
- impactReport.suggestions = this.generateSuggestions(normalizedClass, impactReport);
9506
- return impactReport;
9507
- }
9508
- findAffectedComponents(className, scanResult) {
9509
- const components = [];
9510
- if (!className || className.trim() === "") {
9511
- return components;
9512
- }
9513
- if (!scanResult || !Array.isArray(scanResult.files)) {
9514
- return components;
9515
- }
9516
- const normalizedClass = className.startsWith(".") ? className.slice(1) : className;
9517
- const classParts = normalizedClass.split(":");
9518
- for (const file of scanResult.files) {
9519
- if (!file || !file.file) continue;
9520
- const filePath = file.file;
9521
- const classes = file.classes || [];
9522
- const variants = file.variants || [];
9523
- for (const [i, fileClass] of classes.entries()) {
9524
- if (!fileClass) continue;
9525
- const normalizedFileClass = fileClass.startsWith(".") ? fileClass.slice(1) : fileClass;
9526
- if (normalizedFileClass === normalizedClass) {
9527
- components.push({
9528
- file: filePath,
9529
- line: file.lineNumbers?.[i] || 1,
9530
- column: file.columnNumbers?.[i] || 1,
9531
- usageType: "direct"
9532
- });
9533
- } else if (normalizedFileClass.includes(normalizedClass)) {
9534
- const variant = classParts.length > 1 ? classParts[0] : void 0;
9535
- components.push({
9536
- file: filePath,
9537
- line: file.lineNumbers?.[i] || 1,
9538
- column: file.columnNumbers?.[i] || 1,
9539
- usageType: "variant",
9540
- variant
9541
- });
9542
- }
9543
- }
9544
- for (const [i, variant] of variants.entries()) {
9545
- if (!variant) continue;
9546
- if (variant.includes(normalizedClass)) {
9547
- const baseClass = variant.split(":").pop();
9548
- if (baseClass === normalizedClass) {
9549
- components.push({
9550
- file: filePath,
9551
- line: file.lineNumbers?.[i] || 1,
9552
- column: file.columnNumbers?.[i] || 1,
9553
- usageType: "variant",
9554
- variant: variant.split(":")[0]
9555
- });
9556
- }
9557
- }
9558
- }
9559
- }
9560
- return components;
9561
- }
9562
- calculateRisk(className, impact) {
9563
- if (!className || className.trim() === "") {
9564
- return "low";
9565
- }
9566
- if (!impact) {
9567
- return "low";
9568
- }
9569
- const normalizedClass = className.startsWith(".") ? className.slice(1) : className;
9570
- if (impact.totalComponents > 10) {
9571
- return "high";
9572
- }
9573
- if (this.isCriticalClass(normalizedClass)) {
9574
- return "high";
9441
+ const native = getNativeEngineBinding();
9442
+ if (native?.computeImpactMetadata) {
9443
+ const impactJson = JSON.stringify({
9444
+ className: normalizedClass,
9445
+ totalComponents,
9446
+ indirectUsage,
9447
+ bundleSizeBytes
9448
+ });
9449
+ const result = JSON.parse(native.computeImpactMetadata(normalizedClass, impactJson));
9450
+ return {
9451
+ className: normalizedClass,
9452
+ totalComponents,
9453
+ directUsage,
9454
+ indirectUsage,
9455
+ bundleSizeBytes,
9456
+ estimatedSavings: result.estimatedSavings,
9457
+ riskLevel: result.riskLevel,
9458
+ suggestions: result.suggestions
9459
+ };
9575
9460
  }
9576
- if (impact.totalComponents >= 5 && impact.totalComponents <= 10) {
9577
- return "medium";
9461
+ if (native?.calculateImpact) {
9462
+ const impactJson = JSON.stringify({
9463
+ className: normalizedClass,
9464
+ totalComponents,
9465
+ indirectUsage,
9466
+ bundleSizeBytes
9467
+ });
9468
+ const result = JSON.parse(native.calculateImpact(impactJson));
9469
+ return {
9470
+ className: normalizedClass,
9471
+ totalComponents,
9472
+ directUsage,
9473
+ indirectUsage,
9474
+ bundleSizeBytes,
9475
+ estimatedSavings: result.estimatedSavings,
9476
+ riskLevel: result.riskLevel,
9477
+ suggestions: result.suggestions
9478
+ };
9578
9479
  }
9579
- return "low";
9480
+ throw new Error("FATAL: Native binding 'computeImpactMetadata' or 'calculateImpact' is required but not available.");
9580
9481
  }
9581
- generateSuggestions(className, impact) {
9582
- const suggestions = [];
9583
- if (!className || className.trim() === "") {
9584
- return suggestions;
9585
- }
9586
- if (!impact) {
9587
- return suggestions;
9482
+ findAffectedComponents(className, scanResult) {
9483
+ if (!className || !scanResult) return [];
9484
+ const native = getNativeEngineBinding();
9485
+ if (!native?.calculateImpactScores) {
9486
+ throw new Error("FATAL: Native binding 'calculateImpactScores' is required but not available.");
9588
9487
  }
9589
9488
  const normalizedClass = className.startsWith(".") ? className.slice(1) : className;
9590
- if (impact.riskLevel === "high") {
9591
- if (impact.totalComponents > 10) {
9592
- suggestions.push(
9593
- `This class is used in ${impact.totalComponents} components. Consider creating a utility component instead.`
9594
- );
9595
- }
9596
- if (this.isCriticalClass(normalizedClass)) {
9597
- suggestions.push(
9598
- "This is a critical positioning/display class. Review all usages before removal."
9599
- );
9600
- }
9601
- suggestions.push("Manual code review recommended before removing this class.");
9602
- } else if (impact.riskLevel === "medium") {
9603
- suggestions.push(
9604
- `This class is used in ${impact.totalComponents} components. Test each component after removal.`
9605
- );
9606
- if (impact.indirectUsage > 0) {
9607
- suggestions.push("Check for indirect usages via variants before removing.");
9608
- }
9609
- } else {
9610
- if (impact.totalComponents > 0) {
9611
- suggestions.push("Low risk: class is used in fewer than 5 components.");
9612
- } else {
9613
- suggestions.push("This class appears to be unused. Consider removing it.");
9614
- }
9615
- }
9616
- if (impact.estimatedSavings > 0) {
9617
- suggestions.push(`Estimated bundle size savings: ~${impact.estimatedSavings} bytes.`);
9618
- }
9619
- if (impact.bundleSizeBytes > 100) {
9620
- suggestions.push(
9621
- "This class has significant CSS bundle contribution. Removal will improve load times."
9622
- );
9489
+ const scores = native.calculateImpactScores(
9490
+ [normalizedClass],
9491
+ JSON.stringify(scanResult),
9492
+ "",
9493
+ 1,
9494
+ 0
9495
+ );
9496
+ if (!scores[0]?.usageCount) return [];
9497
+ const components = [];
9498
+ for (const file of scanResult.files) {
9499
+ if (!file.classes?.includes(normalizedClass)) continue;
9500
+ components.push({
9501
+ file: file.file,
9502
+ line: 1,
9503
+ column: 1,
9504
+ usageType: "direct"
9505
+ });
9623
9506
  }
9624
- return suggestions;
9507
+ return components;
9625
9508
  }
9509
+ /**
9510
+ * Cek apakah sebuah class dianggap "critical" (tidak boleh dihapus).
9511
+ *
9512
+ * Native: Rust `is_critical_class()` — O(n) pattern match di CRITICAL_PATTERNS.
9513
+ * Lebih cepat dari regex JS untuk daftar panjang karena no backtracking.
9514
+ *
9515
+ * @example
9516
+ * tracker.isCriticalClass("sr-only") // true
9517
+ * tracker.isCriticalClass("hidden") // true
9518
+ * tracker.isCriticalClass("bg-red-500") // false
9519
+ */
9626
9520
  isCriticalClass(className) {
9627
- const normalized = className.startsWith(".") ? className.slice(1) : className;
9628
- return this.criticalPatterns.some(
9629
- (pattern) => normalized === pattern || normalized.startsWith(`${pattern}:`)
9630
- );
9521
+ const native = getNativeEngineBinding();
9522
+ if (native?.isCriticalClass) {
9523
+ return native.isCriticalClass(className);
9524
+ }
9525
+ return false;
9631
9526
  }
9632
- calculateSavings(bundleSize, componentCount) {
9633
- const baseSavings = bundleSize;
9634
- const componentOverhead = componentCount * 50;
9635
- return Math.max(0, baseSavings - componentOverhead);
9527
+ /**
9528
+ * Generate human-readable suggestions berdasarkan impact analysis.
9529
+ *
9530
+ * Native: `generate_suggestions()` di Rust — pattern matching di CRITICAL_PATTERNS
9531
+ * + threshold-based risk categories.
9532
+ *
9533
+ * Biasanya dipanggil setelah `calculateImpact` yang sudah set riskLevel.
9534
+ */
9535
+ generateSuggestions(className, report) {
9536
+ const native = getNativeEngineBinding();
9537
+ if (native?.generateSuggestions) {
9538
+ return native.generateSuggestions(className, JSON.stringify(report));
9539
+ }
9540
+ return [];
9636
9541
  }
9637
9542
  createEmptyReport(className) {
9638
- const normalizedClass = className?.startsWith(".") ? className.slice(1) : className || "";
9639
9543
  return {
9640
- className: normalizedClass,
9544
+ className: className?.startsWith(".") ? className.slice(1) : className || "",
9641
9545
  totalComponents: 0,
9642
9546
  directUsage: 0,
9643
9547
  indirectUsage: 0,
@@ -9659,6 +9563,15 @@ var RuleId = class {
9659
9563
  return `R${this.value}`;
9660
9564
  }
9661
9565
  };
9566
+ var SelectorId = class {
9567
+ constructor(value) {
9568
+ this.value = value;
9569
+ }
9570
+ value;
9571
+ toString() {
9572
+ return `S${this.value}`;
9573
+ }
9574
+ };
9662
9575
  var VariantChainId = class {
9663
9576
  constructor(value) {
9664
9577
  this.value = value;
@@ -9716,322 +9629,308 @@ var ConditionId = class {
9716
9629
  return `C${this.value}`;
9717
9630
  }
9718
9631
  };
9719
- var propertyNames = /* @__PURE__ */ new Map();
9720
- var valueNames = /* @__PURE__ */ new Map();
9632
+ var CascadeResolutionId = class {
9633
+ constructor(value) {
9634
+ this.value = value;
9635
+ }
9636
+ value;
9637
+ toString() {
9638
+ return `R${this.value}`;
9639
+ }
9640
+ };
9641
+ var _propertyNamesFallback = /* @__PURE__ */ new Map();
9642
+ var _valueNamesFallback = /* @__PURE__ */ new Map();
9643
+ function registerPropertyName(id, name) {
9644
+ const native = getNativeEngineBinding();
9645
+ if (native?.registerPropertyName) {
9646
+ native.registerPropertyName(id.value, name);
9647
+ return;
9648
+ }
9649
+ _propertyNamesFallback.set(id.value, name);
9650
+ }
9651
+ function registerValueName(id, name) {
9652
+ const native = getNativeEngineBinding();
9653
+ if (native?.registerValueName) {
9654
+ native.registerValueName(id.value, name);
9655
+ return;
9656
+ }
9657
+ _valueNamesFallback.set(id.value, name);
9658
+ }
9721
9659
  function propertyIdToString(id) {
9722
- return propertyNames.get(id.value) ?? `P${id.value}`;
9660
+ const native = getNativeEngineBinding();
9661
+ if (native?.propertyIdToString) {
9662
+ return native.propertyIdToString(id.value);
9663
+ }
9664
+ return _propertyNamesFallback.get(id.value) ?? `P${id.value}`;
9723
9665
  }
9724
9666
  function valueIdToString(id) {
9725
- return valueNames.get(id.value) ?? `V${id.value}`;
9726
- }
9727
- function createFingerprint(parts) {
9667
+ const native = getNativeEngineBinding();
9668
+ if (native?.valueIdToString) {
9669
+ return native.valueIdToString(id.value);
9670
+ }
9671
+ return _valueNamesFallback.get(id.value) ?? `V${id.value}`;
9672
+ }
9673
+ var CascadeStage = /* @__PURE__ */ ((CascadeStage2) => {
9674
+ CascadeStage2[CascadeStage2["Origin"] = 0] = "Origin";
9675
+ CascadeStage2[CascadeStage2["Layer"] = 1] = "Layer";
9676
+ CascadeStage2[CascadeStage2["Importance"] = 2] = "Importance";
9677
+ CascadeStage2[CascadeStage2["Specificity"] = 3] = "Specificity";
9678
+ CascadeStage2[CascadeStage2["Order"] = 4] = "Order";
9679
+ return CascadeStage2;
9680
+ })(CascadeStage || {});
9681
+ function createFingerprintFallback(parts) {
9728
9682
  const hash = parts.reduce(
9729
9683
  (acc, part) => part.split("").reduce((h, char) => (h << 5) - h + char.charCodeAt(0) & h, acc),
9730
9684
  0
9731
9685
  );
9732
9686
  return Math.abs(hash).toString(36);
9733
9687
  }
9688
+ function createFingerprint(parts) {
9689
+ const native = getNativeEngineBinding();
9690
+ if (native?.createFingerprint) {
9691
+ return native.createFingerprint(parts);
9692
+ }
9693
+ return createFingerprintFallback(parts);
9694
+ }
9734
9695
 
9735
9696
  // packages/domain/engine/src/reverseLookup.ts
9736
- var ReverseLookup = class _ReverseLookup {
9737
- parsedCache = /* @__PURE__ */ new Map();
9738
- static MAX_CACHE_SIZE = 1e3;
9739
- /** Jumlah karakter total yang disimpan di cache (approx) */
9740
- cacheSizeBytes = 0;
9741
- static MAX_CACHE_BYTES = 10 * 1024 * 1024;
9742
- // 10MB
9743
- parseCSS(css) {
9744
- const cached = this.parsedCache.get(css);
9745
- if (cached) {
9746
- return cached;
9747
- }
9748
- try {
9749
- const native = (() => {
9750
- try {
9751
- return getNativeEngineBinding();
9752
- } catch {
9753
- return null;
9754
- }
9755
- })();
9756
- if (native?.parseCssRulesNative) {
9757
- const raw = native.parseCssRulesNative(css);
9758
- const rules2 = (raw ?? []).map((r) => ({
9759
- className: r.className,
9760
- property: r.property,
9761
- value: r.value,
9762
- specificity: r.specificity,
9763
- source: { file: "", line: 0, column: 0 },
9764
- isImportant: r.isImportant,
9765
- variants: r.variants,
9766
- isOverride: false
9767
- }));
9768
- this.pruneCache();
9769
- this.parsedCache.set(css, rules2);
9770
- return rules2;
9771
- }
9772
- } catch {
9773
- }
9774
- const rules = [];
9775
- const classMap = /* @__PURE__ */ new Map();
9776
- const selectorRegex = /\.([a-zA-Z_][a-zA-Z0-9_-]*)/g;
9777
- const propertyRegex = /([a-zA-Z-]+)\s*:\s*([^;]+)/g;
9778
- const importantRegex = /!important\s*;?\s*$/;
9779
- const lines = css.split("\n");
9780
- const columnState = { offset: 0 };
9781
- for (const [i, line] of lines.entries()) {
9782
- const lineEnd = columnState.offset + line.length + 1;
9783
- for (const match of line.matchAll(selectorRegex)) {
9784
- const className = match[1];
9785
- const selectorStart = match.index;
9786
- const lineColumn = selectorStart + 1;
9787
- if (!classMap.has(className)) {
9788
- classMap.set(className, /* @__PURE__ */ new Map());
9789
- }
9790
- const braceMatch = css.indexOf("{", lineEnd - 1);
9791
- if (braceMatch !== -1) {
9792
- const closingBraceMatch = this.findClosingBrace(css, braceMatch);
9793
- const ruleContent = css.substring(braceMatch + 1, closingBraceMatch);
9794
- const variants = [];
9795
- const variantMatch = className.match(/^(.+?)(?::([a-zA-Z0-9_-]+))?$/);
9796
- if (variantMatch?.[2]) {
9797
- variants.push(variantMatch[2]);
9798
- }
9799
- const specificity = this.calculateSpecificity(className);
9800
- const source = {
9801
- file: "inline",
9802
- line: i + 1,
9803
- column: lineColumn
9804
- };
9805
- for (const propMatch of ruleContent.matchAll(propertyRegex)) {
9806
- const property = propMatch[1].trim();
9807
- const rawValue = propMatch[2].trim();
9808
- const isImportant = importantRegex.test(rawValue);
9809
- const value = isImportant ? rawValue.replace(importantRegex, "").trim() : rawValue;
9810
- const rule = {
9811
- className,
9812
- property,
9813
- value,
9814
- specificity,
9815
- source,
9816
- isImportant,
9817
- variants,
9818
- isOverride: false
9819
- };
9820
- rules.push(rule);
9821
- const classRules = classMap.get(className);
9822
- const existingProp = classRules.get(property);
9823
- if (existingProp) {
9824
- rule.isOverride = true;
9825
- }
9826
- classRules.set(property, rule);
9827
- }
9828
- }
9829
- }
9830
- columnState.offset = lineEnd;
9831
- }
9832
- this.pruneCache();
9833
- this.parsedCache.set(css, rules);
9834
- return rules;
9697
+ function getNative() {
9698
+ const native = getNativeEngineBinding();
9699
+ if (!native?.reverseLookupFromCss || !native?.reverseLookupByProperty || !native?.reverseLookupFindDependents) {
9700
+ throw new Error(
9701
+ "FATAL: Native bindings 'reverseLookupFromCss', 'reverseLookupByProperty', 'reverseLookupFindDependents' are required but not available.\nBuild the native Rust module: npm run build:rust"
9702
+ );
9835
9703
  }
9836
- findClosingBrace(css, start) {
9837
- let depth = 1;
9838
- for (let pos = start + 1; pos < css.length; pos++) {
9839
- const char = css[pos];
9840
- if (char === "{") depth++;
9841
- else if (char === "}") {
9842
- depth--;
9843
- if (depth === 0) return pos;
9844
- }
9845
- }
9846
- return css.length;
9704
+ return native;
9705
+ }
9706
+ function normaliseNativeResults(raw) {
9707
+ return raw.map((r) => ({
9708
+ property: r.property,
9709
+ value: r.value,
9710
+ usedInClasses: r.usedInClasses.map((u) => ({
9711
+ className: u.className,
9712
+ source: { file: "", line: 0, column: 0 },
9713
+ specificity: u.specificity,
9714
+ isOverride: u.isOverride,
9715
+ variants: u.variants
9716
+ }))
9717
+ }));
9718
+ }
9719
+ var ReverseLookup = class {
9720
+ fromCSS(cssProperty, cssValue, css) {
9721
+ if (!css || !cssProperty) return [];
9722
+ return normaliseNativeResults(getNative().reverseLookupFromCss(css, cssProperty, cssValue));
9847
9723
  }
9848
- calculateSpecificity(className) {
9849
- const pseudoClasses = className.match(/:[a-zA-Z-]+/g) || [];
9850
- const attributes = className.match(/\[[^\]]+\]/g) || [];
9851
- const pseudoElements = className.match(/::[a-zA-Z-]+/g) || [];
9852
- return 1 + pseudoClasses.length * 10 + attributes.length * 10 + pseudoElements.length * 100;
9724
+ findByProperty(property, css) {
9725
+ if (!css || !property) return [];
9726
+ return normaliseNativeResults(getNative().reverseLookupByProperty(css, property));
9853
9727
  }
9854
- fromCSS(cssProperty, cssValue, css) {
9855
- if (!css || !cssProperty) {
9856
- return [];
9857
- }
9858
- const rules = this.parseCSS(css);
9859
- const normalizedProperty = cssProperty.toLowerCase();
9860
- const normalizedValue = cssValue.toLowerCase().trim();
9861
- const usages = [];
9862
- for (const rule of rules) {
9863
- if (rule.property.toLowerCase() !== normalizedProperty) {
9864
- continue;
9865
- }
9866
- const ruleValueLower = rule.value.toLowerCase().trim();
9867
- if (ruleValueLower !== normalizedValue && !ruleValueLower.includes(normalizedValue)) {
9868
- continue;
9869
- }
9870
- usages.push({
9871
- className: rule.className,
9872
- source: rule.source,
9873
- specificity: rule.specificity,
9874
- isOverride: rule.isOverride || false,
9875
- variants: rule.variants
9876
- });
9877
- }
9878
- if (usages.length === 0) {
9879
- return [];
9880
- }
9881
- return [{ property: normalizedProperty, value: cssValue, usedInClasses: usages }];
9728
+ findDependents(className, css) {
9729
+ if (!css || !className) return [];
9730
+ return getNative().reverseLookupFindDependents(css, className);
9882
9731
  }
9883
9732
  fromBundle(className, css) {
9884
- if (!css || !className) {
9885
- return [];
9733
+ if (!css || !className) return [];
9734
+ const native = getNativeEngineBinding();
9735
+ if (!native?.parseCssRules) {
9736
+ throw new Error("FATAL: Native binding 'parseCssRules' is required but not available.");
9886
9737
  }
9887
- const rules = this.parseCSS(css);
9738
+ const raw = native.parseCssRules(css);
9888
9739
  const results = [];
9889
- for (const rule of rules) {
9890
- if (rule.className === className || rule.className.startsWith(`${className}:`)) {
9891
- const ruleIR = {
9892
- id: { value: results.length },
9893
- selector: { value: 0 },
9894
- variantChain: { value: 0 },
9895
- property: { value: 0 },
9896
- value: { value: 0 },
9897
- origin: 2,
9898
- importance: rule.isImportant ? 1 : 0,
9899
- layer: null,
9900
- layerOrder: 0,
9901
- specificity: rule.specificity,
9902
- condition: null,
9903
- conditionResult: 0,
9904
- insertionOrder: results.length,
9905
- fingerprint: "",
9906
- source: rule.source
9907
- };
9908
- results.push(ruleIR);
9909
- }
9740
+ for (const rule of raw ?? []) {
9741
+ if (rule.className !== className && !rule.className.startsWith(`${className}:`)) continue;
9742
+ results.push({
9743
+ id: { value: results.length },
9744
+ selector: { value: 0 },
9745
+ variantChain: { value: 0 },
9746
+ property: { value: 0 },
9747
+ value: { value: 0 },
9748
+ origin: 2,
9749
+ importance: rule.isImportant ? 1 : 0,
9750
+ layer: null,
9751
+ layerOrder: 0,
9752
+ specificity: rule.specificity,
9753
+ condition: null,
9754
+ conditionResult: 0,
9755
+ insertionOrder: results.length,
9756
+ fingerprint: "",
9757
+ source: { file: "", line: 0, column: 0 }
9758
+ });
9910
9759
  }
9911
9760
  return results;
9912
9761
  }
9913
- findDependents(className, css) {
9914
- if (!css || !className) {
9915
- return [];
9916
- }
9917
- const rules = this.parseCSS(css);
9918
- const dependents = /* @__PURE__ */ new Set();
9919
- const classParts = className.split(":");
9920
- const baseClass = classParts[0];
9921
- for (const rule of rules) {
9922
- const ruleBaseClass = rule.className.split(":")[0];
9923
- if (ruleBaseClass === baseClass && rule.className !== className) {
9924
- dependents.add(rule.className);
9925
- }
9926
- if (rule.className.includes(baseClass) && rule.className !== className) {
9927
- const isVariant = rule.className.includes(":");
9928
- if (isVariant && !rule.className.startsWith(`${className}:`)) {
9929
- dependents.add(rule.className);
9930
- }
9931
- }
9932
- }
9933
- return Array.from(dependents);
9762
+ clearCache() {
9763
+ getNativeEngineBinding()?.reverseLookupClearCache?.();
9934
9764
  }
9935
- findByProperty(property, css) {
9936
- if (!css || !property) {
9937
- return [];
9938
- }
9939
- const rules = this.parseCSS(css);
9940
- const normalizedProperty = property.toLowerCase();
9941
- const valueMap = /* @__PURE__ */ new Map();
9942
- for (const rule of rules) {
9943
- if (rule.property.toLowerCase() !== normalizedProperty) {
9944
- continue;
9945
- }
9946
- const classUsage = {
9947
- className: rule.className,
9948
- source: rule.source,
9949
- specificity: rule.specificity,
9950
- isOverride: rule.isOverride || false,
9951
- variants: rule.variants
9952
- };
9953
- let usages = valueMap.get(rule.value);
9954
- if (!usages) {
9955
- usages = [];
9956
- valueMap.set(rule.value, usages);
9957
- }
9958
- usages.push(classUsage);
9959
- }
9960
- const results = [];
9961
- for (const [value, usedInClasses] of valueMap) {
9962
- results.push({ property: normalizedProperty, value, usedInClasses });
9963
- }
9964
- return results;
9765
+ get cacheSize() {
9766
+ return getNativeEngineBinding()?.reverseLookupCacheSize?.() ?? 0;
9767
+ }
9768
+ };
9769
+
9770
+ // packages/domain/engine/src/resolver.ts
9771
+ function toNativeInput(rule) {
9772
+ return {
9773
+ id: rule.id.value,
9774
+ property: rule.property.value,
9775
+ origin: rule.origin,
9776
+ importance: rule.importance,
9777
+ layerOrder: rule.layerOrder,
9778
+ specificity: rule.specificity,
9779
+ conditionResult: rule.conditionResult,
9780
+ insertionOrder: rule.insertionOrder
9781
+ };
9782
+ }
9783
+ function callResolveCascade(rules) {
9784
+ const native = getNativeEngineBinding();
9785
+ if (!native.resolveCascade) {
9786
+ throw new Error(
9787
+ "FATAL: Native binding 'resolveCascade' is required but not available.\nThis function requires native Rust bindings.\n\nResolution steps:\n1. Build the native Rust module: npm run build:rust"
9788
+ );
9789
+ }
9790
+ const json = JSON.stringify(rules.map(toNativeInput));
9791
+ return JSON.parse(native.resolveCascade(json));
9792
+ }
9793
+ function buildResolutionsMap(nativeResult, rules, styleGraph) {
9794
+ const propertyIdMap = /* @__PURE__ */ new Map();
9795
+ for (const rule of rules) {
9796
+ if (!propertyIdMap.has(rule.property.value)) {
9797
+ propertyIdMap.set(rule.property.value, rule.property);
9798
+ }
9799
+ }
9800
+ const resolvedProperties = /* @__PURE__ */ new Map();
9801
+ for (const res of nativeResult.resolutions) {
9802
+ const propertyId = propertyIdMap.get(res.propertyId);
9803
+ if (!propertyId) continue;
9804
+ const winner = { value: res.winnerId };
9805
+ const losers = res.loserIds.map((v) => ({ value: v }));
9806
+ const existing = styleGraph.ruleConflicts.get(winner) ?? [];
9807
+ styleGraph.ruleConflicts.set(winner, [...existing, ...losers.filter((l) => !existing.some((e) => e.value === l.value))]);
9808
+ resolvedProperties.set(propertyId, {
9809
+ id: new CascadeResolutionId(res.id),
9810
+ property: propertyId,
9811
+ winner,
9812
+ losers,
9813
+ reason: { causes: res.causes, finalDecision: res.finalDecision },
9814
+ stage: res.stage
9815
+ });
9816
+ }
9817
+ return resolvedProperties;
9818
+ }
9819
+ var CascadeResolver = class {
9820
+ rules = /* @__PURE__ */ new Map();
9821
+ classRules = /* @__PURE__ */ new Map();
9822
+ styleGraph = { ruleConflicts: /* @__PURE__ */ new Map() };
9823
+ addRule(rule) {
9824
+ this.rules.set(rule.id, rule);
9825
+ }
9826
+ addRules(rules) {
9827
+ for (const rule of rules) this.addRule(rule);
9828
+ }
9829
+ registerClass(className, ruleIds) {
9830
+ this.classRules.set(className, ruleIds);
9831
+ }
9832
+ getRule(ruleId) {
9833
+ return this.rules.get(ruleId);
9834
+ }
9835
+ getClassRules(className) {
9836
+ return this.classRules.get(className);
9837
+ }
9838
+ getStyleGraph() {
9839
+ return this.styleGraph;
9965
9840
  }
9966
9841
  /**
9967
- * Kosongkan seluruh parsed cache.
9968
- * Panggil ini saat CSS berubah (watch mode) atau saat memory pressure.
9842
+ * Resolve cascade for a specific class.
9843
+ * Delegates sort + winner selection to Rust.
9969
9844
  */
9970
- clearCache() {
9971
- this.parsedCache.clear();
9972
- this.cacheSizeBytes = 0;
9845
+ resolveByClassName(className) {
9846
+ const ruleIds = this.classRules.get(className);
9847
+ if (!ruleIds || ruleIds.length === 0) return null;
9848
+ const classRules = ruleIds.map((id) => this.rules.get(id)).filter((r) => r !== void 0);
9849
+ if (classRules.length === 0) return null;
9850
+ const nativeResult = callResolveCascade(classRules);
9851
+ return { resolvedProperties: buildResolutionsMap(nativeResult, classRules, this.styleGraph) };
9973
9852
  }
9974
9853
  /**
9975
- * Hapus entri cache lama sampai di bawah threshold.
9976
- * Dipakai oleh parseCSS secara internal.
9854
+ * Resolve cascade for all rules.
9855
+ * Delegates sort + winner selection to Rust.
9977
9856
  */
9978
- pruneCache() {
9979
- while ((this.parsedCache.size >= _ReverseLookup.MAX_CACHE_SIZE || this.cacheSizeBytes >= _ReverseLookup.MAX_CACHE_BYTES) && this.parsedCache.size > 0) {
9980
- const firstKey = this.parsedCache.keys().next().value;
9981
- if (firstKey === void 0) break;
9982
- const removed = this.parsedCache.get(firstKey);
9983
- this.parsedCache.delete(firstKey);
9984
- this.cacheSizeBytes -= firstKey.length + (removed?.length ?? 0) * 100;
9985
- if (this.cacheSizeBytes < 0) this.cacheSizeBytes = 0;
9986
- }
9857
+ resolveAllProperties() {
9858
+ const allRules = Array.from(this.rules.values());
9859
+ if (allRules.length === 0) return /* @__PURE__ */ new Map();
9860
+ const nativeResult = callResolveCascade(allRules);
9861
+ return buildResolutionsMap(nativeResult, allRules, this.styleGraph);
9987
9862
  }
9988
- /** Cache size untuk observability/diagnostics */
9989
- get cacheSize() {
9990
- return this.parsedCache.size;
9863
+ /**
9864
+ * Resolve cascade for a specific set of rule IDs.
9865
+ */
9866
+ resolveForClass(classRuleIds) {
9867
+ const classRules = classRuleIds.map((id) => this.rules.get(id)).filter((r) => r !== void 0);
9868
+ if (classRules.length === 0) return /* @__PURE__ */ new Map();
9869
+ const nativeResult = callResolveCascade(classRules);
9870
+ return buildResolutionsMap(nativeResult, classRules, this.styleGraph);
9871
+ }
9872
+ /**
9873
+ * Resolve cascade for a single property bucket.
9874
+ */
9875
+ resolveProperty(property) {
9876
+ const bucketRuleIds = Array.from(this.rules.values()).filter((r) => r.property.value === property.value);
9877
+ if (bucketRuleIds.length === 0) return null;
9878
+ const nativeResult = callResolveCascade(bucketRuleIds);
9879
+ const resolved = buildResolutionsMap(nativeResult, bucketRuleIds, this.styleGraph);
9880
+ return resolved.get(property) ?? null;
9881
+ }
9882
+ getResolution(_id) {
9883
+ return void 0;
9991
9884
  }
9992
9885
  };
9993
9886
 
9994
- // packages/infrastructure/cli/src/utils/traceService.ts
9995
- init_src2();
9996
- init_src();
9997
- var createIdGenerator = () => {
9998
- const _counters = {
9999
- ruleId: 0,
10000
- selectorId: 0,
10001
- propertyId: 0,
10002
- valueId: 0,
10003
- layerId: 0,
10004
- conditionId: 0,
10005
- insertionOrder: 0
10006
- };
10007
- const generateRuleId = () => new RuleId(_counters.ruleId++);
10008
- const generateSelectorId = () => new RuleId(_counters.selectorId++);
10009
- const generatePropertyId = (propertyName) => new PropertyId(_counters.propertyId++, propertyName);
10010
- const generateValueId = (valueName) => new ValueId(_counters.valueId++, valueName);
10011
- const generateLayerId = () => new LayerId(_counters.layerId++);
10012
- const generateConditionId = () => new ConditionId(_counters.conditionId++);
10013
- const getNextInsertionOrder = () => _counters.insertionOrder++;
10014
- const reset = () => {
10015
- _counters.ruleId = 0;
10016
- _counters.selectorId = 0;
10017
- _counters.propertyId = 0;
10018
- _counters.valueId = 0;
10019
- _counters.layerId = 0;
10020
- _counters.conditionId = 0;
10021
- _counters.insertionOrder = 0;
9887
+ // packages/domain/engine/src/cssToIr.ts
9888
+ function createIdGenerator() {
9889
+ const state = {
9890
+ ruleIdCounter: 0,
9891
+ selectorIdCounter: 0,
9892
+ propertyIdCounter: 0,
9893
+ valueIdCounter: 0,
9894
+ layerIdCounter: 0,
9895
+ conditionIdCounter: 0,
9896
+ insertionOrderCounter: 0
10022
9897
  };
10023
9898
  return {
10024
- generateRuleId,
10025
- generateSelectorId,
10026
- generatePropertyId,
10027
- generateValueId,
10028
- generateLayerId,
10029
- generateConditionId,
10030
- getNextInsertionOrder,
10031
- reset
9899
+ generateRuleId: () => new RuleId(state.ruleIdCounter++),
9900
+ generateSelectorId: () => new SelectorId(state.selectorIdCounter++),
9901
+ generatePropertyId: (name) => {
9902
+ const id = new PropertyId(state.propertyIdCounter++);
9903
+ registerPropertyName(id, name);
9904
+ return id;
9905
+ },
9906
+ generateValueId: (name) => {
9907
+ const id = new ValueId(state.valueIdCounter++);
9908
+ registerValueName(id, name);
9909
+ return id;
9910
+ },
9911
+ generateLayerId: () => new LayerId(state.layerIdCounter++),
9912
+ generateConditionId: () => new ConditionId(state.conditionIdCounter++),
9913
+ getNextInsertionOrder: () => state.insertionOrderCounter++,
9914
+ reset: () => {
9915
+ state.ruleIdCounter = 0;
9916
+ state.selectorIdCounter = 0;
9917
+ state.propertyIdCounter = 0;
9918
+ state.valueIdCounter = 0;
9919
+ state.layerIdCounter = 0;
9920
+ state.conditionIdCounter = 0;
9921
+ state.insertionOrderCounter = 0;
9922
+ }
10032
9923
  };
10033
- };
10034
- var idGenerator = createIdGenerator();
9924
+ }
9925
+ var _defaultIdGen = createIdGenerator();
9926
+ var generateRuleId = () => _defaultIdGen.generateRuleId();
9927
+ var generateSelectorId = () => _defaultIdGen.generateSelectorId();
9928
+ var generatePropertyId = (name) => _defaultIdGen.generatePropertyId(name);
9929
+ var generateValueId = (name) => _defaultIdGen.generateValueId(name);
9930
+ var generateLayerId = () => _defaultIdGen.generateLayerId();
9931
+ var generateConditionId = () => _defaultIdGen.generateConditionId();
9932
+ var getNextInsertionOrder = () => _defaultIdGen.getNextInsertionOrder();
9933
+ var resetIdGenerator = () => _defaultIdGen.reset();
10035
9934
  var layerMap = /* @__PURE__ */ new Map();
10036
9935
  var layerOrderMap = /* @__PURE__ */ new Map();
10037
9936
  var LAYER_ORDER = {
@@ -10043,109 +9942,41 @@ var LAYER_ORDER = {
10043
9942
  function getOrCreateLayerId(layerName) {
10044
9943
  const existing = layerMap.get(layerName);
10045
9944
  if (existing) return existing;
10046
- const order = LAYER_ORDER[layerName] ?? 4;
10047
- const layerId = idGenerator.generateLayerId();
9945
+ const layerId = generateLayerId();
10048
9946
  layerMap.set(layerName, layerId);
10049
- layerOrderMap.set(layerName, order);
9947
+ layerOrderMap.set(layerName, LAYER_ORDER[layerName] ?? 4);
10050
9948
  return layerId;
10051
9949
  }
10052
- function calculateSpecificity(selector) {
10053
- const classCount = selector.className.split(":").length * 10;
10054
- const pseudoCount = selector.pseudoClasses.length * 10;
10055
- const mediaCount = selector.mediaQuery ? 1e3 : 0;
10056
- return classCount + pseudoCount + mediaCount;
10057
- }
10058
- function parseSelector(selectorText) {
10059
- const mediaMatch = selectorText.match(/^@media[^{]+\{(.+)$/);
10060
- const mediaQuery = mediaMatch ? mediaMatch[0] : null;
10061
- const baseClass = (mediaMatch ? mediaMatch[1].trim() : selectorText).startsWith(".") ? (mediaMatch ? mediaMatch[1].trim() : selectorText).slice(1) : mediaMatch ? mediaMatch[1].trim() : selectorText;
10062
- const escapedColon = /\\:/g;
10063
- const baseClassClean = baseClass.startsWith(".") ? baseClass.slice(1) : baseClass;
10064
- const baseClassFinal = baseClassClean.replace(escapedColon, "\u200B").split(":")[0].replace(/\u200B/g, ":");
10065
- const variantRegex = /^(hover|focus|active|visited|checked|disabled|required|optional|first|last|odd|even|before|after|placeholder|file|selection|backdrop|group|peer)/i;
10066
- const pseudoRegex = /^:([a-zA-Z-]+)$/;
10067
- const parts = baseClassFinal.split(":").slice(1);
10068
- const { variants, pseudoClasses } = parts.reduce(
10069
- (acc, part) => {
10070
- const normalized = `:${part}`;
10071
- if (variantRegex.test(part)) {
10072
- acc.variants.push(part);
10073
- } else if (pseudoRegex.test(normalized)) {
10074
- acc.pseudoClasses.push(normalized);
10075
- } else {
10076
- acc.variants.push(part);
10077
- }
10078
- return acc;
10079
- },
10080
- { variants: [], pseudoClasses: [] }
10081
- );
10082
- return {
10083
- className: baseClassFinal,
10084
- variants,
10085
- pseudoClasses,
10086
- mediaQuery
10087
- };
10088
- }
10089
- function parseDeclaration(block) {
10090
- const declarations = [];
10091
- for (const match of block.matchAll(/([a-zA-Z-]+)\s*:\s*([^;!]+)(!important)?/g)) {
10092
- const property = match[1].trim();
10093
- const value = match[2].trim();
10094
- const important = match[3] !== void 0;
10095
- declarations.push({ property, value, important });
10096
- }
10097
- return declarations;
10098
- }
10099
- function parseRules(css) {
10100
- const rules = [];
10101
- for (const match of css.matchAll(/([^{}]+)\s*\{([^{}]*)\}/g)) {
10102
- const selectorText = match[1].trim();
10103
- const declarationBlock = match[2].trim();
10104
- if (selectorText.startsWith("@")) {
10105
- continue;
10106
- }
10107
- const parsedSelector = parseSelector(selectorText);
10108
- const declarations = parseDeclaration(declarationBlock);
10109
- for (const decl of declarations) {
10110
- rules.push({
10111
- selector: parsedSelector,
10112
- property: decl.property,
10113
- value: decl.value,
10114
- important: decl.important
10115
- });
10116
- }
10117
- }
10118
- return rules;
10119
- }
10120
- function detectLayerFromSelector(className) {
10121
- const layerPrefixes = ["tw-", "tailwind-"];
10122
- for (const prefix of layerPrefixes) {
10123
- if (className.startsWith(prefix)) {
10124
- return "tailwind";
10125
- }
10126
- }
9950
+ function detectLayerFromClassName(className) {
9951
+ if (className.startsWith("tw-") || className.startsWith("tailwind-")) return "tailwind";
10127
9952
  return null;
10128
9953
  }
10129
- function parseCssToIr(css, prefix = "") {
10130
- idGenerator.reset();
9954
+ function parseCssToIr(css, options = {}) {
9955
+ resetIdGenerator();
10131
9956
  layerMap.clear();
10132
9957
  layerOrderMap.clear();
9958
+ const native = getNativeEngineBinding();
9959
+ if (!native?.parseCssRules) {
9960
+ throw new Error("FATAL: Native binding 'parseCssRules' is required but not available.");
9961
+ }
9962
+ const prefix = options.prefix ?? "";
10133
9963
  const rules = [];
10134
9964
  const classToRuleIds = /* @__PURE__ */ new Map();
10135
- const parsedRules = parseRules(css);
10136
- for (const parsedRule of parsedRules) {
10137
- const className = prefix + parsedRule.selector.className;
10138
- const specificity = calculateSpecificity(parsedRule.selector);
10139
- const layerName = detectLayerFromSelector(className);
9965
+ const parsed = native.parseCssRules(css);
9966
+ for (const r of parsed) {
9967
+ const className = prefix + r.className;
9968
+ r.variants.length > 0;
9969
+ const layerName = detectLayerFromClassName(className);
10140
9970
  const layer = layerName ? getOrCreateLayerId(layerName) : null;
10141
9971
  const layerOrder = layerName ? layerOrderMap.get(layerName) ?? 4 : 4;
10142
- const selectorId = idGenerator.generateSelectorId();
10143
- const propertyId = idGenerator.generatePropertyId(parsedRule.property);
10144
- const valueId = idGenerator.generateValueId(parsedRule.value);
10145
- const conditionId = parsedRule.selector.mediaQuery ? idGenerator.generateConditionId() : null;
10146
- const conditionResult = parsedRule.selector.mediaQuery ? 2 /* Unknown */ : 2 /* Unknown */;
10147
- const fingerprint = createFingerprint([className, parsedRule.property, parsedRule.value]);
10148
- const ruleId = idGenerator.generateRuleId();
9972
+ const selectorId = generateSelectorId();
9973
+ const propertyId = generatePropertyId(r.property);
9974
+ const valueId = generateValueId(r.value);
9975
+ const hasMedia = r.variants.some((v) => v.startsWith("@") || v === "dark" || v === "print");
9976
+ const conditionId = hasMedia ? generateConditionId() : null;
9977
+ const conditionResult = hasMedia ? 2 /* Unknown */ : 2 /* Unknown */;
9978
+ const ruleId = generateRuleId();
9979
+ const fingerprint = createFingerprint([className, r.property, r.value]);
10149
9980
  const rule = {
10150
9981
  id: ruleId,
10151
9982
  selector: selectorId,
@@ -10153,117 +9984,58 @@ function parseCssToIr(css, prefix = "") {
10153
9984
  property: propertyId,
10154
9985
  value: valueId,
10155
9986
  origin: 2 /* AuthorNormal */,
10156
- importance: parsedRule.important ? 1 /* Important */ : 0 /* Normal */,
9987
+ importance: r.isImportant ? 1 /* Important */ : 0 /* Normal */,
10157
9988
  layer,
10158
9989
  layerOrder,
10159
- specificity,
9990
+ specificity: r.specificity,
9991
+ // from native — no JS recalculation
10160
9992
  condition: conditionId,
10161
9993
  conditionResult,
10162
- insertionOrder: idGenerator.getNextInsertionOrder(),
9994
+ insertionOrder: getNextInsertionOrder(),
10163
9995
  fingerprint,
10164
- source: {
10165
- file: "",
10166
- line: 1,
10167
- column: 1
10168
- }
9996
+ source: { file: "", line: 1, column: 1 }
10169
9997
  };
10170
9998
  rules.push(rule);
10171
- const existingRuleIds = classToRuleIds.get(className) || [];
10172
- existingRuleIds.push(ruleId);
10173
- classToRuleIds.set(className, existingRuleIds);
9999
+ const existing = classToRuleIds.get(className) ?? [];
10000
+ existing.push(ruleId);
10001
+ classToRuleIds.set(className, existing);
10174
10002
  }
10175
10003
  return { rules, classToRuleIds };
10176
10004
  }
10177
- var CascadeResolver = class {
10178
- propertyBuckets = /* @__PURE__ */ new Map();
10179
- rules = /* @__PURE__ */ new Map();
10180
- classRules = /* @__PURE__ */ new Map();
10181
- addRule(rule) {
10182
- this.rules.set(rule.id, rule);
10183
- const property = rule.property;
10184
- const existingBucket = this.propertyBuckets.get(property);
10185
- if (!existingBucket) {
10186
- this.propertyBuckets.set(property, {
10187
- property,
10188
- rules: [rule.id]
10189
- });
10190
- } else {
10191
- this.propertyBuckets.set(property, {
10192
- ...existingBucket,
10193
- rules: [...existingBucket.rules, rule.id]
10194
- });
10195
- }
10196
- }
10197
- addRules(rules) {
10198
- for (const rule of rules) {
10199
- this.addRule(rule);
10200
- }
10201
- }
10202
- getRule(ruleId) {
10203
- return this.rules.get(ruleId);
10204
- }
10205
- registerClass(className, ruleIds) {
10206
- this.classRules.set(className, ruleIds);
10207
- }
10208
- getClassRules(className) {
10209
- return this.classRules.get(className);
10210
- }
10211
- resolveByClassName(className) {
10212
- const ruleIds = this.classRules.get(className);
10213
- if (!ruleIds) {
10214
- return null;
10215
- }
10216
- const classRules = [];
10217
- for (const ruleId of ruleIds) {
10218
- const rule = this.rules.get(ruleId);
10219
- if (rule) {
10220
- classRules.push(rule);
10221
- }
10222
- }
10223
- const propertyMap = /* @__PURE__ */ new Map();
10224
- for (const rule of classRules) {
10225
- const existing = propertyMap.get(rule.property) || [];
10226
- existing.push(rule);
10227
- propertyMap.set(rule.property, existing);
10228
- }
10229
- const resolved = /* @__PURE__ */ new Map();
10230
- for (const [property, rules] of propertyMap) {
10231
- if (rules.length > 0) {
10232
- const activeRules = rules.filter((r) => r.conditionResult !== 1 /* Inactive */);
10233
- if (activeRules.length > 0) {
10234
- activeRules.sort((a, b) => {
10235
- const originDiff = b.origin - a.origin;
10236
- if (originDiff !== 0) return originDiff;
10237
- const layerDiff = b.layerOrder - a.layerOrder;
10238
- if (layerDiff !== 0) return layerDiff;
10239
- const importanceDiff = b.importance - a.importance;
10240
- if (importanceDiff !== 0) return importanceDiff;
10241
- const specificityDiff = b.specificity - a.specificity;
10242
- if (specificityDiff !== 0) return specificityDiff;
10243
- return b.insertionOrder - a.insertionOrder;
10244
- });
10245
- const winner = activeRules[0];
10246
- resolved.set(property, { winner: winner.id });
10247
- }
10248
- }
10249
- }
10250
- return { resolvedProperties: resolved };
10251
- }
10252
- };
10253
- function trace(className, resolver) {
10254
- const provenance = {
10005
+
10006
+ // packages/domain/engine/src/trace.ts
10007
+ function buildProvenanceChain(className) {
10008
+ return {
10009
+ className,
10255
10010
  source: { file: "", line: 0, column: 0 },
10256
10011
  variants: /* @__PURE__ */ new Map(),
10257
10012
  rules: /* @__PURE__ */ new Map()
10258
10013
  };
10014
+ }
10015
+ function formatCause(c) {
10016
+ switch (c.type) {
10017
+ case "LowerOrigin":
10018
+ return "lower origin";
10019
+ case "LowerLayer":
10020
+ return "lower layer";
10021
+ case "LowerImportance":
10022
+ return "lower importance";
10023
+ case "LowerSpecificity":
10024
+ return `specificity ${c.delta}`;
10025
+ case "EarlierOrder":
10026
+ return `earlier order ${c.delta}`;
10027
+ case "InactiveCondition":
10028
+ return "inactive condition";
10029
+ }
10030
+ }
10031
+ function trace(className, resolver) {
10032
+ const provenance = buildProvenanceChain(className);
10259
10033
  const classRuleIds = resolver.getClassRules(className);
10260
10034
  const allRules = [];
10261
10035
  if (classRuleIds) {
10262
10036
  for (const ruleId of classRuleIds) {
10263
10037
  const rule = resolver.getRule(ruleId);
10264
- if (rule) {
10265
- allRules.push(rule);
10266
- }
10038
+ if (rule) allRules.push(rule);
10267
10039
  }
10268
10040
  }
10269
10041
  for (const rules of provenance.rules.values()) {
@@ -10272,57 +10044,49 @@ function trace(className, resolver) {
10272
10044
  const rulesByProperty = /* @__PURE__ */ new Map();
10273
10045
  for (const rule of allRules) {
10274
10046
  const propKey = rule.property.toString();
10275
- if (!rulesByProperty.has(propKey)) {
10276
- rulesByProperty.set(propKey, []);
10277
- }
10278
- rulesByProperty.get(propKey).push(rule);
10047
+ const bucket = rulesByProperty.get(propKey) ?? [];
10048
+ bucket.push(rule);
10049
+ rulesByProperty.set(propKey, bucket);
10279
10050
  }
10051
+ const resolved = resolver.resolveByClassName(className);
10280
10052
  const ruleTraces = [];
10281
10053
  const conflictTraces = [];
10282
- for (const [property, rules] of rulesByProperty) {
10283
- if (rules.length === 0) continue;
10284
- const activeRules = rules.filter((r) => r.conditionResult !== 1 /* Inactive */);
10285
- if (activeRules.length === 0) continue;
10286
- activeRules.sort((a, b) => {
10287
- const originDiff = b.origin - a.origin;
10288
- if (originDiff !== 0) return originDiff;
10289
- const layerDiff = b.layerOrder - a.layerOrder;
10290
- if (layerDiff !== 0) return layerDiff;
10291
- const importanceDiff = b.importance - a.importance;
10292
- if (importanceDiff !== 0) return importanceDiff;
10293
- const specificityDiff = b.specificity - a.specificity;
10294
- if (specificityDiff !== 0) return specificityDiff;
10295
- return b.insertionOrder - a.insertionOrder;
10296
- });
10297
- const winnerRule = activeRules[0];
10298
- const losers = activeRules.slice(1);
10299
- ruleTraces.push({
10300
- property,
10301
- value: winnerRule.value.toString(),
10302
- applied: true,
10303
- reason: null,
10304
- source: winnerRule.source,
10305
- specificity: winnerRule.specificity
10306
- });
10307
- for (const loserRule of losers) {
10308
- ruleTraces.push({
10309
- property,
10310
- value: loserRule.value.toString(),
10311
- applied: false,
10312
- reason: "lower specificity",
10313
- source: loserRule.source,
10314
- specificity: loserRule.specificity
10315
- });
10316
- conflictTraces.push({
10317
- property,
10318
- winner: winnerRule.value.toString(),
10319
- loser: loserRule.value.toString(),
10320
- stage: "Specificity",
10321
- causes: ["lower specificity"]
10322
- });
10054
+ if (resolved) {
10055
+ for (const [propId, resolution] of resolved.resolvedProperties) {
10056
+ const property = propId.toString();
10057
+ const rules = rulesByProperty.get(property) ?? [];
10058
+ const winnerRule = rules.find((r) => r.id.value === resolution.winner.value);
10059
+ if (winnerRule) {
10060
+ ruleTraces.push({
10061
+ property,
10062
+ value: winnerRule.value.toString(),
10063
+ applied: true,
10064
+ reason: null,
10065
+ source: winnerRule.source,
10066
+ specificity: winnerRule.specificity
10067
+ });
10068
+ }
10069
+ for (const loserId of resolution.losers) {
10070
+ const loserRule = rules.find((r) => r.id.value === loserId.value);
10071
+ if (!loserRule) continue;
10072
+ ruleTraces.push({
10073
+ property,
10074
+ value: loserRule.value.toString(),
10075
+ applied: false,
10076
+ reason: resolution.reason.finalDecision,
10077
+ source: loserRule.source,
10078
+ specificity: loserRule.specificity
10079
+ });
10080
+ conflictTraces.push({
10081
+ property,
10082
+ winner: winnerRule?.value.toString() ?? "",
10083
+ loser: loserRule.value.toString(),
10084
+ stage: CascadeStage[resolution.stage],
10085
+ causes: resolution.reason.causes.map(formatCause)
10086
+ });
10087
+ }
10323
10088
  }
10324
10089
  }
10325
- const resolved = resolver.resolveByClassName(className);
10326
10090
  const finalStyle = [];
10327
10091
  if (resolved) {
10328
10092
  for (const [propId, resolution] of resolved.resolvedProperties) {
@@ -10342,6 +10106,30 @@ function trace(className, resolver) {
10342
10106
  finalStyle
10343
10107
  };
10344
10108
  }
10109
+
10110
+ // packages/infrastructure/cli/src/utils/traceService.ts
10111
+ init_src2();
10112
+ init_src();
10113
+ function safeToString(value) {
10114
+ if (value === null || value === void 0) return "";
10115
+ if (typeof value === "string") return value;
10116
+ if (typeof value === "number") return String(value);
10117
+ if (typeof value === "object") {
10118
+ const obj = value;
10119
+ if (typeof obj.name === "string" && obj.name.length > 0) return obj.name;
10120
+ if (obj.value !== void 0) return String(obj.value);
10121
+ const toStr = obj.toString;
10122
+ if (typeof toStr === "function") {
10123
+ try {
10124
+ const result = toStr.call(value);
10125
+ if (typeof result === "string" && result !== "[object Object]") return result;
10126
+ } catch {
10127
+ }
10128
+ }
10129
+ return "?";
10130
+ }
10131
+ return String(value);
10132
+ }
10345
10133
  async function traceClass(className, options) {
10346
10134
  const root = options?.root ?? process.cwd();
10347
10135
  const scanResult = await scanWorkspace(root, {
@@ -10375,53 +10163,16 @@ async function traceClass(className, options) {
10375
10163
  const { rules, classToRuleIds } = parseCssToIr(cssResult.code);
10376
10164
  const ruleIds = classToRuleIds.get(className);
10377
10165
  if (!ruleIds || ruleIds.length === 0) {
10378
- throw TwError.fromCompile("TRACE_NO_RULES_FOUND", `No rules found for class "${className}" after parsing CSS.`);
10166
+ throw TwError.fromCompile(
10167
+ "TRACE_NO_RULES_FOUND",
10168
+ `No rules found for class "${className}" after parsing CSS.`
10169
+ );
10379
10170
  }
10380
10171
  const resolver = new CascadeResolver();
10381
10172
  resolver.addRules(rules);
10382
10173
  resolver.registerClass(className, ruleIds);
10383
- const engineTraceResult = trace(className, resolver);
10384
- return convertTraceResult(engineTraceResult);
10385
- }
10386
- function safeToString(value) {
10387
- if (value === null || value === void 0) return "";
10388
- if (typeof value === "string") return String(value);
10389
- if (typeof value === "number") return String(value);
10390
- if (typeof value === "boolean") return String(value);
10391
- if (typeof value === "object" && value !== null) {
10392
- const obj = value;
10393
- const name = obj.name;
10394
- if (typeof name === "string" && name.length > 0) {
10395
- return name;
10396
- }
10397
- const objValue = obj.value;
10398
- if (objValue !== void 0) {
10399
- return String(objValue);
10400
- }
10401
- const objValueOf = obj.valueOf;
10402
- if (typeof objValueOf === "function") {
10403
- try {
10404
- const vo = objValueOf.call(value);
10405
- if (vo !== value) return String(vo);
10406
- } catch {
10407
- }
10408
- }
10409
- const toStr = obj.toString;
10410
- if (typeof toStr === "function") {
10411
- try {
10412
- const result = toStr.call(value);
10413
- if (typeof result === "string" && result !== "[object Object]") {
10414
- return result;
10415
- }
10416
- } catch {
10417
- }
10418
- }
10419
- return "?";
10420
- }
10421
- return String(value);
10422
- }
10423
- function convertTraceResult(engineResult) {
10424
- return {
10174
+ const engineResult = trace(className, resolver);
10175
+ const result = {
10425
10176
  class: safeToString(engineResult.class),
10426
10177
  definedAt: {
10427
10178
  file: safeToString(engineResult.definedAt.file),
@@ -10433,7 +10184,8 @@ function convertTraceResult(engineResult) {
10433
10184
  value: safeToString(v.value),
10434
10185
  source: {
10435
10186
  file: safeToString(v.source?.file ?? ""),
10436
- line: Number(v.source?.line ?? 0)
10187
+ line: Number(v.source?.line ?? 0),
10188
+ column: Number(v.source?.column ?? 0)
10437
10189
  }
10438
10190
  })),
10439
10191
  rules: engineResult.rules.map((r) => ({
@@ -10443,7 +10195,8 @@ function convertTraceResult(engineResult) {
10443
10195
  reason: r.reason ? safeToString(r.reason) : null,
10444
10196
  source: {
10445
10197
  file: safeToString(r.source?.file ?? ""),
10446
- line: Number(r.source?.line ?? 0)
10198
+ line: Number(r.source?.line ?? 0),
10199
+ column: Number(r.source?.column ?? 0)
10447
10200
  },
10448
10201
  specificity: Number(r.specificity ?? 0)
10449
10202
  })),
@@ -10452,17 +10205,18 @@ function convertTraceResult(engineResult) {
10452
10205
  winner: safeToString(c.winner),
10453
10206
  loser: safeToString(c.loser),
10454
10207
  stage: safeToString(c.stage),
10455
- causes: c.causes?.map(safeToString) ?? []
10208
+ causes: (c.causes ?? []).map(safeToString)
10456
10209
  })),
10457
10210
  finalStyle: engineResult.finalStyle.map((f) => ({
10458
10211
  property: safeToString(f.property),
10459
10212
  value: safeToString(f.value)
10460
10213
  }))
10461
10214
  };
10215
+ return result;
10462
10216
  }
10463
10217
  init_src2();
10464
10218
  function toRelativePath(root, value) {
10465
- const relative = path3.relative(root, value);
10219
+ const relative = path6__default.relative(root, value);
10466
10220
  return relative.length > 0 ? relative : ".";
10467
10221
  }
10468
10222
  function uniqueSorted(values) {
@@ -10531,7 +10285,7 @@ function tryCompileClasses(classes) {
10531
10285
  }
10532
10286
  }
10533
10287
  function traceSingleFile(filePath, root) {
10534
- const source = fs8.readFileSync(filePath, "utf8");
10288
+ const source = fs11__default.readFileSync(filePath, "utf8");
10535
10289
  const classes = uniqueSorted(scanSource(source));
10536
10290
  const imports = extractImports(source);
10537
10291
  const compiled = tryCompileClasses(classes);
@@ -10562,7 +10316,7 @@ function traceDirectory(targetDir, root) {
10562
10316
  const imports = [];
10563
10317
  const importKeys = /* @__PURE__ */ new Set();
10564
10318
  const files = scanResult.files.filter((entry) => isScannableFile(entry.file, DEFAULT_EXTENSIONS)).map((entry) => {
10565
- const source = fs8.readFileSync(entry.file, "utf8");
10319
+ const source = fs11__default.readFileSync(entry.file, "utf8");
10566
10320
  const fileImports = extractImports(source);
10567
10321
  for (const fileImport of fileImports) {
10568
10322
  const key = `${fileImport.kind}:${fileImport.source}`;
@@ -10593,12 +10347,12 @@ function traceDirectory(targetDir, root) {
10593
10347
  };
10594
10348
  }
10595
10349
  async function traceTarget(target, options = {}) {
10596
- const root = path3.resolve(options.root ?? process.cwd());
10597
- const resolvedTarget = path3.resolve(root, target);
10598
- if (!fs8.existsSync(resolvedTarget)) {
10350
+ const root = path6__default.resolve(options.root ?? process.cwd());
10351
+ const resolvedTarget = path6__default.resolve(root, target);
10352
+ if (!fs11__default.existsSync(resolvedTarget)) {
10599
10353
  throw new Error(`Trace target not found: ${resolvedTarget}`);
10600
10354
  }
10601
- const stat = fs8.statSync(resolvedTarget);
10355
+ const stat = fs11__default.statSync(resolvedTarget);
10602
10356
  if (stat.isDirectory()) {
10603
10357
  return traceDirectory(resolvedTarget, root);
10604
10358
  }
@@ -10767,7 +10521,7 @@ async function runGenerateTypesCli(rawArgs) {
10767
10521
  const logger = createCliLogger({ output });
10768
10522
  const cwd2 = process.cwd();
10769
10523
  const outFile = rawArgs.find((a) => a.startsWith("--out="))?.slice(6) ?? "src/types/tailwind-styled.d.ts";
10770
- const outPath = path3.resolve(cwd2, outFile);
10524
+ const outPath = path6__default.resolve(cwd2, outFile);
10771
10525
  output.writeText("");
10772
10526
  output.writeText(import_picocolors6.default.bold(import_picocolors6.default.cyan(" \u25C6 tw generate-types")));
10773
10527
  output.writeText(import_picocolors6.default.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
@@ -10781,12 +10535,11 @@ async function runGenerateTypesCli(rawArgs) {
10781
10535
  throw new Error("Native binding 'generateSubComponentTypes' tidak tersedia \u2014 pastikan build:rust sudah dijalankan");
10782
10536
  }
10783
10537
  result = binding.generateSubComponentTypes(cwd2, outPath);
10538
+ if (!result) throw new Error("generateSubComponentTypes mengembalikan null");
10784
10539
  spinner.stop(`Scanned ${result.filesScanned} files`);
10785
10540
  } catch (err) {
10786
10541
  spinner.error("Scan gagal");
10787
- logger.warn(err instanceof Error ? err.message : String(err));
10788
- output.writeText(import_picocolors6.default.dim(" \u2192 fallback ke JS scanner..."));
10789
- result = await fallbackJsScan(cwd2);
10542
+ throw err instanceof Error ? err : new Error(String(err));
10790
10543
  }
10791
10544
  if (!result) {
10792
10545
  logger.warn("Tidak ada hasil scan");
@@ -10804,12 +10557,12 @@ async function runGenerateTypesCli(rawArgs) {
10804
10557
  }
10805
10558
  output.writeText("");
10806
10559
  output.writeText(import_picocolors6.default.bold(" [2/2]") + import_picocolors6.default.cyan(" generate .d.ts"));
10807
- const outDir = path3.dirname(outPath);
10808
- if (!fs8.existsSync(outDir)) {
10809
- fs8.mkdirSync(outDir, { recursive: true });
10560
+ const outDir = path6__default.dirname(outPath);
10561
+ if (!fs11__default.existsSync(outDir)) {
10562
+ fs11__default.mkdirSync(outDir, { recursive: true });
10810
10563
  }
10811
- fs8.writeFileSync(outPath, result.dtsContent, "utf-8");
10812
- logger.ok(path3.relative(cwd2, outPath));
10564
+ fs11__default.writeFileSync(outPath, result.dtsContent, "utf-8");
10565
+ logger.ok(path6__default.relative(cwd2, outPath));
10813
10566
  output.writeText("");
10814
10567
  output.writeText(import_picocolors6.default.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
10815
10568
  output.writeText(import_picocolors6.default.bold(import_picocolors6.default.green(" \u2713 types generated")));
@@ -10820,11 +10573,11 @@ async function runGenerateTypesCli(rawArgs) {
10820
10573
  }
10821
10574
  async function loadNativeBinding2(cwd2) {
10822
10575
  const candidates = [
10823
- path3.join(cwd2, "native", "tailwind-styled-native.node"),
10824
- path3.join(cwd2, "node_modules", "tailwind-styled-v4", "native", "tailwind-styled-native.node")
10576
+ path6__default.join(cwd2, "native", "tailwind-styled-native.node"),
10577
+ path6__default.join(cwd2, "node_modules", "tailwind-styled-v4", "native", "tailwind-styled-native.node")
10825
10578
  ];
10826
10579
  for (const candidate of candidates) {
10827
- if (fs8.existsSync(candidate)) {
10580
+ if (fs11__default.existsSync(candidate)) {
10828
10581
  try {
10829
10582
  return __require(candidate);
10830
10583
  } catch {
@@ -10833,42 +10586,6 @@ async function loadNativeBinding2(cwd2) {
10833
10586
  }
10834
10587
  return null;
10835
10588
  }
10836
- async function fallbackJsScan(cwd2, outPath) {
10837
- const { execSync } = await import('child_process');
10838
- const registerRe = /registerSubComponent\s*\(\s*\{[^}]*name\s*:\s*["']([a-zA-Z][a-zA-Z0-9_-]*)["']/g;
10839
- const withSubRe = /\.withSub\s*<\s*([^>]+)\s*>/g;
10840
- const literalRe = /["']([a-zA-Z][a-zA-Z0-9_-]*)["']/g;
10841
- const names = /* @__PURE__ */ new Set();
10842
- let filesScanned = 0;
10843
- try {
10844
- const files = execSync(
10845
- `find . -name "*.tsx" -o -name "*.ts" -o -name "*.jsx" -o -name "*.js" | grep -v node_modules | grep -v .next | grep -v dist`,
10846
- { cwd: cwd2, encoding: "utf-8" }
10847
- ).trim().split("\n").filter(Boolean);
10848
- for (const file of files) {
10849
- try {
10850
- const source = fs8.readFileSync(path3.join(cwd2, file), "utf-8");
10851
- filesScanned++;
10852
- for (const m of source.matchAll(registerRe)) names.add(m[1]);
10853
- for (const m of source.matchAll(withSubRe)) {
10854
- for (const lit of m[1].matchAll(literalRe)) names.add(lit[1]);
10855
- }
10856
- } catch {
10857
- }
10858
- }
10859
- } catch {
10860
- }
10861
- const sorted = [...names].sort();
10862
- const union = sorted.map((n) => `"${n}"`).join(" | ") || "never";
10863
- const dtsContent = `// AUTO-GENERATED by tailwind-styled-v4 (JS fallback)
10864
- // DO NOT EDIT \u2014 Run: npx tw generate-types to regenerate
10865
-
10866
- declare module "tailwind-styled-v4" {
10867
- export type DetectedSubComponents = ${union}
10868
- }
10869
- `;
10870
- return { names: sorted, dtsContent, filesScanned };
10871
- }
10872
10589
 
10873
10590
  // packages/infrastructure/cli/src/commands/why.ts
10874
10591
  init_errors();
@@ -10919,7 +10636,7 @@ async function whyClass(className, options) {
10919
10636
  for (const file of scanResult.files) {
10920
10637
  const source = (() => {
10921
10638
  try {
10922
- return fs8.readFileSync(file.file, "utf8");
10639
+ return fs11__default.readFileSync(file.file, "utf8");
10923
10640
  } catch {
10924
10641
  return "";
10925
10642
  }
@@ -10933,7 +10650,7 @@ async function whyClass(className, options) {
10933
10650
  className
10934
10651
  ]);
10935
10652
  usedIn.push({
10936
- file: path3.relative(root, file.file) || path3.basename(file.file),
10653
+ file: path6__default.relative(root, file.file) || path6__default.basename(file.file),
10937
10654
  line: location.line,
10938
10655
  column: location.column,
10939
10656
  usage: normalizeScannedClass(fileClass)
@@ -11099,7 +10816,7 @@ function buildMainProgram(context) {
11099
10816
  new Map(miscCommands.map((command) => [command.name, command]));
11100
10817
  const scriptByName = new Map(scriptCommands.map((command) => [command.name, command]));
11101
10818
  const program2 = new Command("tw");
11102
- program2.name("tw").description("tailwind-styled-v4 CLI").option("--json", "Output strict JSON envelope").option("--debug", "Include stack traces for errors").option("--verbose", "Verbose runtime logs");
10819
+ program2.name("tw").description("tailwind-styled-v4 CLI").version("5.0.4", "--version", "Output the current version").option("--json", "Output strict JSON envelope").option("--debug", "Include stack traces for errors").option("--verbose", "Verbose runtime logs");
11103
10820
  program2.command("setup").description("Auto-setup project").option("--yes", "Skip prompts").option("--next", "Force Next.js").option("--vite", "Force Vite").option("--rspack", "Force Rspack").option("--react", "Force React").option("--dry-run", "Preview changes").option("--skip-install", "Skip package install").action(async (...actionArgs) => {
11104
10821
  const options = actionCommand(actionArgs).opts();
11105
10822
  const args = [];
@@ -11388,12 +11105,20 @@ function buildMainProgram(context) {
11388
11105
 
11389
11106
  // packages/infrastructure/cli/src/index.ts
11390
11107
  init_runtime();
11108
+ init_args();
11109
+ init_args();
11110
+ init_output();
11391
11111
  async function main2() {
11392
11112
  await runCliMain({
11393
11113
  importMetaUrl: import.meta.url,
11394
11114
  buildProgram: buildMainProgram
11395
11115
  });
11396
11116
  }
11397
- main2();
11117
+ var __filename2 = fileURLToPath(import.meta.url);
11118
+ if (process.argv[1] === __filename2) {
11119
+ main2();
11120
+ }
11121
+
11122
+ export { createCliOutput, ensureFlag, parseCliInput as parseCliArgs, runScanCli };
11398
11123
  //# sourceMappingURL=cli.mjs.map
11399
11124
  //# sourceMappingURL=cli.mjs.map