@menapo/vicss 0.0.0-stage → 1.0.0

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.
@@ -0,0 +1,162 @@
1
+ import { l as printBase, st as configError, ut as isPlainObject, y as resolveSystem } from "./print-Ds6fkgio.js";
2
+ import { existsSync } from "node:fs";
3
+ import path from "node:path";
4
+ import { AsyncLocalStorage } from "node:async_hooks";
5
+ import { pathToFileURL } from "node:url";
6
+ //#region src/config/files.ts
7
+ /** Where the plugin installs its recorder (an `AsyncLocalStorage<ConfigLoad>`). */
8
+ const READS = Symbol.for("@menapo/vicss/config-load");
9
+ /** Non-enumerable on a `dtcg()` result: the absolute paths it read. */
10
+ const FILES = Symbol.for("@menapo/vicss/config-files");
11
+ /** Non-enumerable on a `dtcg()` result: a fresh result if a file changed since, else undefined. */
12
+ const RELOAD = Symbol.for("@menapo/vicss/config-reload");
13
+ /**
14
+ * The files recorded on a config object and its presets, depth first. A
15
+ * `dtcg()` result spread into a config loses them; one in `presets` keeps
16
+ * them.
17
+ */
18
+ function filesOf(config, seen = /* @__PURE__ */ new Set()) {
19
+ if (typeof config !== "object" || config === null || seen.has(config)) return [];
20
+ seen.add(config);
21
+ const own = config[FILES];
22
+ const files = Array.isArray(own) ? own.filter((f) => typeof f === "string") : [];
23
+ const presets = config.presets;
24
+ if (Array.isArray(presets)) for (const preset of presets) files.push(...filesOf(preset, seen));
25
+ return [...new Set(files)];
26
+ }
27
+ /**
28
+ * `config` with every `dtcg()` result in its presets whose files changed
29
+ * since it ran replaced by a fresh one. Objects on the way to a replaced one
30
+ * are copied, and everything else is kept by identity, so the caller's
31
+ * objects are never changed. Throws what `dtcg()` throws.
32
+ */
33
+ function refreshed(config, seen = /* @__PURE__ */ new Map()) {
34
+ if (typeof config !== "object" || config === null) return config;
35
+ if (seen.has(config)) return seen.get(config);
36
+ seen.set(config, config);
37
+ const reload = config[RELOAD];
38
+ let out = (typeof reload === "function" ? reload() : void 0) ?? config;
39
+ const presets = out.presets;
40
+ if (Array.isArray(presets)) {
41
+ const next = presets.map((preset) => refreshed(preset, seen));
42
+ if (next.some((preset, i) => preset !== presets[i])) {
43
+ out = Object.create(Object.getPrototypeOf(out), Object.getOwnPropertyDescriptors(out));
44
+ Object.defineProperty(out, "presets", {
45
+ value: next,
46
+ enumerable: true,
47
+ writable: true,
48
+ configurable: true
49
+ });
50
+ }
51
+ }
52
+ seen.set(config, out);
53
+ return out;
54
+ }
55
+ //#endregion
56
+ //#region src/vite/config-loader.ts
57
+ /**
58
+ * Loads `vicss.config.ts` (PLAN §5.3) with Vite's `runnerImport`, so a config
59
+ * can import presets, token JSON and TypeScript the way app code does,
60
+ * without a second bundler. Vite is imported when a load needs it: a scan
61
+ * worker (D17) that Node can import the config for does without it.
62
+ */
63
+ const CONFIG_FILES = [
64
+ "vicss.config.ts",
65
+ "vicss.config.mts",
66
+ "vicss.config.js",
67
+ "vicss.config.mjs"
68
+ ];
69
+ /**
70
+ * One recorder for every copy of the plugin in the process: `dtcg()` reports
71
+ * to whichever is installed (config/files.ts), and the store tells loads
72
+ * running at the same time apart.
73
+ */
74
+ function recorder() {
75
+ const global = globalThis;
76
+ return global[READS] ??= new AsyncLocalStorage();
77
+ }
78
+ /**
79
+ * `option` is a path relative to `root`, a config object, or undefined for the
80
+ * first `vicss.config.*` in `root`. Throws VicssError for an invalid config.
81
+ * `reads` receives the files the config read, also when loading it fails, so
82
+ * a caller can watch a token file that is missing or broken.
83
+ */
84
+ async function loadSystem(root, option, log, reads = /* @__PURE__ */ new Set(), options = {}) {
85
+ if (typeof option === "object") {
86
+ const config = recorder().run({ reads }, () => refreshed(option));
87
+ const files = filesOf(config).map(normalizePath);
88
+ return {
89
+ system: checked(config),
90
+ config,
91
+ file: void 0,
92
+ watch: files
93
+ };
94
+ }
95
+ let file;
96
+ if (typeof option === "string") {
97
+ file = path.resolve(root, option);
98
+ if (!existsSync(file)) throw configError("config", `${option} does not exist in ${root}`);
99
+ } else {
100
+ file = CONFIG_FILES.map((name) => path.join(root, name)).find((f) => existsSync(f));
101
+ if (!file) {
102
+ log(`vicss: no ${CONFIG_FILES.join(", ")} in ${root}; using an empty config`);
103
+ return {
104
+ system: resolveSystem({}),
105
+ config: {},
106
+ file: void 0,
107
+ watch: []
108
+ };
109
+ }
110
+ }
111
+ file = normalizePath(file);
112
+ const entry = file;
113
+ const load = {
114
+ reads,
115
+ dir: path.dirname(entry)
116
+ };
117
+ const { module, dependencies } = await recorder().run(load, async () => {
118
+ if (options.native) return {
119
+ module: await import(pathToFileURL(entry).href),
120
+ dependencies: []
121
+ };
122
+ const { runnerImport } = await import("vite");
123
+ return runnerImport(entry, {
124
+ root,
125
+ logLevel: "error"
126
+ });
127
+ });
128
+ if (!isPlainObject(module.default)) throw configError("config", `${path.basename(file)} must export a config object as default`);
129
+ const config = recorder().run(load, () => refreshed(module.default));
130
+ const read = [...reads, ...filesOf(config)].map(normalizePath);
131
+ return {
132
+ system: checked(config),
133
+ config,
134
+ file,
135
+ watch: [.../* @__PURE__ */ new Set([
136
+ file,
137
+ ...dependencies.map(normalizePath),
138
+ ...read
139
+ ])]
140
+ };
141
+ }
142
+ /** Vite's `normalizePath`: forward slashes on Windows, and no `..`. */
143
+ function normalizePath(file) {
144
+ return path.posix.normalize(process.platform === "win32" ? file.replaceAll("\\", "/") : file);
145
+ }
146
+ /**
147
+ * Resolves the config and prints its own CSS once: `globalCss` and keyframe
148
+ * values are checked only when they print, and an error found here is a
149
+ * config error, reported at startup or keeping the last good config in dev,
150
+ * rather than a failure of the first stylesheet that prints them.
151
+ */
152
+ function checked(config) {
153
+ const system = resolveSystem(config);
154
+ printBase({
155
+ system,
156
+ tokens: false,
157
+ warn: () => {}
158
+ });
159
+ return system;
160
+ }
161
+ //#endregion
162
+ export { loadSystem as n, CONFIG_FILES as t };
@@ -0,0 +1 @@
1
+ export { n as loadSystem } from "./config-loader-DzP68Snn.js";