@uiscore/cli 0.1.5 → 0.1.7
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 +13 -9
- package/dist/index.js +429 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -32,7 +32,17 @@ uiscore add button
|
|
|
32
32
|
|
|
33
33
|
## How It Works
|
|
34
34
|
|
|
35
|
-
`uiscore
|
|
35
|
+
`uiscore init` prepares the consumer project infrastructure:
|
|
36
|
+
|
|
37
|
+
1. Creates `uiscore.config.json`.
|
|
38
|
+
2. Installs `tailwindcss`, `postcss` and `autoprefixer` if they are missing.
|
|
39
|
+
3. Creates or updates `tailwind.config.js` with UIScore content globs.
|
|
40
|
+
4. Creates `postcss.config.js` if it is missing.
|
|
41
|
+
5. Creates `src/shared/ui/styles/uiscore.css` with font import and token markers.
|
|
42
|
+
6. Injects Tailwind directives and the UIScore styles import into the project's global CSS.
|
|
43
|
+
7. Ensures the application entrypoint imports the global CSS file.
|
|
44
|
+
|
|
45
|
+
`uiscore add <name>` then does four things:
|
|
36
46
|
|
|
37
47
|
1. Reads `uiscore.config.json` from the current project.
|
|
38
48
|
2. Downloads the registry item JSON from `registryUrl`.
|
|
@@ -45,7 +55,7 @@ If the registry item contains CSS variables, the CLI also writes them into the c
|
|
|
45
55
|
|
|
46
56
|
### `uiscore init`
|
|
47
57
|
|
|
48
|
-
|
|
58
|
+
Bootstraps the consumer project for UIScore components.
|
|
49
59
|
|
|
50
60
|
Example:
|
|
51
61
|
|
|
@@ -113,13 +123,7 @@ Then:
|
|
|
113
123
|
npx @uiscore/cli add button
|
|
114
124
|
```
|
|
115
125
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
```ts
|
|
119
|
-
import "@/shared/ui/styles/uiscore.css";
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
The CLI does not inject this import automatically.
|
|
126
|
+
If `uiscore init` was used first, the global CSS import is already wired automatically.
|
|
123
127
|
|
|
124
128
|
## Notes
|
|
125
129
|
|
package/dist/index.js
CHANGED
|
@@ -71,8 +71,18 @@ function dependencyInstallArgs(packageManager, dependencies) {
|
|
|
71
71
|
}
|
|
72
72
|
return ["install", ...dependencies];
|
|
73
73
|
}
|
|
74
|
+
function devDependencyInstallArgs(packageManager, dependencies) {
|
|
75
|
+
if (packageManager === "pnpm") {
|
|
76
|
+
return ["add", "-D", ...dependencies];
|
|
77
|
+
}
|
|
78
|
+
if (packageManager === "yarn") {
|
|
79
|
+
return ["add", "-D", ...dependencies];
|
|
80
|
+
}
|
|
81
|
+
return ["install", "-D", ...dependencies];
|
|
82
|
+
}
|
|
74
83
|
|
|
75
84
|
// src/commands/add.ts
|
|
85
|
+
var UISCORE_FONT_IMPORT = '@import url("https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@500;600;700&display=swap");';
|
|
76
86
|
async function runAddCommand(options) {
|
|
77
87
|
const config = loadConfig(options.cwd);
|
|
78
88
|
const url = config.registryUrl.replace("{name}", options.name);
|
|
@@ -124,7 +134,7 @@ async function runAddCommand(options) {
|
|
|
124
134
|
for (const filePath of writtenFiles) {
|
|
125
135
|
info(`- ${filePath}`);
|
|
126
136
|
}
|
|
127
|
-
info(`
|
|
137
|
+
info(`UIScore styles file: ${config.stylesPath}`);
|
|
128
138
|
}
|
|
129
139
|
function writeCssVars({
|
|
130
140
|
cwd,
|
|
@@ -138,19 +148,30 @@ function writeCssVars({
|
|
|
138
148
|
const markerEnd = "/* uiscore:tokens:end */";
|
|
139
149
|
const nextBlock = buildCssVarBlock(cssVars, markerStart, markerEnd);
|
|
140
150
|
if (!existing) {
|
|
141
|
-
writeFileSync(outputPath,
|
|
151
|
+
writeFileSync(outputPath, `${UISCORE_FONT_IMPORT}
|
|
152
|
+
|
|
153
|
+
${nextBlock}`, "utf8");
|
|
142
154
|
return;
|
|
143
155
|
}
|
|
144
|
-
|
|
145
|
-
|
|
156
|
+
const withFontImport = existing.includes(UISCORE_FONT_IMPORT) ? existing : `${UISCORE_FONT_IMPORT}
|
|
157
|
+
|
|
158
|
+
${existing.trimStart()}`;
|
|
159
|
+
if (withFontImport.includes(markerStart) && withFontImport.includes(markerEnd)) {
|
|
160
|
+
const existingCssVars = parseCssVarsFromBlock(withFontImport, markerStart, markerEnd);
|
|
161
|
+
const mergedCssVars = {
|
|
162
|
+
...existingCssVars,
|
|
163
|
+
...cssVars
|
|
164
|
+
};
|
|
165
|
+
const mergedBlock = buildCssVarBlock(mergedCssVars, markerStart, markerEnd);
|
|
166
|
+
const updated = withFontImport.replace(
|
|
146
167
|
new RegExp(`${escapeForRegExp(markerStart)}[\\s\\S]*?${escapeForRegExp(markerEnd)}`),
|
|
147
|
-
|
|
168
|
+
mergedBlock.trimEnd()
|
|
148
169
|
);
|
|
149
170
|
writeFileSync(outputPath, `${updated.trimEnd()}
|
|
150
171
|
`, "utf8");
|
|
151
172
|
return;
|
|
152
173
|
}
|
|
153
|
-
writeFileSync(outputPath, `${
|
|
174
|
+
writeFileSync(outputPath, `${withFontImport.trimEnd()}
|
|
154
175
|
|
|
155
176
|
${nextBlock}`, "utf8");
|
|
156
177
|
}
|
|
@@ -163,24 +184,421 @@ ${vars}
|
|
|
163
184
|
${markerEnd}
|
|
164
185
|
`;
|
|
165
186
|
}
|
|
187
|
+
function parseCssVarsFromBlock(source, markerStart, markerEnd) {
|
|
188
|
+
const blockMatch = source.match(
|
|
189
|
+
new RegExp(
|
|
190
|
+
`${escapeForRegExp(markerStart)}([\\s\\S]*?)${escapeForRegExp(markerEnd)}`
|
|
191
|
+
)
|
|
192
|
+
);
|
|
193
|
+
if (!blockMatch) {
|
|
194
|
+
return {};
|
|
195
|
+
}
|
|
196
|
+
const cssVars = {};
|
|
197
|
+
const matches = blockMatch[1].matchAll(/--([a-z0-9-]+)\s*:\s*([^;]+);/gi);
|
|
198
|
+
for (const match of matches) {
|
|
199
|
+
cssVars[match[1]] = match[2].trim();
|
|
200
|
+
}
|
|
201
|
+
return cssVars;
|
|
202
|
+
}
|
|
166
203
|
function escapeForRegExp(value) {
|
|
167
204
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
168
205
|
}
|
|
169
206
|
|
|
170
207
|
// src/commands/init.ts
|
|
171
|
-
import {
|
|
208
|
+
import {
|
|
209
|
+
existsSync as existsSync4,
|
|
210
|
+
mkdirSync as mkdirSync2,
|
|
211
|
+
readFileSync as readFileSync3,
|
|
212
|
+
writeFileSync as writeFileSync2
|
|
213
|
+
} from "fs";
|
|
214
|
+
import { spawnSync as spawnSync2 } from "child_process";
|
|
172
215
|
import path4 from "path";
|
|
173
216
|
function runInitCommand(cwd) {
|
|
174
217
|
const configPath = getConfigPath(cwd);
|
|
218
|
+
const packageJsonPath = path4.join(cwd, "package.json");
|
|
219
|
+
if (!existsSync4(packageJsonPath)) {
|
|
220
|
+
throw new Error(
|
|
221
|
+
"No package.json found in the current directory. Run `uiscore init` inside a project root."
|
|
222
|
+
);
|
|
223
|
+
}
|
|
175
224
|
if (existsSync4(configPath)) {
|
|
176
225
|
warn(`Config already exists: ${configPath}`);
|
|
226
|
+
} else {
|
|
227
|
+
mkdirSync2(path4.dirname(configPath), { recursive: true });
|
|
228
|
+
writeFileSync2(
|
|
229
|
+
configPath,
|
|
230
|
+
`${JSON.stringify(DEFAULT_CONFIG, null, 2)}
|
|
231
|
+
`,
|
|
232
|
+
"utf8"
|
|
233
|
+
);
|
|
234
|
+
info(`Created ${configPath}`);
|
|
235
|
+
}
|
|
236
|
+
const config = loadConfig(cwd);
|
|
237
|
+
const packageJson = JSON.parse(readFileSync3(packageJsonPath, "utf8"));
|
|
238
|
+
const packageManager = detectPackageManager(cwd);
|
|
239
|
+
ensureTailwindDependencies({
|
|
240
|
+
cwd,
|
|
241
|
+
packageManager,
|
|
242
|
+
packageJson
|
|
243
|
+
});
|
|
244
|
+
const environment = detectEnvironment(cwd);
|
|
245
|
+
ensureTailwindConfig({
|
|
246
|
+
cwd,
|
|
247
|
+
isEsmProject: packageJson.type === "module",
|
|
248
|
+
sourceRoot: config.sourceRoot
|
|
249
|
+
});
|
|
250
|
+
ensurePostcssConfig({
|
|
251
|
+
cwd,
|
|
252
|
+
isEsmProject: packageJson.type === "module"
|
|
253
|
+
});
|
|
254
|
+
ensureDirectory(path4.join(cwd, config.sourceRoot, "components"));
|
|
255
|
+
ensureDirectory(path4.join(cwd, config.sourceRoot, "lib"));
|
|
256
|
+
ensureDirectory(path4.join(cwd, path4.dirname(config.stylesPath)));
|
|
257
|
+
ensureUiscoreStylesFile({
|
|
258
|
+
cwd,
|
|
259
|
+
stylesPath: config.stylesPath
|
|
260
|
+
});
|
|
261
|
+
const globalCssPath = ensureGlobalCssFile({
|
|
262
|
+
cwd,
|
|
263
|
+
environment
|
|
264
|
+
});
|
|
265
|
+
ensureGlobalCssContent({
|
|
266
|
+
globalCssPath,
|
|
267
|
+
stylesPath: path4.join(cwd, config.stylesPath)
|
|
268
|
+
});
|
|
269
|
+
ensureEntryImportsGlobalCss({
|
|
270
|
+
cwd,
|
|
271
|
+
environment,
|
|
272
|
+
globalCssPath
|
|
273
|
+
});
|
|
274
|
+
info("UIScore infrastructure initialized.");
|
|
275
|
+
info("You can now run `uiscore add button`.");
|
|
276
|
+
}
|
|
277
|
+
function ensureTailwindDependencies({
|
|
278
|
+
cwd,
|
|
279
|
+
packageManager,
|
|
280
|
+
packageJson
|
|
281
|
+
}) {
|
|
282
|
+
const requiredDependencies = [
|
|
283
|
+
"tailwindcss@^3.4.17",
|
|
284
|
+
"postcss@^8.5.8",
|
|
285
|
+
"autoprefixer@^10.4.27"
|
|
286
|
+
];
|
|
287
|
+
const installedDependencies = {
|
|
288
|
+
...packageJson.dependencies,
|
|
289
|
+
...packageJson.devDependencies
|
|
290
|
+
};
|
|
291
|
+
const missingDependencies = requiredDependencies.filter((dependency) => {
|
|
292
|
+
const [name] = dependency.split("@", 1);
|
|
293
|
+
return !installedDependencies[name];
|
|
294
|
+
});
|
|
295
|
+
if (!missingDependencies.length) {
|
|
177
296
|
return;
|
|
178
297
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
298
|
+
info(`Installing infrastructure dependencies with ${packageManager}...`);
|
|
299
|
+
const result = spawnSync2(
|
|
300
|
+
packageManager,
|
|
301
|
+
devDependencyInstallArgs(packageManager, requiredDependencies),
|
|
302
|
+
{
|
|
303
|
+
cwd,
|
|
304
|
+
stdio: "inherit",
|
|
305
|
+
shell: process.platform === "win32"
|
|
306
|
+
}
|
|
307
|
+
);
|
|
308
|
+
if (result.status !== 0) {
|
|
309
|
+
throw new Error("Failed to install Tailwind infrastructure dependencies.");
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
function detectEnvironment(cwd) {
|
|
313
|
+
const nextLayoutFiles = [
|
|
314
|
+
path4.join(cwd, "src", "app", "layout.tsx"),
|
|
315
|
+
path4.join(cwd, "src", "app", "layout.jsx"),
|
|
316
|
+
path4.join(cwd, "app", "layout.tsx"),
|
|
317
|
+
path4.join(cwd, "app", "layout.jsx")
|
|
318
|
+
];
|
|
319
|
+
for (const layoutPath of nextLayoutFiles) {
|
|
320
|
+
if (existsSync4(layoutPath)) {
|
|
321
|
+
return {
|
|
322
|
+
type: "next",
|
|
323
|
+
layoutPath
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
const viteMainFiles = [
|
|
328
|
+
path4.join(cwd, "src", "main.tsx"),
|
|
329
|
+
path4.join(cwd, "src", "main.jsx"),
|
|
330
|
+
path4.join(cwd, "src", "main.ts"),
|
|
331
|
+
path4.join(cwd, "src", "main.js")
|
|
332
|
+
];
|
|
333
|
+
for (const mainPath of viteMainFiles) {
|
|
334
|
+
if (existsSync4(mainPath)) {
|
|
335
|
+
return {
|
|
336
|
+
type: "vite",
|
|
337
|
+
mainPath
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
return {
|
|
342
|
+
type: "generic"
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
function ensureTailwindConfig({
|
|
346
|
+
cwd,
|
|
347
|
+
isEsmProject,
|
|
348
|
+
sourceRoot
|
|
349
|
+
}) {
|
|
350
|
+
const configPath = path4.join(cwd, "tailwind.config.js");
|
|
351
|
+
const contentPatterns = [
|
|
352
|
+
"./index.html",
|
|
353
|
+
"./src/**/*.{js,ts,jsx,tsx,mdx}",
|
|
354
|
+
"./app/**/*.{js,ts,jsx,tsx,mdx}",
|
|
355
|
+
"./pages/**/*.{js,ts,jsx,tsx,mdx}",
|
|
356
|
+
"./components/**/*.{js,ts,jsx,tsx,mdx}",
|
|
357
|
+
`./${normalizeForGlob(sourceRoot)}/**/*.{js,ts,jsx,tsx,mdx}`
|
|
358
|
+
];
|
|
359
|
+
const nextConfigSource = buildTailwindConfigSource({
|
|
360
|
+
isEsmProject,
|
|
361
|
+
contentPatterns
|
|
362
|
+
});
|
|
363
|
+
if (!existsSync4(configPath)) {
|
|
364
|
+
writeFileSync2(configPath, nextConfigSource, "utf8");
|
|
365
|
+
info(`Created ${configPath}`);
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
const current = readFileSync3(configPath, "utf8");
|
|
369
|
+
if (contentPatterns.every((pattern) => current.includes(pattern))) {
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
if (!current.includes("content")) {
|
|
373
|
+
warn(`Tailwind config exists but has no content field: ${configPath}`);
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
const markerPattern = /content\s*:\s*\[([\s\S]*?)\]/m;
|
|
377
|
+
const match = current.match(markerPattern);
|
|
378
|
+
if (!match) {
|
|
379
|
+
warn(`Could not safely update Tailwind content globs in ${configPath}`);
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
const existingBlock = match[1];
|
|
383
|
+
const missingPatterns = contentPatterns.filter(
|
|
384
|
+
(pattern) => !existingBlock.includes(pattern)
|
|
385
|
+
);
|
|
386
|
+
if (!missingPatterns.length) {
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
const insertion = missingPatterns.map((pattern) => ` "${pattern}",`).join("\n");
|
|
390
|
+
const replacement = `content: [
|
|
391
|
+
${existingBlock.trimEnd()}
|
|
392
|
+
${insertion}
|
|
393
|
+
]`;
|
|
394
|
+
const updated = current.replace(markerPattern, replacement);
|
|
395
|
+
writeFileSync2(configPath, updated, "utf8");
|
|
396
|
+
info(`Updated Tailwind content globs in ${configPath}`);
|
|
397
|
+
}
|
|
398
|
+
function buildTailwindConfigSource({
|
|
399
|
+
isEsmProject,
|
|
400
|
+
contentPatterns
|
|
401
|
+
}) {
|
|
402
|
+
const lines = contentPatterns.map((pattern) => ` "${pattern}",`).join("\n");
|
|
403
|
+
if (isEsmProject) {
|
|
404
|
+
return `/** @type {import("tailwindcss").Config} */
|
|
405
|
+
export default {
|
|
406
|
+
content: [
|
|
407
|
+
${lines}
|
|
408
|
+
],
|
|
409
|
+
theme: {
|
|
410
|
+
extend: {},
|
|
411
|
+
},
|
|
412
|
+
plugins: [],
|
|
413
|
+
};
|
|
414
|
+
`;
|
|
415
|
+
}
|
|
416
|
+
return `/** @type {import("tailwindcss").Config} */
|
|
417
|
+
module.exports = {
|
|
418
|
+
content: [
|
|
419
|
+
${lines}
|
|
420
|
+
],
|
|
421
|
+
theme: {
|
|
422
|
+
extend: {},
|
|
423
|
+
},
|
|
424
|
+
plugins: [],
|
|
425
|
+
};
|
|
426
|
+
`;
|
|
427
|
+
}
|
|
428
|
+
function ensurePostcssConfig({
|
|
429
|
+
cwd,
|
|
430
|
+
isEsmProject
|
|
431
|
+
}) {
|
|
432
|
+
const configPath = path4.join(cwd, "postcss.config.js");
|
|
433
|
+
if (existsSync4(configPath)) {
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
436
|
+
const content = isEsmProject ? `export default {
|
|
437
|
+
plugins: {
|
|
438
|
+
tailwindcss: {},
|
|
439
|
+
autoprefixer: {},
|
|
440
|
+
},
|
|
441
|
+
};
|
|
442
|
+
` : `module.exports = {
|
|
443
|
+
plugins: {
|
|
444
|
+
tailwindcss: {},
|
|
445
|
+
autoprefixer: {},
|
|
446
|
+
},
|
|
447
|
+
};
|
|
448
|
+
`;
|
|
449
|
+
writeFileSync2(configPath, content, "utf8");
|
|
182
450
|
info(`Created ${configPath}`);
|
|
183
|
-
|
|
451
|
+
}
|
|
452
|
+
function ensureUiscoreStylesFile({
|
|
453
|
+
cwd,
|
|
454
|
+
stylesPath
|
|
455
|
+
}) {
|
|
456
|
+
const outputPath = path4.join(cwd, stylesPath);
|
|
457
|
+
const fontImport = '@import url("https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@500;600;700&display=swap");';
|
|
458
|
+
const markerStart = "/* uiscore:tokens:start */";
|
|
459
|
+
const markerEnd = "/* uiscore:tokens:end */";
|
|
460
|
+
if (!existsSync4(outputPath)) {
|
|
461
|
+
writeFileSync2(
|
|
462
|
+
outputPath,
|
|
463
|
+
`${fontImport}
|
|
464
|
+
|
|
465
|
+
${markerStart}
|
|
466
|
+
:root {
|
|
467
|
+
}
|
|
468
|
+
${markerEnd}
|
|
469
|
+
`,
|
|
470
|
+
"utf8"
|
|
471
|
+
);
|
|
472
|
+
info(`Created ${outputPath}`);
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
let current = readFileSync3(outputPath, "utf8");
|
|
476
|
+
if (!current.includes(fontImport)) {
|
|
477
|
+
current = `${fontImport}
|
|
478
|
+
|
|
479
|
+
${current.trimStart()}`;
|
|
480
|
+
}
|
|
481
|
+
if (!current.includes(markerStart) || !current.includes(markerEnd)) {
|
|
482
|
+
current = `${current.trimEnd()}
|
|
483
|
+
|
|
484
|
+
${markerStart}
|
|
485
|
+
:root {
|
|
486
|
+
}
|
|
487
|
+
${markerEnd}
|
|
488
|
+
`;
|
|
489
|
+
}
|
|
490
|
+
writeFileSync2(outputPath, `${current.trimEnd()}
|
|
491
|
+
`, "utf8");
|
|
492
|
+
}
|
|
493
|
+
function ensureGlobalCssFile({
|
|
494
|
+
cwd,
|
|
495
|
+
environment
|
|
496
|
+
}) {
|
|
497
|
+
const candidates = environment.type === "next" ? [path4.join(cwd, "src", "app", "globals.css"), path4.join(cwd, "app", "globals.css")] : [path4.join(cwd, "src", "index.css")];
|
|
498
|
+
for (const candidate of candidates) {
|
|
499
|
+
if (existsSync4(candidate)) {
|
|
500
|
+
return candidate;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
const fallbackPath = environment.type === "next" ? candidates.find((candidate) => candidate.includes(path4.join("src", "app"))) ?? candidates[0] : path4.join(cwd, "src", "index.css");
|
|
504
|
+
ensureDirectory(path4.dirname(fallbackPath));
|
|
505
|
+
writeFileSync2(fallbackPath, "", "utf8");
|
|
506
|
+
info(`Created ${fallbackPath}`);
|
|
507
|
+
return fallbackPath;
|
|
508
|
+
}
|
|
509
|
+
function ensureGlobalCssContent({
|
|
510
|
+
globalCssPath,
|
|
511
|
+
stylesPath
|
|
512
|
+
}) {
|
|
513
|
+
const stylesImportPath = toCssRelativeImport(globalCssPath, stylesPath);
|
|
514
|
+
const stylesBlock = `/* uiscore:styles:start */
|
|
515
|
+
@import "${stylesImportPath}";
|
|
516
|
+
/* uiscore:styles:end */`;
|
|
517
|
+
const tailwindBlock = `/* uiscore:tailwind:start */
|
|
518
|
+
@tailwind base;
|
|
519
|
+
@tailwind components;
|
|
520
|
+
@tailwind utilities;
|
|
521
|
+
/* uiscore:tailwind:end */`;
|
|
522
|
+
const current = existsSync4(globalCssPath) ? readFileSync3(globalCssPath, "utf8") : "";
|
|
523
|
+
const withoutManagedBlocks = current.replace(
|
|
524
|
+
/\/\* uiscore:styles:start \*\/[\s\S]*?\/\* uiscore:styles:end \*\/\s*/gm,
|
|
525
|
+
""
|
|
526
|
+
).replace(
|
|
527
|
+
/\/\* uiscore:tailwind:start \*\/[\s\S]*?\/\* uiscore:tailwind:end \*\/\s*/gm,
|
|
528
|
+
""
|
|
529
|
+
).trimStart();
|
|
530
|
+
const updated = `${stylesBlock}
|
|
531
|
+
|
|
532
|
+
${tailwindBlock}${withoutManagedBlocks ? `
|
|
533
|
+
|
|
534
|
+
${withoutManagedBlocks}` : ""}`;
|
|
535
|
+
writeFileSync2(globalCssPath, `${updated.trimEnd()}
|
|
536
|
+
`, "utf8");
|
|
537
|
+
}
|
|
538
|
+
function ensureEntryImportsGlobalCss({
|
|
539
|
+
cwd,
|
|
540
|
+
environment,
|
|
541
|
+
globalCssPath
|
|
542
|
+
}) {
|
|
543
|
+
if (environment.type === "vite") {
|
|
544
|
+
ensureImportInCodeFile({
|
|
545
|
+
filePath: environment.mainPath,
|
|
546
|
+
importPath: toCodeRelativeImport(environment.mainPath, globalCssPath)
|
|
547
|
+
});
|
|
548
|
+
return;
|
|
549
|
+
}
|
|
550
|
+
if (environment.type === "next") {
|
|
551
|
+
ensureImportInCodeFile({
|
|
552
|
+
filePath: environment.layoutPath,
|
|
553
|
+
importPath: toCodeRelativeImport(environment.layoutPath, globalCssPath)
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
function ensureImportInCodeFile({
|
|
558
|
+
filePath,
|
|
559
|
+
importPath
|
|
560
|
+
}) {
|
|
561
|
+
const source = readFileSync3(filePath, "utf8");
|
|
562
|
+
const normalizedImport = normalizeImportPath(importPath);
|
|
563
|
+
const importStatement = `import "${normalizedImport}";`;
|
|
564
|
+
const importPattern = new RegExp(
|
|
565
|
+
`^\\s*import\\s+["']${escapeForRegExp2(normalizedImport)}["'];?\\s*$`,
|
|
566
|
+
"m"
|
|
567
|
+
);
|
|
568
|
+
const allImportPattern = new RegExp(
|
|
569
|
+
`^\\s*import\\s+["']${escapeForRegExp2(normalizedImport)}["'];?\\s*$\\n?`,
|
|
570
|
+
"gm"
|
|
571
|
+
);
|
|
572
|
+
if (!importPattern.test(source)) {
|
|
573
|
+
writeFileSync2(filePath, `${importStatement}
|
|
574
|
+
${source}`, "utf8");
|
|
575
|
+
return;
|
|
576
|
+
}
|
|
577
|
+
const withoutDuplicateImports = source.replace(allImportPattern, "");
|
|
578
|
+
writeFileSync2(filePath, `${importStatement}
|
|
579
|
+
${withoutDuplicateImports}`, "utf8");
|
|
580
|
+
}
|
|
581
|
+
function ensureDirectory(directoryPath) {
|
|
582
|
+
mkdirSync2(directoryPath, { recursive: true });
|
|
583
|
+
}
|
|
584
|
+
function toCssRelativeImport(fromFile, toFile) {
|
|
585
|
+
return normalizeImportPath(path4.relative(path4.dirname(fromFile), toFile));
|
|
586
|
+
}
|
|
587
|
+
function toCodeRelativeImport(fromFile, toFile) {
|
|
588
|
+
return normalizeImportPath(path4.relative(path4.dirname(fromFile), toFile));
|
|
589
|
+
}
|
|
590
|
+
function normalizeImportPath(value) {
|
|
591
|
+
const normalized = value.split(path4.sep).join("/");
|
|
592
|
+
if (normalized.startsWith(".")) {
|
|
593
|
+
return normalized;
|
|
594
|
+
}
|
|
595
|
+
return `./${normalized}`;
|
|
596
|
+
}
|
|
597
|
+
function normalizeForGlob(value) {
|
|
598
|
+
return value.split(path4.sep).join("/");
|
|
599
|
+
}
|
|
600
|
+
function escapeForRegExp2(value) {
|
|
601
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
184
602
|
}
|
|
185
603
|
|
|
186
604
|
// src/index.ts
|