boss-css 0.0.1 → 0.0.3

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 (268) hide show
  1. package/README.md +1 -0
  2. package/dist/_virtual/rolldown_runtime.cjs +43 -0
  3. package/dist/_virtual/rolldown_runtime.mjs +20 -0
  4. package/dist/api/browser.cjs +54 -0
  5. package/dist/api/browser.mjs +48 -0
  6. package/dist/api/config.cjs +94 -0
  7. package/dist/api/config.mjs +91 -0
  8. package/dist/api/css.cjs +304 -0
  9. package/dist/api/css.mjs +303 -0
  10. package/dist/api/dictionary.cjs +218 -0
  11. package/dist/api/dictionary.mjs +215 -0
  12. package/dist/api/file/dts.cjs +21 -0
  13. package/dist/api/file/dts.mjs +21 -0
  14. package/dist/api/file/file.cjs +123 -0
  15. package/dist/api/file/file.mjs +120 -0
  16. package/dist/api/file/js.cjs +118 -0
  17. package/dist/api/file/js.mjs +116 -0
  18. package/dist/api/names.cjs +52 -0
  19. package/dist/api/names.mjs +46 -0
  20. package/dist/api/noopCss.cjs +37 -0
  21. package/dist/api/noopCss.mjs +36 -0
  22. package/dist/api/propTree.cjs +54 -0
  23. package/dist/api/propTree.mjs +48 -0
  24. package/dist/api/server.cjs +112 -0
  25. package/dist/api/server.mjs +106 -0
  26. package/dist/cli/build.cjs +1 -0
  27. package/dist/cli/build.mjs +3 -0
  28. package/dist/cli/index.cjs +30 -0
  29. package/dist/cli/index.mjs +29 -0
  30. package/dist/cli/tasks/build.cjs +24 -0
  31. package/dist/cli/tasks/build.mjs +23 -0
  32. package/dist/cli/tasks/choose.cjs +47 -0
  33. package/dist/cli/tasks/choose.mjs +46 -0
  34. package/dist/cli/tasks/compile.cjs +68 -0
  35. package/dist/cli/tasks/compile.mjs +67 -0
  36. package/dist/cli/tasks/dev.cjs +51 -0
  37. package/dist/cli/tasks/dev.mjs +48 -0
  38. package/dist/cli/tasks/init.cjs +1835 -0
  39. package/dist/cli/tasks/init.mjs +1831 -0
  40. package/dist/cli/tasks/watch.cjs +38 -0
  41. package/dist/cli/tasks/watch.mjs +37 -0
  42. package/dist/cli/templates/init.cjs +82 -0
  43. package/dist/cli/templates/init.mjs +78 -0
  44. package/dist/cli/types.cjs +13 -0
  45. package/dist/cli/types.mjs +13 -0
  46. package/dist/cli/utils.cjs +43 -0
  47. package/dist/cli/utils.mjs +41 -0
  48. package/dist/compile/classname-strategy.cjs +79 -0
  49. package/dist/compile/classname-strategy.mjs +77 -0
  50. package/dist/compile/classname.cjs +366 -0
  51. package/dist/compile/classname.mjs +360 -0
  52. package/dist/compile/index.cjs +238 -0
  53. package/dist/compile/index.mjs +235 -0
  54. package/dist/compile/jsx.cjs +803 -0
  55. package/dist/compile/jsx.mjs +800 -0
  56. package/dist/compile/prepared.cjs +88 -0
  57. package/dist/compile/prepared.mjs +87 -0
  58. package/dist/compile/runtime.cjs +33 -0
  59. package/dist/compile/runtime.mjs +32 -0
  60. package/dist/compile/transform.cjs +371 -0
  61. package/dist/compile/transform.mjs +369 -0
  62. package/dist/cx/index.cjs +93 -0
  63. package/dist/cx/index.mjs +85 -0
  64. package/dist/detect-fw/index.cjs +384 -0
  65. package/dist/detect-fw/index.mjs +379 -0
  66. package/dist/dev/client.cjs +39 -0
  67. package/dist/dev/client.mjs +38 -0
  68. package/dist/dev/plugin/browser.cjs +11 -0
  69. package/dist/dev/plugin/browser.mjs +9 -0
  70. package/dist/dev/plugin/server.cjs +86 -0
  71. package/dist/dev/plugin/server.mjs +78 -0
  72. package/dist/dev/port.cjs +46 -0
  73. package/dist/dev/port.mjs +43 -0
  74. package/dist/dev/runtime.cjs +28 -0
  75. package/dist/dev/runtime.mjs +29 -0
  76. package/dist/dev/server.cjs +808 -0
  77. package/dist/dev/server.mjs +805 -0
  78. package/dist/dev/shared.cjs +6 -0
  79. package/dist/dev/shared.mjs +5 -0
  80. package/dist/eslint-plugin/index.cjs +66 -0
  81. package/dist/eslint-plugin/index.mjs +66 -0
  82. package/dist/eslint-plugin/rules/classnames-only.cjs +68 -0
  83. package/dist/eslint-plugin/rules/classnames-only.mjs +68 -0
  84. package/dist/eslint-plugin/rules/format-classnames.cjs +137 -0
  85. package/dist/eslint-plugin/rules/format-classnames.mjs +136 -0
  86. package/dist/eslint-plugin/rules/no-unknown-classes.cjs +119 -0
  87. package/dist/eslint-plugin/rules/no-unknown-classes.mjs +119 -0
  88. package/dist/eslint-plugin/rules/prefer-classnames.cjs +69 -0
  89. package/dist/eslint-plugin/rules/prefer-classnames.mjs +69 -0
  90. package/dist/eslint-plugin/rules/prefer-token-values.cjs +197 -0
  91. package/dist/eslint-plugin/rules/prefer-token-values.mjs +197 -0
  92. package/dist/eslint-plugin/rules/props-only.cjs +115 -0
  93. package/dist/eslint-plugin/rules/props-only.mjs +115 -0
  94. package/dist/eslint-plugin/rules/redundant-cx.cjs +66 -0
  95. package/dist/eslint-plugin/rules/redundant-cx.mjs +66 -0
  96. package/dist/eslint-plugin/rules/require-prop-functions.cjs +130 -0
  97. package/dist/eslint-plugin/rules/require-prop-functions.mjs +130 -0
  98. package/dist/eslint-plugin/utils/api.cjs +30 -0
  99. package/dist/eslint-plugin/utils/api.mjs +29 -0
  100. package/dist/eslint-plugin/utils/ast.cjs +119 -0
  101. package/dist/eslint-plugin/utils/ast.mjs +112 -0
  102. package/dist/eslint-plugin/utils/boss-classes.cjs +185 -0
  103. package/dist/eslint-plugin/utils/boss-classes.mjs +175 -0
  104. package/dist/eslint-plugin/utils/defaults.cjs +99 -0
  105. package/dist/eslint-plugin/utils/defaults.mjs +93 -0
  106. package/dist/eslint-plugin/utils/format.cjs +20 -0
  107. package/dist/eslint-plugin/utils/format.mjs +19 -0
  108. package/dist/eslint-plugin/utils/order.cjs +76 -0
  109. package/dist/eslint-plugin/utils/order.mjs +76 -0
  110. package/dist/eslint-plugin/utils/property-order.cjs +449 -0
  111. package/dist/eslint-plugin/utils/property-order.mjs +448 -0
  112. package/dist/eslint-plugin/utils/static.cjs +36 -0
  113. package/dist/eslint-plugin/utils/static.mjs +35 -0
  114. package/dist/fontsource/directory.cjs +39588 -0
  115. package/dist/fontsource/directory.mjs +39587 -0
  116. package/dist/fontsource/server.cjs +291 -0
  117. package/dist/fontsource/server.mjs +282 -0
  118. package/dist/index.cjs +10 -0
  119. package/dist/index.mjs +6 -0
  120. package/dist/log/browser.cjs +28 -0
  121. package/dist/log/browser.mjs +28 -0
  122. package/dist/log/server.cjs +32 -0
  123. package/dist/log/server.mjs +30 -0
  124. package/dist/merge/index.cjs +590 -0
  125. package/dist/merge/index.mjs +586 -0
  126. package/dist/native/browser.cjs +78 -0
  127. package/dist/native/browser.mjs +77 -0
  128. package/dist/native/server.cjs +180 -0
  129. package/dist/native/server.mjs +176 -0
  130. package/dist/native/styleTypes.cjs +168 -0
  131. package/dist/native/styleTypes.mjs +164 -0
  132. package/dist/parser/classname/server.cjs +239 -0
  133. package/dist/parser/classname/server.mjs +232 -0
  134. package/dist/parser/jsx/browser.cjs +66 -0
  135. package/dist/parser/jsx/browser.mjs +63 -0
  136. package/dist/parser/jsx/extractCode.cjs +99 -0
  137. package/dist/parser/jsx/extractCode.mjs +98 -0
  138. package/dist/parser/jsx/extractPrepared.cjs +123 -0
  139. package/dist/parser/jsx/extractPrepared.mjs +122 -0
  140. package/dist/parser/jsx/extractProps.cjs +234 -0
  141. package/dist/parser/jsx/extractProps.mjs +232 -0
  142. package/dist/parser/jsx/isDOMProp.cjs +17 -0
  143. package/dist/parser/jsx/isDOMProp.mjs +15 -0
  144. package/dist/parser/jsx/native.cjs +110 -0
  145. package/dist/parser/jsx/native.mjs +108 -0
  146. package/dist/parser/jsx/runtime.cjs +4 -0
  147. package/dist/parser/jsx/runtime.mjs +3 -0
  148. package/dist/parser/jsx/server.cjs +278 -0
  149. package/dist/parser/jsx/server.mjs +268 -0
  150. package/dist/postcss/index.cjs +16 -0
  151. package/dist/postcss/index.mjs +16 -0
  152. package/dist/prop/at/runtime-only.cjs +90 -0
  153. package/dist/prop/at/runtime-only.mjs +88 -0
  154. package/dist/prop/at/server.cjs +282 -0
  155. package/dist/prop/at/server.mjs +268 -0
  156. package/dist/prop/at/shared.cjs +153 -0
  157. package/dist/prop/at/shared.mjs +144 -0
  158. package/dist/prop/bosswind/browser.cjs +18 -0
  159. package/dist/prop/bosswind/browser.mjs +16 -0
  160. package/dist/prop/bosswind/runtime-only.cjs +18 -0
  161. package/dist/prop/bosswind/runtime-only.mjs +16 -0
  162. package/dist/prop/bosswind/server.cjs +81 -0
  163. package/dist/prop/bosswind/server.mjs +72 -0
  164. package/dist/prop/bosswind/shared.cjs +861 -0
  165. package/dist/prop/bosswind/shared.mjs +855 -0
  166. package/dist/prop/bosswind/tailwind-theme.cjs +703 -0
  167. package/dist/prop/bosswind/tailwind-theme.mjs +702 -0
  168. package/dist/prop/child/runtime-only.cjs +18 -0
  169. package/dist/prop/child/runtime-only.mjs +15 -0
  170. package/dist/prop/child/server.cjs +81 -0
  171. package/dist/prop/child/server.mjs +72 -0
  172. package/dist/prop/css/getDtsTemplate.cjs +65 -0
  173. package/dist/prop/css/getDtsTemplate.mjs +63 -0
  174. package/dist/prop/css/runtime-only.cjs +14 -0
  175. package/dist/prop/css/runtime-only.mjs +13 -0
  176. package/dist/prop/css/server.cjs +99 -0
  177. package/dist/prop/css/server.mjs +90 -0
  178. package/dist/prop/pseudo/runtime-only.cjs +23 -0
  179. package/dist/prop/pseudo/runtime-only.mjs +21 -0
  180. package/dist/prop/pseudo/server.cjs +91 -0
  181. package/dist/prop/pseudo/server.mjs +82 -0
  182. package/dist/prop/pseudo/shared.cjs +61 -0
  183. package/dist/prop/pseudo/shared.mjs +60 -0
  184. package/dist/reset/server.cjs +34 -0
  185. package/dist/reset/server.mjs +26 -0
  186. package/dist/runtime/index.cjs +119 -0
  187. package/dist/runtime/index.mjs +118 -0
  188. package/dist/runtime/preact.cjs +4 -0
  189. package/dist/runtime/preact.mjs +3 -0
  190. package/dist/runtime/qwik.cjs +21 -0
  191. package/dist/runtime/qwik.mjs +18 -0
  192. package/dist/runtime/react.cjs +4 -0
  193. package/dist/runtime/react.mjs +3 -0
  194. package/dist/runtime/solid.cjs +15 -0
  195. package/dist/runtime/solid.mjs +14 -0
  196. package/dist/runtime/stencil.cjs +25 -0
  197. package/dist/runtime/stencil.mjs +21 -0
  198. package/dist/runtime/style.cjs +14 -0
  199. package/dist/runtime/style.mjs +13 -0
  200. package/dist/shared/boundaries.cjs +288 -0
  201. package/dist/shared/boundaries.mjs +285 -0
  202. package/dist/shared/customCss.cjs +212 -0
  203. package/dist/shared/customCss.mjs +211 -0
  204. package/dist/shared/debug.cjs +76 -0
  205. package/dist/shared/debug.mjs +74 -0
  206. package/dist/shared/file.cjs +21 -0
  207. package/dist/shared/file.mjs +19 -0
  208. package/dist/shared/framework.cjs +10 -0
  209. package/dist/shared/framework.mjs +9 -0
  210. package/dist/shared/json.cjs +58 -0
  211. package/dist/shared/json.mjs +57 -0
  212. package/dist/shared/types.cjs +11 -0
  213. package/dist/shared/types.mjs +10 -0
  214. package/dist/strategy/classic/runtime-only.cjs +190 -0
  215. package/dist/strategy/classic/runtime-only.mjs +186 -0
  216. package/dist/strategy/classname-first/runtime-only.cjs +138 -0
  217. package/dist/strategy/classname-first/runtime-only.mjs +134 -0
  218. package/dist/strategy/classname-first/server.cjs +139 -0
  219. package/dist/strategy/classname-first/server.mjs +133 -0
  220. package/dist/strategy/classname-only/server.cjs +43 -0
  221. package/dist/strategy/classname-only/server.mjs +35 -0
  222. package/dist/strategy/inline-first/browser.cjs +61 -0
  223. package/dist/strategy/inline-first/browser.mjs +58 -0
  224. package/dist/strategy/inline-first/runtime-only.cjs +159 -0
  225. package/dist/strategy/inline-first/runtime-only.mjs +155 -0
  226. package/dist/strategy/inline-first/server.cjs +92 -0
  227. package/dist/strategy/inline-first/server.mjs +83 -0
  228. package/dist/strategy/runtime/runtime-only.cjs +24 -0
  229. package/dist/strategy/runtime/runtime-only.mjs +22 -0
  230. package/dist/strategy/runtime/server.cjs +72 -0
  231. package/dist/strategy/runtime/server.mjs +63 -0
  232. package/dist/strategy/runtime-only/css.cjs +183 -0
  233. package/dist/strategy/runtime-only/css.mjs +181 -0
  234. package/dist/tasks/build.cjs +88 -0
  235. package/dist/tasks/build.mjs +84 -0
  236. package/dist/tasks/compile.cjs +12 -0
  237. package/dist/tasks/compile.mjs +12 -0
  238. package/dist/tasks/postcss.cjs +116 -0
  239. package/dist/tasks/postcss.mjs +113 -0
  240. package/dist/tasks/session.cjs +46 -0
  241. package/dist/tasks/session.mjs +42 -0
  242. package/dist/tasks/watch.cjs +102 -0
  243. package/dist/tasks/watch.mjs +99 -0
  244. package/dist/transform/cache.cjs +24 -0
  245. package/dist/transform/cache.mjs +21 -0
  246. package/dist/transform/processFile.cjs +26 -0
  247. package/dist/transform/processFile.mjs +24 -0
  248. package/dist/use/token/browser.cjs +65 -0
  249. package/dist/use/token/browser.mjs +61 -0
  250. package/dist/use/token/runtime-only.cjs +245 -0
  251. package/dist/use/token/runtime-only.mjs +239 -0
  252. package/dist/use/token/server.cjs +325 -0
  253. package/dist/use/token/server.mjs +313 -0
  254. package/dist/use/token/vars.cjs +47 -0
  255. package/dist/use/token/vars.mjs +46 -0
  256. package/package.json +300 -4
  257. package/src/api/config.d.ts +1 -0
  258. package/src/fontsource/types.d.ts +50 -0
  259. package/src/packages/document-create-element/createElement.browser.js +3 -0
  260. package/src/packages/document-create-element/createElement.js +7 -0
  261. package/src/packages/document-create-element/package.json +17 -0
  262. package/src/packages/is-css-prop/browser.js +13 -0
  263. package/src/packages/is-css-prop/index.js +13 -0
  264. package/src/packages/is-css-prop/package-lock.json +52 -0
  265. package/src/packages/is-css-prop/package.json +17 -0
  266. package/src/prop/css/csstype.json +4387 -0
  267. package/src/prop/css/package.json +3 -0
  268. package/src/reset/reset.css +259 -0
