@master/css-cli 2.0.0-rc.72 → 2.0.0-rc.74
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/LICENSE +21 -0
- package/dist/bin/index.js +6 -0
- package/dist/constants.js +4 -0
- package/dist/core.js +31 -0
- package/dist/scan.js +199 -0
- package/package.json +56 -1
- package/dist/bin/index.mjs +0 -4
- package/dist/core.mjs +0 -36
- package/dist/scan.mjs +0 -181
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Aoyue Design LLC.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
package/dist/core.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { DEFAULT_SCAN_OUTPUT } from "./constants.js";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { dirname, resolve } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { Command } from "commander";
|
|
6
|
+
//#region src/core.ts
|
|
7
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
const pkg = JSON.parse(readFileSync(resolve(__dirname, "../package.json"), "utf8"));
|
|
9
|
+
const removedCommands = /* @__PURE__ */ new Set([
|
|
10
|
+
"extract",
|
|
11
|
+
"render",
|
|
12
|
+
"scan"
|
|
13
|
+
]);
|
|
14
|
+
function errorRemovedCommand(program, command) {
|
|
15
|
+
program.error(`The "${command}" command was removed. Use "${pkg.name}" directly, for example "${pkg.name} -w".`);
|
|
16
|
+
}
|
|
17
|
+
async function runProgram(argv = process.argv) {
|
|
18
|
+
const program = new Command();
|
|
19
|
+
program.name(pkg.name).description(pkg.description).version(pkg.version || "0.0.0").argument("[source paths...]", "The glob pattern paths to scan sources").option("-w, --watch", "Watch file changes and generate CSS rules.").option("-o, --output <path>", "Specify your CSS file output path", DEFAULT_SCAN_OUTPUT).option("-v, --verbose <level>", "Verbose logging 0~N", "1").option("--no-export", "Print only CSS results.").action(async (sourcePaths, options) => {
|
|
20
|
+
const removedCommand = sourcePaths[0];
|
|
21
|
+
if (removedCommand && removedCommands.has(removedCommand)) errorRemovedCommand(program, removedCommand);
|
|
22
|
+
const { default: runScan } = await import("./scan.js");
|
|
23
|
+
return runScan(sourcePaths, options);
|
|
24
|
+
});
|
|
25
|
+
const firstArgument = argv[2];
|
|
26
|
+
if (firstArgument && removedCommands.has(firstArgument)) errorRemovedCommand(program, firstArgument);
|
|
27
|
+
await program.parseAsync(argv);
|
|
28
|
+
return program;
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
31
|
+
export { runProgram as default };
|
package/dist/scan.js
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { DEFAULT_SCAN_OUTPUT } from "./constants.js";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
//#region src/scan.ts
|
|
5
|
+
const DEFAULT_SOURCE_PATTERNS = ["**/*.{html,htm,js,jsx,cjs,ts,tsx,mts,cts,svelte,astro,vue,md,mdx,pug,php}"];
|
|
6
|
+
let scannerModulePromise;
|
|
7
|
+
let stylesheetModulePromise;
|
|
8
|
+
let projectEntriesModulePromise;
|
|
9
|
+
let fastGlobModulePromise;
|
|
10
|
+
let chokidarModulePromise;
|
|
11
|
+
let loggerPromise;
|
|
12
|
+
let bytesPromise;
|
|
13
|
+
async function registerManagedCSSEntries(scanner, styleCSSSources) {
|
|
14
|
+
const [{ registerStyleCSSSource }, { findCSSManifestEntryFiles }] = await Promise.all([loadStylesheetModule(), loadProjectEntriesModule()]);
|
|
15
|
+
styleCSSSources.clear();
|
|
16
|
+
for (const entry of await findCSSManifestEntryFiles(scanner.cwd)) await registerStyleCSSSource(scanner, styleCSSSources, entry, fs.readFileSync(entry, "utf8"), { projectDir: scanner.cwd });
|
|
17
|
+
scanner.resetDependencies = [...new Set(Array.from(styleCSSSources.values()).flatMap((source) => source.dependencies))];
|
|
18
|
+
}
|
|
19
|
+
function normalizeSourcePatterns(specifiedSourcePaths) {
|
|
20
|
+
return specifiedSourcePaths?.length ? specifiedSourcePaths : DEFAULT_SOURCE_PATTERNS;
|
|
21
|
+
}
|
|
22
|
+
function normalizeGlobPatterns(patterns) {
|
|
23
|
+
return patterns.map((pattern) => pattern.replace(/\\/g, "/"));
|
|
24
|
+
}
|
|
25
|
+
function resolveSourcePaths(scanner, fg, sourcePatterns, ignore = []) {
|
|
26
|
+
return fg.sync(normalizeGlobPatterns(sourcePatterns), {
|
|
27
|
+
cwd: scanner.cwd,
|
|
28
|
+
ignore: normalizeGlobPatterns(ignore)
|
|
29
|
+
}).filter(Boolean);
|
|
30
|
+
}
|
|
31
|
+
async function scanSourceFile(scanner, source) {
|
|
32
|
+
const filepath = path.resolve(scanner.cwd, source);
|
|
33
|
+
await scanner.scan(source, fs.readFileSync(filepath, "utf8"));
|
|
34
|
+
}
|
|
35
|
+
async function scanSourceFiles(scanner, sourcePaths) {
|
|
36
|
+
await Promise.all(sourcePaths.map((source) => scanSourceFile(scanner, source)));
|
|
37
|
+
}
|
|
38
|
+
async function prepareScanner(scanner, styleCSSSources, sourcePaths) {
|
|
39
|
+
await registerManagedCSSEntries(scanner, styleCSSSources);
|
|
40
|
+
await scanSourceFiles(scanner, sourcePaths);
|
|
41
|
+
}
|
|
42
|
+
async function exportCSS(scanner, css, filename = DEFAULT_SCAN_OUTPUT) {
|
|
43
|
+
const filepath = path.resolve(scanner.cwd, filename);
|
|
44
|
+
const dir = path.dirname(filepath);
|
|
45
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
46
|
+
fs.writeFileSync(filepath, css);
|
|
47
|
+
if (scanner.options.verbose) {
|
|
48
|
+
const [logger, bytes] = await Promise.all([loadLogger(), loadBytes()]);
|
|
49
|
+
logger.success(`${filename} exported ${bytes(css.length)}`);
|
|
50
|
+
}
|
|
51
|
+
scanner.emit("export", filename, filepath);
|
|
52
|
+
}
|
|
53
|
+
function formatWatchedPath(cwd, file) {
|
|
54
|
+
return path.isAbsolute(file) ? path.relative(cwd, file) : file;
|
|
55
|
+
}
|
|
56
|
+
async function waitForWatcherReady(watcher) {
|
|
57
|
+
await new Promise((resolve) => watcher.once("ready", resolve));
|
|
58
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
59
|
+
}
|
|
60
|
+
async function runScan(specifiedSourcePaths = [], options = {}) {
|
|
61
|
+
const pipelineModules = Promise.all([loadStylesheetModule(), loadProjectEntriesModule()]);
|
|
62
|
+
const [CSSScanner, fg] = await Promise.all([loadCSSScanner(), loadFastGlob()]);
|
|
63
|
+
const { watch, output, verbose, cwd } = options;
|
|
64
|
+
const scanner = new CSSScanner({}, cwd);
|
|
65
|
+
const styleCSSSources = /* @__PURE__ */ new Map();
|
|
66
|
+
const sourcePatterns = normalizeSourcePatterns(specifiedSourcePaths);
|
|
67
|
+
const writeOutput = async () => {
|
|
68
|
+
const { createExtractedCSS } = await loadStylesheetModule();
|
|
69
|
+
const css = await createExtractedCSS({
|
|
70
|
+
scanner,
|
|
71
|
+
styleCSSSources,
|
|
72
|
+
projectDir: scanner.cwd
|
|
73
|
+
});
|
|
74
|
+
if (options.export) await exportCSS(scanner, css, output);
|
|
75
|
+
else console.log(css);
|
|
76
|
+
};
|
|
77
|
+
scanner.on("init", (options) => {
|
|
78
|
+
if (!specifiedSourcePaths.length) {
|
|
79
|
+
if (!options.exclude?.includes("**/node_modules/**")) options.exclude?.push("**/node_modules/**");
|
|
80
|
+
if (!options.exclude?.includes("node_modules")) options.exclude?.push("node_modules");
|
|
81
|
+
}
|
|
82
|
+
options.verbose = verbose ? +verbose : options.verbose;
|
|
83
|
+
});
|
|
84
|
+
await scanner.init();
|
|
85
|
+
const scanPaths = () => resolveSourcePaths(scanner, fg, sourcePatterns, specifiedSourcePaths.length ? [] : scanner.options.exclude);
|
|
86
|
+
if (watch) {
|
|
87
|
+
const chokidar = await loadChokidar();
|
|
88
|
+
const watchers = [];
|
|
89
|
+
let restarting = false;
|
|
90
|
+
let writing = Promise.resolve();
|
|
91
|
+
const queueWrite = () => {
|
|
92
|
+
writing = writing.then(writeOutput);
|
|
93
|
+
return writing;
|
|
94
|
+
};
|
|
95
|
+
const closeWatchers = async () => {
|
|
96
|
+
await Promise.all(watchers.splice(0).map((watcher) => watcher.close()));
|
|
97
|
+
};
|
|
98
|
+
const startWatchers = async () => {
|
|
99
|
+
const sourcePaths = scanPaths();
|
|
100
|
+
if (sourcePaths.length) {
|
|
101
|
+
const sourceWatcher = chokidar.watch(sourcePaths, {
|
|
102
|
+
cwd: scanner.cwd,
|
|
103
|
+
ignoreInitial: true
|
|
104
|
+
});
|
|
105
|
+
sourceWatcher.on("add", (source) => {
|
|
106
|
+
scanSourceFile(scanner, source).then(queueWrite);
|
|
107
|
+
});
|
|
108
|
+
sourceWatcher.on("change", (source) => {
|
|
109
|
+
scanSourceFile(scanner, source).then(queueWrite);
|
|
110
|
+
});
|
|
111
|
+
watchers.push(sourceWatcher);
|
|
112
|
+
await waitForWatcherReady(sourceWatcher);
|
|
113
|
+
}
|
|
114
|
+
if (scanner.resetDependencies.length) {
|
|
115
|
+
const planWatcher = chokidar.watch(scanner.resetDependencies, { ignoreInitial: true });
|
|
116
|
+
const handlePlanChange = async (resetDependency) => {
|
|
117
|
+
if (restarting) return;
|
|
118
|
+
restarting = true;
|
|
119
|
+
try {
|
|
120
|
+
if (scanner.options.verbose) {
|
|
121
|
+
const logger = await loadLogger();
|
|
122
|
+
logger.log("");
|
|
123
|
+
logger.info(`[change] ${formatWatchedPath(scanner.cwd, resetDependency)}`);
|
|
124
|
+
}
|
|
125
|
+
await closeWatchers();
|
|
126
|
+
await scanner.reset(scanner.customOptions, { emit: false });
|
|
127
|
+
await prepareScanner(scanner, styleCSSSources, scanPaths());
|
|
128
|
+
await queueWrite();
|
|
129
|
+
await startWatchers();
|
|
130
|
+
const logger = await loadLogger();
|
|
131
|
+
logger.log("");
|
|
132
|
+
logger.info("Restart watching source changes");
|
|
133
|
+
scanner.emit("resetDependencyChange");
|
|
134
|
+
} finally {
|
|
135
|
+
restarting = false;
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
planWatcher.on("add", (resetDependency) => {
|
|
139
|
+
handlePlanChange(resetDependency);
|
|
140
|
+
});
|
|
141
|
+
planWatcher.on("change", (resetDependency) => {
|
|
142
|
+
handlePlanChange(resetDependency);
|
|
143
|
+
});
|
|
144
|
+
planWatcher.on("unlink", (resetDependency) => {
|
|
145
|
+
handlePlanChange(resetDependency);
|
|
146
|
+
});
|
|
147
|
+
watchers.push(planWatcher);
|
|
148
|
+
await waitForWatcherReady(planWatcher);
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
process.once("SIGTERM", () => {
|
|
152
|
+
closeWatchers().finally(() => process.exit(0));
|
|
153
|
+
});
|
|
154
|
+
process.once("SIGINT", () => {
|
|
155
|
+
closeWatchers().finally(() => process.exit(0));
|
|
156
|
+
});
|
|
157
|
+
await pipelineModules;
|
|
158
|
+
await prepareScanner(scanner, styleCSSSources, scanPaths());
|
|
159
|
+
await queueWrite();
|
|
160
|
+
await startWatchers();
|
|
161
|
+
const logger = await loadLogger();
|
|
162
|
+
logger.log("");
|
|
163
|
+
logger.info("Start watching source changes");
|
|
164
|
+
} else {
|
|
165
|
+
await pipelineModules;
|
|
166
|
+
await prepareScanner(scanner, styleCSSSources, scanPaths());
|
|
167
|
+
await writeOutput();
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
function loadCSSScanner() {
|
|
171
|
+
scannerModulePromise ||= import("@master/css-scanner").then((mod) => mod.default);
|
|
172
|
+
return scannerModulePromise;
|
|
173
|
+
}
|
|
174
|
+
function loadStylesheetModule() {
|
|
175
|
+
stylesheetModulePromise ||= import("@master/css-stylesheet");
|
|
176
|
+
return stylesheetModulePromise;
|
|
177
|
+
}
|
|
178
|
+
function loadProjectEntriesModule() {
|
|
179
|
+
projectEntriesModulePromise ||= import("@master/css-project/entries");
|
|
180
|
+
return projectEntriesModulePromise;
|
|
181
|
+
}
|
|
182
|
+
function loadFastGlob() {
|
|
183
|
+
fastGlobModulePromise ||= import("fast-glob").then((mod) => mod.default || mod);
|
|
184
|
+
return fastGlobModulePromise;
|
|
185
|
+
}
|
|
186
|
+
function loadChokidar() {
|
|
187
|
+
chokidarModulePromise ||= import("chokidar").then((mod) => mod.default);
|
|
188
|
+
return chokidarModulePromise;
|
|
189
|
+
}
|
|
190
|
+
function loadLogger() {
|
|
191
|
+
loggerPromise ||= import("consola").then(({ createConsola }) => createConsola({ level: 3 }));
|
|
192
|
+
return loggerPromise;
|
|
193
|
+
}
|
|
194
|
+
function loadBytes() {
|
|
195
|
+
bytesPromise ||= import("bytes").then((mod) => mod.default || mod);
|
|
196
|
+
return bytesPromise;
|
|
197
|
+
}
|
|
198
|
+
//#endregion
|
|
199
|
+
export { runScan as default };
|
package/package.json
CHANGED
|
@@ -1 +1,56 @@
|
|
|
1
|
-
{
|
|
1
|
+
{
|
|
2
|
+
"name": "@master/css-cli",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"description": "Master CSS CLI",
|
|
6
|
+
"author": "Aoyue Design LLC.",
|
|
7
|
+
"funding": "https://rc.css.master.co/sponsor",
|
|
8
|
+
"homepage": "https://css.master.co",
|
|
9
|
+
"bugs": {
|
|
10
|
+
"url": "https://github.com/master-co/css/issues"
|
|
11
|
+
},
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "https://github.com/master-co/css.git",
|
|
15
|
+
"directory": "packages/cli"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"cli",
|
|
19
|
+
"css",
|
|
20
|
+
"mastercss"
|
|
21
|
+
],
|
|
22
|
+
"files": [
|
|
23
|
+
"dist"
|
|
24
|
+
],
|
|
25
|
+
"publishConfig": {
|
|
26
|
+
"access": "public",
|
|
27
|
+
"provenance": true
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"bytes": "^3.1.2",
|
|
31
|
+
"chokidar": "^5.0.0",
|
|
32
|
+
"commander": "^14.0.3",
|
|
33
|
+
"consola": "^3.4.2",
|
|
34
|
+
"fast-glob": "^3.3.3",
|
|
35
|
+
"@master/css": "^2.0.0-rc.74",
|
|
36
|
+
"@master/css-project": "^2.0.0-rc.74",
|
|
37
|
+
"@master/css-scanner": "^2.0.0-rc.74",
|
|
38
|
+
"@master/css-stylesheet": "^2.0.0-rc.74"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/bytes": "^3.1.5",
|
|
42
|
+
"upath": "^2.0.1",
|
|
43
|
+
"@master/css-lexer": "^2.0.0-rc.74"
|
|
44
|
+
},
|
|
45
|
+
"version": "2.0.0-rc.74",
|
|
46
|
+
"scripts": {
|
|
47
|
+
"build": "tsdown --config ../../shared/tsdown-package.config.ts",
|
|
48
|
+
"dev": "tsdown --config ../../shared/tsdown-package.config.ts --watch",
|
|
49
|
+
"lint": "eslint",
|
|
50
|
+
"type-check": "tsc -b tsconfig.typecheck.json",
|
|
51
|
+
"test": "vitest"
|
|
52
|
+
},
|
|
53
|
+
"bin": {
|
|
54
|
+
"css-cli": "./dist/bin/index.js"
|
|
55
|
+
}
|
|
56
|
+
}
|
package/dist/bin/index.mjs
DELETED
package/dist/core.mjs
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { resolve } from 'node:path';
|
|
2
|
-
import { Command } from 'commander';
|
|
3
|
-
import { readJSONFileSync } from '@techor/fs';
|
|
4
|
-
import { dirname } from 'path';
|
|
5
|
-
import { fileURLToPath } from 'url';
|
|
6
|
-
import runScan, { DEFAULT_SCAN_OUTPUT } from './scan.mjs';
|
|
7
|
-
|
|
8
|
-
const __filename$1 = fileURLToPath(import.meta.url);
|
|
9
|
-
const __dirname$1 = dirname(__filename$1);
|
|
10
|
-
const pkg = readJSONFileSync(resolve(__dirname$1, '../package.json'));
|
|
11
|
-
const removedCommands = new Set([
|
|
12
|
-
'extract',
|
|
13
|
-
'render',
|
|
14
|
-
'scan'
|
|
15
|
-
]);
|
|
16
|
-
function errorRemovedCommand(program, command) {
|
|
17
|
-
program.error(`The "${command}" command was removed. Use "${pkg.name}" directly, for example "${pkg.name} -w".`);
|
|
18
|
-
}
|
|
19
|
-
async function runProgram(argv = process.argv) {
|
|
20
|
-
const program = new Command();
|
|
21
|
-
program.name(pkg.name).description(pkg.description).version(pkg.version || '0.0.0').argument('[source paths...]', 'The glob pattern paths to scan sources').option('-w, --watch', 'Watch file changes and generate CSS rules.').option('-o, --output <path>', 'Specify your CSS file output path', DEFAULT_SCAN_OUTPUT).option('-v, --verbose <level>', 'Verbose logging 0~N', '1').option('--no-export', 'Print only CSS results.').action((sourcePaths, options)=>{
|
|
22
|
-
const removedCommand = sourcePaths[0];
|
|
23
|
-
if (removedCommand && removedCommands.has(removedCommand)) {
|
|
24
|
-
errorRemovedCommand(program, removedCommand);
|
|
25
|
-
}
|
|
26
|
-
return runScan(sourcePaths, options);
|
|
27
|
-
});
|
|
28
|
-
const firstArgument = argv[2];
|
|
29
|
-
if (firstArgument && removedCommands.has(firstArgument)) {
|
|
30
|
-
errorRemovedCommand(program, firstArgument);
|
|
31
|
-
}
|
|
32
|
-
await program.parseAsync(argv);
|
|
33
|
-
return program;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export { runProgram as default };
|
package/dist/scan.mjs
DELETED
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
import { createExtractedCSS, registerStyleCSSSource } from '@master/css-stylesheet';
|
|
2
|
-
import { findCSSManifestEntryFiles } from '@master/css-project/entries';
|
|
3
|
-
import log from '@techor/log';
|
|
4
|
-
import { explorePathsSync } from '@techor/glob';
|
|
5
|
-
import bytes from 'bytes';
|
|
6
|
-
import chokidar from 'chokidar';
|
|
7
|
-
import fs from 'node:fs';
|
|
8
|
-
import path from 'node:path';
|
|
9
|
-
|
|
10
|
-
const DEFAULT_SCAN_OUTPUT = 'master.css';
|
|
11
|
-
const DEFAULT_SOURCE_PATTERNS = [
|
|
12
|
-
'**/*.{html,htm,js,jsx,mjs,cjs,ts,tsx,mts,cts,svelte,astro,vue,md,mdx,pug,php}'
|
|
13
|
-
];
|
|
14
|
-
async function registerManagedCSSEntries(scanner, styleCSSSources) {
|
|
15
|
-
styleCSSSources.clear();
|
|
16
|
-
for (const entry of (await findCSSManifestEntryFiles(scanner.cwd))){
|
|
17
|
-
await registerStyleCSSSource(scanner, styleCSSSources, entry, fs.readFileSync(entry, 'utf8'), {
|
|
18
|
-
projectDir: scanner.cwd
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
scanner.resetDependencies = [
|
|
22
|
-
...new Set(Array.from(styleCSSSources.values()).flatMap((source)=>source.dependencies))
|
|
23
|
-
];
|
|
24
|
-
}
|
|
25
|
-
function normalizeSourcePatterns(specifiedSourcePaths) {
|
|
26
|
-
return specifiedSourcePaths?.length ? specifiedSourcePaths : DEFAULT_SOURCE_PATTERNS;
|
|
27
|
-
}
|
|
28
|
-
function resolveSourcePaths(scanner, sourcePatterns, ignore = []) {
|
|
29
|
-
return explorePathsSync(sourcePatterns, {
|
|
30
|
-
cwd: scanner.cwd,
|
|
31
|
-
ignore
|
|
32
|
-
}).filter(Boolean);
|
|
33
|
-
}
|
|
34
|
-
async function scanSourceFile(scanner, source) {
|
|
35
|
-
const filepath = path.resolve(scanner.cwd, source);
|
|
36
|
-
await scanner.scan(source, fs.readFileSync(filepath, 'utf8'));
|
|
37
|
-
}
|
|
38
|
-
async function scanSourceFiles(scanner, sourcePaths) {
|
|
39
|
-
await Promise.all(sourcePaths.map((source)=>scanSourceFile(scanner, source)));
|
|
40
|
-
}
|
|
41
|
-
async function prepareScanner(scanner, styleCSSSources, sourcePaths) {
|
|
42
|
-
await registerManagedCSSEntries(scanner, styleCSSSources);
|
|
43
|
-
await scanSourceFiles(scanner, sourcePaths);
|
|
44
|
-
}
|
|
45
|
-
function exportCSS(scanner, css, filename = DEFAULT_SCAN_OUTPUT) {
|
|
46
|
-
const filepath = path.resolve(scanner.cwd, filename);
|
|
47
|
-
const dir = path.dirname(filepath);
|
|
48
|
-
if (!fs.existsSync(dir)) {
|
|
49
|
-
fs.mkdirSync(dir, {
|
|
50
|
-
recursive: true
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
fs.writeFileSync(filepath, css);
|
|
54
|
-
if (scanner.options.verbose) {
|
|
55
|
-
log.ok`**${filename}** exported ${bytes(css.length)}`;
|
|
56
|
-
}
|
|
57
|
-
scanner.emit('export', filename, filepath);
|
|
58
|
-
}
|
|
59
|
-
function formatWatchedPath(cwd, file) {
|
|
60
|
-
return path.isAbsolute(file) ? path.relative(cwd, file) : file;
|
|
61
|
-
}
|
|
62
|
-
async function waitForWatcherReady(watcher) {
|
|
63
|
-
await new Promise((resolve)=>watcher.once('ready', resolve));
|
|
64
|
-
// Let chokidar finish registering native watchers before callers mutate files.
|
|
65
|
-
await new Promise((resolve)=>setTimeout(resolve, 0));
|
|
66
|
-
}
|
|
67
|
-
async function runScan(specifiedSourcePaths = [], options = {}) {
|
|
68
|
-
const CSSScanner = (await import('@master/css-scanner')).default;
|
|
69
|
-
const { watch, output, verbose, cwd } = options;
|
|
70
|
-
const scanner = new CSSScanner({}, cwd);
|
|
71
|
-
const styleCSSSources = new Map();
|
|
72
|
-
const sourcePatterns = normalizeSourcePatterns(specifiedSourcePaths);
|
|
73
|
-
const writeOutput = async ()=>{
|
|
74
|
-
const css = await createExtractedCSS({
|
|
75
|
-
scanner,
|
|
76
|
-
styleCSSSources,
|
|
77
|
-
projectDir: scanner.cwd
|
|
78
|
-
});
|
|
79
|
-
if (options.export) {
|
|
80
|
-
exportCSS(scanner, css, output);
|
|
81
|
-
} else {
|
|
82
|
-
console.log(css);
|
|
83
|
-
}
|
|
84
|
-
};
|
|
85
|
-
scanner.on('init', (options)=>{
|
|
86
|
-
if (!specifiedSourcePaths.length) {
|
|
87
|
-
if (!options.exclude?.includes('**/node_modules/**')) {
|
|
88
|
-
options.exclude?.push('**/node_modules/**');
|
|
89
|
-
}
|
|
90
|
-
if (!options.exclude?.includes('node_modules')) {
|
|
91
|
-
options.exclude?.push('node_modules');
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
options.verbose = verbose ? +verbose : options.verbose;
|
|
95
|
-
});
|
|
96
|
-
await scanner.init();
|
|
97
|
-
const scanPaths = ()=>resolveSourcePaths(scanner, sourcePatterns, specifiedSourcePaths.length ? [] : scanner.options.exclude);
|
|
98
|
-
if (watch) {
|
|
99
|
-
const watchers = [];
|
|
100
|
-
let restarting = false;
|
|
101
|
-
let writing = Promise.resolve();
|
|
102
|
-
const queueWrite = ()=>{
|
|
103
|
-
writing = writing.then(writeOutput);
|
|
104
|
-
return writing;
|
|
105
|
-
};
|
|
106
|
-
const closeWatchers = async ()=>{
|
|
107
|
-
await Promise.all(watchers.splice(0).map((watcher)=>watcher.close()));
|
|
108
|
-
};
|
|
109
|
-
const startWatchers = async ()=>{
|
|
110
|
-
const sourcePaths = scanPaths();
|
|
111
|
-
if (sourcePaths.length) {
|
|
112
|
-
const sourceWatcher = chokidar.watch(sourcePaths, {
|
|
113
|
-
cwd: scanner.cwd,
|
|
114
|
-
ignoreInitial: true
|
|
115
|
-
});
|
|
116
|
-
sourceWatcher.on('add', (source)=>{
|
|
117
|
-
void scanSourceFile(scanner, source).then(queueWrite);
|
|
118
|
-
});
|
|
119
|
-
sourceWatcher.on('change', (source)=>{
|
|
120
|
-
void scanSourceFile(scanner, source).then(queueWrite);
|
|
121
|
-
});
|
|
122
|
-
watchers.push(sourceWatcher);
|
|
123
|
-
await waitForWatcherReady(sourceWatcher);
|
|
124
|
-
}
|
|
125
|
-
if (scanner.resetDependencies.length) {
|
|
126
|
-
const planWatcher = chokidar.watch(scanner.resetDependencies, {
|
|
127
|
-
ignoreInitial: true
|
|
128
|
-
});
|
|
129
|
-
const handlePlanChange = async (resetDependency)=>{
|
|
130
|
-
if (restarting) return;
|
|
131
|
-
restarting = true;
|
|
132
|
-
try {
|
|
133
|
-
if (scanner.options.verbose) {
|
|
134
|
-
log``;
|
|
135
|
-
log`[change] **${formatWatchedPath(scanner.cwd, resetDependency)}**`;
|
|
136
|
-
}
|
|
137
|
-
await closeWatchers();
|
|
138
|
-
await scanner.reset(scanner.customOptions, {
|
|
139
|
-
emit: false
|
|
140
|
-
});
|
|
141
|
-
await prepareScanner(scanner, styleCSSSources, scanPaths());
|
|
142
|
-
await queueWrite();
|
|
143
|
-
await startWatchers();
|
|
144
|
-
log``;
|
|
145
|
-
log.t`Restart watching source changes`;
|
|
146
|
-
scanner.emit('resetDependencyChange');
|
|
147
|
-
} finally{
|
|
148
|
-
restarting = false;
|
|
149
|
-
}
|
|
150
|
-
};
|
|
151
|
-
planWatcher.on('add', (resetDependency)=>{
|
|
152
|
-
void handlePlanChange(resetDependency);
|
|
153
|
-
});
|
|
154
|
-
planWatcher.on('change', (resetDependency)=>{
|
|
155
|
-
void handlePlanChange(resetDependency);
|
|
156
|
-
});
|
|
157
|
-
planWatcher.on('unlink', (resetDependency)=>{
|
|
158
|
-
void handlePlanChange(resetDependency);
|
|
159
|
-
});
|
|
160
|
-
watchers.push(planWatcher);
|
|
161
|
-
await waitForWatcherReady(planWatcher);
|
|
162
|
-
}
|
|
163
|
-
};
|
|
164
|
-
process.once('SIGTERM', ()=>{
|
|
165
|
-
void closeWatchers().finally(()=>process.exit(0));
|
|
166
|
-
});
|
|
167
|
-
process.once('SIGINT', ()=>{
|
|
168
|
-
void closeWatchers().finally(()=>process.exit(0));
|
|
169
|
-
});
|
|
170
|
-
await prepareScanner(scanner, styleCSSSources, scanPaths());
|
|
171
|
-
await queueWrite();
|
|
172
|
-
await startWatchers();
|
|
173
|
-
log``;
|
|
174
|
-
log.t`Start watching source changes`;
|
|
175
|
-
} else {
|
|
176
|
-
await prepareScanner(scanner, styleCSSSources, scanPaths());
|
|
177
|
-
await writeOutput();
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
export { DEFAULT_SCAN_OUTPUT, runScan as default };
|