@flairjs/parcel-transformer 0.0.1-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/README.md +0 -0
- package/dist/cjs/index.js +287 -0
- package/dist/esm/index.js +251 -0
- package/dist/types/index.d.ts +14 -0
- package/dist/types/index.js +5446 -0
- package/package.json +40 -0
package/README.md
ADDED
|
File without changes
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
//#region rolldown:runtime
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
10
|
+
key = keys[i];
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
12
|
+
get: ((k) => from[k]).bind(null, key),
|
|
13
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
19
|
+
value: mod,
|
|
20
|
+
enumerable: true
|
|
21
|
+
}) : target, mod));
|
|
22
|
+
|
|
23
|
+
//#endregion
|
|
24
|
+
let node_module = require("node:module");
|
|
25
|
+
node_module = __toESM(node_module);
|
|
26
|
+
let node_fs = require("node:fs");
|
|
27
|
+
node_fs = __toESM(node_fs);
|
|
28
|
+
let node_fs_promises = require("node:fs/promises");
|
|
29
|
+
node_fs_promises = __toESM(node_fs_promises);
|
|
30
|
+
let node_path = require("node:path");
|
|
31
|
+
node_path = __toESM(node_path);
|
|
32
|
+
let esbuild = require("esbuild");
|
|
33
|
+
esbuild = __toESM(esbuild);
|
|
34
|
+
let fs = require("fs");
|
|
35
|
+
fs = __toESM(fs);
|
|
36
|
+
let node_url = require("node:url");
|
|
37
|
+
node_url = __toESM(node_url);
|
|
38
|
+
let path = require("path");
|
|
39
|
+
path = __toESM(path);
|
|
40
|
+
let url = require("url");
|
|
41
|
+
url = __toESM(url);
|
|
42
|
+
let picomatch = require("picomatch");
|
|
43
|
+
picomatch = __toESM(picomatch);
|
|
44
|
+
let __flairjs_core = require("@flairjs/core");
|
|
45
|
+
__flairjs_core = __toESM(__flairjs_core);
|
|
46
|
+
let __home_runner_work_flairjs_flairjs_node_modules__pnpm__parcel_plugin_2_16_0__parcel_core_2_16_0__swc_helpers_0_5_17__node_modules__parcel_plugin_lib_PluginAPI_js = require("/home/runner/work/flairjs/flairjs/node_modules/.pnpm/@parcel+plugin@2.16.0_@parcel+core@2.16.0_@swc+helpers@0.5.17_/node_modules/@parcel/plugin/lib/PluginAPI.js");
|
|
47
|
+
__home_runner_work_flairjs_flairjs_node_modules__pnpm__parcel_plugin_2_16_0__parcel_core_2_16_0__swc_helpers_0_5_17__node_modules__parcel_plugin_lib_PluginAPI_js = __toESM(__home_runner_work_flairjs_flairjs_node_modules__pnpm__parcel_plugin_2_16_0__parcel_core_2_16_0__swc_helpers_0_5_17__node_modules__parcel_plugin_lib_PluginAPI_js);
|
|
48
|
+
let __home_runner_work_flairjs_flairjs_node_modules__pnpm__parcel_source_map_2_1_1_node_modules__parcel_source_map_dist_node_js = require("/home/runner/work/flairjs/flairjs/node_modules/.pnpm/@parcel+source-map@2.1.1/node_modules/@parcel/source-map/dist/node.js");
|
|
49
|
+
__home_runner_work_flairjs_flairjs_node_modules__pnpm__parcel_source_map_2_1_1_node_modules__parcel_source_map_dist_node_js = __toESM(__home_runner_work_flairjs_flairjs_node_modules__pnpm__parcel_source_map_2_1_1_node_modules__parcel_source_map_dist_node_js);
|
|
50
|
+
|
|
51
|
+
//#region ../shared/dist/esm/index.js
|
|
52
|
+
String.raw;
|
|
53
|
+
const buildThemeTokens = (theme, themeName) => {
|
|
54
|
+
let css$1 = "";
|
|
55
|
+
const { tokens, selector } = theme;
|
|
56
|
+
if (typeof selector === "string") css$1 += `${selector} {\n`;
|
|
57
|
+
css$1 += tokensToCSSVars(tokens, theme.prefix ? [theme.prefix] : []);
|
|
58
|
+
if (typeof selector === "string") css$1 += `}\n`;
|
|
59
|
+
else css$1 = selector(css$1, themeName);
|
|
60
|
+
Object.entries(theme.themes ?? {}).forEach(([name, themeConfig]) => {
|
|
61
|
+
css$1 += buildThemeTokens({
|
|
62
|
+
prefix: theme.prefix,
|
|
63
|
+
selector: theme.selector,
|
|
64
|
+
...themeConfig
|
|
65
|
+
}, name);
|
|
66
|
+
});
|
|
67
|
+
return css$1;
|
|
68
|
+
};
|
|
69
|
+
function tokensToCSSVars(tokens, prefix = []) {
|
|
70
|
+
let css$1 = "";
|
|
71
|
+
for (const [key, value] of Object.entries(tokens)) {
|
|
72
|
+
const newPrefix = [...prefix, key];
|
|
73
|
+
if (typeof value === "string" || typeof value === "number") css$1 += `--${newPrefix.join("-")}: ${value};\n`;
|
|
74
|
+
else if (typeof value === "object" && value !== null) css$1 += tokensToCSSVars(value, newPrefix);
|
|
75
|
+
}
|
|
76
|
+
return css$1;
|
|
77
|
+
}
|
|
78
|
+
var Store = class {
|
|
79
|
+
fileNameToGeneratedCssNameMap = /* @__PURE__ */ new Map();
|
|
80
|
+
lastThemeUpdate = Date.now();
|
|
81
|
+
userTheme = /* @__PURE__ */ new Map();
|
|
82
|
+
getUserTheme() {
|
|
83
|
+
return this.userTheme.get(this.lastThemeUpdate) ?? null;
|
|
84
|
+
}
|
|
85
|
+
setUserTheme(theme) {
|
|
86
|
+
this.userTheme.set(this.lastThemeUpdate, theme);
|
|
87
|
+
}
|
|
88
|
+
getLastThemeUpdate() {
|
|
89
|
+
return this.lastThemeUpdate;
|
|
90
|
+
}
|
|
91
|
+
setLastThemeUpdate(timestamp) {
|
|
92
|
+
this.lastThemeUpdate = timestamp;
|
|
93
|
+
}
|
|
94
|
+
setFileNameToGeneratedCssNameMap(fileName, generatedCssName) {
|
|
95
|
+
this.fileNameToGeneratedCssNameMap.set(fileName, generatedCssName);
|
|
96
|
+
}
|
|
97
|
+
getGeneratedCssName(fileName) {
|
|
98
|
+
return this.fileNameToGeneratedCssNameMap.get(fileName);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
const store = new Store();
|
|
102
|
+
const __dirname$1 = (0, node_path.dirname)((0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href));
|
|
103
|
+
const getUserTheme = async () => {
|
|
104
|
+
if (store.getUserTheme()) return store.getUserTheme();
|
|
105
|
+
try {
|
|
106
|
+
let userThemeFilePath = path.default.resolve(process.cwd(), "flair.theme.ts");
|
|
107
|
+
if (!(0, fs.existsSync)(userThemeFilePath)) userThemeFilePath = path.default.resolve(process.cwd(), "flair.theme.js");
|
|
108
|
+
if (!(0, fs.existsSync)(userThemeFilePath)) return null;
|
|
109
|
+
const outFile = path.default.resolve(__dirname$1, `flair.theme.js`);
|
|
110
|
+
await esbuild.build({
|
|
111
|
+
entryPoints: [userThemeFilePath],
|
|
112
|
+
outfile: outFile,
|
|
113
|
+
platform: "node",
|
|
114
|
+
bundle: true,
|
|
115
|
+
format: "esm",
|
|
116
|
+
external: ["*"]
|
|
117
|
+
});
|
|
118
|
+
const cacheBuster = Date.now();
|
|
119
|
+
const userTheme = await import(`${(0, url.pathToFileURL)(outFile).href}?update=${cacheBuster}`);
|
|
120
|
+
if (userTheme.default) {
|
|
121
|
+
store.setUserTheme({
|
|
122
|
+
theme: userTheme.default,
|
|
123
|
+
originalPath: userThemeFilePath
|
|
124
|
+
});
|
|
125
|
+
return {
|
|
126
|
+
theme: userTheme.default,
|
|
127
|
+
originalPath: userThemeFilePath
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
store.setUserTheme(null);
|
|
131
|
+
return null;
|
|
132
|
+
} catch (error) {
|
|
133
|
+
console.error("Error loading user theme:", error);
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
const require$1 = node_module.default.createRequire(require("url").pathToFileURL(__filename).href);
|
|
138
|
+
const getGeneratedCssDir = () => {
|
|
139
|
+
const flairThemeFile = require$1.resolve("@flairjs/client/theme.css");
|
|
140
|
+
return node_path.default.resolve(flairThemeFile, "../generated-css");
|
|
141
|
+
};
|
|
142
|
+
const setupGeneratedCssDir = async () => {
|
|
143
|
+
const flairGeneratedCssDir = getGeneratedCssDir();
|
|
144
|
+
try {
|
|
145
|
+
if (!(0, node_fs.existsSync)(flairGeneratedCssDir)) await (0, node_fs_promises.mkdir)(flairGeneratedCssDir);
|
|
146
|
+
else {
|
|
147
|
+
await (0, node_fs_promises.rm)(flairGeneratedCssDir, {
|
|
148
|
+
recursive: true,
|
|
149
|
+
force: true
|
|
150
|
+
});
|
|
151
|
+
await (0, node_fs_promises.mkdir)(flairGeneratedCssDir);
|
|
152
|
+
}
|
|
153
|
+
} catch (err) {
|
|
154
|
+
if (err?.code === "EEXIST") return flairGeneratedCssDir;
|
|
155
|
+
else if ((0, node_fs.existsSync)(flairGeneratedCssDir)) return flairGeneratedCssDir;
|
|
156
|
+
console.error(`[flairjs] Could not create generated CSS directory: ${flairGeneratedCssDir}`, err);
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
return flairGeneratedCssDir;
|
|
160
|
+
};
|
|
161
|
+
const setupUserThemeFile = async ({ buildThemeFile }) => {
|
|
162
|
+
const flairThemeFile = require$1.resolve("@flairjs/client/theme.css");
|
|
163
|
+
let userTheme = await getUserTheme();
|
|
164
|
+
const buildThemeCSS = buildThemeFile ?? buildThemeTokens;
|
|
165
|
+
if (userTheme) {
|
|
166
|
+
const themeCSS = buildThemeCSS(userTheme.theme);
|
|
167
|
+
store.setLastThemeUpdate(Date.now());
|
|
168
|
+
await (0, node_fs_promises.writeFile)(flairThemeFile, themeCSS, "utf-8");
|
|
169
|
+
(0, node_fs.watch)(userTheme.originalPath, async () => {
|
|
170
|
+
userTheme = await getUserTheme();
|
|
171
|
+
store.setLastThemeUpdate(Date.now());
|
|
172
|
+
if (!userTheme) return;
|
|
173
|
+
const themeCSS$1 = buildThemeCSS(userTheme.theme);
|
|
174
|
+
await (0, node_fs_promises.writeFile)(flairThemeFile, themeCSS$1, "utf-8");
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
return userTheme;
|
|
178
|
+
};
|
|
179
|
+
const removeOutdatedCssFiles = async (sourceFilePath, cssFilePath, { flairGeneratedCssDir }) => {
|
|
180
|
+
const previousGeneratedCssName = store.getGeneratedCssName(sourceFilePath);
|
|
181
|
+
if (previousGeneratedCssName && previousGeneratedCssName !== cssFilePath) setTimeout(() => {
|
|
182
|
+
(0, node_fs_promises.rm)(node_path.default.join(flairGeneratedCssDir, previousGeneratedCssName), { force: true });
|
|
183
|
+
}, 2e3);
|
|
184
|
+
else store.setFileNameToGeneratedCssNameMap(sourceFilePath, cssFilePath);
|
|
185
|
+
};
|
|
186
|
+
function shouldProcessFile(id, include, exclude) {
|
|
187
|
+
const isIncluded = (0, picomatch.default)(include ?? ["**/*.{js,ts,jsx,tsx}"]);
|
|
188
|
+
const isExcluded = (0, picomatch.default)(exclude ?? ["**/node_modules/**"]);
|
|
189
|
+
if (!isIncluded(normalizeFilePath(id))) return false;
|
|
190
|
+
if (isExcluded(normalizeFilePath(id))) return false;
|
|
191
|
+
return true;
|
|
192
|
+
}
|
|
193
|
+
function normalizeFilePath(filePath) {
|
|
194
|
+
return filePath.replace(/\\/g, "/");
|
|
195
|
+
}
|
|
196
|
+
const colors = {
|
|
197
|
+
reset: "\x1B[0m",
|
|
198
|
+
fg: {
|
|
199
|
+
red: "\x1B[31m",
|
|
200
|
+
yellow: "\x1B[33m",
|
|
201
|
+
blue: "\x1B[34m",
|
|
202
|
+
white: "\x1B[37m"
|
|
203
|
+
},
|
|
204
|
+
bg: {
|
|
205
|
+
red: "\x1B[41m",
|
|
206
|
+
yellow: "\x1B[43m",
|
|
207
|
+
blue: "\x1B[44m"
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
const logger = {
|
|
211
|
+
error: (msg) => {
|
|
212
|
+
console.log(`${colors.bg.red}${colors.fg.white}[flairjs/Error]${colors.reset} ${colors.fg.red}${msg}${colors.reset}`);
|
|
213
|
+
},
|
|
214
|
+
warn: (msg) => {
|
|
215
|
+
console.log(`${colors.bg.yellow}${colors.fg.white}[flairjs/Warning]${colors.reset} ${msg}${colors.reset}`);
|
|
216
|
+
},
|
|
217
|
+
info: (msg) => {
|
|
218
|
+
console.log(`${colors.bg.blue}${colors.fg.white}[flairjs/Info]${colors.reset} ${msg}${colors.reset}`);
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
const transformCode = (code, filePath, options) => {
|
|
222
|
+
const result = (0, __flairjs_core.transformCode)(code, filePath, {
|
|
223
|
+
cssOutDir: options.cssOutDir,
|
|
224
|
+
classNameList: options.classNameList,
|
|
225
|
+
useTheme: options.useTheme,
|
|
226
|
+
theme: options.theme,
|
|
227
|
+
appendTimestampToCssFile: options.appendTimestampToCssFile
|
|
228
|
+
}, options.cssPreprocessor);
|
|
229
|
+
(result?.logs ?? []).forEach((log) => {
|
|
230
|
+
if (logger[log.level]) logger[log.level](log.message);
|
|
231
|
+
});
|
|
232
|
+
return result;
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
//#endregion
|
|
236
|
+
//#region src/index.ts
|
|
237
|
+
const SourceMap = __home_runner_work_flairjs_flairjs_node_modules__pnpm__parcel_source_map_2_1_1_node_modules__parcel_source_map_dist_node_js.default.default ?? __home_runner_work_flairjs_flairjs_node_modules__pnpm__parcel_source_map_2_1_1_node_modules__parcel_source_map_dist_node_js.default;
|
|
238
|
+
var src_default = new __home_runner_work_flairjs_flairjs_node_modules__pnpm__parcel_plugin_2_16_0__parcel_core_2_16_0__swc_helpers_0_5_17__node_modules__parcel_plugin_lib_PluginAPI_js.Transformer({
|
|
239
|
+
async loadConfig({ config }) {
|
|
240
|
+
const getConfigResult = await config.getConfig(["tool.config.js"]);
|
|
241
|
+
const filePath = getConfigResult?.filePath;
|
|
242
|
+
const configContents = getConfigResult?.contents;
|
|
243
|
+
if (filePath?.endsWith(".js")) config.invalidateOnStartup();
|
|
244
|
+
const cssGeneratedDir = await setupGeneratedCssDir();
|
|
245
|
+
const userTheme = await setupUserThemeFile({ buildThemeFile: configContents?.buildThemeFile });
|
|
246
|
+
return {
|
|
247
|
+
...configContents,
|
|
248
|
+
cssGeneratedDir,
|
|
249
|
+
userTheme
|
|
250
|
+
};
|
|
251
|
+
},
|
|
252
|
+
async transform({ asset, config, logger: logger$1, options }) {
|
|
253
|
+
const filePath = asset.filePath;
|
|
254
|
+
const cssOutDir = config?.cssGeneratedDir ?? null;
|
|
255
|
+
if (!shouldProcessFile(filePath, config.include, config.exclude)) return [asset];
|
|
256
|
+
if (!cssOutDir) return [asset];
|
|
257
|
+
try {
|
|
258
|
+
const code = await asset.getCode();
|
|
259
|
+
const result = transformCode(code, asset.filePath, {
|
|
260
|
+
appendTimestampToCssFile: true,
|
|
261
|
+
classNameList: config?.classNameList,
|
|
262
|
+
cssPreprocessor: config?.cssPreprocessor ? (css) => config.cssPreprocessor(css, asset.filePath) : void 0,
|
|
263
|
+
theme: config.userTheme?.theme,
|
|
264
|
+
useTheme: !!config.userTheme,
|
|
265
|
+
cssOutDir
|
|
266
|
+
});
|
|
267
|
+
if (!result) return [asset];
|
|
268
|
+
if (result.generatedCssName) removeOutdatedCssFiles(asset.filePath, result.generatedCssName, { flairGeneratedCssDir: cssOutDir });
|
|
269
|
+
asset.setCode(result.code);
|
|
270
|
+
if (result.sourcemap) {
|
|
271
|
+
const sourcemap = new SourceMap(options.projectRoot);
|
|
272
|
+
sourcemap.addVLQMap(JSON.parse(result.sourcemap));
|
|
273
|
+
asset.setMap(sourcemap);
|
|
274
|
+
}
|
|
275
|
+
return [asset];
|
|
276
|
+
} catch (error) {
|
|
277
|
+
logger$1.error({
|
|
278
|
+
message: `Error during flairjs transformation: ${error instanceof Error ? error.message : String(error)}`,
|
|
279
|
+
origin: "@flairjs/parcel-transformer"
|
|
280
|
+
});
|
|
281
|
+
return [asset];
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
//#endregion
|
|
287
|
+
module.exports = src_default;
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import module from "node:module";
|
|
2
|
+
import { existsSync, watch } from "node:fs";
|
|
3
|
+
import { mkdir, rm, writeFile } from "node:fs/promises";
|
|
4
|
+
import path, { dirname } from "node:path";
|
|
5
|
+
import * as esbuild from "esbuild";
|
|
6
|
+
import { existsSync as existsSync$1 } from "fs";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
import path$1 from "path";
|
|
9
|
+
import { pathToFileURL } from "url";
|
|
10
|
+
import picomatch from "picomatch";
|
|
11
|
+
import { transformCode } from "@flairjs/core";
|
|
12
|
+
import { Transformer } from "/home/runner/work/flairjs/flairjs/node_modules/.pnpm/@parcel+plugin@2.16.0_@parcel+core@2.16.0_@swc+helpers@0.5.17_/node_modules/@parcel/plugin/lib/PluginAPI.js";
|
|
13
|
+
import SourceMapImport from "/home/runner/work/flairjs/flairjs/node_modules/.pnpm/@parcel+source-map@2.1.1/node_modules/@parcel/source-map/dist/node.js";
|
|
14
|
+
|
|
15
|
+
//#region ../shared/dist/esm/index.js
|
|
16
|
+
String.raw;
|
|
17
|
+
const buildThemeTokens = (theme, themeName) => {
|
|
18
|
+
let css$1 = "";
|
|
19
|
+
const { tokens, selector } = theme;
|
|
20
|
+
if (typeof selector === "string") css$1 += `${selector} {\n`;
|
|
21
|
+
css$1 += tokensToCSSVars(tokens, theme.prefix ? [theme.prefix] : []);
|
|
22
|
+
if (typeof selector === "string") css$1 += `}\n`;
|
|
23
|
+
else css$1 = selector(css$1, themeName);
|
|
24
|
+
Object.entries(theme.themes ?? {}).forEach(([name, themeConfig]) => {
|
|
25
|
+
css$1 += buildThemeTokens({
|
|
26
|
+
prefix: theme.prefix,
|
|
27
|
+
selector: theme.selector,
|
|
28
|
+
...themeConfig
|
|
29
|
+
}, name);
|
|
30
|
+
});
|
|
31
|
+
return css$1;
|
|
32
|
+
};
|
|
33
|
+
function tokensToCSSVars(tokens, prefix = []) {
|
|
34
|
+
let css$1 = "";
|
|
35
|
+
for (const [key, value] of Object.entries(tokens)) {
|
|
36
|
+
const newPrefix = [...prefix, key];
|
|
37
|
+
if (typeof value === "string" || typeof value === "number") css$1 += `--${newPrefix.join("-")}: ${value};\n`;
|
|
38
|
+
else if (typeof value === "object" && value !== null) css$1 += tokensToCSSVars(value, newPrefix);
|
|
39
|
+
}
|
|
40
|
+
return css$1;
|
|
41
|
+
}
|
|
42
|
+
var Store = class {
|
|
43
|
+
fileNameToGeneratedCssNameMap = /* @__PURE__ */ new Map();
|
|
44
|
+
lastThemeUpdate = Date.now();
|
|
45
|
+
userTheme = /* @__PURE__ */ new Map();
|
|
46
|
+
getUserTheme() {
|
|
47
|
+
return this.userTheme.get(this.lastThemeUpdate) ?? null;
|
|
48
|
+
}
|
|
49
|
+
setUserTheme(theme) {
|
|
50
|
+
this.userTheme.set(this.lastThemeUpdate, theme);
|
|
51
|
+
}
|
|
52
|
+
getLastThemeUpdate() {
|
|
53
|
+
return this.lastThemeUpdate;
|
|
54
|
+
}
|
|
55
|
+
setLastThemeUpdate(timestamp) {
|
|
56
|
+
this.lastThemeUpdate = timestamp;
|
|
57
|
+
}
|
|
58
|
+
setFileNameToGeneratedCssNameMap(fileName, generatedCssName) {
|
|
59
|
+
this.fileNameToGeneratedCssNameMap.set(fileName, generatedCssName);
|
|
60
|
+
}
|
|
61
|
+
getGeneratedCssName(fileName) {
|
|
62
|
+
return this.fileNameToGeneratedCssNameMap.get(fileName);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
const store = new Store();
|
|
66
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
67
|
+
const getUserTheme = async () => {
|
|
68
|
+
if (store.getUserTheme()) return store.getUserTheme();
|
|
69
|
+
try {
|
|
70
|
+
let userThemeFilePath = path$1.resolve(process.cwd(), "flair.theme.ts");
|
|
71
|
+
if (!existsSync$1(userThemeFilePath)) userThemeFilePath = path$1.resolve(process.cwd(), "flair.theme.js");
|
|
72
|
+
if (!existsSync$1(userThemeFilePath)) return null;
|
|
73
|
+
const outFile = path$1.resolve(__dirname, `flair.theme.js`);
|
|
74
|
+
await esbuild.build({
|
|
75
|
+
entryPoints: [userThemeFilePath],
|
|
76
|
+
outfile: outFile,
|
|
77
|
+
platform: "node",
|
|
78
|
+
bundle: true,
|
|
79
|
+
format: "esm",
|
|
80
|
+
external: ["*"]
|
|
81
|
+
});
|
|
82
|
+
const cacheBuster = Date.now();
|
|
83
|
+
const userTheme = await import(`${pathToFileURL(outFile).href}?update=${cacheBuster}`);
|
|
84
|
+
if (userTheme.default) {
|
|
85
|
+
store.setUserTheme({
|
|
86
|
+
theme: userTheme.default,
|
|
87
|
+
originalPath: userThemeFilePath
|
|
88
|
+
});
|
|
89
|
+
return {
|
|
90
|
+
theme: userTheme.default,
|
|
91
|
+
originalPath: userThemeFilePath
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
store.setUserTheme(null);
|
|
95
|
+
return null;
|
|
96
|
+
} catch (error) {
|
|
97
|
+
console.error("Error loading user theme:", error);
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
const require = module.createRequire(import.meta.url);
|
|
102
|
+
const getGeneratedCssDir = () => {
|
|
103
|
+
const flairThemeFile = require.resolve("@flairjs/client/theme.css");
|
|
104
|
+
return path.resolve(flairThemeFile, "../generated-css");
|
|
105
|
+
};
|
|
106
|
+
const setupGeneratedCssDir = async () => {
|
|
107
|
+
const flairGeneratedCssDir = getGeneratedCssDir();
|
|
108
|
+
try {
|
|
109
|
+
if (!existsSync(flairGeneratedCssDir)) await mkdir(flairGeneratedCssDir);
|
|
110
|
+
else {
|
|
111
|
+
await rm(flairGeneratedCssDir, {
|
|
112
|
+
recursive: true,
|
|
113
|
+
force: true
|
|
114
|
+
});
|
|
115
|
+
await mkdir(flairGeneratedCssDir);
|
|
116
|
+
}
|
|
117
|
+
} catch (err) {
|
|
118
|
+
if (err?.code === "EEXIST") return flairGeneratedCssDir;
|
|
119
|
+
else if (existsSync(flairGeneratedCssDir)) return flairGeneratedCssDir;
|
|
120
|
+
console.error(`[flairjs] Could not create generated CSS directory: ${flairGeneratedCssDir}`, err);
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
return flairGeneratedCssDir;
|
|
124
|
+
};
|
|
125
|
+
const setupUserThemeFile = async ({ buildThemeFile }) => {
|
|
126
|
+
const flairThemeFile = require.resolve("@flairjs/client/theme.css");
|
|
127
|
+
let userTheme = await getUserTheme();
|
|
128
|
+
const buildThemeCSS = buildThemeFile ?? buildThemeTokens;
|
|
129
|
+
if (userTheme) {
|
|
130
|
+
const themeCSS = buildThemeCSS(userTheme.theme);
|
|
131
|
+
store.setLastThemeUpdate(Date.now());
|
|
132
|
+
await writeFile(flairThemeFile, themeCSS, "utf-8");
|
|
133
|
+
watch(userTheme.originalPath, async () => {
|
|
134
|
+
userTheme = await getUserTheme();
|
|
135
|
+
store.setLastThemeUpdate(Date.now());
|
|
136
|
+
if (!userTheme) return;
|
|
137
|
+
const themeCSS$1 = buildThemeCSS(userTheme.theme);
|
|
138
|
+
await writeFile(flairThemeFile, themeCSS$1, "utf-8");
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
return userTheme;
|
|
142
|
+
};
|
|
143
|
+
const removeOutdatedCssFiles = async (sourceFilePath, cssFilePath, { flairGeneratedCssDir }) => {
|
|
144
|
+
const previousGeneratedCssName = store.getGeneratedCssName(sourceFilePath);
|
|
145
|
+
if (previousGeneratedCssName && previousGeneratedCssName !== cssFilePath) setTimeout(() => {
|
|
146
|
+
rm(path.join(flairGeneratedCssDir, previousGeneratedCssName), { force: true });
|
|
147
|
+
}, 2e3);
|
|
148
|
+
else store.setFileNameToGeneratedCssNameMap(sourceFilePath, cssFilePath);
|
|
149
|
+
};
|
|
150
|
+
function shouldProcessFile(id, include, exclude) {
|
|
151
|
+
const isIncluded = picomatch(include ?? ["**/*.{js,ts,jsx,tsx}"]);
|
|
152
|
+
const isExcluded = picomatch(exclude ?? ["**/node_modules/**"]);
|
|
153
|
+
if (!isIncluded(normalizeFilePath(id))) return false;
|
|
154
|
+
if (isExcluded(normalizeFilePath(id))) return false;
|
|
155
|
+
return true;
|
|
156
|
+
}
|
|
157
|
+
function normalizeFilePath(filePath) {
|
|
158
|
+
return filePath.replace(/\\/g, "/");
|
|
159
|
+
}
|
|
160
|
+
const colors = {
|
|
161
|
+
reset: "\x1B[0m",
|
|
162
|
+
fg: {
|
|
163
|
+
red: "\x1B[31m",
|
|
164
|
+
yellow: "\x1B[33m",
|
|
165
|
+
blue: "\x1B[34m",
|
|
166
|
+
white: "\x1B[37m"
|
|
167
|
+
},
|
|
168
|
+
bg: {
|
|
169
|
+
red: "\x1B[41m",
|
|
170
|
+
yellow: "\x1B[43m",
|
|
171
|
+
blue: "\x1B[44m"
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
const logger = {
|
|
175
|
+
error: (msg) => {
|
|
176
|
+
console.log(`${colors.bg.red}${colors.fg.white}[flairjs/Error]${colors.reset} ${colors.fg.red}${msg}${colors.reset}`);
|
|
177
|
+
},
|
|
178
|
+
warn: (msg) => {
|
|
179
|
+
console.log(`${colors.bg.yellow}${colors.fg.white}[flairjs/Warning]${colors.reset} ${msg}${colors.reset}`);
|
|
180
|
+
},
|
|
181
|
+
info: (msg) => {
|
|
182
|
+
console.log(`${colors.bg.blue}${colors.fg.white}[flairjs/Info]${colors.reset} ${msg}${colors.reset}`);
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
const transformCode$1 = (code, filePath, options) => {
|
|
186
|
+
const result = transformCode(code, filePath, {
|
|
187
|
+
cssOutDir: options.cssOutDir,
|
|
188
|
+
classNameList: options.classNameList,
|
|
189
|
+
useTheme: options.useTheme,
|
|
190
|
+
theme: options.theme,
|
|
191
|
+
appendTimestampToCssFile: options.appendTimestampToCssFile
|
|
192
|
+
}, options.cssPreprocessor);
|
|
193
|
+
(result?.logs ?? []).forEach((log) => {
|
|
194
|
+
if (logger[log.level]) logger[log.level](log.message);
|
|
195
|
+
});
|
|
196
|
+
return result;
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
//#endregion
|
|
200
|
+
//#region src/index.ts
|
|
201
|
+
const SourceMap = SourceMapImport.default ?? SourceMapImport;
|
|
202
|
+
var src_default = new Transformer({
|
|
203
|
+
async loadConfig({ config }) {
|
|
204
|
+
const getConfigResult = await config.getConfig(["tool.config.js"]);
|
|
205
|
+
const filePath = getConfigResult?.filePath;
|
|
206
|
+
const configContents = getConfigResult?.contents;
|
|
207
|
+
if (filePath?.endsWith(".js")) config.invalidateOnStartup();
|
|
208
|
+
const cssGeneratedDir = await setupGeneratedCssDir();
|
|
209
|
+
const userTheme = await setupUserThemeFile({ buildThemeFile: configContents?.buildThemeFile });
|
|
210
|
+
return {
|
|
211
|
+
...configContents,
|
|
212
|
+
cssGeneratedDir,
|
|
213
|
+
userTheme
|
|
214
|
+
};
|
|
215
|
+
},
|
|
216
|
+
async transform({ asset, config, logger: logger$1, options }) {
|
|
217
|
+
const filePath = asset.filePath;
|
|
218
|
+
const cssOutDir = config?.cssGeneratedDir ?? null;
|
|
219
|
+
if (!shouldProcessFile(filePath, config.include, config.exclude)) return [asset];
|
|
220
|
+
if (!cssOutDir) return [asset];
|
|
221
|
+
try {
|
|
222
|
+
const code = await asset.getCode();
|
|
223
|
+
const result = transformCode$1(code, asset.filePath, {
|
|
224
|
+
appendTimestampToCssFile: true,
|
|
225
|
+
classNameList: config?.classNameList,
|
|
226
|
+
cssPreprocessor: config?.cssPreprocessor ? (css) => config.cssPreprocessor(css, asset.filePath) : void 0,
|
|
227
|
+
theme: config.userTheme?.theme,
|
|
228
|
+
useTheme: !!config.userTheme,
|
|
229
|
+
cssOutDir
|
|
230
|
+
});
|
|
231
|
+
if (!result) return [asset];
|
|
232
|
+
if (result.generatedCssName) removeOutdatedCssFiles(asset.filePath, result.generatedCssName, { flairGeneratedCssDir: cssOutDir });
|
|
233
|
+
asset.setCode(result.code);
|
|
234
|
+
if (result.sourcemap) {
|
|
235
|
+
const sourcemap = new SourceMap(options.projectRoot);
|
|
236
|
+
sourcemap.addVLQMap(JSON.parse(result.sourcemap));
|
|
237
|
+
asset.setMap(sourcemap);
|
|
238
|
+
}
|
|
239
|
+
return [asset];
|
|
240
|
+
} catch (error) {
|
|
241
|
+
logger$1.error({
|
|
242
|
+
message: `Error during flairjs transformation: ${error instanceof Error ? error.message : String(error)}`,
|
|
243
|
+
origin: "@flairjs/parcel-transformer"
|
|
244
|
+
});
|
|
245
|
+
return [asset];
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
//#endregion
|
|
251
|
+
export { src_default as default };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Transformer } from "@parcel/plugin";
|
|
2
|
+
declare const _default: Transformer<{
|
|
3
|
+
cssGeneratedDir: string | null;
|
|
4
|
+
userTheme: {
|
|
5
|
+
theme: any;
|
|
6
|
+
originalPath: string;
|
|
7
|
+
} | null;
|
|
8
|
+
cssPreprocessor?: (css: string, id: string) => string;
|
|
9
|
+
include?: string | string[];
|
|
10
|
+
exclude?: string | string[];
|
|
11
|
+
buildThemeFile?: (theme: import("@flairjs/client").FlairThemeConfig) => string;
|
|
12
|
+
classNameList?: string[];
|
|
13
|
+
}>;
|
|
14
|
+
export default _default;
|