@@ -0,0 +1,1831 @@
1
+ import { createApi } from "../../api/server.mjs";
2
+ import { parseJson } from "../../shared/json.mjs";
3
+ import { cancelIf } from "../utils.mjs";
4
+ import { detectFramework } from "../../detect-fw/index.mjs";
5
+ import { server_exports, settings } from "../../parser/jsx/server.mjs";
6
+ import { server_exports as server_exports$1 } from "../../parser/classname/server.mjs";
7
+ import { server_exports as server_exports$2 } from "../../prop/pseudo/server.mjs";
8
+ import { server_exports as server_exports$3 } from "../../prop/at/server.mjs";
9
+ import { server_exports as server_exports$4 } from "../../prop/child/server.mjs";
10
+ import { server_exports as server_exports$5 } from "../../prop/css/server.mjs";
11
+ import { server_exports as server_exports$6 } from "../../prop/bosswind/server.mjs";
12
+ import { server_exports as server_exports$7, settings as settings$1 } from "../../strategy/inline-first/server.mjs";
13
+ import { server_exports as server_exports$8, settings as settings$2 } from "../../strategy/classname-first/server.mjs";
14
+ import { server_exports as server_exports$9 } from "../../strategy/runtime/server.mjs";
15
+ import { server_exports as server_exports$10 } from "../../strategy/classname-only/server.mjs";
16
+ import { server_exports as server_exports$11 } from "../../reset/server.mjs";
17
+ import { server_exports as server_exports$12 } from "../../fontsource/server.mjs";
18
+ import { server_exports as server_exports$13 } from "../../use/token/server.mjs";
19
+ import { server_exports as server_exports$14 } from "../../dev/plugin/server.mjs";
20
+ import { configTemplate, jsconfigTemplate, packageTemplate, postcssTemplate } from "../templates/init.mjs";
21
+ import { RuntimeType } from "../../shared/types.mjs";
22
+ import { PackageManagerType } from "../types.mjs";
23
+ import fs from "node:fs/promises";
24
+ import path from "node:path";
25
+ import { confirm, log, multiselect, select, text } from "@clack/prompts";
26
+ import pluvo, { DEFAULT_COMMENT_STYLES } from "pluvo";
27
+
28
+ //#region src/cli/tasks/init.ts
29
+ const EXTENSIONS = "html,js,jsx,mjs,cjs,ts,tsx,mdx,md";
30
+ const INIT_COMMENT_STYLES = {
31
+ line: DEFAULT_COMMENT_STYLES.line.filter((marker) => !("value" in marker) || marker.value !== "'"),
32
+ block: DEFAULT_COMMENT_STYLES.block
33
+ };
34
+ const AVAILABLE_PLUGINS = [
35
+ {
36
+ id: "fontsource",
37
+ label: "Fontsource fonts",
38
+ importName: "fontsource",
39
+ importPath: "boss-css/fontsource/server",
40
+ defaultEnabled: true
41
+ },
42
+ {
43
+ id: "reset",
44
+ label: "Reset CSS",
45
+ importName: "reset",
46
+ importPath: "boss-css/reset/server",
47
+ defaultEnabled: true
48
+ },
49
+ {
50
+ id: "bosswind",
51
+ label: "Bosswind (Tailwind-style aliases)",
52
+ importName: "bosswind",
53
+ importPath: "boss-css/prop/bosswind/server",
54
+ defaultEnabled: false
55
+ },
56
+ {
57
+ id: "token",
58
+ label: "Tokens",
59
+ importName: "token",
60
+ importPath: "boss-css/use/token/server",
61
+ defaultEnabled: true
62
+ },
63
+ {
64
+ id: "at",
65
+ label: "Media queries (@at)",
66
+ importName: "at",
67
+ importPath: "boss-css/prop/at/server",
68
+ defaultEnabled: true
69
+ },
70
+ {
71
+ id: "child",
72
+ label: "Child selectors",
73
+ importName: "child",
74
+ importPath: "boss-css/prop/child/server",
75
+ defaultEnabled: true
76
+ },
77
+ {
78
+ id: "css",
79
+ label: "CSS props",
80
+ importName: "css",
81
+ importPath: "boss-css/prop/css/server",
82
+ defaultEnabled: true
83
+ },
84
+ {
85
+ id: "pseudo",
86
+ label: "Pseudo selectors",
87
+ importName: "pseudo",
88
+ importPath: "boss-css/prop/pseudo/server",
89
+ defaultEnabled: true
90
+ },
91
+ {
92
+ id: "classname",
93
+ label: "Classname parser",
94
+ importName: "classname",
95
+ importPath: "boss-css/parser/classname/server",
96
+ defaultEnabled: true
97
+ },
98
+ {
99
+ id: "jsx",
100
+ label: "JSX parser",
101
+ importName: "jsx",
102
+ importPath: "boss-css/parser/jsx/server",
103
+ defaultEnabled: true
104
+ },
105
+ {
106
+ id: "devtools",
107
+ label: "Devtools (experimental)",
108
+ importName: "devtools",
109
+ importPath: "boss-css/dev/plugin/server",
110
+ defaultEnabled: false
111
+ }
112
+ ];
113
+ const AVAILABLE_STRATEGIES = [
114
+ {
115
+ id: "inline-first",
116
+ label: "Inline-first strategy",
117
+ importName: "inlineFirst",
118
+ importPath: "boss-css/strategy/inline-first/server",
119
+ defaultEnabled: true
120
+ },
121
+ {
122
+ id: "classname-first",
123
+ label: "Classname-first strategy",
124
+ importName: "classnameFirst",
125
+ importPath: "boss-css/strategy/classname-first/server",
126
+ defaultEnabled: false
127
+ },
128
+ {
129
+ id: "classname-only",
130
+ label: "Classname-only strategy (no runtime)",
131
+ importName: "classnameOnly",
132
+ importPath: "boss-css/strategy/classname-only/server",
133
+ defaultEnabled: false
134
+ },
135
+ {
136
+ id: "runtime-only",
137
+ label: "Runtime-only strategy (client CSS only)",
138
+ importName: "runtime",
139
+ importPath: "boss-css/strategy/runtime/server",
140
+ defaultEnabled: false
141
+ },
142
+ {
143
+ id: "runtime-hybrid",
144
+ label: "Runtime hybrid strategy (server + client)",
145
+ importName: "runtime",
146
+ importPath: "boss-css/strategy/runtime/server",
147
+ defaultEnabled: false
148
+ }
149
+ ];
150
+ const PLUGIN_MODULES = {
151
+ bosswind: server_exports$6,
152
+ reset: server_exports$11,
153
+ fontsource: server_exports$12,
154
+ token: server_exports$13,
155
+ at: server_exports$3,
156
+ child: server_exports$4,
157
+ css: server_exports$5,
158
+ pseudo: server_exports$2,
159
+ classname: server_exports$1,
160
+ jsx: server_exports,
161
+ "inline-first": server_exports$7,
162
+ "classname-first": server_exports$8,
163
+ "classname-only": server_exports$10,
164
+ "runtime-only": server_exports$9,
165
+ "runtime-hybrid": server_exports$9,
166
+ devtools: server_exports$14
167
+ };
168
+ const DEFAULT_PLUGIN_IDS = AVAILABLE_PLUGINS.filter((plugin) => plugin.defaultEnabled).map((plugin) => plugin.id);
169
+ const DEFAULT_STRATEGY_ID = AVAILABLE_STRATEGIES.find((strategy) => strategy.defaultEnabled)?.id ?? "inline-first";
170
+ const STRATEGY_IDS = new Set(AVAILABLE_STRATEGIES.map((strategy) => strategy.id));
171
+ const STRATEGY_ALIASES = new Map([
172
+ ["runtime", "runtime-only"],
173
+ ["hybrid", "runtime-hybrid"],
174
+ ["runtime-hybrid", "runtime-hybrid"],
175
+ ["runtime-only", "runtime-only"]
176
+ ]);
177
+ const POSTCSS_CONFIG_FILES = [
178
+ "postcss.config.js",
179
+ "postcss.config.cjs",
180
+ "postcss.config.mjs",
181
+ ".postcssrc",
182
+ ".postcssrc.json",
183
+ ".postcssrc.js",
184
+ ".postcssrc.cjs",
185
+ ".postcssrc.mjs"
186
+ ];
187
+ const ESLINT_CONFIG_FILES = [
188
+ {
189
+ file: "eslint.config.js",
190
+ type: "flat"
191
+ },
192
+ {
193
+ file: "eslint.config.cjs",
194
+ type: "flat"
195
+ },
196
+ {
197
+ file: "eslint.config.mjs",
198
+ type: "flat"
199
+ },
200
+ {
201
+ file: ".eslintrc",
202
+ type: "eslintrc"
203
+ },
204
+ {
205
+ file: ".eslintrc.json",
206
+ type: "eslintrc"
207
+ },
208
+ {
209
+ file: ".eslintrc.js",
210
+ type: "eslintrc-js"
211
+ },
212
+ {
213
+ file: ".eslintrc.cjs",
214
+ type: "eslintrc-js"
215
+ },
216
+ {
217
+ file: ".eslintrc.mjs",
218
+ type: "eslintrc-js"
219
+ },
220
+ {
221
+ file: ".eslintrc.yaml",
222
+ type: "yaml"
223
+ },
224
+ {
225
+ file: ".eslintrc.yml",
226
+ type: "yaml"
227
+ }
228
+ ];
229
+ const init = async (config) => {
230
+ return [{ prompt: async () => {
231
+ log.info("boss init will scaffold configuration for this project.");
232
+ const cwd = process.cwd();
233
+ const { data: packageJson, indent, newline } = await readPackageJson(cwd);
234
+ if (!packageJson) {
235
+ log.error("No package.json found. Run boss init from a project root.");
236
+ return false;
237
+ }
238
+ const flags = parseFlags(config.argv);
239
+ const isNext = hasDependency(packageJson, "next");
240
+ const framework = await detectFramework({
241
+ cwd,
242
+ packageJson
243
+ });
244
+ const isStencil = framework.id === "stencil";
245
+ const cssAutoLoad = !isStencil;
246
+ const detectedSrcRoot = await detectSrcRoot(cwd);
247
+ const normalizedSrcRoot = normalizeRelativePath(await resolveTextValue({
248
+ label: "Where is your source root?",
249
+ value: flags.srcRoot,
250
+ fallback: detectedSrcRoot,
251
+ yes: flags.yes
252
+ }), cwd);
253
+ const defaultConfigFolder = ".bo$$";
254
+ const defaultConfigDir = normalizeRelativePath(path.join(normalizedSrcRoot, defaultConfigFolder), cwd);
255
+ const normalizedConfigDir = normalizeRelativePath(await resolveTextValue({
256
+ label: `Where should the ${defaultConfigFolder} folder live?`,
257
+ value: flags.configDir,
258
+ fallback: defaultConfigDir,
259
+ yes: flags.yes
260
+ }), cwd);
261
+ const configFolder = formatConfigFolder(normalizedConfigDir);
262
+ const selectedStrategyId = await resolveStrategySelection({
263
+ value: flags.strategy,
264
+ plugins: flags.plugins,
265
+ yes: flags.yes
266
+ });
267
+ const selectedPluginIds = await resolvePluginSelection({
268
+ value: flags.plugins,
269
+ yes: flags.yes,
270
+ frameworkId: framework.id,
271
+ selectedStrategyId
272
+ });
273
+ const postcssDetection = await detectPostcss(cwd, packageJson);
274
+ const postcssMode = isStencil ? "skip" : await resolvePostcssMode({
275
+ detection: postcssDetection,
276
+ yes: flags.yes,
277
+ value: flags.postcss
278
+ });
279
+ const globalsEnabled = selectedStrategyId === "classname-only" ? false : await resolveGlobalsEnabled({
280
+ value: flags.globals,
281
+ yes: flags.yes
282
+ });
283
+ const eslintDetection = await detectEslint(cwd, packageJson);
284
+ const shouldConfigureEslint = eslintDetection.hasDependency || eslintDetection.hasConfig || flags.eslintPlugin !== void 0;
285
+ const useEslintPlugin = await resolveEslintPlugin({
286
+ value: flags.eslintPlugin,
287
+ yes: flags.yes,
288
+ enabled: shouldConfigureEslint
289
+ });
290
+ const outputDir = path.resolve(cwd, normalizedConfigDir);
291
+ if (!await confirmOverwriteIfExists(outputDir, flags.yes)) return false;
292
+ const contentGlobs = buildContentGlobs({
293
+ srcRoot: normalizedSrcRoot,
294
+ isNext
295
+ });
296
+ const pluginState = buildPluginState({
297
+ selectedPluginIds,
298
+ selectedStrategyId
299
+ });
300
+ const packageUpdate = updatePackageJson(packageJson, {
301
+ configDir: normalizedConfigDir,
302
+ srcRoot: normalizedSrcRoot,
303
+ addBossCss: true,
304
+ bossCssVersion: await resolveBossCssVersion(),
305
+ addPostcss: postcssMode === "auto" && !postcssDetection.hasDependency,
306
+ includePostcssPlugin: postcssMode === "auto" && (postcssDetection.hasPackageConfig || !postcssDetection.hasConfigFile),
307
+ addEslintPlugin: useEslintPlugin === true
308
+ });
309
+ let packageData = packageUpdate.data;
310
+ let eslintUpdated = false;
311
+ let packageJsonChanged = packageUpdate.changed;
312
+ if (shouldConfigureEslint && (globalsEnabled || useEslintPlugin !== void 0)) {
313
+ const eslintUpdate = await configureEslint({
314
+ detection: eslintDetection,
315
+ globalsEnabled,
316
+ useEslintPlugin: useEslintPlugin === true,
317
+ allowReactGlobalsRule: shouldAllowReactGlobalsRule(packageData),
318
+ packageJson: packageData
319
+ });
320
+ eslintUpdated = eslintUpdate.updated;
321
+ if (eslintUpdate.packageJsonChanged) {
322
+ packageData = eslintUpdate.packageJson;
323
+ packageJsonChanged = true;
324
+ }
325
+ }
326
+ if (packageJsonChanged) await writePackageJson(cwd, packageData, indent, newline);
327
+ await writeInitFiles({
328
+ outputDir,
329
+ configFolder,
330
+ contentGlobs,
331
+ pluginState,
332
+ selectedStrategyId,
333
+ isNext,
334
+ postcssMode,
335
+ postcssDetection,
336
+ includeAutoprefixer: hasDependency(packageJson, "autoprefixer"),
337
+ packageJson: packageData,
338
+ dirDependencies: true,
339
+ usePostcssOptions: false,
340
+ srcRoot: normalizedSrcRoot,
341
+ configDir: normalizedConfigDir,
342
+ globalsEnabled,
343
+ cssAutoLoad
344
+ });
345
+ await generateRuntime({
346
+ outputDir,
347
+ configFolder,
348
+ pluginState,
349
+ contentGlobs,
350
+ globalsEnabled,
351
+ cssAutoLoad,
352
+ selectedStrategyId
353
+ });
354
+ if (isStencil) await ensureStencilSetup({
355
+ cwd,
356
+ srcRoot: normalizedSrcRoot,
357
+ configDir: normalizedConfigDir,
358
+ packageJson: packageData
359
+ });
360
+ const packageManager = await detectPackageManager(cwd, config.runtimeType);
361
+ const installCommand = packageUpdate.bossCssAdded ? formatInstallCommand(packageManager) : null;
362
+ logInitSummary({
363
+ configDir: normalizedConfigDir,
364
+ isNext,
365
+ postcssMode,
366
+ postcssDetection,
367
+ configFolder,
368
+ srcRoot: normalizedSrcRoot,
369
+ globalsEnabled,
370
+ eslintUpdated,
371
+ useEslintPlugin: useEslintPlugin === true,
372
+ frameworkId: framework.id,
373
+ selectedStrategyId,
374
+ cssAutoLoad,
375
+ installCommand
376
+ });
377
+ return true;
378
+ } }];
379
+ };
380
+ const resolveTextValue = async ({ label, value, fallback, yes }) => {
381
+ if (value) return value;
382
+ if (yes) return fallback;
383
+ const response = await text({
384
+ message: label,
385
+ initialValue: fallback,
386
+ validate: (input) => input?.trim() ? void 0 : "Value is required"
387
+ });
388
+ cancelIf(response);
389
+ return response;
390
+ };
391
+ const resolveStrategySelection = async ({ value, plugins, yes }) => {
392
+ const normalizedValue = value ? normalizeStrategyId(value) : void 0;
393
+ if (normalizedValue) {
394
+ if (STRATEGY_IDS.has(normalizedValue)) return normalizedValue;
395
+ log.warn(`Unknown strategy "${value}". Falling back to the default strategy.`);
396
+ }
397
+ const pluginStrategies = (plugins ?? []).map(normalizeStrategyId).filter((id) => STRATEGY_IDS.has(id));
398
+ if (pluginStrategies.length > 1) {
399
+ log.warn(`Multiple strategies provided (${pluginStrategies.join(", ")}). Using "${pluginStrategies[0]}".`);
400
+ return pluginStrategies[0];
401
+ }
402
+ if (pluginStrategies.length === 1) return pluginStrategies[0];
403
+ if (yes) return DEFAULT_STRATEGY_ID;
404
+ const selection = await select({
405
+ message: "Select output strategy.",
406
+ options: AVAILABLE_STRATEGIES.map((strategy) => ({
407
+ value: strategy.id,
408
+ label: strategy.label
409
+ })),
410
+ initialValue: DEFAULT_STRATEGY_ID
411
+ });
412
+ cancelIf(selection);
413
+ return selection;
414
+ };
415
+ const resolvePluginSelection = async ({ value, yes, frameworkId, selectedStrategyId }) => {
416
+ const isClassnameOnly = selectedStrategyId === "classname-only";
417
+ const disallowedPlugins = isClassnameOnly ? new Set(["jsx", "devtools"]) : null;
418
+ const defaults = isClassnameOnly ? DEFAULT_PLUGIN_IDS.filter((id) => !(disallowedPlugins && disallowedPlugins.has(id))) : DEFAULT_PLUGIN_IDS;
419
+ if (value?.length) {
420
+ const normalized = value.map(normalizePluginId);
421
+ const filtered = normalized.filter((id) => !STRATEGY_IDS.has(id));
422
+ if (filtered.length !== normalized.length) log.info("Strategies are selected separately. Use --strategy to choose the output strategy.");
423
+ const selected = filtered.filter((id) => AVAILABLE_PLUGINS.some((plugin) => plugin.id === id));
424
+ const allowed = disallowedPlugins ? selected.filter((id) => !disallowedPlugins.has(id)) : selected;
425
+ if (selected.length && disallowedPlugins && allowed.length !== selected.length) log.warn("Classname-only strategy ignores jsx and devtools plugins.");
426
+ if (!allowed.length) {
427
+ log.warn("No matching plugins found for the provided flags. Falling back to defaults.");
428
+ return defaults;
429
+ }
430
+ return allowed;
431
+ }
432
+ if (yes) return defaults;
433
+ const selection = await multiselect({
434
+ message: "Select Boss CSS plugins and features.",
435
+ options: (disallowedPlugins ? AVAILABLE_PLUGINS.filter((plugin) => !disallowedPlugins.has(plugin.id)) : AVAILABLE_PLUGINS).map((plugin) => ({
436
+ value: plugin.id,
437
+ label: plugin.label
438
+ })),
439
+ initialValues: defaults
440
+ });
441
+ cancelIf(selection);
442
+ return selection;
443
+ };
444
+ const buildPluginState = ({ selectedPluginIds, selectedStrategyId }) => {
445
+ const disallowedPlugins = selectedStrategyId === "classname-only" ? new Set(["jsx", "devtools"]) : null;
446
+ const pluginState = AVAILABLE_PLUGINS.map((plugin) => ({
447
+ ...plugin,
448
+ enabled: selectedPluginIds.includes(plugin.id) && !(disallowedPlugins && disallowedPlugins.has(plugin.id))
449
+ }));
450
+ const strategyState = {
451
+ ...AVAILABLE_STRATEGIES.find((strategy) => strategy.id === selectedStrategyId) ?? AVAILABLE_STRATEGIES[0],
452
+ enabled: true
453
+ };
454
+ const devtoolsIndex = pluginState.findIndex((plugin) => plugin.id === "devtools");
455
+ if (devtoolsIndex === -1) return [...pluginState, strategyState];
456
+ return [
457
+ ...pluginState.slice(0, devtoolsIndex),
458
+ strategyState,
459
+ ...pluginState.slice(devtoolsIndex)
460
+ ];
461
+ };
462
+ const normalizePluginId = (id) => {
463
+ return id.trim().replace(/_/g, "-").replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
464
+ };
465
+ const normalizeStrategyId = (id) => {
466
+ const normalized = normalizePluginId(id);
467
+ return STRATEGY_ALIASES.get(normalized) ?? normalized;
468
+ };
469
+ const resolvePostcssMode = async ({ detection, yes, value }) => {
470
+ if (value) return value;
471
+ if (detection.hasDependency || detection.hasConfigFile || detection.hasPackageConfig) return "auto";
472
+ if (yes) return "auto";
473
+ const shouldInstall = await confirm({
474
+ message: "PostCSS was not detected. Install and configure it automatically?",
475
+ initialValue: true
476
+ });
477
+ cancelIf(shouldInstall);
478
+ return shouldInstall ? "auto" : "manual";
479
+ };
480
+ const resolveGlobalsEnabled = async ({ value, yes }) => {
481
+ if (value !== void 0) return value;
482
+ if (yes) return true;
483
+ const enableGlobals = await confirm({
484
+ message: "Enable global $$ (no import needed)?",
485
+ initialValue: true
486
+ });
487
+ cancelIf(enableGlobals);
488
+ return enableGlobals;
489
+ };
490
+ const resolveEslintPlugin = async ({ value, yes, enabled }) => {
491
+ if (!enabled && value === void 0) return void 0;
492
+ if (value !== void 0) return value;
493
+ if (yes) return true;
494
+ const usePlugin = await confirm({
495
+ message: "Use the Boss ESLint plugin for Boss-specific linting?",
496
+ initialValue: true
497
+ });
498
+ cancelIf(usePlugin);
499
+ return usePlugin;
500
+ };
501
+ const parseFlags = (argv) => {
502
+ return {
503
+ yes: argv.y === true || argv.yes === true,
504
+ srcRoot: getStringArg(argv, ["srcRoot", "src-root"]),
505
+ configDir: getStringArg(argv, [
506
+ "configDir",
507
+ "config-dir",
508
+ "bossDir",
509
+ "boss-dir"
510
+ ]),
511
+ plugins: parseListArg(getArg(argv, ["plugins", "plugin"])),
512
+ strategy: getStringArg(argv, ["strategy"]),
513
+ postcss: normalizePostcssMode(getArg(argv, ["postcss"])) ?? void 0,
514
+ globals: normalizeBooleanArg(getArg(argv, ["globals"])),
515
+ eslintPlugin: normalizeBooleanArg(getArg(argv, ["eslintPlugin", "eslint-plugin"]))
516
+ };
517
+ };
518
+ const getArg = (argv, keys) => {
519
+ for (const key of keys) if (Object.prototype.hasOwnProperty.call(argv, key)) return argv[key];
520
+ };
521
+ const getStringArg = (argv, keys) => {
522
+ const value = getArg(argv, keys);
523
+ if (typeof value === "string" && value.trim()) return value.trim();
524
+ };
525
+ const normalizeBooleanArg = (value) => {
526
+ if (typeof value === "boolean") return value;
527
+ if (typeof value === "string") {
528
+ const normalized = value.trim().toLowerCase();
529
+ if (normalized === "true" || normalized === "1" || normalized === "yes") return true;
530
+ if (normalized === "false" || normalized === "0" || normalized === "no") return false;
531
+ }
532
+ };
533
+ const parseListArg = (value) => {
534
+ if (!value) return void 0;
535
+ const parsed = (Array.isArray(value) ? value : [value]).flatMap((item) => typeof item === "string" ? item.split(",") : []).map((item) => item.trim()).filter(Boolean);
536
+ return parsed.length ? parsed : void 0;
537
+ };
538
+ const normalizePostcssMode = (value) => {
539
+ if (value === true) return "auto";
540
+ if (value === false) return "skip";
541
+ if (typeof value === "string") {
542
+ const normalized = value.toLowerCase().trim();
543
+ if (normalized === "auto" || normalized === "manual" || normalized === "skip") return normalized;
544
+ }
545
+ };
546
+ const detectSrcRoot = async (cwd) => {
547
+ for (const candidate of [
548
+ "src",
549
+ "app",
550
+ "pages",
551
+ "lib",
552
+ "components"
553
+ ]) if (await exists(path.join(cwd, candidate))) return candidate;
554
+ return "src";
555
+ };
556
+ const normalizeRelativePath = (input, cwd) => {
557
+ const trimmed = input.trim();
558
+ if (!trimmed) return ".";
559
+ return (path.isAbsolute(trimmed) ? path.relative(cwd, trimmed) : trimmed).replace(/\\/g, "/").replace(/\/+$/g, "") || ".";
560
+ };
561
+ const normalizeImportPath = (input) => {
562
+ const normalized = input.replace(/\\/g, "/");
563
+ if (!normalized || normalized === ".") return ".";
564
+ if (normalized.startsWith("./") || normalized.startsWith("../")) return normalized;
565
+ if (normalized.startsWith(".")) return `./${normalized}`;
566
+ return `./${normalized}`;
567
+ };
568
+ const formatConfigFolder = (configDir) => {
569
+ if (configDir === ".") return "./.bo$$";
570
+ if (configDir.startsWith("./") || configDir.startsWith("../")) return configDir;
571
+ if (configDir.startsWith("/")) return configDir;
572
+ return `./${configDir}`;
573
+ };
574
+ const buildContentGlobs = ({ srcRoot, isNext }) => {
575
+ if (isNext) return [`{src,pages,app,lib,components}/**/*.{${EXTENSIONS}}`];
576
+ if (srcRoot === "." || srcRoot === "") return [`{src,app,lib,components}/**/*.{${EXTENSIONS}}`];
577
+ return [`${srcRoot}/**/*.{${EXTENSIONS}}`];
578
+ };
579
+ const detectPostcss = async (cwd, packageJson) => {
580
+ let configFilePath;
581
+ for (const file of POSTCSS_CONFIG_FILES) {
582
+ const fullPath = path.join(cwd, file);
583
+ if (await exists(fullPath)) {
584
+ configFilePath = fullPath;
585
+ break;
586
+ }
587
+ }
588
+ return {
589
+ hasDependency: hasDependency(packageJson, "postcss"),
590
+ hasConfigFile: Boolean(configFilePath),
591
+ hasPackageConfig: Boolean(packageJson.postcss),
592
+ configFilePath
593
+ };
594
+ };
595
+ const detectEslint = async (cwd, packageJson) => {
596
+ const hasEslintDependency = hasDependency(packageJson, "eslint");
597
+ for (const config of ESLINT_CONFIG_FILES) {
598
+ const fullPath = path.join(cwd, config.file);
599
+ if (await exists(fullPath)) {
600
+ let configFormat;
601
+ if (config.type === "flat" || config.type === "eslintrc-js") configFormat = inferEslintConfigFormat(await fs.readFile(fullPath, "utf-8"), fullPath);
602
+ return {
603
+ hasDependency: hasEslintDependency,
604
+ hasConfig: true,
605
+ configFilePath: fullPath,
606
+ configType: config.type,
607
+ configFormat
608
+ };
609
+ }
610
+ }
611
+ if (packageJson.eslintConfig && typeof packageJson.eslintConfig === "object") return {
612
+ hasDependency: hasEslintDependency,
613
+ hasConfig: true,
614
+ configType: "package"
615
+ };
616
+ return {
617
+ hasDependency: hasEslintDependency,
618
+ hasConfig: false
619
+ };
620
+ };
621
+ const inferEslintConfigFormat = (content, filePath) => {
622
+ if (filePath.endsWith(".cjs")) return "cjs";
623
+ if (filePath.endsWith(".mjs")) return "esm";
624
+ if (/\bmodule\.exports\b/.test(content) || /\brequire\(/.test(content)) return "cjs";
625
+ if (/\bexport\s+default\b/.test(content) || /\bimport\s+/.test(content)) return "esm";
626
+ return "esm";
627
+ };
628
+ const updatePackageJson = (packageJson, options) => {
629
+ let changed = false;
630
+ let bossCssAdded = false;
631
+ const nextPackageJson = { ...packageJson };
632
+ if (shouldStoreConfigDir(options.configDir, options.srcRoot)) {
633
+ const boConfig = { ...nextPackageJson.bo$$ ?? {} };
634
+ if (boConfig.configDir !== options.configDir) {
635
+ boConfig.configDir = options.configDir;
636
+ nextPackageJson.bo$$ = boConfig;
637
+ changed = true;
638
+ }
639
+ }
640
+ if (options.addBossCss && !hasDependency(nextPackageJson, "boss-css")) {
641
+ const { updated, next } = ensureDependency(nextPackageJson, "boss-css", options.bossCssVersion || "latest", "dependencies");
642
+ if (updated) {
643
+ changed = true;
644
+ bossCssAdded = true;
645
+ Object.assign(nextPackageJson, next);
646
+ }
647
+ }
648
+ if (options.addPostcss && !hasDependency(nextPackageJson, "postcss")) {
649
+ const { updated, next } = ensureDependency(nextPackageJson, "postcss", "^8", "devDependencies");
650
+ if (updated) {
651
+ changed = true;
652
+ Object.assign(nextPackageJson, next);
653
+ }
654
+ }
655
+ if (options.includePostcssPlugin) {
656
+ const { updated, next, needsManual } = ensurePackagePostcssPlugin(nextPackageJson, options.postcssPluginOptions);
657
+ if (needsManual) log.message("PostCSS config in package.json uses an array; add boss-css/postcss via plugins object map.");
658
+ if (updated) {
659
+ changed = true;
660
+ Object.assign(nextPackageJson, next);
661
+ }
662
+ }
663
+ return {
664
+ changed,
665
+ data: nextPackageJson,
666
+ bossCssAdded
667
+ };
668
+ };
669
+ const shouldStoreConfigDir = (configDir, srcRoot) => {
670
+ if (configDir === ".bo$$") return false;
671
+ const normalizedSrc = srcRoot === "." ? "" : srcRoot.replace(/\/+$/g, "");
672
+ return configDir !== (normalizedSrc ? `${normalizedSrc}/.bo$$` : ".bo$$");
673
+ };
674
+ const ensureDependency = (packageJson, name, version, field) => {
675
+ const next = { ...packageJson };
676
+ const bucket = { ...next[field] ?? {} };
677
+ if (bucket[name]) return {
678
+ updated: false,
679
+ next
680
+ };
681
+ bucket[name] = version;
682
+ next[field] = bucket;
683
+ return {
684
+ updated: true,
685
+ next
686
+ };
687
+ };
688
+ const ensurePackagePostcssPlugin = (packageJson, pluginOptions) => {
689
+ const next = { ...packageJson };
690
+ if (!next.postcss || typeof next.postcss !== "object") return {
691
+ updated: false,
692
+ next
693
+ };
694
+ const postcssConfig = { ...next.postcss };
695
+ const plugins = postcssConfig.plugins;
696
+ if (Array.isArray(plugins)) return {
697
+ updated: false,
698
+ next,
699
+ needsManual: true
700
+ };
701
+ if (plugins && typeof plugins === "object") {
702
+ if (!Object.prototype.hasOwnProperty.call(plugins, "boss-css/postcss")) {
703
+ postcssConfig.plugins = {
704
+ "boss-css/postcss": pluginOptions ?? {},
705
+ ...plugins
706
+ };
707
+ next.postcss = postcssConfig;
708
+ return {
709
+ updated: true,
710
+ next
711
+ };
712
+ }
713
+ if (pluginOptions) {
714
+ postcssConfig.plugins = {
715
+ ...plugins,
716
+ "boss-css/postcss": pluginOptions
717
+ };
718
+ next.postcss = postcssConfig;
719
+ return {
720
+ updated: true,
721
+ next
722
+ };
723
+ }
724
+ return {
725
+ updated: false,
726
+ next
727
+ };
728
+ }
729
+ if (!plugins) {
730
+ postcssConfig.plugins = { "boss-css/postcss": pluginOptions ?? {} };
731
+ next.postcss = postcssConfig;
732
+ return {
733
+ updated: true,
734
+ next
735
+ };
736
+ }
737
+ return {
738
+ updated: false,
739
+ next
740
+ };
741
+ };
742
+ const configureEslint = async ({ detection, globalsEnabled, useEslintPlugin, allowReactGlobalsRule, packageJson }) => {
743
+ if (!detection.hasConfig) {
744
+ if (!globalsEnabled && !useEslintPlugin) return {
745
+ updated: false,
746
+ packageJsonChanged: false,
747
+ packageJson
748
+ };
749
+ const configFile = selectEslintConfigFile(packageJson);
750
+ const configText = createEslintConfigText({
751
+ globalsEnabled,
752
+ useEslintPlugin,
753
+ allowReactGlobalsRule
754
+ });
755
+ if (configText) {
756
+ await writeFile(path.join(process.cwd(), configFile), configText);
757
+ return {
758
+ updated: true,
759
+ packageJsonChanged: false,
760
+ packageJson
761
+ };
762
+ }
763
+ return {
764
+ updated: false,
765
+ packageJsonChanged: false,
766
+ packageJson
767
+ };
768
+ }
769
+ if (detection.configType === "package") {
770
+ if (!packageJson.eslintConfig || typeof packageJson.eslintConfig !== "object") {
771
+ log.warn("package.json eslintConfig is not an object. Skipping ESLint updates.");
772
+ return {
773
+ updated: false,
774
+ packageJsonChanged: false,
775
+ packageJson
776
+ };
777
+ }
778
+ const update = updateEslintConfigObject(packageJson.eslintConfig, {
779
+ globalsEnabled,
780
+ useEslintPlugin,
781
+ allowReactGlobalsRule
782
+ });
783
+ if (update.changed) return {
784
+ updated: true,
785
+ packageJsonChanged: true,
786
+ packageJson: {
787
+ ...packageJson,
788
+ eslintConfig: update.config
789
+ }
790
+ };
791
+ return {
792
+ updated: false,
793
+ packageJsonChanged: false,
794
+ packageJson
795
+ };
796
+ }
797
+ if (!detection.configFilePath) return {
798
+ updated: false,
799
+ packageJsonChanged: false,
800
+ packageJson
801
+ };
802
+ if (detection.configType === "flat") {
803
+ const update = updateFlatEslintConfigContent(await fs.readFile(detection.configFilePath, "utf-8"), {
804
+ globalsEnabled,
805
+ useEslintPlugin,
806
+ allowReactGlobalsRule,
807
+ configFormat: detection.configFormat ?? "esm"
808
+ });
809
+ if (!update.handled) {
810
+ log.warn("Unable to update ESLint config automatically. Add $$ globals manually.");
811
+ return {
812
+ updated: false,
813
+ packageJsonChanged: false,
814
+ packageJson
815
+ };
816
+ }
817
+ if (update.updated) await fs.writeFile(detection.configFilePath, update.content);
818
+ return {
819
+ updated: update.updated,
820
+ packageJsonChanged: false,
821
+ packageJson
822
+ };
823
+ }
824
+ if (detection.configType === "eslintrc") {
825
+ const content = await fs.readFile(detection.configFilePath, "utf-8");
826
+ try {
827
+ const update = updateEslintConfigObject(parseJson(content, {
828
+ filePath: detection.configFilePath,
829
+ allowTrailingCommas: true
830
+ }), {
831
+ globalsEnabled,
832
+ useEslintPlugin,
833
+ allowReactGlobalsRule
834
+ });
835
+ if (update.changed) await fs.writeFile(detection.configFilePath, JSON.stringify(update.config, null, 2) + "\n");
836
+ return {
837
+ updated: update.changed,
838
+ packageJsonChanged: false,
839
+ packageJson
840
+ };
841
+ } catch (error) {
842
+ log.warn("Unable to parse ESLint config JSON. Add $$ globals manually.");
843
+ return {
844
+ updated: false,
845
+ packageJsonChanged: false,
846
+ packageJson
847
+ };
848
+ }
849
+ }
850
+ if (detection.configType === "eslintrc-js") {
851
+ const update = updateEslintObjectConfigContent(await fs.readFile(detection.configFilePath, "utf-8"), {
852
+ globalsEnabled,
853
+ useEslintPlugin,
854
+ allowReactGlobalsRule
855
+ });
856
+ if (!update.handled) {
857
+ log.warn("Unable to update ESLint config automatically. Add $$ globals manually.");
858
+ return {
859
+ updated: false,
860
+ packageJsonChanged: false,
861
+ packageJson
862
+ };
863
+ }
864
+ if (update.updated) await fs.writeFile(detection.configFilePath, update.content);
865
+ return {
866
+ updated: update.updated,
867
+ packageJsonChanged: false,
868
+ packageJson
869
+ };
870
+ }
871
+ log.warn("ESLint config format not supported for automatic updates.");
872
+ return {
873
+ updated: false,
874
+ packageJsonChanged: false,
875
+ packageJson
876
+ };
877
+ };
878
+ const selectEslintConfigFile = (packageJson) => {
879
+ return packageJson.type === "module" ? "eslint.config.js" : "eslint.config.mjs";
880
+ };
881
+ const createEslintConfigText = ({ globalsEnabled, useEslintPlugin, allowReactGlobalsRule }) => {
882
+ const lines = buildEslintManagedArrayEntries({
883
+ includePluginConfig: useEslintPlugin,
884
+ includeGlobals: globalsEnabled && !useEslintPlugin,
885
+ includeAllowGlobalsRule: globalsEnabled && allowReactGlobalsRule
886
+ });
887
+ if (!lines.length) return "";
888
+ if (useEslintPlugin) return `import bossCss from 'boss-css/eslint-plugin'
889
+
890
+ export default [
891
+ ${buildManagedBlock(lines, " ")}
892
+ ]
893
+ `;
894
+ return `export default [
895
+ ${buildManagedBlock(lines, " ")}
896
+ ]
897
+ `;
898
+ };
899
+ const updateEslintConfigObject = (config, { globalsEnabled, useEslintPlugin, allowReactGlobalsRule }) => {
900
+ let changed = false;
901
+ const next = { ...config };
902
+ if (globalsEnabled) {
903
+ const globals = { ...next.globals };
904
+ if (globals.$$ !== "readonly") {
905
+ globals.$$ = "readonly";
906
+ next.globals = globals;
907
+ changed = true;
908
+ }
909
+ if (allowReactGlobalsRule) {
910
+ const allowGlobals = ensureAllowGlobalsRule({ ...next.rules });
911
+ if (allowGlobals.changed) {
912
+ next.rules = allowGlobals.rules;
913
+ changed = true;
914
+ }
915
+ }
916
+ }
917
+ if (useEslintPlugin) {
918
+ const plugins = normalizeToArray(next.plugins);
919
+ if (!plugins.includes("boss-css")) {
920
+ plugins.unshift("boss-css");
921
+ next.plugins = plugins;
922
+ changed = true;
923
+ }
924
+ const extendsList = normalizeToArray(next.extends);
925
+ if (!extendsList.includes("plugin:boss-css/recommended")) {
926
+ extendsList.unshift("plugin:boss-css/recommended");
927
+ next.extends = extendsList;
928
+ changed = true;
929
+ }
930
+ }
931
+ return {
932
+ changed,
933
+ config: next
934
+ };
935
+ };
936
+ const normalizeToArray = (value) => {
937
+ if (!value) return [];
938
+ if (Array.isArray(value)) return value.filter((item) => typeof item === "string");
939
+ if (typeof value === "string") return [value];
940
+ return [];
941
+ };
942
+ const updateFlatEslintConfigContent = (content, { globalsEnabled, useEslintPlugin, allowReactGlobalsRule, configFormat }) => {
943
+ let next = content;
944
+ let updated = false;
945
+ const legacyImportUpdate = replaceLegacyBossEslintImport(next);
946
+ if (legacyImportUpdate !== next) {
947
+ next = legacyImportUpdate;
948
+ updated = true;
949
+ }
950
+ if (useEslintPlugin && !hasBossEslintImport(next)) {
951
+ next = ensureEslintPluginImport(next, configFormat);
952
+ updated = true;
953
+ }
954
+ const hasBlock = hasManagedBlock(next);
955
+ const needsGlobals = globalsEnabled && !hasEslintGlobal(next) && !useEslintPlugin;
956
+ const needsAllowGlobalsRule = globalsEnabled && allowReactGlobalsRule && !hasEslintAllowGlobalsRule(next);
957
+ const needsPluginConfig = useEslintPlugin && !hasBossEslintConfig(next);
958
+ const managedLines = buildEslintManagedArrayEntries({
959
+ includePluginConfig: useEslintPlugin && (needsPluginConfig || hasBlock),
960
+ includeGlobals: globalsEnabled && !useEslintPlugin && (needsGlobals || hasBlock),
961
+ includeAllowGlobalsRule: globalsEnabled && allowReactGlobalsRule && (needsAllowGlobalsRule || hasBlock)
962
+ });
963
+ if (managedLines.length && (needsGlobals || needsAllowGlobalsRule || needsPluginConfig || hasBlock)) {
964
+ const bounds = findExportArrayBounds(next);
965
+ if (!bounds) return {
966
+ updated: false,
967
+ content,
968
+ handled: false
969
+ };
970
+ const insert = upsertManagedBlockIntoArray(next, bounds, managedLines);
971
+ next = insert.content;
972
+ updated = updated || insert.updated;
973
+ }
974
+ return {
975
+ updated,
976
+ content: next,
977
+ handled: true
978
+ };
979
+ };
980
+ const updateEslintObjectConfigContent = (content, { globalsEnabled, useEslintPlugin, allowReactGlobalsRule }) => {
981
+ if (findExportObjectStart(content) === null) return {
982
+ updated: false,
983
+ content,
984
+ handled: false
985
+ };
986
+ let next = content;
987
+ let updated = false;
988
+ if (useEslintPlugin) {
989
+ const pluginEntry = `'boss-css'`;
990
+ const extendEntry = `'plugin:boss-css/recommended'`;
991
+ const pluginsUpdate = ensureArrayEntry(next, "plugins", pluginEntry);
992
+ next = pluginsUpdate.content;
993
+ updated = updated || pluginsUpdate.updated;
994
+ const extendsUpdate = ensureArrayEntry(next, "extends", extendEntry);
995
+ next = extendsUpdate.content;
996
+ updated = updated || extendsUpdate.updated;
997
+ }
998
+ const hasBlock = hasManagedBlock(next);
999
+ const needsGlobals = globalsEnabled && !hasEslintGlobal(next);
1000
+ const needsAllowGlobalsRule = globalsEnabled && allowReactGlobalsRule && !hasEslintAllowGlobalsRule(next);
1001
+ const managedLines = buildEslintManagedObjectLines({
1002
+ includeGlobals: globalsEnabled && (needsGlobals || hasBlock),
1003
+ includeAllowGlobalsRule: globalsEnabled && allowReactGlobalsRule && (needsAllowGlobalsRule || hasBlock)
1004
+ });
1005
+ if (managedLines.length && (needsGlobals || needsAllowGlobalsRule || hasBlock)) {
1006
+ const insert = upsertManagedBlockInObject(next, managedLines);
1007
+ next = insert.content;
1008
+ updated = updated || insert.updated;
1009
+ }
1010
+ return {
1011
+ updated,
1012
+ content: next,
1013
+ handled: true
1014
+ };
1015
+ };
1016
+ const hasBossEslintConfig = (content) => /bossCss\.configs\./.test(content);
1017
+ const hasBossEslintImport = (content) => /boss-css\/eslint-plugin/.test(content) || /@boss-css\/eslint-plugin-boss-css/.test(content);
1018
+ const replaceLegacyBossEslintImport = (content) => content.replace(/@boss-css\/eslint-plugin-boss-css/g, "boss-css/eslint-plugin");
1019
+ const hasEslintGlobal = (content) => /['"]\$\$['"]\s*:/.test(content);
1020
+ const hasEslintAllowGlobalsRule = (content) => /react\/jsx-no-undef/.test(content) && /allowGlobals\s*:\s*true/.test(content);
1021
+ const hasManagedBlock = (content) => /\/\/\s*bo\$\$:begin/.test(content) && /\/\/\s*bo\$\$:end/.test(content);
1022
+ const ensureEslintPluginImport = (content, configFormat) => {
1023
+ return insertImports(content, [configFormat === "esm" ? "import bossCss from 'boss-css/eslint-plugin'" : "const bossCss = require('boss-css/eslint-plugin')"]);
1024
+ };
1025
+ const findExportArrayBounds = (content) => {
1026
+ const exportMatch = content.match(/export\s+default\s*\[/);
1027
+ const moduleMatch = content.match(/module\.exports\s*=\s*\[/);
1028
+ const match = exportMatch ?? moduleMatch;
1029
+ if (match) {
1030
+ if (match.index == null) return null;
1031
+ const startIndex = match.index + match[0].length - 1;
1032
+ const endIndex = findMatchingIndex(content, startIndex, "[", "]");
1033
+ if (endIndex === -1) return null;
1034
+ return {
1035
+ startIndex,
1036
+ endIndex
1037
+ };
1038
+ }
1039
+ const defineExportMatch = content.match(/export\s+default\s+defineConfig\s*\(/);
1040
+ if (defineExportMatch) {
1041
+ if (defineExportMatch.index == null) return null;
1042
+ return findDefineConfigArrayBounds(content, defineExportMatch.index + defineExportMatch[0].length - 1);
1043
+ }
1044
+ const identifier = findExportIdentifier(content);
1045
+ if (!identifier) return null;
1046
+ return findArrayBoundsByIdentifier(content, identifier) ?? findDefineConfigArrayBoundsByIdentifier(content, identifier);
1047
+ };
1048
+ const findExportObjectStart = (content) => {
1049
+ const exportMatch = content.match(/export\s+default\s*\{/);
1050
+ const moduleMatch = content.match(/module\.exports\s*=\s*\{/);
1051
+ const match = exportMatch ?? moduleMatch;
1052
+ if (match) {
1053
+ if (match.index == null) return null;
1054
+ return match.index + match[0].length - 1;
1055
+ }
1056
+ const identifier = findExportIdentifier(content);
1057
+ if (!identifier) return null;
1058
+ return findObjectStartByIdentifier(content, identifier);
1059
+ };
1060
+ const findExportIdentifier = (content) => {
1061
+ const exportMatch = content.match(/export\s+default\s+([A-Za-z_$][\w$]*)/);
1062
+ if (exportMatch) return exportMatch[1];
1063
+ const moduleMatch = content.match(/module\.exports\s*=\s*([A-Za-z_$][\w$]*)/);
1064
+ if (moduleMatch) return moduleMatch[1];
1065
+ return null;
1066
+ };
1067
+ const findArrayBoundsByIdentifier = (content, identifier) => {
1068
+ const escaped = escapeRegExp(identifier);
1069
+ const match = content.match(/* @__PURE__ */ new RegExp(`\\b(?:const|let|var)\\s+${escaped}\\s*=\\s*\\[`));
1070
+ if (!match) return null;
1071
+ if (match.index == null) return null;
1072
+ const startIndex = match.index + match[0].length - 1;
1073
+ const endIndex = findMatchingIndex(content, startIndex, "[", "]");
1074
+ if (endIndex === -1) return null;
1075
+ return {
1076
+ startIndex,
1077
+ endIndex
1078
+ };
1079
+ };
1080
+ const findDefineConfigArrayBoundsByIdentifier = (content, identifier) => {
1081
+ const escaped = escapeRegExp(identifier);
1082
+ const match = content.match(/* @__PURE__ */ new RegExp(`\\b(?:const|let|var)\\s+${escaped}\\s*=\\s*defineConfig\\s*\\(`));
1083
+ if (!match) return null;
1084
+ if (match.index == null) return null;
1085
+ return findDefineConfigArrayBounds(content, match.index + match[0].length - 1);
1086
+ };
1087
+ const findDefineConfigArrayBounds = (content, callStart) => {
1088
+ const callEnd = findMatchingIndex(content, callStart, "(", ")");
1089
+ if (callEnd === -1) return null;
1090
+ const arrayStart = content.indexOf("[", callStart);
1091
+ if (arrayStart === -1 || arrayStart > callEnd) return null;
1092
+ const arrayEnd = findMatchingIndex(content, arrayStart, "[", "]");
1093
+ if (arrayEnd === -1 || arrayEnd > callEnd) return null;
1094
+ return {
1095
+ startIndex: arrayStart,
1096
+ endIndex: arrayEnd
1097
+ };
1098
+ };
1099
+ const findObjectStartByIdentifier = (content, identifier) => {
1100
+ const escaped = escapeRegExp(identifier);
1101
+ const match = content.match(/* @__PURE__ */ new RegExp(`\\b(?:const|let|var)\\s+${escaped}\\s*=\\s*\\{`));
1102
+ if (!match) return null;
1103
+ if (match.index == null) return null;
1104
+ return match.index + match[0].length - 1;
1105
+ };
1106
+ const buildEslintManagedArrayEntries = ({ includePluginConfig, includeGlobals, includeAllowGlobalsRule }) => {
1107
+ const lines = [];
1108
+ if (includePluginConfig) lines.push("bossCss.configs.recommended,");
1109
+ if (includeGlobals || includeAllowGlobalsRule) {
1110
+ lines.push("{");
1111
+ if (includeGlobals) lines.push(" languageOptions: {", " globals: {", " $$: 'readonly',", " },", " },");
1112
+ if (includeAllowGlobalsRule) lines.push(" rules: {", " 'react/jsx-no-undef': ['error', { allowGlobals: true }],", " },");
1113
+ lines.push("},");
1114
+ }
1115
+ return lines;
1116
+ };
1117
+ const buildEslintManagedObjectLines = ({ includeGlobals, includeAllowGlobalsRule }) => {
1118
+ const lines = [];
1119
+ if (includeGlobals) lines.push("globals: {", " '$$': 'readonly',", "},");
1120
+ if (includeAllowGlobalsRule) lines.push("rules: {", " 'react/jsx-no-undef': ['error', { allowGlobals: true }],", "},");
1121
+ return lines;
1122
+ };
1123
+ const upsertManagedBlockIntoArray = (content, bounds, lines) => {
1124
+ const replaced = replaceManagedBlock(content, lines);
1125
+ if (replaced.found) return {
1126
+ updated: replaced.updated,
1127
+ content: replaced.content
1128
+ };
1129
+ const block = buildManagedBlock(lines, `${getIndentFromIndex(content, bounds.startIndex)} `);
1130
+ const insertion = `${needsArrayComma(content, bounds) ? "," : ""}\n${block}\n`;
1131
+ return {
1132
+ updated: true,
1133
+ content: `${content.slice(0, bounds.endIndex)}${insertion}${content.slice(bounds.endIndex)}`
1134
+ };
1135
+ };
1136
+ const upsertManagedBlockInObject = (content, lines) => {
1137
+ const replaced = replaceManagedBlock(content, lines);
1138
+ if (replaced.found) return {
1139
+ updated: replaced.updated,
1140
+ content: replaced.content
1141
+ };
1142
+ const objectStart = findExportObjectStart(content);
1143
+ if (objectStart === null) return {
1144
+ updated: false,
1145
+ content
1146
+ };
1147
+ const insertion = `\n${buildManagedBlock(lines, `${getIndentFromIndex(content, objectStart)} `)}\n`;
1148
+ return {
1149
+ updated: true,
1150
+ content: `${content.slice(0, objectStart + 1)}${insertion}${content.slice(objectStart + 1)}`
1151
+ };
1152
+ };
1153
+ const buildManagedBlock = (lines, indent = "") => {
1154
+ const start = `${indent}// bo$$:begin`;
1155
+ const end = `${indent}// bo$$:end`;
1156
+ return [
1157
+ start,
1158
+ ...lines.map((line) => line ? `${indent}${line}` : line),
1159
+ end
1160
+ ].join("\n");
1161
+ };
1162
+ const replaceManagedBlock = (content, lines) => {
1163
+ const regex = /(^[ \t]*)\/\/\s*bo\$\$?:begin[\s\S]*?^[ \t]*\/\/\s*bo\$\$?:end/m;
1164
+ const match = regex.exec(content);
1165
+ if (!match) return {
1166
+ updated: false,
1167
+ content,
1168
+ found: false
1169
+ };
1170
+ const block = buildManagedBlock(lines, match[1] ?? "");
1171
+ if (match.index == null) return {
1172
+ updated: false,
1173
+ content,
1174
+ found: false
1175
+ };
1176
+ const next = `${content.slice(0, match.index)}${block}${content.slice(match.index + match[0].length).replace(new RegExp(regex.source, "gm"), "")}`;
1177
+ return {
1178
+ updated: next !== content,
1179
+ content: ensureManagedBlockNewline(next),
1180
+ found: true
1181
+ };
1182
+ };
1183
+ const ensureManagedBlockNewline = (content) => {
1184
+ return content.replace(/(\/\/\s*bo\$\$:end)(?=[^\n])/g, "$1\n");
1185
+ };
1186
+ const needsArrayComma = (content, bounds) => {
1187
+ let index = bounds.endIndex - 1;
1188
+ while (index > bounds.startIndex && /\s/.test(content[index])) index -= 1;
1189
+ const lastChar = content[index];
1190
+ if (!lastChar) return false;
1191
+ return lastChar !== "[" && lastChar !== ",";
1192
+ };
1193
+ const ensureArrayEntry = (content, key, entry) => {
1194
+ const arrayMatch = content.match(/* @__PURE__ */ new RegExp(`${key}\\s*:\\s*\\[`));
1195
+ const stringMatch = !arrayMatch ? content.match(/* @__PURE__ */ new RegExp(`${key}\\s*:\\s*(['"][^'"]+['"])`)) : null;
1196
+ if (stringMatch) {
1197
+ const entryValue$1 = entry.replace(/^['"]|['"]$/g, "");
1198
+ if (stringMatch[1].replace(/^['"]|['"]$/g, "") === entryValue$1) return {
1199
+ updated: false,
1200
+ content
1201
+ };
1202
+ const replacement = `${key}: [${stringMatch[1]}, ${entry}]`;
1203
+ return {
1204
+ updated: true,
1205
+ content: content.replace(stringMatch[0], replacement)
1206
+ };
1207
+ }
1208
+ if (!arrayMatch) {
1209
+ const objectStart = findExportObjectStart(content);
1210
+ if (objectStart === null) return {
1211
+ updated: false,
1212
+ content
1213
+ };
1214
+ const insertion$1 = `\n${`${getIndentFromIndex(content, objectStart)} `}${key}: [${entry}],`;
1215
+ return {
1216
+ updated: true,
1217
+ content: `${content.slice(0, objectStart + 1)}${insertion$1}${content.slice(objectStart + 1)}`
1218
+ };
1219
+ }
1220
+ if (arrayMatch.index == null) return {
1221
+ updated: false,
1222
+ content
1223
+ };
1224
+ const startIndex = arrayMatch.index + arrayMatch[0].length - 1;
1225
+ const endIndex = findMatchingIndex(content, startIndex, "[", "]");
1226
+ if (endIndex === -1) return {
1227
+ updated: false,
1228
+ content
1229
+ };
1230
+ const entryValue = entry.replace(/^['"]|['"]$/g, "");
1231
+ if ((/* @__PURE__ */ new RegExp(`['"]${escapeRegExp(entryValue)}['"]`)).test(content.slice(startIndex, endIndex))) return {
1232
+ updated: false,
1233
+ content
1234
+ };
1235
+ const insertion = `\n${`${getIndentFromIndex(content, startIndex)} `}${entry},`;
1236
+ return {
1237
+ updated: true,
1238
+ content: `${content.slice(0, endIndex)}${insertion}${content.slice(endIndex)}`
1239
+ };
1240
+ };
1241
+ const ensureAllowGlobalsRule = (rules) => {
1242
+ const existing = rules["react/jsx-no-undef"];
1243
+ if (Array.isArray(existing)) {
1244
+ const options = typeof existing[1] === "object" && existing[1] ? { ...existing[1] } : {};
1245
+ if (options.allowGlobals === true) return {
1246
+ changed: false,
1247
+ rules
1248
+ };
1249
+ return {
1250
+ changed: true,
1251
+ rules: {
1252
+ ...rules,
1253
+ "react/jsx-no-undef": [
1254
+ existing[0] ?? "error",
1255
+ {
1256
+ ...options,
1257
+ allowGlobals: true
1258
+ },
1259
+ ...existing.slice(2)
1260
+ ]
1261
+ }
1262
+ };
1263
+ }
1264
+ if (existing !== void 0) return {
1265
+ changed: true,
1266
+ rules: {
1267
+ ...rules,
1268
+ "react/jsx-no-undef": [existing, { allowGlobals: true }]
1269
+ }
1270
+ };
1271
+ return {
1272
+ changed: true,
1273
+ rules: {
1274
+ ...rules,
1275
+ "react/jsx-no-undef": ["error", { allowGlobals: true }]
1276
+ }
1277
+ };
1278
+ };
1279
+ const shouldAllowReactGlobalsRule = (packageJson) => {
1280
+ return hasDependency(packageJson, "eslint-plugin-react") || hasDependency(packageJson, "eslint-config-next") || hasDependency(packageJson, "next");
1281
+ };
1282
+ const findMatchingIndex = (content, startIndex, openChar, closeChar) => {
1283
+ let depth = 0;
1284
+ for (let index = startIndex; index < content.length; index += 1) {
1285
+ const char = content[index];
1286
+ if (char === openChar) depth += 1;
1287
+ else if (char === closeChar) {
1288
+ depth -= 1;
1289
+ if (depth === 0) return index;
1290
+ }
1291
+ }
1292
+ return -1;
1293
+ };
1294
+ const writeInitFiles = async ({ outputDir, configFolder, contentGlobs, pluginState, selectedStrategyId, isNext, postcssMode, postcssDetection, includeAutoprefixer, packageJson, dirDependencies, usePostcssOptions, srcRoot, configDir, globalsEnabled, cssAutoLoad }) => {
1295
+ await fs.mkdir(outputDir, { recursive: true });
1296
+ const isRuntimeStrategy = selectedStrategyId === "runtime-only" || selectedStrategyId === "runtime-hybrid";
1297
+ const configText = pluvo(configTemplate, {
1298
+ plugins: pluginState,
1299
+ folder: configFolder,
1300
+ content: contentGlobs,
1301
+ jsxEnabled: pluginState.some((plugin) => plugin.id === "jsx" && plugin.enabled),
1302
+ globalsEnabled,
1303
+ runtimeEnabled: isRuntimeStrategy,
1304
+ runtimeStrategy: "inline-first",
1305
+ runtimeOnly: selectedStrategyId === "runtime-only",
1306
+ cssAutoLoad
1307
+ }, { commentStyles: INIT_COMMENT_STYLES });
1308
+ await writeFile(path.join(outputDir, "config.js"), configText);
1309
+ await writeFile(path.join(outputDir, "jsconfig.json"), jsconfigTemplate);
1310
+ await writeFile(path.join(outputDir, "package.json"), packageTemplate);
1311
+ await ensureFile(path.join(outputDir, "styles.css"));
1312
+ if (postcssMode === "auto") {
1313
+ if (!postcssDetection.hasConfigFile && !postcssDetection.hasPackageConfig) {
1314
+ const postcssText = pluvo(postcssTemplate, {
1315
+ includeAutoprefixer,
1316
+ dirDependencies,
1317
+ useOptions: usePostcssOptions
1318
+ }, { commentStyles: INIT_COMMENT_STYLES });
1319
+ await writeFile(path.join(process.cwd(), "postcss.config.js"), postcssText);
1320
+ } else if (postcssDetection.hasConfigFile && postcssDetection.configFilePath) {
1321
+ const update = await updatePostcssConfigFile(postcssDetection.configFilePath, {
1322
+ dirDependencies,
1323
+ useOptions: usePostcssOptions
1324
+ });
1325
+ if (!update.updated && !update.hasBoss) await warnIfPostcssPluginMissing(postcssDetection.configFilePath);
1326
+ } else if (packageJson.postcss && typeof packageJson.postcss === "object") {}
1327
+ }
1328
+ if (isNext && selectedStrategyId !== "classname-only") await ensureNextInstrumentationFiles({
1329
+ srcRoot,
1330
+ configDir,
1331
+ packageJson
1332
+ });
1333
+ };
1334
+ const ensureNextInstrumentationFiles = async ({ srcRoot, configDir, packageJson }) => {
1335
+ const cwd = process.cwd();
1336
+ const existingExt = await detectInstrumentationExtension(cwd, srcRoot);
1337
+ const useTypeScript = existingExt === ".ts" || await exists(path.join(cwd, "tsconfig.json")) || hasDependency(packageJson, "typescript");
1338
+ const ext = existingExt ?? (useTypeScript ? ".ts" : ".js");
1339
+ const instrumentationDir = path.resolve(cwd, srcRoot === "." ? "" : srcRoot);
1340
+ const configDirAbs = path.resolve(cwd, configDir);
1341
+ const importRoot = normalizeImportPath(path.relative(instrumentationDir, configDirAbs));
1342
+ await ensureInstrumentationFile({
1343
+ filePath: path.join(instrumentationDir, `instrumentation${ext}`),
1344
+ importPaths: [importRoot],
1345
+ template: (importPath) => `import '${importPath}'\n`
1346
+ });
1347
+ await ensureInstrumentationFile({
1348
+ filePath: path.join(instrumentationDir, `instrumentation-client${ext}`),
1349
+ importPaths: [importRoot],
1350
+ template: (importPath) => `import '${importPath}'\n`
1351
+ });
1352
+ };
1353
+ const STENCIL_CONFIG_FILES = [
1354
+ "stencil.config.ts",
1355
+ "stencil.config.js",
1356
+ "stencil.config.mjs",
1357
+ "stencil.config.cjs"
1358
+ ];
1359
+ const ensureStencilSetup = async ({ cwd, srcRoot, configDir, packageJson }) => {
1360
+ const stencilConfigPath = await detectStencilConfigPath(cwd);
1361
+ if (!stencilConfigPath) {
1362
+ log.warn("Stencil config not found. Add globalScript/globalStyle manually.");
1363
+ return;
1364
+ }
1365
+ const globalScriptPath = await resolveStencilGlobalScriptPath(cwd, srcRoot, packageJson);
1366
+ const globalScriptRelative = normalizeRelativePath(path.relative(cwd, globalScriptPath), cwd);
1367
+ const globalStyleRelative = path.join(configDir, "styles.css").replace(/\\/g, "/");
1368
+ const configUpdated = await ensureStencilConfigFields({
1369
+ filePath: stencilConfigPath,
1370
+ fields: [{
1371
+ key: "globalScript",
1372
+ line: `globalScript: '${globalScriptRelative}',`
1373
+ }, {
1374
+ key: "globalStyle",
1375
+ line: `globalStyle: '${globalStyleRelative}',`
1376
+ }]
1377
+ });
1378
+ await ensureStencilGlobalScriptFile({
1379
+ filePath: globalScriptPath,
1380
+ configDirAbs: path.resolve(cwd, configDir)
1381
+ });
1382
+ if (configUpdated) log.message("Stencil config updated with Boss CSS globals.");
1383
+ };
1384
+ const detectStencilConfigPath = async (cwd) => {
1385
+ for (const file of STENCIL_CONFIG_FILES) {
1386
+ const fullPath = path.join(cwd, file);
1387
+ if (await exists(fullPath)) return fullPath;
1388
+ }
1389
+ return null;
1390
+ };
1391
+ const resolveStencilGlobalScriptPath = async (cwd, srcRoot, packageJson) => {
1392
+ const baseDir = path.resolve(cwd, srcRoot, "global");
1393
+ const tsPath = path.join(baseDir, "app.ts");
1394
+ const jsPath = path.join(baseDir, "app.js");
1395
+ if (await exists(tsPath)) return tsPath;
1396
+ if (await exists(jsPath)) return jsPath;
1397
+ const useTypeScript = await exists(path.join(cwd, "tsconfig.json")) || hasDependency(packageJson, "typescript");
1398
+ return path.join(baseDir, `app.${useTypeScript ? "ts" : "js"}`);
1399
+ };
1400
+ const ensureStencilGlobalScriptFile = async ({ filePath, configDirAbs }) => {
1401
+ const importPath = normalizeImportPath(path.relative(path.dirname(filePath), configDirAbs));
1402
+ if (!await exists(filePath)) {
1403
+ await writeFile(filePath, `import '${importPath}'\n\nexport default function () {}\n`);
1404
+ return;
1405
+ }
1406
+ const current = await fs.readFile(filePath, "utf-8");
1407
+ const updated = ensureSideEffectImports(current, [importPath]);
1408
+ if (updated !== current) await fs.writeFile(filePath, updated);
1409
+ };
1410
+ const ensureStencilConfigFields = async ({ filePath, fields }) => {
1411
+ const current = await fs.readFile(filePath, "utf-8");
1412
+ const missing = fields.filter((field) => !new RegExp(`^\\s*${field.key}\\s*:`, "m").test(current));
1413
+ if (!missing.length) return false;
1414
+ const lines = current.split("\n");
1415
+ const namespaceIndex = lines.findIndex((line) => /^\s*namespace\s*:/.test(line));
1416
+ let insertIndex = namespaceIndex;
1417
+ if (insertIndex === -1) insertIndex = findStencilConfigInsertIndex(lines);
1418
+ if (insertIndex === -1) {
1419
+ log.warn("Unable to update stencil.config. Add globalScript/globalStyle manually.");
1420
+ return false;
1421
+ }
1422
+ const indent = lines[namespaceIndex]?.match(/^\s+/)?.[0] ?? current.match(/^[ \t]+(?=[A-Za-z_])/m)?.[0] ?? " ";
1423
+ const insertLines = missing.map((field) => `${indent}${field.line}`);
1424
+ lines.splice(insertIndex + 1, 0, ...insertLines);
1425
+ await fs.writeFile(filePath, lines.join("\n"));
1426
+ return true;
1427
+ };
1428
+ const findStencilConfigInsertIndex = (lines) => {
1429
+ const configLineIndex = lines.findIndex((line) => /export\s+const\s+config\b/.test(line) || /\bconst\s+config\b/.test(line));
1430
+ if (configLineIndex === -1) return -1;
1431
+ if (lines[configLineIndex].includes("{")) return configLineIndex;
1432
+ for (let index = configLineIndex + 1; index < lines.length; index += 1) if (lines[index].includes("{")) return index;
1433
+ return configLineIndex;
1434
+ };
1435
+ const detectInstrumentationExtension = async (cwd, srcRoot) => {
1436
+ const baseDir = path.resolve(cwd, srcRoot === "." ? "" : srcRoot);
1437
+ for (const ext of [".ts", ".js"]) {
1438
+ const serverPath = path.join(baseDir, `instrumentation${ext}`);
1439
+ const clientPath = path.join(baseDir, `instrumentation-client${ext}`);
1440
+ if (await exists(serverPath) || await exists(clientPath)) return ext;
1441
+ }
1442
+ };
1443
+ const ensureInstrumentationFile = async ({ filePath, importPaths, template }) => {
1444
+ if (!await exists(filePath)) {
1445
+ await writeFile(filePath, buildManagedBlock([`import '${importPaths[0]}'`]));
1446
+ return;
1447
+ }
1448
+ const current = await fs.readFile(filePath, "utf-8");
1449
+ const normalized = normalizeInstrumentationImports(current);
1450
+ const replaced = replaceManagedBlock(normalized, [`import '${importPaths[0]}'`]);
1451
+ if (replaced.found) {
1452
+ if (replaced.updated) await writeFile(filePath, replaced.content);
1453
+ return;
1454
+ }
1455
+ const next = insertManagedBlock(stripUnmanagedBossImports(normalized), [`import '${importPaths[0]}'`]);
1456
+ if (next !== current) await writeFile(filePath, next);
1457
+ };
1458
+ const ensureSideEffectImports = (content, importPaths) => {
1459
+ const missing = importPaths.filter((importPath) => !hasImportPath(content, importPath));
1460
+ if (!missing.length) return content;
1461
+ return insertImports(content, missing.map((importPath) => `import '${importPath}'`));
1462
+ };
1463
+ const normalizeInstrumentationImports = (content) => {
1464
+ const replacement = "import './.bo$$'";
1465
+ const lines = content.split("\n");
1466
+ const seen = /* @__PURE__ */ new Set();
1467
+ return lines.map((line) => {
1468
+ const match = line.match(/^\s*import\s+(['"])([^'"]+)\1\s*;?\s*$/);
1469
+ if (!match) return line;
1470
+ let importPath = match[2];
1471
+ if (importPath === ".bo$$" || importPath === "./.bo$$" || importPath === ".bo$$/styles.css") importPath = "./.bo$$";
1472
+ else if (importPath === ".bo$" || importPath === "./.bo$") importPath = "./.bo$$";
1473
+ if (importPath === "./.bo$$") {
1474
+ if (seen.has(importPath)) return "";
1475
+ seen.add(importPath);
1476
+ return replacement;
1477
+ }
1478
+ return line;
1479
+ }).filter((line) => line !== "").join("\n");
1480
+ };
1481
+ const stripUnmanagedBossImports = (content) => {
1482
+ return content.split("\n").filter((line) => !line.match(/^\s*import\s+['"](\.\/)?\.bo\$\$(\/styles\.css)?['"]\s*;?\s*$/)).join("\n");
1483
+ };
1484
+ const insertManagedBlock = (content, lines) => {
1485
+ const blockLines = buildManagedBlock(lines).split("\n");
1486
+ const output = content.split("\n");
1487
+ const insertIndex = getImportInsertIndex(output);
1488
+ const insertLines = insertIndex < output.length && output[insertIndex].trim() !== "" ? [...blockLines, ""] : blockLines;
1489
+ output.splice(insertIndex, 0, ...insertLines);
1490
+ return ensureManagedBlockNewline(output.join("\n"));
1491
+ };
1492
+ const escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1493
+ const hasImportPath = (content, importPath) => {
1494
+ const escaped = escapeRegExp(importPath);
1495
+ return (/* @__PURE__ */ new RegExp(`['"]${escaped}['"]`)).test(content);
1496
+ };
1497
+ const insertImports = (content, importLines) => {
1498
+ const lines = content.split("\n");
1499
+ const insertIndex = getImportInsertIndex(lines);
1500
+ const insertLines = insertIndex < lines.length && lines[insertIndex].trim() !== "" ? [...importLines, ""] : importLines;
1501
+ lines.splice(insertIndex, 0, ...insertLines);
1502
+ return lines.join("\n");
1503
+ };
1504
+ const getImportInsertIndex = (lines) => {
1505
+ let index = 0;
1506
+ while (index < lines.length) {
1507
+ const trimmed = lines[index].trim();
1508
+ if (!trimmed) {
1509
+ index += 1;
1510
+ continue;
1511
+ }
1512
+ if (trimmed.startsWith("//") || trimmed.startsWith("/*") || trimmed.startsWith("*") || trimmed.startsWith("*/") || /^['"]use (client|strict)['"];?$/.test(trimmed)) {
1513
+ index += 1;
1514
+ continue;
1515
+ }
1516
+ break;
1517
+ }
1518
+ return index;
1519
+ };
1520
+ const generateRuntime = async ({ outputDir, configFolder, pluginState, contentGlobs, globalsEnabled, cssAutoLoad, selectedStrategyId }) => {
1521
+ if (selectedStrategyId === "classname-only") return;
1522
+ const enabledPlugins = pluginState.filter((plugin) => plugin.enabled);
1523
+ const modules = enabledPlugins.map((plugin) => PLUGIN_MODULES[plugin.id]).filter(Boolean);
1524
+ if (globalsEnabled && enabledPlugins.some((plugin) => plugin.id === "jsx")) settings.set?.("globals", true);
1525
+ if (enabledPlugins.some((plugin) => plugin.id === "jsx")) settings.set?.("emitRuntime", true);
1526
+ if (enabledPlugins.some((plugin) => plugin.id === "inline-first")) settings$1.set?.("emitRuntime", true);
1527
+ if (enabledPlugins.some((plugin) => plugin.id === "classname-first")) settings$2.set?.("emitRuntime", true);
1528
+ const api = await createApi({
1529
+ folder: configFolder,
1530
+ plugins: modules,
1531
+ content: contentGlobs,
1532
+ css: cssAutoLoad ? void 0 : { autoLoad: false }
1533
+ }, true);
1534
+ await api.file.js.write();
1535
+ if (api.file.native?.hasContent) await api.file.native.write();
1536
+ };
1537
+ const warnIfPostcssPluginMissing = async (configFilePath) => {
1538
+ if ((await fs.readFile(configFilePath, "utf-8")).includes("boss-css/postcss")) return;
1539
+ log.warn(`PostCSS config detected at ${path.relative(process.cwd(), configFilePath)} but boss-css/postcss is missing.`);
1540
+ log.message("Add boss-css/postcss to your PostCSS plugins to enable Boss CSS.");
1541
+ };
1542
+ const updatePostcssConfigFile = async (configFilePath, options) => {
1543
+ const update = updatePostcssConfigContent(await fs.readFile(configFilePath, "utf-8"), configFilePath, options);
1544
+ if (update.updated) await fs.writeFile(configFilePath, update.content);
1545
+ return update;
1546
+ };
1547
+ const updatePostcssConfigContent = (content, configFilePath, options) => {
1548
+ const hasBoss = content.includes("boss-css/postcss");
1549
+ const hasBossCall = /\bboss\s*\(/.test(content);
1550
+ const isEsm = configFilePath.endsWith(".mjs") || /\bexport\s+default\b/.test(content) || /\bimport\b/.test(content);
1551
+ const arrayMatch = content.match(/plugins\s*:\s*\[/);
1552
+ const objectMatch = content.match(/plugins\s*:\s*\{/);
1553
+ const useOptions = options.useOptions;
1554
+ const bossCall = useOptions ? `boss({ dirDependencies: ${options.dirDependencies ? "true" : "false"} })` : "boss()";
1555
+ const bossObject = useOptions ? `{ dirDependencies: ${options.dirDependencies ? "true" : "false"} }` : "{}";
1556
+ const managedEntry = bossCall;
1557
+ if (arrayMatch) {
1558
+ let nextContent = content;
1559
+ const managedLines = [`${managedEntry},`];
1560
+ const replaced = replaceManagedBlock(nextContent, managedLines);
1561
+ if (replaced.found) {
1562
+ nextContent = ensureBossImport(replaced.content, isEsm);
1563
+ return {
1564
+ updated: nextContent !== content,
1565
+ content: nextContent,
1566
+ hasBoss: true
1567
+ };
1568
+ }
1569
+ const replacedArray = replaceBossPluginInArray(nextContent, arrayMatch, bossCall);
1570
+ if (replacedArray.updated) {
1571
+ nextContent = ensureBossImport(replacedArray.content, isEsm);
1572
+ return {
1573
+ updated: nextContent !== content,
1574
+ content: nextContent,
1575
+ hasBoss: true
1576
+ };
1577
+ }
1578
+ if (!hasBoss && !hasBossCall) {
1579
+ if (arrayMatch.index == null) return {
1580
+ updated: false,
1581
+ content,
1582
+ hasBoss: hasBoss || hasBossCall
1583
+ };
1584
+ const insertAt = arrayMatch.index + arrayMatch[0].length;
1585
+ const block = buildManagedBlock(managedLines, `${getIndentFromIndex(content, arrayMatch.index)} `);
1586
+ nextContent = `${content.slice(0, insertAt)}\n${block}${content.slice(insertAt)}`;
1587
+ nextContent = ensureBossImport(nextContent, isEsm);
1588
+ return {
1589
+ updated: nextContent !== content,
1590
+ content: nextContent,
1591
+ hasBoss: true
1592
+ };
1593
+ }
1594
+ if (hasBossCall) {
1595
+ nextContent = ensureBossImport(nextContent, isEsm);
1596
+ return {
1597
+ updated: nextContent !== content,
1598
+ content: nextContent,
1599
+ hasBoss: true
1600
+ };
1601
+ }
1602
+ return {
1603
+ updated: false,
1604
+ content,
1605
+ hasBoss: hasBoss || hasBossCall
1606
+ };
1607
+ }
1608
+ if (objectMatch) {
1609
+ let nextContent = content;
1610
+ const entry = useOptions ? bossObject : "{}";
1611
+ const managedLines = [`'boss-css/postcss': ${entry},`];
1612
+ const replaced = replaceManagedBlock(nextContent, managedLines);
1613
+ if (replaced.found) return {
1614
+ updated: replaced.content !== content,
1615
+ content: replaced.content,
1616
+ hasBoss: true
1617
+ };
1618
+ const objectEntryRegex = /['"]boss-css\/postcss['"]\s*:\s*[^,}]+/;
1619
+ if (hasBoss) {
1620
+ if (useOptions && objectEntryRegex.test(nextContent)) nextContent = nextContent.replace(objectEntryRegex, `'boss-css/postcss': ${entry}`);
1621
+ return {
1622
+ updated: nextContent !== content,
1623
+ content: nextContent,
1624
+ hasBoss: true
1625
+ };
1626
+ }
1627
+ if (objectMatch.index == null) return {
1628
+ updated: false,
1629
+ content,
1630
+ hasBoss
1631
+ };
1632
+ const insertAt = objectMatch.index + objectMatch[0].length;
1633
+ const block = buildManagedBlock(managedLines, `${getIndentFromIndex(content, objectMatch.index)} `);
1634
+ nextContent = `${content.slice(0, insertAt)}\n${block}${content.slice(insertAt)}`;
1635
+ return {
1636
+ updated: nextContent !== content,
1637
+ content: nextContent,
1638
+ hasBoss: true
1639
+ };
1640
+ }
1641
+ return {
1642
+ updated: false,
1643
+ content,
1644
+ hasBoss: hasBoss || hasBossCall
1645
+ };
1646
+ };
1647
+ const replaceBossPluginInArray = (content, arrayMatch, bossCall) => {
1648
+ if (arrayMatch.index === void 0) return {
1649
+ updated: false,
1650
+ content
1651
+ };
1652
+ const arrayIndex = arrayMatch.index + arrayMatch[0].lastIndexOf("[");
1653
+ const arrayEnd = findMatchingIndex(content, arrayIndex, "[", "]");
1654
+ if (arrayEnd === -1) return {
1655
+ updated: false,
1656
+ content
1657
+ };
1658
+ const arrayBody = content.slice(arrayIndex + 1, arrayEnd);
1659
+ const replacedBody = arrayBody.replace(/['"]boss-css\/postcss['"]/, bossCall);
1660
+ if (replacedBody === arrayBody) return {
1661
+ updated: false,
1662
+ content
1663
+ };
1664
+ const next = `${content.slice(0, arrayIndex + 1)}${replacedBody}${content.slice(arrayEnd)}`;
1665
+ return {
1666
+ updated: next !== content,
1667
+ content: next
1668
+ };
1669
+ };
1670
+ const ensureBossImport = (content, isEsm) => {
1671
+ if (content.includes("boss-css/postcss")) {
1672
+ if (isEsm ? /import\s+boss\s+from\s+['"]boss-css\/postcss['"]/.test(content) : /const\s+boss\s*=\s*require\(['"]boss-css\/postcss['"]\)/.test(content)) return content;
1673
+ }
1674
+ if (isEsm) {
1675
+ if (content.includes("import boss from")) return content;
1676
+ return `import boss from 'boss-css/postcss'\n${content}`;
1677
+ }
1678
+ if (content.includes("const boss = require")) return content;
1679
+ return `const boss = require('boss-css/postcss')\n${content}`;
1680
+ };
1681
+ const getIndentFromIndex = (content, index) => {
1682
+ const lineStart = content.lastIndexOf("\n", index);
1683
+ const match = content.slice(lineStart + 1).match(/^\s+/);
1684
+ return match ? match[0] : "";
1685
+ };
1686
+ const confirmOverwriteIfExists = async (dirPath, yes) => {
1687
+ if (!await exists(dirPath)) return true;
1688
+ if (yes) return true;
1689
+ const shouldContinue = await confirm({
1690
+ message: `Existing ${path.basename(dirPath)} folder detected. Overwrite its contents?`,
1691
+ initialValue: false
1692
+ });
1693
+ cancelIf(shouldContinue);
1694
+ return shouldContinue;
1695
+ };
1696
+ const readPackageJson = async (cwd) => {
1697
+ const filePath = path.join(cwd, "package.json");
1698
+ if (!await exists(filePath)) return {
1699
+ data: null,
1700
+ indent: " ",
1701
+ newline: "\n"
1702
+ };
1703
+ const raw = await fs.readFile(filePath, "utf-8");
1704
+ return {
1705
+ data: parseJson(raw, {
1706
+ filePath,
1707
+ allowTrailingCommas: true
1708
+ }),
1709
+ indent: detectIndent(raw),
1710
+ newline: raw.endsWith("\n") ? "\n" : ""
1711
+ };
1712
+ };
1713
+ const writePackageJson = async (cwd, data, indent, newline) => {
1714
+ const filePath = path.join(cwd, "package.json");
1715
+ const output = JSON.stringify(data, null, indent) + (newline || "\n");
1716
+ await fs.writeFile(filePath, output);
1717
+ };
1718
+ const writeFile = async (filePath, content) => {
1719
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
1720
+ await fs.writeFile(filePath, content.trimEnd() + "\n");
1721
+ };
1722
+ const ensureFile = async (filePath) => {
1723
+ if (await exists(filePath)) return;
1724
+ await fs.writeFile(filePath, "");
1725
+ };
1726
+ const detectIndent = (raw) => {
1727
+ const match = raw.match(/^[\t ]+(?=")/m);
1728
+ return match ? match[0] : " ";
1729
+ };
1730
+ const hasDependency = (packageJson, name) => {
1731
+ return Boolean(packageJson.dependencies?.[name] || packageJson.devDependencies?.[name]);
1732
+ };
1733
+ const resolveBossCssVersion = async () => {
1734
+ const root = path.resolve(__dirname, "..", "..", "..");
1735
+ const filePath = path.join(root, "package.json");
1736
+ try {
1737
+ const data = parseJson(await fs.readFile(filePath, "utf8"), {
1738
+ filePath,
1739
+ allowTrailingCommas: true
1740
+ });
1741
+ if (typeof data?.version === "string" && data.version.trim()) return data.version.trim();
1742
+ } catch {}
1743
+ return "latest";
1744
+ };
1745
+ const detectPackageManager = async (cwd, runtimeType) => {
1746
+ const agent = process.env.npm_config_user_agent;
1747
+ if (agent) {
1748
+ const name = agent.split("/")[0];
1749
+ if (name === PackageManagerType.PNPM) return PackageManagerType.PNPM;
1750
+ if (name === PackageManagerType.YARN) return PackageManagerType.YARN;
1751
+ if (name === PackageManagerType.BUN) return PackageManagerType.BUN;
1752
+ if (name === PackageManagerType.NPM) return PackageManagerType.NPM;
1753
+ }
1754
+ if (runtimeType === RuntimeType.DENO) return PackageManagerType.NPM;
1755
+ const candidates = [
1756
+ ["pnpm-lock.yaml", PackageManagerType.PNPM],
1757
+ ["yarn.lock", PackageManagerType.YARN],
1758
+ ["bun.lockb", PackageManagerType.BUN],
1759
+ ["package-lock.json", PackageManagerType.NPM]
1760
+ ];
1761
+ for (const [file, manager] of candidates) if (await exists(path.join(cwd, file))) return manager;
1762
+ return PackageManagerType.NPM;
1763
+ };
1764
+ const formatInstallCommand = (manager) => {
1765
+ switch (manager) {
1766
+ case PackageManagerType.PNPM: return "pnpm install";
1767
+ case PackageManagerType.YARN: return "yarn install";
1768
+ case PackageManagerType.BUN: return "bun install";
1769
+ case PackageManagerType.NPM:
1770
+ default: return "npm install";
1771
+ }
1772
+ };
1773
+ const exists = async (filePath) => {
1774
+ try {
1775
+ await fs.access(filePath);
1776
+ return true;
1777
+ } catch {
1778
+ return false;
1779
+ }
1780
+ };
1781
+ const logInitSummary = ({ configDir, isNext, postcssMode, postcssDetection, configFolder, srcRoot, globalsEnabled, eslintUpdated, useEslintPlugin, frameworkId, selectedStrategyId, cssAutoLoad, installCommand }) => {
1782
+ log.info("boss init complete.");
1783
+ log.message(`Generated Boss CSS config in ${configDir}`);
1784
+ if (selectedStrategyId === "classname-only") log.message("Classname-only does not auto-load styles. Import styles.css manually.");
1785
+ if (postcssMode === "manual" && !postcssDetection.hasDependency) {
1786
+ log.message("Manual PostCSS setup needed:");
1787
+ log.message("1) Install PostCSS (npm install -D postcss).");
1788
+ log.message("2) Add postcss.config.js with { plugins: { 'boss-css/postcss': {} } }.");
1789
+ }
1790
+ if (installCommand) log.message(`Install dependencies before running the app: ${installCommand}`);
1791
+ if (isNext) {
1792
+ log.message("Next.js note:");
1793
+ if (selectedStrategyId === "classname-only") {
1794
+ const importRoot = normalizeImportPath(path.relative(srcRoot, configDir));
1795
+ const importStyles = normalizeImportPath(path.join(importRoot, "styles.css"));
1796
+ log.message(`- Classname-only mode skips instrumentation. Import ${importStyles} in your app entry.`);
1797
+ } else {
1798
+ log.message("- Updated instrumentation files with Boss CSS imports.");
1799
+ log.message("Boss PostCSS auto-disables dirDependencies when a Turbopack env flag is set.");
1800
+ if (!cssAutoLoad) {
1801
+ const importRoot = normalizeImportPath(path.relative(srcRoot, configDir));
1802
+ const importStyles = normalizeImportPath(path.join(importRoot, "styles.css"));
1803
+ log.message(`- css.autoLoad is false. Import ${importStyles} in your app entry.`);
1804
+ }
1805
+ }
1806
+ } else {
1807
+ const importRoot = normalizeImportPath(path.relative(srcRoot, configDir));
1808
+ const importStyles = normalizeImportPath(path.join(importRoot, "styles.css"));
1809
+ if (selectedStrategyId === "classname-only") {
1810
+ log.message("Add the generated stylesheet to your app entrypoint (e.g. src/main.tsx):");
1811
+ log.message(`import '${importStyles}'`);
1812
+ } else if (!cssAutoLoad) {
1813
+ log.message("Add these to your app entrypoint (e.g. src/main.tsx):");
1814
+ log.message(`import '${importRoot}'`);
1815
+ log.message(`import '${importStyles}'`);
1816
+ } else {
1817
+ log.message("Add this to your app entrypoint (e.g. src/main.tsx):");
1818
+ log.message(`import '${importRoot}'`);
1819
+ }
1820
+ }
1821
+ if (frameworkId === "stencil") {
1822
+ log.message("Stencil note:");
1823
+ log.message("- PostCSS setup is skipped; run `npx boss-css watch` for CSS generation.");
1824
+ }
1825
+ if (globalsEnabled) log.message("Global $$ enabled for JSX usage.");
1826
+ if (eslintUpdated) log.message(useEslintPlugin ? "ESLint updated with Boss CSS plugin." : "ESLint updated with $$ globals.");
1827
+ };
1828
+ var init_default = init;
1829
+
1830
+ //#endregion
1831
+ export { init_default as default };