boss-css 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/_virtual/rolldown_runtime.cjs +43 -0
- package/dist/_virtual/rolldown_runtime.mjs +20 -0
- package/dist/api/browser.cjs +54 -0
- package/dist/api/browser.mjs +48 -0
- package/dist/api/config.cjs +94 -0
- package/dist/api/config.mjs +91 -0
- package/dist/api/css.cjs +304 -0
- package/dist/api/css.mjs +303 -0
- package/dist/api/dictionary.cjs +218 -0
- package/dist/api/dictionary.mjs +215 -0
- package/dist/api/file/dts.cjs +21 -0
- package/dist/api/file/dts.mjs +21 -0
- package/dist/api/file/file.cjs +123 -0
- package/dist/api/file/file.mjs +120 -0
- package/dist/api/file/js.cjs +118 -0
- package/dist/api/file/js.mjs +116 -0
- package/dist/api/names.cjs +52 -0
- package/dist/api/names.mjs +46 -0
- package/dist/api/noopCss.cjs +37 -0
- package/dist/api/noopCss.mjs +36 -0
- package/dist/api/propTree.cjs +54 -0
- package/dist/api/propTree.mjs +48 -0
- package/dist/api/server.cjs +112 -0
- package/dist/api/server.mjs +106 -0
- package/dist/cli/build.cjs +1 -0
- package/dist/cli/build.mjs +3 -0
- package/dist/cli/index.cjs +30 -0
- package/dist/cli/index.mjs +29 -0
- package/dist/cli/tasks/build.cjs +24 -0
- package/dist/cli/tasks/build.mjs +23 -0
- package/dist/cli/tasks/choose.cjs +47 -0
- package/dist/cli/tasks/choose.mjs +46 -0
- package/dist/cli/tasks/compile.cjs +68 -0
- package/dist/cli/tasks/compile.mjs +67 -0
- package/dist/cli/tasks/dev.cjs +51 -0
- package/dist/cli/tasks/dev.mjs +48 -0
- package/dist/cli/tasks/init.cjs +1835 -0
- package/dist/cli/tasks/init.mjs +1831 -0
- package/dist/cli/tasks/watch.cjs +38 -0
- package/dist/cli/tasks/watch.mjs +37 -0
- package/dist/cli/templates/init.cjs +82 -0
- package/dist/cli/templates/init.mjs +78 -0
- package/dist/cli/types.cjs +13 -0
- package/dist/cli/types.mjs +13 -0
- package/dist/cli/utils.cjs +43 -0
- package/dist/cli/utils.mjs +41 -0
- package/dist/compile/classname-strategy.cjs +79 -0
- package/dist/compile/classname-strategy.mjs +77 -0
- package/dist/compile/classname.cjs +366 -0
- package/dist/compile/classname.mjs +360 -0
- package/dist/compile/index.cjs +238 -0
- package/dist/compile/index.mjs +235 -0
- package/dist/compile/jsx.cjs +803 -0
- package/dist/compile/jsx.mjs +800 -0
- package/dist/compile/prepared.cjs +88 -0
- package/dist/compile/prepared.mjs +87 -0
- package/dist/compile/runtime.cjs +33 -0
- package/dist/compile/runtime.mjs +32 -0
- package/dist/compile/transform.cjs +371 -0
- package/dist/compile/transform.mjs +369 -0
- package/dist/cx/index.cjs +93 -0
- package/dist/cx/index.mjs +85 -0
- package/dist/detect-fw/index.cjs +384 -0
- package/dist/detect-fw/index.mjs +379 -0
- package/dist/dev/client.cjs +39 -0
- package/dist/dev/client.mjs +38 -0
- package/dist/dev/plugin/browser.cjs +11 -0
- package/dist/dev/plugin/browser.mjs +9 -0
- package/dist/dev/plugin/server.cjs +86 -0
- package/dist/dev/plugin/server.mjs +78 -0
- package/dist/dev/port.cjs +46 -0
- package/dist/dev/port.mjs +43 -0
- package/dist/dev/runtime.cjs +28 -0
- package/dist/dev/runtime.mjs +29 -0
- package/dist/dev/server.cjs +808 -0
- package/dist/dev/server.mjs +805 -0
- package/dist/dev/shared.cjs +6 -0
- package/dist/dev/shared.mjs +5 -0
- package/dist/eslint-plugin/index.cjs +66 -0
- package/dist/eslint-plugin/index.mjs +66 -0
- package/dist/eslint-plugin/rules/classnames-only.cjs +68 -0
- package/dist/eslint-plugin/rules/classnames-only.mjs +68 -0
- package/dist/eslint-plugin/rules/format-classnames.cjs +137 -0
- package/dist/eslint-plugin/rules/format-classnames.mjs +136 -0
- package/dist/eslint-plugin/rules/no-unknown-classes.cjs +119 -0
- package/dist/eslint-plugin/rules/no-unknown-classes.mjs +119 -0
- package/dist/eslint-plugin/rules/prefer-classnames.cjs +69 -0
- package/dist/eslint-plugin/rules/prefer-classnames.mjs +69 -0
- package/dist/eslint-plugin/rules/prefer-token-values.cjs +197 -0
- package/dist/eslint-plugin/rules/prefer-token-values.mjs +197 -0
- package/dist/eslint-plugin/rules/props-only.cjs +115 -0
- package/dist/eslint-plugin/rules/props-only.mjs +115 -0
- package/dist/eslint-plugin/rules/redundant-cx.cjs +66 -0
- package/dist/eslint-plugin/rules/redundant-cx.mjs +66 -0
- package/dist/eslint-plugin/rules/require-prop-functions.cjs +130 -0
- package/dist/eslint-plugin/rules/require-prop-functions.mjs +130 -0
- package/dist/eslint-plugin/utils/api.cjs +30 -0
- package/dist/eslint-plugin/utils/api.mjs +29 -0
- package/dist/eslint-plugin/utils/ast.cjs +119 -0
- package/dist/eslint-plugin/utils/ast.mjs +112 -0
- package/dist/eslint-plugin/utils/boss-classes.cjs +185 -0
- package/dist/eslint-plugin/utils/boss-classes.mjs +175 -0
- package/dist/eslint-plugin/utils/defaults.cjs +99 -0
- package/dist/eslint-plugin/utils/defaults.mjs +93 -0
- package/dist/eslint-plugin/utils/format.cjs +20 -0
- package/dist/eslint-plugin/utils/format.mjs +19 -0
- package/dist/eslint-plugin/utils/order.cjs +76 -0
- package/dist/eslint-plugin/utils/order.mjs +76 -0
- package/dist/eslint-plugin/utils/property-order.cjs +449 -0
- package/dist/eslint-plugin/utils/property-order.mjs +448 -0
- package/dist/eslint-plugin/utils/static.cjs +36 -0
- package/dist/eslint-plugin/utils/static.mjs +35 -0
- package/dist/fontsource/directory.cjs +39588 -0
- package/dist/fontsource/directory.mjs +39587 -0
- package/dist/fontsource/server.cjs +291 -0
- package/dist/fontsource/server.mjs +282 -0
- package/dist/index.cjs +10 -0
- package/dist/index.mjs +6 -0
- package/dist/log/browser.cjs +28 -0
- package/dist/log/browser.mjs +28 -0
- package/dist/log/server.cjs +32 -0
- package/dist/log/server.mjs +30 -0
- package/dist/merge/index.cjs +590 -0
- package/dist/merge/index.mjs +586 -0
- package/dist/native/browser.cjs +78 -0
- package/dist/native/browser.mjs +77 -0
- package/dist/native/server.cjs +180 -0
- package/dist/native/server.mjs +176 -0
- package/dist/native/styleTypes.cjs +168 -0
- package/dist/native/styleTypes.mjs +164 -0
- package/dist/parser/classname/server.cjs +239 -0
- package/dist/parser/classname/server.mjs +232 -0
- package/dist/parser/jsx/browser.cjs +66 -0
- package/dist/parser/jsx/browser.mjs +63 -0
- package/dist/parser/jsx/extractCode.cjs +99 -0
- package/dist/parser/jsx/extractCode.mjs +98 -0
- package/dist/parser/jsx/extractPrepared.cjs +123 -0
- package/dist/parser/jsx/extractPrepared.mjs +122 -0
- package/dist/parser/jsx/extractProps.cjs +234 -0
- package/dist/parser/jsx/extractProps.mjs +232 -0
- package/dist/parser/jsx/isDOMProp.cjs +17 -0
- package/dist/parser/jsx/isDOMProp.mjs +15 -0
- package/dist/parser/jsx/native.cjs +110 -0
- package/dist/parser/jsx/native.mjs +108 -0
- package/dist/parser/jsx/runtime.cjs +4 -0
- package/dist/parser/jsx/runtime.mjs +3 -0
- package/dist/parser/jsx/server.cjs +278 -0
- package/dist/parser/jsx/server.mjs +268 -0
- package/dist/postcss/index.cjs +16 -0
- package/dist/postcss/index.mjs +16 -0
- package/dist/prop/at/runtime-only.cjs +90 -0
- package/dist/prop/at/runtime-only.mjs +88 -0
- package/dist/prop/at/server.cjs +282 -0
- package/dist/prop/at/server.mjs +268 -0
- package/dist/prop/at/shared.cjs +153 -0
- package/dist/prop/at/shared.mjs +144 -0
- package/dist/prop/bosswind/browser.cjs +18 -0
- package/dist/prop/bosswind/browser.mjs +16 -0
- package/dist/prop/bosswind/runtime-only.cjs +18 -0
- package/dist/prop/bosswind/runtime-only.mjs +16 -0
- package/dist/prop/bosswind/server.cjs +81 -0
- package/dist/prop/bosswind/server.mjs +72 -0
- package/dist/prop/bosswind/shared.cjs +861 -0
- package/dist/prop/bosswind/shared.mjs +855 -0
- package/dist/prop/bosswind/tailwind-theme.cjs +703 -0
- package/dist/prop/bosswind/tailwind-theme.mjs +702 -0
- package/dist/prop/child/runtime-only.cjs +18 -0
- package/dist/prop/child/runtime-only.mjs +15 -0
- package/dist/prop/child/server.cjs +81 -0
- package/dist/prop/child/server.mjs +72 -0
- package/dist/prop/css/getDtsTemplate.cjs +65 -0
- package/dist/prop/css/getDtsTemplate.mjs +63 -0
- package/dist/prop/css/runtime-only.cjs +14 -0
- package/dist/prop/css/runtime-only.mjs +13 -0
- package/dist/prop/css/server.cjs +99 -0
- package/dist/prop/css/server.mjs +90 -0
- package/dist/prop/pseudo/runtime-only.cjs +23 -0
- package/dist/prop/pseudo/runtime-only.mjs +21 -0
- package/dist/prop/pseudo/server.cjs +91 -0
- package/dist/prop/pseudo/server.mjs +82 -0
- package/dist/prop/pseudo/shared.cjs +61 -0
- package/dist/prop/pseudo/shared.mjs +60 -0
- package/dist/reset/server.cjs +34 -0
- package/dist/reset/server.mjs +26 -0
- package/dist/runtime/index.cjs +119 -0
- package/dist/runtime/index.mjs +118 -0
- package/dist/runtime/preact.cjs +4 -0
- package/dist/runtime/preact.mjs +3 -0
- package/dist/runtime/qwik.cjs +21 -0
- package/dist/runtime/qwik.mjs +18 -0
- package/dist/runtime/react.cjs +4 -0
- package/dist/runtime/react.mjs +3 -0
- package/dist/runtime/solid.cjs +15 -0
- package/dist/runtime/solid.mjs +14 -0
- package/dist/runtime/stencil.cjs +25 -0
- package/dist/runtime/stencil.mjs +21 -0
- package/dist/runtime/style.cjs +14 -0
- package/dist/runtime/style.mjs +13 -0
- package/dist/shared/boundaries.cjs +288 -0
- package/dist/shared/boundaries.mjs +285 -0
- package/dist/shared/customCss.cjs +212 -0
- package/dist/shared/customCss.mjs +211 -0
- package/dist/shared/debug.cjs +76 -0
- package/dist/shared/debug.mjs +74 -0
- package/dist/shared/file.cjs +21 -0
- package/dist/shared/file.mjs +19 -0
- package/dist/shared/framework.cjs +10 -0
- package/dist/shared/framework.mjs +9 -0
- package/dist/shared/json.cjs +58 -0
- package/dist/shared/json.mjs +57 -0
- package/dist/shared/types.cjs +11 -0
- package/dist/shared/types.mjs +10 -0
- package/dist/strategy/classic/runtime-only.cjs +190 -0
- package/dist/strategy/classic/runtime-only.mjs +186 -0
- package/dist/strategy/classname-first/runtime-only.cjs +138 -0
- package/dist/strategy/classname-first/runtime-only.mjs +134 -0
- package/dist/strategy/classname-first/server.cjs +139 -0
- package/dist/strategy/classname-first/server.mjs +133 -0
- package/dist/strategy/classname-only/server.cjs +43 -0
- package/dist/strategy/classname-only/server.mjs +35 -0
- package/dist/strategy/inline-first/browser.cjs +61 -0
- package/dist/strategy/inline-first/browser.mjs +58 -0
- package/dist/strategy/inline-first/runtime-only.cjs +159 -0
- package/dist/strategy/inline-first/runtime-only.mjs +155 -0
- package/dist/strategy/inline-first/server.cjs +92 -0
- package/dist/strategy/inline-first/server.mjs +83 -0
- package/dist/strategy/runtime/runtime-only.cjs +24 -0
- package/dist/strategy/runtime/runtime-only.mjs +22 -0
- package/dist/strategy/runtime/server.cjs +72 -0
- package/dist/strategy/runtime/server.mjs +63 -0
- package/dist/strategy/runtime-only/css.cjs +183 -0
- package/dist/strategy/runtime-only/css.mjs +181 -0
- package/dist/tasks/build.cjs +88 -0
- package/dist/tasks/build.mjs +84 -0
- package/dist/tasks/compile.cjs +12 -0
- package/dist/tasks/compile.mjs +12 -0
- package/dist/tasks/postcss.cjs +116 -0
- package/dist/tasks/postcss.mjs +113 -0
- package/dist/tasks/session.cjs +46 -0
- package/dist/tasks/session.mjs +42 -0
- package/dist/tasks/watch.cjs +102 -0
- package/dist/tasks/watch.mjs +99 -0
- package/dist/transform/cache.cjs +24 -0
- package/dist/transform/cache.mjs +21 -0
- package/dist/transform/processFile.cjs +26 -0
- package/dist/transform/processFile.mjs +24 -0
- package/dist/use/token/browser.cjs +65 -0
- package/dist/use/token/browser.mjs +61 -0
- package/dist/use/token/runtime-only.cjs +245 -0
- package/dist/use/token/runtime-only.mjs +239 -0
- package/dist/use/token/server.cjs +325 -0
- package/dist/use/token/server.mjs +313 -0
- package/dist/use/token/vars.cjs +47 -0
- package/dist/use/token/vars.mjs +46 -0
- package/package.json +300 -4
- package/src/api/config.d.ts +1 -0
- package/src/fontsource/types.d.ts +50 -0
- package/src/packages/document-create-element/createElement.browser.js +3 -0
- package/src/packages/document-create-element/createElement.js +7 -0
- package/src/packages/document-create-element/package.json +17 -0
- package/src/packages/is-css-prop/browser.js +13 -0
- package/src/packages/is-css-prop/index.js +13 -0
- package/src/packages/is-css-prop/package-lock.json +52 -0
- package/src/packages/is-css-prop/package.json +17 -0
- package/src/prop/css/csstype.json +4387 -0
- package/src/prop/css/package.json +3 -0
- 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 };
|