@unocss/cli 66.5.11 → 66.6.0-beta.1

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/dist/cli.mjs CHANGED
@@ -1,25 +1,21 @@
1
- import { i as version, r as handleError, t as build } from "./src-gL19Lj2z.mjs";
1
+ import { n as handleError, r as version, t as build } from "./src-DuVJx9sa.mjs";
2
2
  import process from "node:process";
3
- import { loadConfig } from "@unocss/config";
4
- import { toArray } from "@unocss/core";
3
+ import { green } from "colorette";
4
+ import { resolve } from "pathe";
5
5
  import { cac } from "cac";
6
6
 
7
7
  //#region src/cli-start.ts
8
8
  async function startCli(cwd = process.cwd(), argv = process.argv, options = {}) {
9
9
  const cli = cac("unocss");
10
- cli.command("[...patterns]", "Glob patterns", { ignoreOptionDefaultValue: true }).option("-o, --out-file <file>", "Output file", { default: cwd }).option("--stdout", "Output to STDOUT", { default: false }).option("-c, --config [file]", "Config file").option("-w, --watch", "Watch for file changes").option("--write-transformed", "Update source files with transformed utilities", { default: false }).option("--preflights", "Enable preflights", { default: true }).option("-m, --minify", "Minify generated CSS", { default: false }).action(async (patterns, flags) => {
11
- var _config$cli;
10
+ cli.command("[...patterns]", "Glob patterns", { ignoreOptionDefaultValue: true }).option("-o, --out-file <file>", "Output file", { default: resolve(cwd, "uno.css") }).option("--stdout", "Output to STDOUT", { default: false }).option("-c, --config [file]", "Config file").option("-w, --watch", "Watch for file changes").option("--rewrite", "Update source files with transformed utilities", { default: false }).option("--write-transformed", "Update source files with transformed utilities (deprecated, use --rewrite)", { default: false }).option("--preflights", "Enable preflights", { default: true }).option("-m, --minify", "Minify generated CSS", { default: false }).option("--debug", "Enable debug mode", { default: false }).option("--split-css [mode]", `Whether to output CSS files scanned from patterns to outFile. Options: ${green("true")}, ${green("false")}, ${green("multi")}, ${green("single")}`, { default: true }).option("--preset [default-preset]", `Switch ${green("wind3")} or ${green("wind4")} preset as default. If you have configured uno.config, this option will be ignored.`, { default: "wind4" }).action(async (patterns, flags) => {
12
11
  Object.assign(options, {
13
12
  cwd,
14
13
  ...flags
15
14
  });
15
+ if (String(options.splitCss) === "true") options.splitCss = true;
16
+ if (String(options.splitCss) === "false") options.splitCss = false;
16
17
  if (patterns) options.patterns = patterns;
17
- const { config } = await loadConfig(cwd, options.config);
18
- const entries = toArray(((_config$cli = config.cli) === null || _config$cli === void 0 ? void 0 : _config$cli.entry) || options);
19
- await Promise.all(entries.map((entry) => build({
20
- ...options,
21
- ...entry
22
- })));
18
+ await build(options);
23
19
  });
24
20
  cli.help();
25
21
  cli.version(version);
package/dist/index.d.mts CHANGED
@@ -1,21 +1,75 @@
1
+ import "@unocss/core";
2
+
1
3
  //#region src/types.d.ts
2
- /** Mark some properties as required, leaving others unchanged */
3
- declare type MarkRequired<T, RK extends keyof T> = Exclude<T, RK> & Required<Pick<T, RK>>;
4
- interface CliOptions {
4
+ interface CliGenericOptions {
5
+ /**
6
+ * Enable preflights
7
+ */
8
+ preflights?: boolean;
9
+ /**
10
+ * Minify generated CSS
11
+ */
12
+ minify?: boolean;
13
+ }
14
+ interface CliOptions extends CliGenericOptions {
15
+ /**
16
+ * Current working directory
17
+ *
18
+ * @default process.cwd()
19
+ */
5
20
  cwd?: string;
21
+ /**
22
+ * Glob patterns to scan for files
23
+ */
6
24
  patterns?: Array<string>;
25
+ /**
26
+ * Output file path
27
+ */
7
28
  outFile?: string;
29
+ /**
30
+ * Watch mode to rebuild on change
31
+ */
8
32
  watch?: boolean;
33
+ /**
34
+ * UnoCSS config file path
35
+ */
9
36
  config?: string;
37
+ /**
38
+ * Output to standard output
39
+ */
10
40
  stdout?: boolean;
41
+ /**
42
+ * Update source files with transformed utilities
43
+ */
44
+ rewrite?: boolean;
45
+ /**
46
+ * Update source files with transformed utilities (deprecated, use --rewrite)
47
+ *
48
+ * @deprecated use `rewrite` instead
49
+ */
11
50
  writeTransformed?: boolean;
12
- preflights?: boolean;
13
- minify?: boolean;
51
+ /**
52
+ * Enable debug mode
53
+ */
54
+ debug?: boolean;
55
+ /**
56
+ * Whether to output CSS files scanned from patterns to outFile
57
+ *
58
+ * - false: Do not output CSS files
59
+ * - true: Transform and output scanned CSS file contents to outFile
60
+ * - 'multi': Output each CSS file separately with filename format `${originFile}-[hash]`
61
+ * - 'single': Merge multiple CSS files into one output file named `outFile-merged.css`
62
+ *
63
+ * @default false
64
+ */
65
+ splitCss?: boolean | 'multi' | 'single';
66
+ /**
67
+ * Switch wind3 or wind4 preset as default. If you have configured uno.config, this option will be ignored.
68
+ */
69
+ preset?: 'wind3' | 'wind4';
14
70
  }
15
- type ResolvedCliOptions = MarkRequired<CliOptions, 'patterns'>;
16
71
  //#endregion
17
72
  //#region src/index.d.ts
18
- declare function resolveOptions(options: CliOptions): Promise<ResolvedCliOptions>;
19
- declare function build(_options: CliOptions): Promise<void>;
73
+ declare function build(_options: CliOptions): Promise<void[] | undefined>;
20
74
  //#endregion
21
- export { build, resolveOptions };
75
+ export { build };
package/dist/index.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { n as resolveOptions, t as build } from "./src-gL19Lj2z.mjs";
1
+ import { t as build } from "./src-DuVJx9sa.mjs";
2
2
 
3
- export { build, resolveOptions };
3
+ export { build };
@@ -0,0 +1,490 @@
1
+ import { existsSync, promises } from "node:fs";
2
+ import process from "node:process";
3
+ import { createRecoveryConfigLoader } from "@unocss/config";
4
+ import { BetterMap, createGenerator, cssIdRE, toArray } from "@unocss/core";
5
+ import { createFilter } from "unplugin-utils";
6
+ import remapping from "@jridgewell/remapping";
7
+ import MagicString from "magic-string";
8
+ import { cyan, dim, green, yellow } from "colorette";
9
+ import consola, { consola as consola$1 } from "consola";
10
+ import { basename, dirname, normalize, relative, resolve } from "pathe";
11
+ import { debounce } from "perfect-debounce";
12
+ import { glob } from "tinyglobby";
13
+
14
+ //#region ../../virtual-shared/integration/src/constants.ts
15
+ const INCLUDE_COMMENT = "@unocss-include";
16
+ const IGNORE_COMMENT = "@unocss-ignore";
17
+ const CSS_PLACEHOLDER = "@unocss-placeholder";
18
+ const SKIP_START_COMMENT = "@unocss-skip-start";
19
+ const SKIP_END_COMMENT = "@unocss-skip-end";
20
+ const SKIP_COMMENT_RE = new RegExp(`(\/\/\\s*?${SKIP_START_COMMENT}\\s*?|\\/\\*\\s*?${SKIP_START_COMMENT}\\s*?\\*\\/|<!--\\s*?${SKIP_START_COMMENT}\\s*?-->)[\\s\\S]*?(\/\/\\s*?${SKIP_END_COMMENT}\\s*?|\\/\\*\\s*?${SKIP_END_COMMENT}\\s*?\\*\\/|<!--\\s*?${SKIP_END_COMMENT}\\s*?-->)`, "g");
21
+
22
+ //#endregion
23
+ //#region ../../virtual-shared/integration/src/defaults.ts
24
+ const defaultPipelineExclude = [cssIdRE];
25
+ const defaultPipelineInclude = [/\.(vue|svelte|[jt]sx|vine.ts|mdx?|astro|elm|php|phtml|marko|html)($|\?)/];
26
+
27
+ //#endregion
28
+ //#region ../../virtual-shared/integration/src/deprecation.ts
29
+ function deprecationCheck(config) {}
30
+
31
+ //#endregion
32
+ //#region ../../virtual-shared/integration/src/context.ts
33
+ function createContext(configOrPath, defaults = {}, extraConfigSources = [], resolveConfigResult = () => {}) {
34
+ let root = process.cwd();
35
+ let rawConfig = {};
36
+ let configFileList = [];
37
+ let uno;
38
+ const _uno = createGenerator(rawConfig, defaults).then((r) => {
39
+ uno = r;
40
+ return r;
41
+ });
42
+ let rollupFilter = createFilter(defaultPipelineInclude, defaultPipelineExclude, { resolve: typeof configOrPath === "string" ? configOrPath : root });
43
+ const invalidations = [];
44
+ const reloadListeners = [];
45
+ const modules = new BetterMap();
46
+ const tokens = /* @__PURE__ */ new Set();
47
+ const tasks = [];
48
+ const affectedModules = /* @__PURE__ */ new Set();
49
+ const loadConfig = createRecoveryConfigLoader();
50
+ let ready = reloadConfig();
51
+ async function reloadConfig() {
52
+ var _rawConfig$content, _rawConfig$content2, _rawConfig$content3;
53
+ await _uno;
54
+ const result = await loadConfig(root, configOrPath, extraConfigSources, defaults);
55
+ resolveConfigResult(result);
56
+ /* @__PURE__ */ deprecationCheck(result.config);
57
+ rawConfig = result.config;
58
+ configFileList = result.sources;
59
+ await uno.setConfig(rawConfig);
60
+ uno.config.envMode = "dev";
61
+ rollupFilter = ((_rawConfig$content = rawConfig.content) === null || _rawConfig$content === void 0 ? void 0 : _rawConfig$content.pipeline) === false ? () => false : createFilter(((_rawConfig$content2 = rawConfig.content) === null || _rawConfig$content2 === void 0 || (_rawConfig$content2 = _rawConfig$content2.pipeline) === null || _rawConfig$content2 === void 0 ? void 0 : _rawConfig$content2.include) || defaultPipelineInclude, ((_rawConfig$content3 = rawConfig.content) === null || _rawConfig$content3 === void 0 || (_rawConfig$content3 = _rawConfig$content3.pipeline) === null || _rawConfig$content3 === void 0 ? void 0 : _rawConfig$content3.exclude) || defaultPipelineExclude, { resolve: typeof configOrPath === "string" ? configOrPath : root });
62
+ tokens.clear();
63
+ await Promise.all(modules.map((code, id) => uno.applyExtractors(code.replace(SKIP_COMMENT_RE, ""), id, tokens)));
64
+ invalidate();
65
+ dispatchReload();
66
+ return result;
67
+ }
68
+ async function updateRoot(newRoot) {
69
+ if (newRoot !== root) {
70
+ root = newRoot;
71
+ ready = reloadConfig();
72
+ }
73
+ return await ready;
74
+ }
75
+ function invalidate() {
76
+ invalidations.forEach((cb) => cb());
77
+ }
78
+ function dispatchReload() {
79
+ reloadListeners.forEach((cb) => cb());
80
+ }
81
+ async function extract(code, id) {
82
+ const uno$1 = await _uno;
83
+ if (id) modules.set(id, code);
84
+ const len = tokens.size;
85
+ await uno$1.applyExtractors(code.replace(SKIP_COMMENT_RE, ""), id, tokens);
86
+ if (tokens.size > len) invalidate();
87
+ }
88
+ function filter(code, id) {
89
+ if (code.includes(IGNORE_COMMENT)) return false;
90
+ return code.includes(INCLUDE_COMMENT) || code.includes(CSS_PLACEHOLDER) || rollupFilter(id.replace(/\?v=\w+$/, ""));
91
+ }
92
+ async function getConfig() {
93
+ await ready;
94
+ return rawConfig;
95
+ }
96
+ async function flushTasks() {
97
+ const _tasks = [...tasks];
98
+ await Promise.all(_tasks);
99
+ if (tasks[0] === _tasks[0]) tasks.splice(0, _tasks.length);
100
+ }
101
+ /**
102
+ * Get regexes to match virtual module ids
103
+ */
104
+ const vmpCache = /* @__PURE__ */ new Map();
105
+ async function getVMPRegexes() {
106
+ const prefix = (await getConfig()).virtualModulePrefix || "__uno";
107
+ if (vmpCache.has(prefix)) return vmpCache.get(prefix);
108
+ const regexes = {
109
+ prefix,
110
+ RESOLVED_ID_WITH_QUERY_RE: /* @__PURE__ */ new RegExp(`[/\\\\]${prefix}(_.*?)?\\.css(\\?.*)?$`),
111
+ RESOLVED_ID_RE: /* @__PURE__ */ new RegExp(`[/\\\\]${prefix}(?:_(.*?))?\.css$`)
112
+ };
113
+ vmpCache.set(prefix, regexes);
114
+ return regexes;
115
+ }
116
+ return {
117
+ get ready() {
118
+ return ready;
119
+ },
120
+ tokens,
121
+ modules,
122
+ affectedModules,
123
+ tasks,
124
+ flushTasks,
125
+ invalidate,
126
+ onInvalidate(fn) {
127
+ invalidations.push(fn);
128
+ },
129
+ filter,
130
+ reloadConfig,
131
+ onReload(fn) {
132
+ reloadListeners.push(fn);
133
+ },
134
+ get uno() {
135
+ if (!uno) throw new Error("Run `await context.ready` before accessing `context.uno`");
136
+ return uno;
137
+ },
138
+ extract,
139
+ getConfig,
140
+ get root() {
141
+ return root;
142
+ },
143
+ updateRoot,
144
+ getConfigFileList: () => configFileList,
145
+ getVMPRegexes
146
+ };
147
+ }
148
+
149
+ //#endregion
150
+ //#region ../../virtual-shared/integration/src/utils.ts
151
+ function hash(str) {
152
+ let i;
153
+ let l;
154
+ let hval = 2166136261;
155
+ for (i = 0, l = str.length; i < l; i++) {
156
+ hval ^= str.charCodeAt(i);
157
+ hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
158
+ }
159
+ return `00000${(hval >>> 0).toString(36)}`.slice(-6);
160
+ }
161
+ function transformSkipCode(code, map, SKIP_RULES_RE, keyFlag) {
162
+ for (const item of Array.from(code.matchAll(SKIP_RULES_RE))) if (item != null) {
163
+ const matched = item[0];
164
+ const withHashKey = `${keyFlag}${hash(matched)}`;
165
+ map.set(withHashKey, matched);
166
+ code = code.replace(matched, withHashKey);
167
+ }
168
+ return code;
169
+ }
170
+ function restoreSkipCode(code, map) {
171
+ for (const [withHashKey, matched] of map.entries()) code = code.replaceAll(withHashKey, matched);
172
+ return code;
173
+ }
174
+
175
+ //#endregion
176
+ //#region ../../virtual-shared/integration/src/transformers.ts
177
+ async function applyTransformers(ctx, original, id, enforce = "default") {
178
+ if (original.includes(IGNORE_COMMENT)) return;
179
+ const transformers = (ctx.uno.config.transformers || []).filter((i) => (i.enforce || "default") === enforce);
180
+ if (!transformers.length) return;
181
+ const skipMap = /* @__PURE__ */ new Map();
182
+ let code = original;
183
+ let s = new MagicString(transformSkipCode(code, skipMap, SKIP_COMMENT_RE, "@unocss-skip-placeholder-"));
184
+ const maps = [];
185
+ for (const t of transformers) {
186
+ if (t.idFilter) {
187
+ if (!t.idFilter(id)) continue;
188
+ } else if (!ctx.filter(code, id)) continue;
189
+ await t.transform(s, id, ctx);
190
+ if (s.hasChanged()) {
191
+ code = restoreSkipCode(s.toString(), skipMap);
192
+ maps.push(s.generateMap({
193
+ hires: true,
194
+ source: id
195
+ }));
196
+ s = new MagicString(code);
197
+ }
198
+ }
199
+ if (code !== original) return {
200
+ code,
201
+ map: remapping(maps, (_, ctx$1) => {
202
+ ctx$1.content = code;
203
+ return null;
204
+ })
205
+ };
206
+ }
207
+
208
+ //#endregion
209
+ //#region package.json
210
+ var version = "66.6.0-beta.1";
211
+
212
+ //#endregion
213
+ //#region src/debug.ts
214
+ /**
215
+ * generate and print a debug details table
216
+ *
217
+ * Example:
218
+ *
219
+ * File Generation Details:
220
+ * ---------------------+----------------------
221
+ * | Output File | Source Files (1) |
222
+ * ---------------------+----------------------
223
+ * | src/styles/uno.css | src/styles/mock.css |
224
+ * ---------------------+----------------------
225
+ */
226
+ function debugDetailsTable(options, outFile, files) {
227
+ const table = [["Output File", `Source Files (${files.length})`]];
228
+ files.forEach((f, i) => {
229
+ table.push([i === 0 ? relative(options.cwd, outFile) : "", relative(options.cwd, f.id)]);
230
+ });
231
+ const colWidths = table[0].map((_, colIndex) => Math.max(...table.map((row) => row[colIndex].length)));
232
+ const separator = colWidths.map((width) => "-".repeat(width + 3)).join("+");
233
+ consola.log(yellow("File Generation Details:"));
234
+ consola.log(separator);
235
+ for (const row of table) {
236
+ const rowStr = row.map((cell, index) => ` ${cell.padEnd(colWidths[index])} `).join("|");
237
+ consola.log(`|${rowStr}|`);
238
+ consola.log(separator);
239
+ }
240
+ }
241
+
242
+ //#endregion
243
+ //#region src/errors.ts
244
+ var PrettyError = class extends Error {
245
+ constructor(message) {
246
+ super(message);
247
+ this.name = this.constructor.name;
248
+ if (typeof Error.captureStackTrace === "function") Error.captureStackTrace(this, this.constructor);
249
+ else this.stack = new Error(message).stack;
250
+ }
251
+ };
252
+ function handleError(error) {
253
+ if (error instanceof PrettyError) consola$1.error(error.message);
254
+ process.exitCode = 1;
255
+ }
256
+
257
+ //#endregion
258
+ //#region src/watcher.ts
259
+ let watcher;
260
+ async function getWatcher(options) {
261
+ if (watcher && !options) return watcher;
262
+ if (!options) return { close: () => {} };
263
+ const { watch } = await import("chokidar");
264
+ const ignored = ["**/{.git,node_modules}/**"];
265
+ const cwd = (options === null || options === void 0 ? void 0 : options.cwd) || process.cwd();
266
+ const newWatcher = watch((options === null || options === void 0 ? void 0 : options.patterns).map((p) => {
267
+ const abs = resolve(cwd, p);
268
+ if (abs.endsWith("/**/*")) return abs.slice(0, -5);
269
+ return abs;
270
+ }), {
271
+ ignoreInitial: false,
272
+ ignorePermissionErrors: true,
273
+ ignored,
274
+ usePolling: true,
275
+ interval: 100
276
+ });
277
+ watcher = newWatcher;
278
+ return newWatcher;
279
+ }
280
+
281
+ //#endregion
282
+ //#region src/index.ts
283
+ async function resolveOptions(options, userConfig) {
284
+ var _options$patterns, _userConfig$cli;
285
+ const resolvedOptions = {
286
+ ...options,
287
+ entries: [],
288
+ debug: options.debug || false
289
+ };
290
+ if ((_options$patterns = options.patterns) === null || _options$patterns === void 0 ? void 0 : _options$patterns.length) resolvedOptions.entries.push({
291
+ patterns: options.patterns,
292
+ outFile: options.outFile ?? resolve(options.cwd, "uno.css"),
293
+ rewrite: (options.rewrite || options.writeTransformed) ?? false,
294
+ splitCss: options.splitCss ?? true
295
+ });
296
+ const configEntries = toArray(((_userConfig$cli = userConfig.cli) === null || _userConfig$cli === void 0 ? void 0 : _userConfig$cli.entry) || []).map((entry) => ({
297
+ ...entry,
298
+ rewrite: entry.rewrite !== void 0 ? entry.rewrite : (options.rewrite || options.writeTransformed) ?? false,
299
+ splitCss: entry.splitCss !== void 0 ? entry.splitCss : options.splitCss ?? true
300
+ }));
301
+ resolvedOptions.entries.push(...configEntries);
302
+ if (!resolvedOptions.entries.length) throw new PrettyError(`No glob patterns provided. Try ${cyan("unocss <path/to/**/*>")} or configure entries in ${cyan("uno.config")} file. See ${cyan("https://unocss.dev/integrations/cli#configurations")}`);
303
+ if (resolvedOptions.writeTransformed) consola$1.warn(`--write-transformed is deprecated, please use ${yellow("--rewrite")} instead.`);
304
+ return resolvedOptions;
305
+ }
306
+ async function initializeConfig(options) {
307
+ const { cwd = process.cwd(), config: configPath, preset } = options;
308
+ const ctx = createContext(configPath);
309
+ if (!(await ctx.updateRoot(cwd)).sources.map(normalize).length) {
310
+ const defaultPresets = {
311
+ wind3: import("@unocss/preset-wind3").then((m) => m.default),
312
+ wind4: import("@unocss/preset-wind4").then((m) => m.default)
313
+ };
314
+ if (preset && preset in defaultPresets) await ctx.uno.setConfig({
315
+ presets: [await defaultPresets[preset]],
316
+ transformers: [(await import("@unocss/transformer-directives").then((m) => m.default))()]
317
+ });
318
+ }
319
+ return {
320
+ ctx,
321
+ config: ctx.uno.config
322
+ };
323
+ }
324
+ async function parseEntries(options, cache) {
325
+ const newCache = /* @__PURE__ */ new Map();
326
+ for (const entry of options.entries) {
327
+ const { outFile, rewrite } = entry;
328
+ const files = await glob(entry.patterns, {
329
+ cwd: options.cwd,
330
+ absolute: true,
331
+ expandDirectories: false
332
+ });
333
+ const cssFiles = files.filter((f) => f.endsWith(".css")).filter((f) => f !== resolve(options.cwd, outFile));
334
+ const otherFiles = files.filter((f) => !f.endsWith(".css"));
335
+ const singleKey = outFile.replace(/(\.css)?$/, "-merged.css");
336
+ const addToCache = (file, code, key) => {
337
+ const existing = newCache.get(key) || [];
338
+ existing.push({
339
+ id: file,
340
+ code,
341
+ rewrite
342
+ });
343
+ newCache.set(key, existing);
344
+ };
345
+ for (const file of otherFiles) addToCache(file, await promises.readFile(file, "utf-8"), outFile);
346
+ for (const file of cssFiles) {
347
+ const code = await promises.readFile(file, "utf-8");
348
+ if (entry.splitCss === true) addToCache(file, code, outFile);
349
+ else if (entry.splitCss === "single") addToCache(file, code, singleKey);
350
+ else if (entry.splitCss === "multi") {
351
+ const fileHash = hash(file);
352
+ const currentOutFile = file.replace(/(\.css)?$/, `-${fileHash}.css`);
353
+ addToCache(file, code, files.length > 1 ? currentOutFile : outFile);
354
+ }
355
+ }
356
+ }
357
+ cache.clear();
358
+ for (const [key, value] of newCache) cache.set(key, value);
359
+ }
360
+ async function build(_options) {
361
+ _options.cwd ?? (_options.cwd = process.cwd());
362
+ /**
363
+ * Cache of files to process
364
+ *
365
+ * key: output file path
366
+ *
367
+ * value: array of source files with their code
368
+ */
369
+ const fileCache = /* @__PURE__ */ new Map();
370
+ const configResult = await initializeConfig(_options);
371
+ const options = await resolveOptions(_options, configResult.config);
372
+ options.ctx = configResult.ctx;
373
+ if (options.stdout && options.outFile) {
374
+ consola$1.fatal(`Cannot use --stdout and --out-file at the same time`);
375
+ return;
376
+ }
377
+ consola$1.log(green(`UnoCSS v${version}`));
378
+ if (options.watch) consola$1.start(`UnoCSS in watch mode...`);
379
+ else consola$1.start(`UnoCSS for production...`);
380
+ await parseEntries(options, fileCache);
381
+ if (fileCache.size === 0) {
382
+ consola$1.warn("No files matched the provided patterns.");
383
+ return;
384
+ }
385
+ if (!options.watch) return await generate(options);
386
+ const debouncedBuild = debounce(async () => {
387
+ generate(options).catch(handleError);
388
+ }, 100);
389
+ await startWatcher().catch(handleError);
390
+ async function generate(options$1) {
391
+ return Promise.all(Array.from(fileCache.entries()).map(([outFile, entries]) => generateSingle(options$1, outFile, entries)));
392
+ }
393
+ async function startWatcher() {
394
+ if (!options.watch) return;
395
+ const { ctx } = options;
396
+ const watcher$1 = await getWatcher(options);
397
+ const watchedFiles = [...fileCache.values().flatMap((files) => files.map((f) => f.id)), ...ctx.getConfigFileList()];
398
+ watcher$1.add(watchedFiles);
399
+ watcher$1.on("all", async (type, file) => {
400
+ const absolutePath = resolve(options.cwd, file);
401
+ if (type === "addDir" || type === "unlinkDir") return;
402
+ if (ctx.getConfigFileList().map(normalize).includes(absolutePath)) {
403
+ await ctx.reloadConfig();
404
+ const newOtions = await resolveOptions(_options, ctx.uno.config);
405
+ Object.assign(options, newOtions);
406
+ await parseEntries(options, fileCache);
407
+ const configSources = ctx.getConfigFileList().map(normalize);
408
+ if (configSources.length) watcher$1.add(configSources);
409
+ if (type === "change") consola$1.info(`${cyan(basename(file))} changed, setting new config`);
410
+ consola$1.info(`Watching for changes in ${[...options.entries.flatMap((i) => i.patterns), ...configSources].map(cyan).join(", ")}`);
411
+ } else if (type === "change") {
412
+ consola$1.log(`${green(type)} ${dim(file)}`);
413
+ const content = await promises.readFile(absolutePath, "utf8");
414
+ if (fileCache.keys().find((outfile) => outfile === absolutePath)) return;
415
+ for (const [, files] of fileCache.entries()) {
416
+ const fileEntry = files.find((f) => f.id === absolutePath);
417
+ if (fileEntry) fileEntry.code = content;
418
+ }
419
+ } else if (type === "unlink") {
420
+ consola$1.log(`${green(type)} ${dim(file)}`);
421
+ for (const [, files] of fileCache.entries()) {
422
+ const index = files.findIndex((f) => f.id === absolutePath);
423
+ if (index !== -1) files.splice(index, 1);
424
+ }
425
+ } else if (type === "add") {
426
+ consola$1.log(`${green(type)} ${dim(file)}`);
427
+ await parseEntries(options, fileCache);
428
+ }
429
+ debouncedBuild();
430
+ });
431
+ }
432
+ }
433
+ async function transformFiles(ctx, sources) {
434
+ const run = (sources$1, enforce) => Promise.all(sources$1.map((source) => new Promise((resolve$1) => {
435
+ applyTransformers(ctx, source.transformedCode ?? source.code, source.id, enforce).then((transformsRes) => {
436
+ resolve$1({
437
+ ...source,
438
+ transformedCode: (transformsRes === null || transformsRes === void 0 ? void 0 : transformsRes.code) ?? source.transformedCode
439
+ });
440
+ });
441
+ })));
442
+ return await run(await run(await run(sources, "pre"), "default"), "post");
443
+ }
444
+ async function generateSingle(options, outFile, files) {
445
+ const start = performance.now();
446
+ const { ctx } = options;
447
+ const transformedFiles = await transformFiles(ctx, files);
448
+ const tokens = /* @__PURE__ */ new Set();
449
+ const rewriter = [];
450
+ const css = [];
451
+ let matchedLen = 0;
452
+ for (const file of transformedFiles) {
453
+ const input = (file.transformedCode || file.code).replace(SKIP_COMMENT_RE, "");
454
+ if (!input) continue;
455
+ if (file.id.endsWith(".css")) css.push(process.env.CI || process.env.VITEST ? input : `/* Source: ${file.id} */\n${input}`.trim());
456
+ else (await ctx.uno.generate(input, {
457
+ preflights: false,
458
+ minify: true,
459
+ id: file.id
460
+ })).matched.forEach((i) => tokens.add(i));
461
+ if (file.rewrite && file.transformedCode) rewriter.push(promises.writeFile(file.id, file.transformedCode, "utf-8"));
462
+ }
463
+ await Promise.all(rewriter);
464
+ if (tokens.size > 0) {
465
+ const result = await ctx.uno.generate(tokens, {
466
+ preflights: options.preflights,
467
+ minify: options.minify
468
+ });
469
+ css.push(result.css);
470
+ matchedLen = result.matched.size;
471
+ }
472
+ const finalCss = css.join("\n");
473
+ if (options.stdout) {
474
+ process.stdout.write(finalCss);
475
+ return;
476
+ }
477
+ if (options.debug) debugDetailsTable(options, outFile, files);
478
+ const outFileResolved = resolve(options.cwd, outFile);
479
+ const dir = dirname(outFileResolved);
480
+ if (!existsSync(dir)) await promises.mkdir(dir, { recursive: true });
481
+ await promises.writeFile(outFileResolved, finalCss, "utf-8");
482
+ if (!options.watch) {
483
+ const duration = (performance.now() - start).toFixed(2);
484
+ if (rewriter.length > 0) consola$1.success(`${rewriter.length} file${rewriter.length > 1 ? "s" : ""} rewritten in ${green(duration)}ms`);
485
+ if (matchedLen > 0) consola$1.success(`${matchedLen} utilities generated to ${cyan(relative(process.cwd(), outFileResolved))} in ${green(duration)}ms\n`);
486
+ }
487
+ }
488
+
489
+ //#endregion
490
+ export { handleError as n, version as r, build as t };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@unocss/cli",
3
3
  "type": "module",
4
- "version": "66.5.11",
4
+ "version": "66.6.0-beta.1",
5
5
  "description": "CLI for UnoCSS",
6
6
  "author": {
7
7
  "name": "Johann Schopplich",
@@ -50,9 +50,11 @@
50
50
  "perfect-debounce": "^2.0.0",
51
51
  "tinyglobby": "^0.2.15",
52
52
  "unplugin-utils": "^0.3.1",
53
- "@unocss/config": "66.5.11",
54
- "@unocss/core": "66.5.11",
55
- "@unocss/preset-uno": "66.5.11"
53
+ "@unocss/config": "66.6.0-beta.1",
54
+ "@unocss/core": "66.6.0-beta.1",
55
+ "@unocss/preset-wind3": "66.6.0-beta.1",
56
+ "@unocss/preset-wind4": "66.6.0-beta.1",
57
+ "@unocss/transformer-directives": "66.6.0-beta.1"
56
58
  },
57
59
  "scripts": {
58
60
  "build": "tsdown --config-loader unrun",
@@ -1,364 +0,0 @@
1
- import { existsSync, promises } from "node:fs";
2
- import process from "node:process";
3
- import { createRecoveryConfigLoader } from "@unocss/config";
4
- import { BetterMap, createGenerator, cssIdRE, toArray } from "@unocss/core";
5
- import { createFilter } from "unplugin-utils";
6
- import remapping from "@jridgewell/remapping";
7
- import MagicString from "magic-string";
8
- import { cyan, dim, green } from "colorette";
9
- import { consola } from "consola";
10
- import { basename, dirname, normalize, relative, resolve } from "pathe";
11
- import { debounce } from "perfect-debounce";
12
- import { glob } from "tinyglobby";
13
- import presetUno from "@unocss/preset-uno";
14
-
15
- //#region ../../virtual-shared/integration/src/constants.ts
16
- const INCLUDE_COMMENT = "@unocss-include";
17
- const IGNORE_COMMENT = "@unocss-ignore";
18
- const CSS_PLACEHOLDER = "@unocss-placeholder";
19
- const SKIP_START_COMMENT = "@unocss-skip-start";
20
- const SKIP_END_COMMENT = "@unocss-skip-end";
21
- const SKIP_COMMENT_RE = new RegExp(`(\/\/\\s*?${SKIP_START_COMMENT}\\s*?|\\/\\*\\s*?${SKIP_START_COMMENT}\\s*?\\*\\/|<!--\\s*?${SKIP_START_COMMENT}\\s*?-->)[\\s\\S]*?(\/\/\\s*?${SKIP_END_COMMENT}\\s*?|\\/\\*\\s*?${SKIP_END_COMMENT}\\s*?\\*\\/|<!--\\s*?${SKIP_END_COMMENT}\\s*?-->)`, "g");
22
-
23
- //#endregion
24
- //#region ../../virtual-shared/integration/src/defaults.ts
25
- const defaultPipelineExclude = [cssIdRE];
26
- const defaultPipelineInclude = [/\.(vue|svelte|[jt]sx|vine.ts|mdx?|astro|elm|php|phtml|marko|html)($|\?)/];
27
-
28
- //#endregion
29
- //#region ../../virtual-shared/integration/src/deprecation.ts
30
- function deprecationCheck(config) {}
31
-
32
- //#endregion
33
- //#region ../../virtual-shared/integration/src/context.ts
34
- function createContext(configOrPath, defaults = {}, extraConfigSources = [], resolveConfigResult = () => {}) {
35
- let root = process.cwd();
36
- let rawConfig = {};
37
- let configFileList = [];
38
- let uno;
39
- const _uno = createGenerator(rawConfig, defaults).then((r) => {
40
- uno = r;
41
- return r;
42
- });
43
- let rollupFilter = createFilter(defaultPipelineInclude, defaultPipelineExclude, { resolve: typeof configOrPath === "string" ? configOrPath : root });
44
- const invalidations = [];
45
- const reloadListeners = [];
46
- const modules = new BetterMap();
47
- const tokens = /* @__PURE__ */ new Set();
48
- const tasks = [];
49
- const affectedModules = /* @__PURE__ */ new Set();
50
- const loadConfig$1 = createRecoveryConfigLoader();
51
- let ready = reloadConfig();
52
- async function reloadConfig() {
53
- var _rawConfig$content, _rawConfig$content2, _rawConfig$content3;
54
- await _uno;
55
- const result = await loadConfig$1(root, configOrPath, extraConfigSources, defaults);
56
- resolveConfigResult(result);
57
- /* @__PURE__ */ deprecationCheck(result.config);
58
- rawConfig = result.config;
59
- configFileList = result.sources;
60
- await uno.setConfig(rawConfig);
61
- uno.config.envMode = "dev";
62
- rollupFilter = ((_rawConfig$content = rawConfig.content) === null || _rawConfig$content === void 0 ? void 0 : _rawConfig$content.pipeline) === false ? () => false : createFilter(((_rawConfig$content2 = rawConfig.content) === null || _rawConfig$content2 === void 0 || (_rawConfig$content2 = _rawConfig$content2.pipeline) === null || _rawConfig$content2 === void 0 ? void 0 : _rawConfig$content2.include) || defaultPipelineInclude, ((_rawConfig$content3 = rawConfig.content) === null || _rawConfig$content3 === void 0 || (_rawConfig$content3 = _rawConfig$content3.pipeline) === null || _rawConfig$content3 === void 0 ? void 0 : _rawConfig$content3.exclude) || defaultPipelineExclude, { resolve: typeof configOrPath === "string" ? configOrPath : root });
63
- tokens.clear();
64
- await Promise.all(modules.map((code, id) => uno.applyExtractors(code.replace(SKIP_COMMENT_RE, ""), id, tokens)));
65
- invalidate();
66
- dispatchReload();
67
- return result;
68
- }
69
- async function updateRoot(newRoot) {
70
- if (newRoot !== root) {
71
- root = newRoot;
72
- ready = reloadConfig();
73
- }
74
- return await ready;
75
- }
76
- function invalidate() {
77
- invalidations.forEach((cb) => cb());
78
- }
79
- function dispatchReload() {
80
- reloadListeners.forEach((cb) => cb());
81
- }
82
- async function extract(code, id) {
83
- const uno$1 = await _uno;
84
- if (id) modules.set(id, code);
85
- const len = tokens.size;
86
- await uno$1.applyExtractors(code.replace(SKIP_COMMENT_RE, ""), id, tokens);
87
- if (tokens.size > len) invalidate();
88
- }
89
- function filter(code, id) {
90
- if (code.includes(IGNORE_COMMENT)) return false;
91
- return code.includes(INCLUDE_COMMENT) || code.includes(CSS_PLACEHOLDER) || rollupFilter(id.replace(/\?v=\w+$/, ""));
92
- }
93
- async function getConfig() {
94
- await ready;
95
- return rawConfig;
96
- }
97
- async function flushTasks() {
98
- const _tasks = [...tasks];
99
- await Promise.all(_tasks);
100
- if (tasks[0] === _tasks[0]) tasks.splice(0, _tasks.length);
101
- }
102
- /**
103
- * Get regexes to match virtual module ids
104
- */
105
- const vmpCache = /* @__PURE__ */ new Map();
106
- async function getVMPRegexes() {
107
- const prefix = (await getConfig()).virtualModulePrefix || "__uno";
108
- if (vmpCache.has(prefix)) return vmpCache.get(prefix);
109
- const regexes = {
110
- prefix,
111
- RESOLVED_ID_WITH_QUERY_RE: /* @__PURE__ */ new RegExp(`[/\\\\]${prefix}(_.*?)?\\.css(\\?.*)?$`),
112
- RESOLVED_ID_RE: /* @__PURE__ */ new RegExp(`[/\\\\]${prefix}(?:_(.*?))?\.css$`)
113
- };
114
- vmpCache.set(prefix, regexes);
115
- return regexes;
116
- }
117
- return {
118
- get ready() {
119
- return ready;
120
- },
121
- tokens,
122
- modules,
123
- affectedModules,
124
- tasks,
125
- flushTasks,
126
- invalidate,
127
- onInvalidate(fn) {
128
- invalidations.push(fn);
129
- },
130
- filter,
131
- reloadConfig,
132
- onReload(fn) {
133
- reloadListeners.push(fn);
134
- },
135
- get uno() {
136
- if (!uno) throw new Error("Run `await context.ready` before accessing `context.uno`");
137
- return uno;
138
- },
139
- extract,
140
- getConfig,
141
- get root() {
142
- return root;
143
- },
144
- updateRoot,
145
- getConfigFileList: () => configFileList,
146
- getVMPRegexes
147
- };
148
- }
149
-
150
- //#endregion
151
- //#region ../../virtual-shared/integration/src/utils.ts
152
- function hash(str) {
153
- let i;
154
- let l;
155
- let hval = 2166136261;
156
- for (i = 0, l = str.length; i < l; i++) {
157
- hval ^= str.charCodeAt(i);
158
- hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
159
- }
160
- return `00000${(hval >>> 0).toString(36)}`.slice(-6);
161
- }
162
- function transformSkipCode(code, map, SKIP_RULES_RE, keyFlag) {
163
- for (const item of Array.from(code.matchAll(SKIP_RULES_RE))) if (item != null) {
164
- const matched = item[0];
165
- const withHashKey = `${keyFlag}${hash(matched)}`;
166
- map.set(withHashKey, matched);
167
- code = code.replace(matched, withHashKey);
168
- }
169
- return code;
170
- }
171
- function restoreSkipCode(code, map) {
172
- for (const [withHashKey, matched] of map.entries()) code = code.replaceAll(withHashKey, matched);
173
- return code;
174
- }
175
-
176
- //#endregion
177
- //#region ../../virtual-shared/integration/src/transformers.ts
178
- async function applyTransformers(ctx, original, id, enforce = "default") {
179
- if (original.includes(IGNORE_COMMENT)) return;
180
- const transformers = (ctx.uno.config.transformers || []).filter((i) => (i.enforce || "default") === enforce);
181
- if (!transformers.length) return;
182
- const skipMap = /* @__PURE__ */ new Map();
183
- let code = original;
184
- let s = new MagicString(transformSkipCode(code, skipMap, SKIP_COMMENT_RE, "@unocss-skip-placeholder-"));
185
- const maps = [];
186
- for (const t of transformers) {
187
- if (t.idFilter) {
188
- if (!t.idFilter(id)) continue;
189
- } else if (!ctx.filter(code, id)) continue;
190
- await t.transform(s, id, ctx);
191
- if (s.hasChanged()) {
192
- code = restoreSkipCode(s.toString(), skipMap);
193
- maps.push(s.generateMap({
194
- hires: true,
195
- source: id
196
- }));
197
- s = new MagicString(code);
198
- }
199
- }
200
- if (code !== original) return {
201
- code,
202
- map: remapping(maps, (_, ctx$1) => {
203
- ctx$1.content = code;
204
- return null;
205
- })
206
- };
207
- }
208
-
209
- //#endregion
210
- //#region package.json
211
- var version = "66.5.11";
212
-
213
- //#endregion
214
- //#region src/config.ts
215
- const defaultConfig = {
216
- envMode: "build",
217
- presets: [presetUno()]
218
- };
219
-
220
- //#endregion
221
- //#region src/errors.ts
222
- var PrettyError = class extends Error {
223
- constructor(message) {
224
- super(message);
225
- this.name = this.constructor.name;
226
- if (typeof Error.captureStackTrace === "function") Error.captureStackTrace(this, this.constructor);
227
- else this.stack = new Error(message).stack;
228
- }
229
- };
230
- function handleError(error) {
231
- if (error instanceof PrettyError) consola.error(error.message);
232
- process.exitCode = 1;
233
- }
234
-
235
- //#endregion
236
- //#region src/watcher.ts
237
- let watcher;
238
- async function getWatcher(options) {
239
- if (watcher && !options) return watcher;
240
- const { watch } = await import("chokidar");
241
- const ignored = ["**/{.git,node_modules}/**"];
242
- const cwd = (options === null || options === void 0 ? void 0 : options.cwd) || process.cwd();
243
- const newWatcher = watch((options === null || options === void 0 ? void 0 : options.patterns).map((p) => {
244
- const abs = resolve(cwd, p);
245
- if (abs.endsWith("/**/*")) return abs.slice(0, -5);
246
- return abs;
247
- }), {
248
- ignoreInitial: false,
249
- ignorePermissionErrors: true,
250
- ignored,
251
- usePolling: true,
252
- interval: 100
253
- });
254
- watcher = newWatcher;
255
- return newWatcher;
256
- }
257
-
258
- //#endregion
259
- //#region src/index.ts
260
- const name = "unocss";
261
- async function resolveOptions(options) {
262
- var _options$patterns;
263
- if (!((_options$patterns = options.patterns) === null || _options$patterns === void 0 ? void 0 : _options$patterns.length)) throw new PrettyError(`No glob patterns, try ${cyan(`${name} <path/to/**/*>`)}`);
264
- return options;
265
- }
266
- async function build(_options) {
267
- const fileCache = /* @__PURE__ */ new Map();
268
- const cwd = _options.cwd || process.cwd();
269
- const options = await resolveOptions(_options);
270
- async function loadConfig$1() {
271
- const ctx$1 = createContext(options.config, defaultConfig);
272
- return {
273
- ctx: ctx$1,
274
- configSources: (await ctx$1.updateRoot(cwd)).sources.map((i) => normalize(i))
275
- };
276
- }
277
- const { ctx, configSources } = await loadConfig$1();
278
- const files = await glob(options.patterns, {
279
- cwd,
280
- absolute: true,
281
- expandDirectories: false
282
- });
283
- await Promise.all(files.map(async (file) => {
284
- fileCache.set(file, await promises.readFile(file, "utf8"));
285
- }));
286
- if (options.stdout && options.outFile) {
287
- consola.fatal(`Cannot use --stdout and --out-file at the same time`);
288
- return;
289
- }
290
- consola.log(green(`${name} v${version}`));
291
- if (options.watch) consola.start("UnoCSS in watch mode...");
292
- else consola.start("UnoCSS for production...");
293
- const debouncedBuild = debounce(async () => {
294
- generate(options).catch(handleError);
295
- }, 100);
296
- const startWatcher = async () => {
297
- if (!options.watch) return;
298
- const { patterns } = options;
299
- const watcher$1 = await getWatcher(options);
300
- if (configSources.length) watcher$1.add(configSources);
301
- watcher$1.on("all", async (type, file) => {
302
- const absolutePath = resolve(cwd, file);
303
- if (type === "addDir" || type === "unlinkDir") return;
304
- if (configSources.includes(absolutePath)) {
305
- await ctx.reloadConfig();
306
- if (configSources.length) watcher$1.add(configSources);
307
- consola.info(`${cyan(basename(file))} changed, setting new config`);
308
- } else {
309
- consola.log(`${green(type)} ${dim(file)}`);
310
- if (type.startsWith("unlink")) fileCache.delete(absolutePath);
311
- else fileCache.set(absolutePath, await promises.readFile(absolutePath, "utf8"));
312
- }
313
- debouncedBuild();
314
- });
315
- consola.info(`Watching for changes in ${toArray(patterns).map((i) => cyan(i)).join(", ")}`);
316
- };
317
- await generate(options);
318
- await startWatcher().catch(handleError);
319
- function transformFiles(sources, enforce = "default") {
320
- return Promise.all(sources.map(({ id, code, transformedCode }) => new Promise((resolve$1) => {
321
- applyTransformers(ctx, code, id, enforce).then((transformsRes) => {
322
- resolve$1({
323
- id,
324
- code,
325
- transformedCode: (transformsRes === null || transformsRes === void 0 ? void 0 : transformsRes.code) || transformedCode
326
- });
327
- });
328
- })));
329
- }
330
- async function generate(options$1) {
331
- const afterPostTrans = await transformFiles(await transformFiles(await transformFiles(Array.from(fileCache).map(([id, code]) => ({
332
- id,
333
- code
334
- })), "pre")), "post");
335
- if (options$1.writeTransformed) await Promise.all(afterPostTrans.filter(({ transformedCode }) => !!transformedCode).map(async ({ transformedCode, id }) => {
336
- if (existsSync(id)) await promises.writeFile(id, transformedCode, "utf-8");
337
- }));
338
- const tokens = /* @__PURE__ */ new Set();
339
- for (const file of afterPostTrans) {
340
- const { matched: matched$1 } = await ctx.uno.generate((file.transformedCode || file.code).replace(SKIP_COMMENT_RE, ""), {
341
- preflights: false,
342
- minify: true,
343
- id: file.id
344
- });
345
- matched$1.forEach((i) => tokens.add(i));
346
- }
347
- const { css, matched } = await ctx.uno.generate(tokens, {
348
- preflights: options$1.preflights,
349
- minify: options$1.minify
350
- });
351
- if (options$1.stdout) {
352
- process.stdout.write(css);
353
- return;
354
- }
355
- const outFile = resolve(options$1.cwd || process.cwd(), options$1.outFile ?? "uno.css");
356
- const dir = dirname(outFile);
357
- if (!existsSync(dir)) await promises.mkdir(dir, { recursive: true });
358
- await promises.writeFile(outFile, css, "utf-8");
359
- if (!options$1.watch) consola.success(`${[...matched].length} utilities generated to ${cyan(relative(process.cwd(), outFile))}\n`);
360
- }
361
- }
362
-
363
- //#endregion
364
- export { version as i, resolveOptions as n, handleError as r, build as t };