cssints 0.0.0-stage → 0.2.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.
- package/LICENSE +21 -0
- package/README.md +188 -2
- package/dist/author-types-C1AhsnrT.d.mts +80 -0
- package/dist/check.d.mts +22 -0
- package/dist/check.mjs +37 -0
- package/dist/color-BYIxVLlS.mjs +29 -0
- package/dist/color-C8OzjAeg.mjs +2 -0
- package/dist/contrast-DhK69Xak.mjs +83 -0
- package/dist/derived.d.mts +14 -0
- package/dist/derived.mjs +391 -0
- package/dist/errors-D4ZbcwRo.d.mts +32 -0
- package/dist/frame-BoBKjgBB.mjs +92 -0
- package/dist/frame.d.mts +72 -0
- package/dist/frame.mjs +2 -0
- package/dist/group-common-9zpBxfUF.d.mts +1 -0
- package/dist/group-types-9ttphdku.d.mts +55 -0
- package/dist/groups/compositing-2.d.mts +20 -0
- package/dist/groups/css-align-3.d.mts +29 -0
- package/dist/groups/css-anchor-position-1.d.mts +49 -0
- package/dist/groups/css-anchor-position-2.d.mts +50 -0
- package/dist/groups/css-animations-1.d.mts +28 -0
- package/dist/groups/css-animations-2.d.mts +29 -0
- package/dist/groups/css-backgrounds-3.d.mts +27 -0
- package/dist/groups/css-backgrounds-4.d.mts +29 -0
- package/dist/groups/css-borders-4.d.mts +95 -0
- package/dist/groups/css-box-4.d.mts +38 -0
- package/dist/groups/css-break-4.d.mts +23 -0
- package/dist/groups/css-cascade-5.d.mts +18 -0
- package/dist/groups/css-cascade-6.d.mts +18 -0
- package/dist/groups/css-color-4.d.mts +29 -0
- package/dist/groups/css-color-5.d.mts +32 -0
- package/dist/groups/css-color-6.d.mts +32 -0
- package/dist/groups/css-color-adjust-1.d.mts +20 -0
- package/dist/groups/css-color-hdr-1.d.mts +19 -0
- package/dist/groups/css-conditional-3.d.mts +17 -0
- package/dist/groups/css-conditional-4.d.mts +17 -0
- package/dist/groups/css-conditional-5.d.mts +22 -0
- package/dist/groups/css-contain-2.d.mts +19 -0
- package/dist/groups/css-content-3.d.mts +23 -0
- package/dist/groups/css-counter-styles-3.d.mts +16 -0
- package/dist/groups/css-display-4.d.mts +22 -0
- package/dist/groups/css-easing-2.d.mts +18 -0
- package/dist/groups/css-env-1.d.mts +16 -0
- package/dist/groups/css-flexbox-1.d.mts +24 -0
- package/dist/groups/css-fonts-4.d.mts +46 -0
- package/dist/groups/css-fonts-5.d.mts +44 -0
- package/dist/groups/css-forms-1.d.mts +19 -0
- package/dist/groups/css-gaps-1.d.mts +21 -0
- package/dist/groups/css-gcpm-3.d.mts +20 -0
- package/dist/groups/css-gcpm-4.d.mts +20 -0
- package/dist/groups/css-grid-2.d.mts +34 -0
- package/dist/groups/css-grid-3.d.mts +34 -0
- package/dist/groups/css-images-3.d.mts +25 -0
- package/dist/groups/css-images-4.d.mts +32 -0
- package/dist/groups/css-images-5.d.mts +33 -0
- package/dist/groups/css-inline-3.d.mts +28 -0
- package/dist/groups/css-lists-3.d.mts +26 -0
- package/dist/groups/css-logical-1.d.mts +35 -0
- package/dist/groups/css-masking-1.d.mts +37 -0
- package/dist/groups/css-multicol-2.d.mts +24 -0
- package/dist/groups/css-overflow-3.d.mts +28 -0
- package/dist/groups/css-overflow-4.d.mts +29 -0
- package/dist/groups/css-overflow-5.d.mts +31 -0
- package/dist/groups/css-overscroll-1.d.mts +22 -0
- package/dist/groups/css-page-3.d.mts +18 -0
- package/dist/groups/css-page-floats-3.d.mts +19 -0
- package/dist/groups/css-position-3.d.mts +29 -0
- package/dist/groups/css-position-4.d.mts +30 -0
- package/dist/groups/css-rhythm-1.d.mts +18 -0
- package/dist/groups/css-round-display-1.d.mts +16 -0
- package/dist/groups/css-ruby-1.d.mts +21 -0
- package/dist/groups/css-scroll-anchoring-1.d.mts +18 -0
- package/dist/groups/css-scroll-snap-1.d.mts +42 -0
- package/dist/groups/css-scroll-snap-2.d.mts +43 -0
- package/dist/groups/css-scrollbars-1.d.mts +19 -0
- package/dist/groups/css-shapes-1.d.mts +27 -0
- package/dist/groups/css-shapes-2.d.mts +27 -0
- package/dist/groups/css-size-adjust-1.d.mts +18 -0
- package/dist/groups/css-sizing-3.d.mts +34 -0
- package/dist/groups/css-sizing-4.d.mts +33 -0
- package/dist/groups/css-speech-1.d.mts +18 -0
- package/dist/groups/css-tables-3.d.mts +22 -0
- package/dist/groups/css-text-3.d.mts +36 -0
- package/dist/groups/css-text-4.d.mts +40 -0
- package/dist/groups/css-text-decor-3.d.mts +30 -0
- package/dist/groups/css-text-decor-4.d.mts +31 -0
- package/dist/groups/css-transforms-1.d.mts +31 -0
- package/dist/groups/css-transforms-2.d.mts +48 -0
- package/dist/groups/css-transitions-1.d.mts +22 -0
- package/dist/groups/css-transitions-2.d.mts +23 -0
- package/dist/groups/css-ui-4.d.mts +35 -0
- package/dist/groups/css-values-4.d.mts +38 -0
- package/dist/groups/css-values-5.d.mts +43 -0
- package/dist/groups/css-variables-2.d.mts +6 -0
- package/dist/groups/css-view-transitions-2.d.mts +20 -0
- package/dist/groups/css-viewport.d.mts +18 -0
- package/dist/groups/css-will-change-1.d.mts +18 -0
- package/dist/groups/css-writing-modes-4.d.mts +22 -0
- package/dist/groups/css2.d.mts +19 -0
- package/dist/groups/fill-stroke-3.d.mts +27 -0
- package/dist/groups/filter-effects-1.d.mts +32 -0
- package/dist/groups/filter-effects-2.d.mts +33 -0
- package/dist/groups/limited-availability.d.mts +2 -0
- package/dist/groups/mediaqueries-4.d.mts +16 -0
- package/dist/groups/mediaqueries-5.d.mts +16 -0
- package/dist/groups/motion-1.d.mts +24 -0
- package/dist/groups/newly-available.d.mts +631 -0
- package/dist/groups/not-discouraged.d.mts +727 -0
- package/dist/groups/scroll-animations-1.d.mts +30 -0
- package/dist/groups/selectors-4.d.mts +54 -0
- package/dist/groups/selectors-5.d.mts +54 -0
- package/dist/groups/widely-available.d.mts +616 -0
- package/dist/index.d.mts +48 -0
- package/dist/index.mjs +1269 -0
- package/dist/instrument-gCazujmb.mjs +1624 -0
- package/dist/lowered-D2KusPLp.mjs +28 -0
- package/dist/node-OJ_w_Usj.d.mts +233 -0
- package/dist/parent-vars.d.mts +13 -0
- package/dist/parent-vars.mjs +65 -0
- package/dist/plugin-types.d.mts +377 -0
- package/dist/plugin.d.mts +3 -0
- package/dist/plugin.mjs +30 -0
- package/dist/registry-CTumHB8p.mjs +73 -0
- package/dist/runtime-Dt4Tm0Q7.d.mts +19 -0
- package/dist/runtime.d.mts +18 -0
- package/dist/runtime.mjs +25 -0
- package/dist/scope-ZVhUxQH1.d.mts +2101 -0
- package/dist/sheet-BKsMTa0c.mjs +757 -0
- package/dist/surface.d.mts +228 -0
- package/dist/surface.mjs +101 -0
- package/dist/theme-BsP2E4LB.mjs +929 -0
- package/dist/theme-types-Bqv0Ggz_.d.mts +1808 -0
- package/dist/trace-otlp-CbKFDsn9.mjs +14 -0
- package/dist/tui-types.d.mts +181 -0
- package/dist/tui.d.mts +23 -0
- package/dist/tui.mjs +427 -0
- package/dist/types.d.mts +2 -0
- package/dist/vite.d.mts +134 -0
- package/dist/vite.mjs +977 -0
- package/docs/API.md +1193 -0
- package/package.json +85 -4
- package/skills/cssints/SKILL.md +203 -0
- package/skills/cssints/references/errors.md +86 -0
- package/skills/cssints/references/plugins.md +91 -0
- package/skills/cssints/references/tokens.md +91 -0
- package/skills/cssints-plugin/SKILL.md +177 -0
- package/skills/cssints-plugin/references/table.md +124 -0
- package/skills/cssints-plugin/references/testing.md +122 -0
package/dist/vite.mjs
ADDED
|
@@ -0,0 +1,977 @@
|
|
|
1
|
+
import { c as EvalError, d as MacroError, f as MemberError, i as forgetWarnings, l as HookError, n as forget, p as SiteMissingError, t as Registry } from "./registry-CTumHB8p.mjs";
|
|
2
|
+
import { C as fallbackEntries, T as runtimeNames, a as closeNames, b as DERIVED, c as layerEntries, f as themedEntries, l as layerStatements, m as usesDerived, n as addGlobal, o as globalEntries, r as addLayers, s as globalNames, t as LAYERS, u as renderSheet, v as kernelEntries, w as runtimeModule, x as RUNTIME_ID } from "./sheet-BKsMTa0c.mjs";
|
|
3
|
+
import { a as runtimeImport, i as instrument, o as writeSite } from "./instrument-gCazujmb.mjs";
|
|
4
|
+
import { r as verifyChecks } from "./contrast-DhK69Xak.mjs";
|
|
5
|
+
import { createRequire } from "node:module";
|
|
6
|
+
import { targets as targets$1, useTargets } from "@cssints/css-grammar/support";
|
|
7
|
+
import { Cause, Clock, Config, Data, Effect, Exit, Formatter, Option, Predicate, Result, Schema, Semaphore } from "effect";
|
|
8
|
+
import { createHash } from "node:crypto";
|
|
9
|
+
import { basename, join, relative, resolve, sep } from "node:path";
|
|
10
|
+
import { browserslistToTargets } from "lightningcss";
|
|
11
|
+
import MagicString from "magic-string";
|
|
12
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
13
|
+
import { readFile } from "node:fs/promises";
|
|
14
|
+
import { browsers as browsers$1 } from "@cssints/css-grammar/browsers";
|
|
15
|
+
import { createFilter, createServer, createServerModuleRunner, normalizePath, transformWithOxc } from "vite";
|
|
16
|
+
import { fileURLToPath } from "node:url";
|
|
17
|
+
import { Window } from "happy-dom";
|
|
18
|
+
import { ESModulesEvaluator, ssrModuleExportsKey } from "vite/module-runner";
|
|
19
|
+
import { gzipSync } from "node:zlib";
|
|
20
|
+
//#region src/evaluate.ts
|
|
21
|
+
var DomEvaluator = class extends ESModulesEvaluator {
|
|
22
|
+
win = Object.assign(new Window(), { __jsx: () => null });
|
|
23
|
+
names = Object.getOwnPropertyNames(this.win).filter((k) => !Reflect.has(globalThis, k));
|
|
24
|
+
async runInlinedModule(context, code) {
|
|
25
|
+
const keys = Object.keys(context);
|
|
26
|
+
const fn = new Function(...this.names, `return async function (${keys.join(",")}) {"use strict";\n${code}\n}`);
|
|
27
|
+
const globals = this.win;
|
|
28
|
+
const values = context;
|
|
29
|
+
await fn(...this.names.map((k) => globals[k]))(...keys.map((k) => values[k]));
|
|
30
|
+
Object.seal(context[ssrModuleExportsKey]);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
const evalLock = Semaphore.makeUnsafe(1);
|
|
34
|
+
const LIB = fileURLToPath(new URL("./index.ts", import.meta.url));
|
|
35
|
+
const clearApp = ({ idToModuleMap, urlToIdModuleMap, fileToModulesMap }) => {
|
|
36
|
+
const lib = /* @__PURE__ */ new Set();
|
|
37
|
+
const walk = (m) => {
|
|
38
|
+
if (!m || lib.has(m)) return;
|
|
39
|
+
lib.add(m);
|
|
40
|
+
m.imports.forEach((id) => walk(idToModuleMap.get(id)));
|
|
41
|
+
};
|
|
42
|
+
walk(idToModuleMap.get(LIB));
|
|
43
|
+
for (const map of [idToModuleMap, urlToIdModuleMap]) for (const [k, m] of map) if (!lib.has(m)) map.delete(k);
|
|
44
|
+
for (const [k, ms] of fileToModulesMap) for (const m of ms) if (!lib.has(m) && ms.delete(m) && !ms.size) fileToModulesMap.delete(k);
|
|
45
|
+
};
|
|
46
|
+
const isMacroError = (e) => Predicate.isTagged(e, "MacroError");
|
|
47
|
+
const isMemberError = (e) => Predicate.isTagged(e, "MemberError");
|
|
48
|
+
const failureOf = (id, registry) => (e) => {
|
|
49
|
+
if (isMacroError(e)) return new MacroError({
|
|
50
|
+
message: e.message,
|
|
51
|
+
file: e.file,
|
|
52
|
+
site: e.site,
|
|
53
|
+
offset: e.offset,
|
|
54
|
+
cause: e.cause
|
|
55
|
+
});
|
|
56
|
+
if (isMemberError(e)) return new MemberError({
|
|
57
|
+
message: e.message,
|
|
58
|
+
pluginName: e.pluginName,
|
|
59
|
+
file: e.file,
|
|
60
|
+
site: e.site,
|
|
61
|
+
offset: e.offset,
|
|
62
|
+
cause: e.cause
|
|
63
|
+
});
|
|
64
|
+
const at = registry.at;
|
|
65
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
66
|
+
if (!at) return new EvalError({
|
|
67
|
+
file: id,
|
|
68
|
+
message,
|
|
69
|
+
cause: e
|
|
70
|
+
});
|
|
71
|
+
const m = e instanceof ReferenceError ? /^(?:(\S+) is not defined|Cannot access '(\S+)' before initialization)$/.exec(e.message) : null;
|
|
72
|
+
const name = m?.[1] ?? m?.[2];
|
|
73
|
+
return new MacroError({
|
|
74
|
+
message: name ? `cssints: css arguments must be known at build time: \`${name}\` is not defined where the call is evaluated (a parameter, a prop or state). Use cn(base, on && p(4)), a cv variant, or a token in a style prop` : message,
|
|
75
|
+
cause: e,
|
|
76
|
+
...at
|
|
77
|
+
});
|
|
78
|
+
};
|
|
79
|
+
const evaluateModule = Effect.fnUntraced(function* (runner, id, targets) {
|
|
80
|
+
const registry = yield* Registry;
|
|
81
|
+
useTargets(targets);
|
|
82
|
+
registry.sites.delete(id);
|
|
83
|
+
registry.nodes.delete(id);
|
|
84
|
+
forget(id);
|
|
85
|
+
registry.at = void 0;
|
|
86
|
+
registry.files.clear();
|
|
87
|
+
registry.gen++;
|
|
88
|
+
clearApp(runner.evaluatedModules);
|
|
89
|
+
yield* Effect.tryPromise({
|
|
90
|
+
try: () => runner.import(id).then((m) => m.__cssints_hoisted?.()),
|
|
91
|
+
catch: failureOf(id, registry)
|
|
92
|
+
}).pipe(Effect.withSpan("cssints.runner.import", { attributes: { file: id } }), Effect.timeoutOrElse({
|
|
93
|
+
duration: "30 seconds",
|
|
94
|
+
orElse: () => Effect.fail(new EvalError({
|
|
95
|
+
file: id,
|
|
96
|
+
message: `cssints: evaluating ${id} took more than 30 seconds`
|
|
97
|
+
}))
|
|
98
|
+
}));
|
|
99
|
+
yield* verifyChecks((c) => c.gen === registry.gen);
|
|
100
|
+
return registry.sites.get(id) ?? /* @__PURE__ */ new Map();
|
|
101
|
+
});
|
|
102
|
+
/**
|
|
103
|
+
* Evaluates `id` for the browser `targets` (default: those of process.cwd()) and runs `whileLocked` on its sites before
|
|
104
|
+
* the next evaluation may start (runner.qnt `rules`).
|
|
105
|
+
*/
|
|
106
|
+
const evaluate = Effect.fn("cssints.evaluate")(function* (runner, id, whileLocked, targets) {
|
|
107
|
+
return yield* evalLock.withPermit(evaluateModule(runner, id, targets).pipe(Effect.flatMap(whileLocked)));
|
|
108
|
+
});
|
|
109
|
+
//#endregion
|
|
110
|
+
//#region src/devtools-server.ts
|
|
111
|
+
const DEVTOOLS_ID = "virtual:cssints/devtools";
|
|
112
|
+
const RESOLVED = `\0${DEVTOOLS_ID}`;
|
|
113
|
+
const SHEET$1 = "\0virtual:cssints.css";
|
|
114
|
+
const GROUP = /^_g(-[\w-]+)?$/;
|
|
115
|
+
const table = Effect.fn("cssints.devtoolsTable")(function* (root, usedBy, callsOf) {
|
|
116
|
+
const { rules, kernels, defs, scopes, layers } = yield* Registry;
|
|
117
|
+
const entries = [...new Set([...usedBy.values()].flatMap((s) => s.split("\n")))];
|
|
118
|
+
const sheet = yield* renderSheet(entries);
|
|
119
|
+
const classes = {};
|
|
120
|
+
for (const cls of entries) {
|
|
121
|
+
const r = rules.get(cls);
|
|
122
|
+
if (!r) continue;
|
|
123
|
+
const scope = r.prop.startsWith("--") ? [...scopes.keys()].find((s) => r.prop.startsWith(`--${s}-`)) : void 0;
|
|
124
|
+
classes[cls] = {
|
|
125
|
+
kind: "class",
|
|
126
|
+
layer: r.layer,
|
|
127
|
+
wrap: r.wrap,
|
|
128
|
+
prop: r.prop,
|
|
129
|
+
css: r.css,
|
|
130
|
+
tokens: r.tokens ?? [],
|
|
131
|
+
...scope ? { plugin: scope } : {},
|
|
132
|
+
sites: []
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
for (const [key, k] of kernels) for (const m of k.markers) classes[m] = {
|
|
136
|
+
kind: "marker",
|
|
137
|
+
layer: "_.k",
|
|
138
|
+
wrap: [],
|
|
139
|
+
prop: "",
|
|
140
|
+
css: k.kernel.css,
|
|
141
|
+
tokens: [],
|
|
142
|
+
plugin: key,
|
|
143
|
+
sites: []
|
|
144
|
+
};
|
|
145
|
+
const sites = [];
|
|
146
|
+
for (const [file, calls] of callsOf) {
|
|
147
|
+
if (!usedBy.has(file)) continue;
|
|
148
|
+
for (const call of calls) {
|
|
149
|
+
const known = call.classes.filter((c) => {
|
|
150
|
+
if (!classes[c] && GROUP.test(c)) classes[c] = {
|
|
151
|
+
kind: "group",
|
|
152
|
+
layer: "",
|
|
153
|
+
wrap: [],
|
|
154
|
+
prop: "",
|
|
155
|
+
css: "",
|
|
156
|
+
tokens: [],
|
|
157
|
+
sites: []
|
|
158
|
+
};
|
|
159
|
+
return !!classes[c];
|
|
160
|
+
});
|
|
161
|
+
if (!known.length) continue;
|
|
162
|
+
const n = sites.push({
|
|
163
|
+
...call,
|
|
164
|
+
file,
|
|
165
|
+
classes: known
|
|
166
|
+
}) - 1;
|
|
167
|
+
for (const c of known) classes[c].sites.push(n);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
const tokens = {};
|
|
171
|
+
for (const [name, d] of defs) tokens[name] = {
|
|
172
|
+
path: d.path,
|
|
173
|
+
value: d.value
|
|
174
|
+
};
|
|
175
|
+
const statements = (before) => layerStatements([...layers.values()].flatMap((l) => l.before === before ? [l.names] : []));
|
|
176
|
+
const engine = LAYERS.slice(7, -1).split(", ");
|
|
177
|
+
const order = [
|
|
178
|
+
...statements(true).flat(),
|
|
179
|
+
...engine,
|
|
180
|
+
...statements(false).flat()
|
|
181
|
+
];
|
|
182
|
+
return {
|
|
183
|
+
root,
|
|
184
|
+
sheet,
|
|
185
|
+
layers: [...new Set(order)],
|
|
186
|
+
classes,
|
|
187
|
+
sites,
|
|
188
|
+
tokens
|
|
189
|
+
};
|
|
190
|
+
});
|
|
191
|
+
const ASK = "cssints:devtools:ask";
|
|
192
|
+
const ASKED = "cssints:devtools:asked";
|
|
193
|
+
const MAX_PROMPT = 16e3;
|
|
194
|
+
const Asking = Schema.Struct({
|
|
195
|
+
ref: Schema.Finite,
|
|
196
|
+
prompt: Schema.String
|
|
197
|
+
});
|
|
198
|
+
var OpenCodeError = class extends Data.TaggedError("OpenCodeError") {};
|
|
199
|
+
const workspace = (root) => root.split(sep).map((_, i, parts) => parts.slice(0, parts.length - i).join(sep) || sep).find((dir) => existsSync(join(dir, ".git"))) ?? root;
|
|
200
|
+
const connect = Effect.fn("cssints.opencodeConnect")(function* () {
|
|
201
|
+
const unavailable = (message) => () => new OpenCodeError({
|
|
202
|
+
status: "unavailable",
|
|
203
|
+
message
|
|
204
|
+
});
|
|
205
|
+
const { OpenCode } = yield* Effect.tryPromise({
|
|
206
|
+
try: () => import("@opencode/client"),
|
|
207
|
+
catch: unavailable("opencode is on, but @opencode/client is not installed: add it to the devDependencies of the app")
|
|
208
|
+
});
|
|
209
|
+
const { Service } = yield* Effect.tryPromise({
|
|
210
|
+
try: () => import("@opencode/client/service"),
|
|
211
|
+
catch: unavailable("opencode is on, but @opencode/client is not installed: add it to the devDependencies of the app")
|
|
212
|
+
});
|
|
213
|
+
const service = yield* Effect.tryPromise({
|
|
214
|
+
try: () => Service.discover(),
|
|
215
|
+
catch: (e) => unavailable(Predicate.isError(e) ? e.message : String(e))()
|
|
216
|
+
});
|
|
217
|
+
if (!service) return yield* new OpenCodeError({
|
|
218
|
+
status: "unavailable",
|
|
219
|
+
message: "No OpenCode service is running. Start OpenCode (or `opencode serve --service`) and send again."
|
|
220
|
+
});
|
|
221
|
+
return OpenCode.make({
|
|
222
|
+
baseUrl: service.url,
|
|
223
|
+
headers: Service.headers(service)
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
const ask = Effect.fn("cssints.opencodeAsk")(function* (root, options, ref, prompt, say) {
|
|
227
|
+
const client = yield* connect();
|
|
228
|
+
const call = (f) => Effect.tryPromise({
|
|
229
|
+
try: f,
|
|
230
|
+
catch: (e) => new OpenCodeError({
|
|
231
|
+
status: "failed",
|
|
232
|
+
message: Predicate.isError(e) ? e.message : String(e)
|
|
233
|
+
})
|
|
234
|
+
});
|
|
235
|
+
const { id } = yield* call(() => client.session.create({
|
|
236
|
+
title: "cssints devtools: UI change",
|
|
237
|
+
...options.agent ? { agent: options.agent } : {},
|
|
238
|
+
location: { directory: workspace(root) }
|
|
239
|
+
}));
|
|
240
|
+
say({
|
|
241
|
+
ref,
|
|
242
|
+
status: "running",
|
|
243
|
+
id
|
|
244
|
+
});
|
|
245
|
+
yield* call(() => client.session.prompt({
|
|
246
|
+
sessionID: id,
|
|
247
|
+
text: prompt.slice(0, MAX_PROMPT),
|
|
248
|
+
...options.skills?.length ? { skills: options.skills.map((s) => ({ id: s })) } : {}
|
|
249
|
+
}));
|
|
250
|
+
yield* call(() => client.session.wait({ sessionID: id }));
|
|
251
|
+
const { outcome } = yield* call(() => client.session.get({ sessionID: id }));
|
|
252
|
+
say({
|
|
253
|
+
ref,
|
|
254
|
+
status: outcome === "succeeded" ? "completed" : outcome ?? "failed",
|
|
255
|
+
id
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
const entryModule = (overlay, root, opencode) => overlay ? `import { mount } from ${Formatter.formatJson(overlay)};
|
|
259
|
+
const hot = import.meta.hot;
|
|
260
|
+
mount({
|
|
261
|
+
root: ${Formatter.formatJson(root)},
|
|
262
|
+
request: () => hot.send("cssints:devtools:get"),
|
|
263
|
+
on: (event, listener) => hot.on(event, listener),${opencode ? `\n ask: (ref, prompt) => hot.send("${ASK}", { ref, prompt }),` : ""}
|
|
264
|
+
});
|
|
265
|
+
` : `console.warn("cssints: devtools is on, but @cssints/devtools/overlay is not installed (or not built): add @cssints/devtools to the devDependencies of the app");\n`;
|
|
266
|
+
/**
|
|
267
|
+
* The dev-only plugin of `cssints({ devtools: true })`: the overlay's entry in every HTML page, and the table on request.
|
|
268
|
+
* `apply: "serve"`, so a build has none of it.
|
|
269
|
+
* @param {Map<string, string>} usedBy the entries of each client module (plugin.ts)
|
|
270
|
+
* @param {Map<string, DevSite[]>} callsOf the sites of each client module
|
|
271
|
+
* @param {OpenCodeOptions | undefined} opencode set: the overlay's prompt box starts OpenCode sessions through this server
|
|
272
|
+
* @returns {Plugin} the plugin
|
|
273
|
+
*/
|
|
274
|
+
const devtoolsPlugin = (usedBy, callsOf, opencode) => {
|
|
275
|
+
let server;
|
|
276
|
+
const stale = () => Effect.sync(() => server?.environments.client.hot.send("cssints:devtools:stale"));
|
|
277
|
+
const entry = Effect.fn("cssints.devtoolsEntry")(function* (resolve) {
|
|
278
|
+
const overlay = yield* Effect.tryPromise(resolve).pipe(Effect.orElseSucceed(() => null));
|
|
279
|
+
return entryModule(overlay?.id, server?.config.root ?? "", !!opencode);
|
|
280
|
+
});
|
|
281
|
+
return {
|
|
282
|
+
name: "cssints:devtools",
|
|
283
|
+
apply: "serve",
|
|
284
|
+
configureServer(s) {
|
|
285
|
+
server = s;
|
|
286
|
+
s.environments.client.hot.on("cssints:devtools:get", (_, client) => client.send("cssints:devtools", Effect.runSync(table(s.config.root, usedBy, callsOf))));
|
|
287
|
+
if (opencode) s.environments.client.hot.on(ASK, (data) => {
|
|
288
|
+
const asking = Schema.decodeUnknownOption(Asking)(data);
|
|
289
|
+
if (Option.isNone(asking)) return;
|
|
290
|
+
const { ref, prompt } = asking.value;
|
|
291
|
+
const say = (asked) => s.environments.client.hot.send(ASKED, asked);
|
|
292
|
+
Effect.runFork(ask(s.config.root, opencode, ref, prompt, say).pipe(Effect.catchTag("OpenCodeError", (e) => Effect.sync(() => say({
|
|
293
|
+
ref,
|
|
294
|
+
status: e.status,
|
|
295
|
+
message: e.message
|
|
296
|
+
})))));
|
|
297
|
+
});
|
|
298
|
+
},
|
|
299
|
+
transformIndexHtml: () => [{
|
|
300
|
+
tag: "script",
|
|
301
|
+
attrs: {
|
|
302
|
+
type: "module",
|
|
303
|
+
src: `/@id/${DEVTOOLS_ID}`
|
|
304
|
+
},
|
|
305
|
+
injectTo: "body"
|
|
306
|
+
}],
|
|
307
|
+
resolveId(id) {
|
|
308
|
+
if (id === "virtual:cssints/devtools") return RESOLVED;
|
|
309
|
+
},
|
|
310
|
+
load(id) {
|
|
311
|
+
if (id !== RESOLVED) return;
|
|
312
|
+
return Effect.runPromise(entry(() => this.resolve("@cssints/devtools/overlay", void 0, { skipSelf: true })));
|
|
313
|
+
},
|
|
314
|
+
transform: {
|
|
315
|
+
order: "post",
|
|
316
|
+
handler(_, id) {
|
|
317
|
+
if (this.environment.name === "client" && (id === SHEET$1 || callsOf.has(id))) Effect.runSync(stale());
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
};
|
|
321
|
+
};
|
|
322
|
+
const TABLE_FILE = "__CSSINTS_DEVTOOLS_TABLE__";
|
|
323
|
+
const loaderModule = (overlay, base) => `const key = (e) => {
|
|
324
|
+
if (e.altKey && e.shiftKey && e.code === "KeyC") {
|
|
325
|
+
e.preventDefault();
|
|
326
|
+
open();
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
const button = document.createElement("button");
|
|
330
|
+
button.textContent = "cssints";
|
|
331
|
+
button.title = "cssints devtools (Alt+Shift+C)";
|
|
332
|
+
button.style.cssText = "position:fixed;right:12px;bottom:12px;z-index:2147483647;padding:4px 8px;border:1px solid #374151;border-radius:999px;background:#111827;color:#e5e7eb;font:11px ui-monospace,monospace;cursor:pointer;opacity:.75";
|
|
333
|
+
button.onclick = () => open();
|
|
334
|
+
const open = () => {
|
|
335
|
+
button.remove();
|
|
336
|
+
removeEventListener("keydown", key, true);
|
|
337
|
+
import(${Formatter.formatJson(overlay)}).then(({ mount }) => {
|
|
338
|
+
const listeners = {};
|
|
339
|
+
mount({
|
|
340
|
+
root: "",
|
|
341
|
+
build: true,
|
|
342
|
+
request: () => fetch(new URL(${Formatter.formatJson(base)} + "${TABLE_FILE}", document.baseURI))
|
|
343
|
+
.then((r) => r.json())
|
|
344
|
+
.then((table) => listeners["cssints:devtools"]?.(table)),
|
|
345
|
+
on: (event, listener) => { listeners[event] = listener; },
|
|
346
|
+
});
|
|
347
|
+
});
|
|
348
|
+
};
|
|
349
|
+
addEventListener("keydown", key, true);
|
|
350
|
+
document.body.append(button);
|
|
351
|
+
`;
|
|
352
|
+
const kb = (n) => `${(n / 1024).toFixed(1)} kB`;
|
|
353
|
+
/**
|
|
354
|
+
* The build side of `cssints({ devtools: "build" })`: the overlay in every page behind a button, the table as a JSON asset.
|
|
355
|
+
* Nothing loads until the first open. The files of the sites are relative to the root, so the asset holds no path of this machine.
|
|
356
|
+
* @param {Map<string, string>} usedBy the entries of each client module (plugin.ts)
|
|
357
|
+
* @param {Map<string, DevSite[]>} callsOf the sites of each client module
|
|
358
|
+
* @returns {Plugin} the plugin
|
|
359
|
+
*/
|
|
360
|
+
const devtoolsBuildPlugin = (usedBy, callsOf) => ({
|
|
361
|
+
name: "cssints:devtools-build",
|
|
362
|
+
apply: "build",
|
|
363
|
+
transformIndexHtml: {
|
|
364
|
+
order: "pre",
|
|
365
|
+
handler: () => [{
|
|
366
|
+
tag: "script",
|
|
367
|
+
attrs: {
|
|
368
|
+
type: "module",
|
|
369
|
+
src: DEVTOOLS_ID
|
|
370
|
+
},
|
|
371
|
+
injectTo: "body"
|
|
372
|
+
}]
|
|
373
|
+
},
|
|
374
|
+
resolveId(id) {
|
|
375
|
+
if (id === "virtual:cssints/devtools") return RESOLVED;
|
|
376
|
+
},
|
|
377
|
+
load(id) {
|
|
378
|
+
if (id !== RESOLVED) return;
|
|
379
|
+
return Effect.runPromise(Effect.tryPromise(() => this.resolve("@cssints/devtools/overlay", void 0, { skipSelf: true })).pipe(Effect.orElseSucceed(() => null), Effect.map((overlay) => overlay ? loaderModule(overlay.id, this.environment.config.base) : `console.warn("cssints: devtools is on, but @cssints/devtools/overlay is not installed: add @cssints/devtools to the devDependencies of the app");\n`)));
|
|
380
|
+
},
|
|
381
|
+
generateBundle(_, bundle) {
|
|
382
|
+
if (this.environment.name !== "client") return;
|
|
383
|
+
const chunks = Object.values(bundle).flatMap((f) => f.type === "chunk" ? [f] : []);
|
|
384
|
+
const loader = chunks.find((c) => c.code.includes(TABLE_FILE));
|
|
385
|
+
if (!loader) return;
|
|
386
|
+
const { root } = this.environment.config;
|
|
387
|
+
const t = Effect.runSync(table(root, usedBy, callsOf));
|
|
388
|
+
const json = Formatter.formatJson({
|
|
389
|
+
...t,
|
|
390
|
+
root: "",
|
|
391
|
+
sites: t.sites.map((s) => ({
|
|
392
|
+
...s,
|
|
393
|
+
file: relative(root, s.file)
|
|
394
|
+
}))
|
|
395
|
+
});
|
|
396
|
+
const ref = this.emitFile({
|
|
397
|
+
type: "asset",
|
|
398
|
+
name: "cssints-devtools.json",
|
|
399
|
+
source: json
|
|
400
|
+
});
|
|
401
|
+
const file = this.getFileName(ref);
|
|
402
|
+
loader.code = loader.code.replace(TABLE_FILE, () => file);
|
|
403
|
+
const overlay = chunks.find((c) => c.isDynamicEntry && c.code.includes("cssints-devtools"));
|
|
404
|
+
this.info(`devtools: ${file} ${kb(Buffer.byteLength(json))} (${kb(gzipSync(json).length)} gzip)` + (overlay ? `, ${overlay.fileName} ${kb(Buffer.byteLength(overlay.code))} (${kb(gzipSync(overlay.code).length)} gzip), loaded on the first open` : ""));
|
|
405
|
+
}
|
|
406
|
+
});
|
|
407
|
+
//#endregion
|
|
408
|
+
//#region src/entries.ts
|
|
409
|
+
const moduleEntries = Effect.fnUntraced(function* (id, sites) {
|
|
410
|
+
const registry = yield* Registry;
|
|
411
|
+
const { rules, properties, themed } = registry;
|
|
412
|
+
const texts = [...sites.values()];
|
|
413
|
+
const classes = texts.flatMap((r) => [...r.matchAll(/"(_[\w-]+(?: _[\w-]+)*)"/g)].flatMap((m) => m[1].split(" ")));
|
|
414
|
+
const kernels = kernelEntries(registry, id);
|
|
415
|
+
const names = new Set([...texts, ...kernels].flatMap((r) => r.match(/--[\w-]+/g) ?? []));
|
|
416
|
+
globalNames(themed, id).forEach((n) => names.add(n));
|
|
417
|
+
for (const c of classes) rules.get(c)?.tokens?.forEach((n) => names.add(n));
|
|
418
|
+
closeNames(names, registry.defs, themed);
|
|
419
|
+
const entries = [
|
|
420
|
+
...classes,
|
|
421
|
+
...[...names].flatMap((n) => properties.get(n)?.css ?? []),
|
|
422
|
+
...themedEntries(themed, id, names),
|
|
423
|
+
...kernels,
|
|
424
|
+
...globalEntries(registry, id),
|
|
425
|
+
...layerEntries(registry, id),
|
|
426
|
+
...yield* fallbackEntries(registry, id)
|
|
427
|
+
];
|
|
428
|
+
const runtimes = runtimeNames(registry, id);
|
|
429
|
+
if (!runtimes.includes("derived") && usesDerived(registry, names)) runtimes.push(DERIVED);
|
|
430
|
+
return {
|
|
431
|
+
entries,
|
|
432
|
+
runtimes
|
|
433
|
+
};
|
|
434
|
+
});
|
|
435
|
+
//#endregion
|
|
436
|
+
//#region src/trace.ts
|
|
437
|
+
const mode = /^otlp(?::(.+))?$/.exec(Effect.runSync(Config.String("CSSINTS_TRACE").pipe(Config.withDefault(""))));
|
|
438
|
+
const otlp = mode ? await import("./trace-otlp-CbKFDsn9.mjs").then((m) => m.start(mode[1] ?? "http://localhost:4318")) : void 0;
|
|
439
|
+
let runtime = otlp;
|
|
440
|
+
const runSync = otlp ? (e) => runtime ? runtime.runSync(e) : Effect.runSync(e) : Effect.runSync;
|
|
441
|
+
const runPromiseExit = otlp ? (e, o) => runtime ? runtime.runPromiseExit(e, o) : Effect.runPromiseExit(e, o) : Effect.runPromiseExit;
|
|
442
|
+
/**
|
|
443
|
+
* Sends what is buffered and stops the exporter, whose timer would keep Node alive (the end of a build, `server.close()`;
|
|
444
|
+
* a script that exits itself calls it first). Later hooks run untraced. A no-op when off.
|
|
445
|
+
* @returns {Promise<void>} resolved when the exporter has stopped
|
|
446
|
+
*/
|
|
447
|
+
const closeTrace = () => {
|
|
448
|
+
const r = runtime;
|
|
449
|
+
runtime = void 0;
|
|
450
|
+
return r ? r.dispose() : Promise.resolve();
|
|
451
|
+
};
|
|
452
|
+
const note = (e) => Effect.flatMap(Effect.all([Effect.currentSpan, Clock.currentTimeNanos]), ([span, now]) => Effect.sync(() => {
|
|
453
|
+
span.event("cssints.error", now, {
|
|
454
|
+
message: e.message,
|
|
455
|
+
file: e.file,
|
|
456
|
+
offset: e.offset
|
|
457
|
+
});
|
|
458
|
+
Object.assign(e, {
|
|
459
|
+
traceId: span.traceId,
|
|
460
|
+
spanId: span.spanId,
|
|
461
|
+
message: `${e.message} (trace ${span.traceId})`
|
|
462
|
+
});
|
|
463
|
+
})).pipe(Effect.ignore);
|
|
464
|
+
const hook = otlp ? (name, file, program, environment) => program.pipe(Effect.tapCause((cause) => {
|
|
465
|
+
const e = Cause.squash(cause);
|
|
466
|
+
return Predicate.hasProperty(e, "message") ? note(e) : Effect.void;
|
|
467
|
+
}), Effect.withSpan(name, {
|
|
468
|
+
root: true,
|
|
469
|
+
attributes: {
|
|
470
|
+
file,
|
|
471
|
+
environment
|
|
472
|
+
}
|
|
473
|
+
})) : (_name, _file, program) => program;
|
|
474
|
+
const warned = otlp ? (ws, file) => Effect.flatMap(Effect.all([Effect.currentSpan, Clock.currentTimeNanos]), ([span, now]) => Effect.sync(() => ws.forEach((message) => span.event("cssints.warning", now, {
|
|
475
|
+
message,
|
|
476
|
+
file
|
|
477
|
+
})))).pipe(Effect.ignore) : () => Effect.void;
|
|
478
|
+
//#endregion
|
|
479
|
+
//#region src/plugin.ts
|
|
480
|
+
const FILE_RE = /\.(ts|tsx|js|jsx|mts|mjs)$/;
|
|
481
|
+
const VERSION = /[?&]v=\w+$/;
|
|
482
|
+
const SHEET_IMPORT = "virtual:cssints.css";
|
|
483
|
+
const SHEET = `\0${SHEET_IMPORT}`;
|
|
484
|
+
const ATTRIBUTE = /type\s*:\s*["']cssints["']/;
|
|
485
|
+
const marked = (code, id) => code.includes("cssints") && (!id.includes("node_modules") || ATTRIBUTE.test(code));
|
|
486
|
+
const Deps = Schema.optional(Schema.Record(Schema.String, Schema.String));
|
|
487
|
+
const Manifest = Schema.fromJsonString(Schema.Struct({
|
|
488
|
+
dependencies: Deps,
|
|
489
|
+
devDependencies: Deps,
|
|
490
|
+
peerDependencies: Deps
|
|
491
|
+
}));
|
|
492
|
+
const decodeManifest = Schema.decodeUnknownOption(Manifest);
|
|
493
|
+
const packagesOnCssints = (root) => Effect.sync(() => {
|
|
494
|
+
const read = (file) => Option.getOrUndefined(Option.flatMap(Result.getSuccess(Result.try(() => readFileSync(file, "utf8"))), decodeManifest));
|
|
495
|
+
const app = read(join(root, "package.json"));
|
|
496
|
+
const lookup = createRequire(join(root, "package.json")).resolve.paths("cssints") ?? [];
|
|
497
|
+
return Object.keys({
|
|
498
|
+
...app?.dependencies,
|
|
499
|
+
...app?.devDependencies
|
|
500
|
+
}).filter((name) => {
|
|
501
|
+
const m = lookup.map((dir) => read(join(dir, name, "package.json"))).find(Boolean);
|
|
502
|
+
return !!m && Object.hasOwn({
|
|
503
|
+
...m.dependencies,
|
|
504
|
+
...m.peerDependencies
|
|
505
|
+
}, "cssints");
|
|
506
|
+
});
|
|
507
|
+
});
|
|
508
|
+
const hash = (s) => createHash("sha1").update(s).digest("hex").slice(0, 8);
|
|
509
|
+
/**
|
|
510
|
+
* LightningCSS targets (css.lightningcss.targets) from the browserslist config of process.cwd(), read when vite.config.ts
|
|
511
|
+
* imports this module: the support warnings read the one of the Vite root, the same unless the root is elsewhere.
|
|
512
|
+
*/
|
|
513
|
+
const targets = browserslistToTargets(Effect.runSync(browsers$1()));
|
|
514
|
+
const ESBUILD = {
|
|
515
|
+
ios_saf: "ios",
|
|
516
|
+
ie: "ie",
|
|
517
|
+
opera: "opera",
|
|
518
|
+
edge: "edge",
|
|
519
|
+
chrome: "chrome",
|
|
520
|
+
firefox: "firefox",
|
|
521
|
+
safari: "safari"
|
|
522
|
+
};
|
|
523
|
+
/** `build: { cssTarget }`, the browserslist query of `targets`, so a minified build keeps `firstThatWorks` fallbacks. */
|
|
524
|
+
const cssTarget = Effect.runSync(browsers$1()).flatMap((t) => {
|
|
525
|
+
const [agent, version] = t.split(" ");
|
|
526
|
+
return ESBUILD[agent] && /^\d/.test(version) ? [`${ESBUILD[agent]}${version.split("-")[0]}`] : [];
|
|
527
|
+
});
|
|
528
|
+
const run = (program) => runPromiseExit(program).then((exit) => {
|
|
529
|
+
if (Exit.isSuccess(exit)) return exit.value;
|
|
530
|
+
throw Cause.squash(exit.cause);
|
|
531
|
+
});
|
|
532
|
+
const lineCol = (text, offset) => {
|
|
533
|
+
let line = 1;
|
|
534
|
+
let lineStart = 0;
|
|
535
|
+
for (let i = text.indexOf("\n"); i !== -1 && i < offset; i = text.indexOf("\n", i + 1)) {
|
|
536
|
+
line++;
|
|
537
|
+
lineStart = i + 1;
|
|
538
|
+
}
|
|
539
|
+
return {
|
|
540
|
+
line,
|
|
541
|
+
column: offset - lineStart
|
|
542
|
+
};
|
|
543
|
+
};
|
|
544
|
+
const B64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
545
|
+
const vlq = (n) => {
|
|
546
|
+
let v = n < 0 ? -n << 1 | 1 : n << 1;
|
|
547
|
+
let s = "";
|
|
548
|
+
do {
|
|
549
|
+
const d = v & 31;
|
|
550
|
+
v >>>= 5;
|
|
551
|
+
s += B64[v ? d | 32 : d];
|
|
552
|
+
} while (v);
|
|
553
|
+
return s;
|
|
554
|
+
};
|
|
555
|
+
const sheetMap = (text, siteOf, source = (file) => file) => {
|
|
556
|
+
const first = /* @__PURE__ */ new Map();
|
|
557
|
+
for (const [file, at] of [...siteOf].sort(([a], [b]) => a < b ? -1 : 1)) for (const [cls, loc] of at) if (!first.has(cls)) first.set(cls, [file, loc]);
|
|
558
|
+
const sources = [];
|
|
559
|
+
let prev = [
|
|
560
|
+
0,
|
|
561
|
+
0,
|
|
562
|
+
0
|
|
563
|
+
];
|
|
564
|
+
return {
|
|
565
|
+
version: 3,
|
|
566
|
+
sources,
|
|
567
|
+
names: [],
|
|
568
|
+
mappings: text.split("\n").map((l) => {
|
|
569
|
+
const segs = [];
|
|
570
|
+
let col = 0;
|
|
571
|
+
let mapped = false;
|
|
572
|
+
for (const m of l.matchAll(/(?<=^|[{};])\s*([^{};\s][^{};]*)(?=\{)/g)) {
|
|
573
|
+
const at = m.index + m[0].length - m[1].length;
|
|
574
|
+
const hit = [...m[1].matchAll(/\.(_[\w-]+)/g)].map((c) => first.get(c[1])).find(Boolean);
|
|
575
|
+
if (!hit && !mapped) continue;
|
|
576
|
+
let out = vlq(at - col);
|
|
577
|
+
if (hit) {
|
|
578
|
+
const [file, { line, column }] = hit;
|
|
579
|
+
const name = source(file);
|
|
580
|
+
const seg = [
|
|
581
|
+
sources.includes(name) ? sources.indexOf(name) : sources.push(name) - 1,
|
|
582
|
+
line - 1,
|
|
583
|
+
column
|
|
584
|
+
];
|
|
585
|
+
out += seg.map((x, i) => vlq(x - prev[i])).join("");
|
|
586
|
+
prev = seg;
|
|
587
|
+
}
|
|
588
|
+
segs.push(out);
|
|
589
|
+
col = at;
|
|
590
|
+
mapped = !!hit;
|
|
591
|
+
}
|
|
592
|
+
return segs.join(",");
|
|
593
|
+
}).join(";")
|
|
594
|
+
};
|
|
595
|
+
};
|
|
596
|
+
const locate = Effect.fn("cssints.locate")(function* (e, code, id) {
|
|
597
|
+
const file = Predicate.hasProperty(e, "file") && e.file ? e.file : id;
|
|
598
|
+
if (Predicate.hasProperty(e, "offset") && e.offset !== void 0) {
|
|
599
|
+
const text = file === id ? code : yield* Effect.tryPromise(() => readFile(file, "utf8")).pipe(Effect.orElseSucceed(() => void 0));
|
|
600
|
+
if (text !== void 0) Object.assign(e, {
|
|
601
|
+
id: file,
|
|
602
|
+
loc: {
|
|
603
|
+
file,
|
|
604
|
+
...lineCol(text, e.offset)
|
|
605
|
+
}
|
|
606
|
+
});
|
|
607
|
+
}
|
|
608
|
+
return yield* e;
|
|
609
|
+
});
|
|
610
|
+
function cssints({ inner = false, exclude, devtools = false, opencode = false } = {}) {
|
|
611
|
+
const excluded = [exclude ?? []].flat().length ? createFilter(exclude) : () => false;
|
|
612
|
+
let server;
|
|
613
|
+
let ownServer = false;
|
|
614
|
+
let runner;
|
|
615
|
+
let build = false;
|
|
616
|
+
let root = process.cwd();
|
|
617
|
+
let rootTargets;
|
|
618
|
+
let cssPlugins = [];
|
|
619
|
+
let resolveOf = {};
|
|
620
|
+
const usedBy = /* @__PURE__ */ new Map();
|
|
621
|
+
const depsOf = /* @__PURE__ */ new Map();
|
|
622
|
+
const inflight = /* @__PURE__ */ new Set();
|
|
623
|
+
const siteOf = /* @__PURE__ */ new Map();
|
|
624
|
+
let buildMap = false;
|
|
625
|
+
const callsOf = /* @__PURE__ */ new Map();
|
|
626
|
+
const sheet = Effect.fnUntraced(function* (ids = [...usedBy.keys()]) {
|
|
627
|
+
return yield* renderSheet(ids.flatMap((id) => usedBy.get(id)?.split("\n") ?? []));
|
|
628
|
+
});
|
|
629
|
+
const reloadSheet = Effect.fnUntraced(function* () {
|
|
630
|
+
yield* Effect.sync(() => {
|
|
631
|
+
const env = server?.environments.client;
|
|
632
|
+
const mod = env?.moduleGraph.getModuleById(SHEET);
|
|
633
|
+
if (!env || !mod) return;
|
|
634
|
+
env.moduleGraph.invalidateModule(mod);
|
|
635
|
+
env.reloadModule(mod);
|
|
636
|
+
});
|
|
637
|
+
});
|
|
638
|
+
const record = Effect.fnUntraced(function* (id, classes) {
|
|
639
|
+
const s = [...new Set(classes)].sort().join("\n");
|
|
640
|
+
if (usedBy.get(id) === s) return;
|
|
641
|
+
usedBy.set(id, s);
|
|
642
|
+
yield* reloadSheet();
|
|
643
|
+
});
|
|
644
|
+
const drop = Effect.fnUntraced(function* (id) {
|
|
645
|
+
if (!usedBy.delete(id)) return;
|
|
646
|
+
forget(id);
|
|
647
|
+
siteOf.delete(id);
|
|
648
|
+
callsOf.delete(id);
|
|
649
|
+
yield* reloadSheet();
|
|
650
|
+
});
|
|
651
|
+
const runnerDeps = (env, id, out = /* @__PURE__ */ new Set(), seen = /* @__PURE__ */ new Set()) => {
|
|
652
|
+
const mod = env.moduleGraph.getModuleById(id);
|
|
653
|
+
if (!mod || seen.has(id)) return out;
|
|
654
|
+
seen.add(id);
|
|
655
|
+
for (const dep of mod.importedModules) {
|
|
656
|
+
if (!dep.file || dep.file.includes("node_modules")) continue;
|
|
657
|
+
out.add(dep.file);
|
|
658
|
+
runnerDeps(env, dep.id ?? "", out, seen);
|
|
659
|
+
}
|
|
660
|
+
return out;
|
|
661
|
+
};
|
|
662
|
+
const flushWarnings = Effect.fnUntraced(function* (warn, id, code) {
|
|
663
|
+
const { warnings } = yield* Registry;
|
|
664
|
+
const ws = warnings.splice(0);
|
|
665
|
+
for (const { message, at } of ws) {
|
|
666
|
+
const file = at?.file ?? id;
|
|
667
|
+
const text = at === void 0 ? void 0 : at.file === id ? code : yield* Effect.tryPromise(() => readFile(at.file, "utf8")).pipe(Effect.orElseSucceed(() => void 0));
|
|
668
|
+
const loc = at && text !== void 0 ? {
|
|
669
|
+
file: at.file,
|
|
670
|
+
...lineCol(text, at.offset)
|
|
671
|
+
} : void 0;
|
|
672
|
+
yield* Effect.sync(() => warn({
|
|
673
|
+
message,
|
|
674
|
+
...file && { id: file },
|
|
675
|
+
...loc && { loc }
|
|
676
|
+
}));
|
|
677
|
+
}
|
|
678
|
+
yield* warned(ws.map((w) => w.message), id);
|
|
679
|
+
});
|
|
680
|
+
const clientTransform = Effect.fn("cssints.clientTransform")(function* (code, id, parsed, env, warn, watch) {
|
|
681
|
+
const recorded = Effect.fnUntraced(function* (sites) {
|
|
682
|
+
let runtimes = [];
|
|
683
|
+
const files = parsed.sites.length ? [...(yield* Registry).files] : [];
|
|
684
|
+
if (parsed.sites.every((_, n) => sites.has(n))) {
|
|
685
|
+
const made = yield* moduleEntries(id, sites);
|
|
686
|
+
yield* record(id, made.entries);
|
|
687
|
+
runtimes = made.runtimes;
|
|
688
|
+
}
|
|
689
|
+
return {
|
|
690
|
+
sites,
|
|
691
|
+
runtimes,
|
|
692
|
+
files
|
|
693
|
+
};
|
|
694
|
+
});
|
|
695
|
+
const { sites, runtimes, files } = parsed.sites.length ? yield* evaluate(runner, id, recorded, rootTargets).pipe(Effect.ensuring(flushWarnings(warn, id, code))) : yield* Effect.sync(() => forget(id)).pipe(Effect.andThen(recorded(/* @__PURE__ */ new Map())));
|
|
696
|
+
if (!build || buildMap || devtools === "build") {
|
|
697
|
+
const at = /* @__PURE__ */ new Map();
|
|
698
|
+
for (const [n, s] of parsed.sites.entries()) {
|
|
699
|
+
const loc = lineCol(code, s.start);
|
|
700
|
+
for (const m of sites.get(n)?.matchAll(/_[\w-]+/g) ?? []) if (!at.has(m[0])) at.set(m[0], loc);
|
|
701
|
+
}
|
|
702
|
+
siteOf.set(id, at);
|
|
703
|
+
if (devtools) callsOf.set(id, parsed.sites.map((s, n) => ({
|
|
704
|
+
...lineCol(code, s.start),
|
|
705
|
+
classes: sites.get(n)?.match(/_[\w-]+/g) ?? [],
|
|
706
|
+
text: code.slice(s.start, s.end)
|
|
707
|
+
})));
|
|
708
|
+
}
|
|
709
|
+
const ms = new MagicString(code);
|
|
710
|
+
if (runtimes.length) ms.prepend(runtimes.map((n) => `import ${Formatter.formatJson(RUNTIME_ID + n)};\n`).join(""));
|
|
711
|
+
ms.prepend(runtimeImport(sites.values()));
|
|
712
|
+
for (const [n, s] of parsed.sites.entries()) {
|
|
713
|
+
const replacement = sites.get(n);
|
|
714
|
+
if (replacement === void 0) return yield* new SiteMissingError({
|
|
715
|
+
message: `cssints: site ${n} in ${id} was not evaluated`,
|
|
716
|
+
file: id,
|
|
717
|
+
site: n,
|
|
718
|
+
offset: s.start
|
|
719
|
+
});
|
|
720
|
+
writeSite(ms, s, replacement);
|
|
721
|
+
}
|
|
722
|
+
for (const decl of parsed.imp.decls) ms.remove(decl.start, decl.end);
|
|
723
|
+
for (const dep of runnerDeps(env, id)) (depsOf.get(dep) ?? depsOf.set(dep, /* @__PURE__ */ new Set()).get(dep)).add(id);
|
|
724
|
+
for (const file of files) {
|
|
725
|
+
const dep = normalizePath(resolve(file));
|
|
726
|
+
(depsOf.get(dep) ?? depsOf.set(dep, /* @__PURE__ */ new Set()).get(dep)).add(id);
|
|
727
|
+
yield* Effect.sync(() => watch(dep));
|
|
728
|
+
}
|
|
729
|
+
return {
|
|
730
|
+
code: ms.toString(),
|
|
731
|
+
map: ms.generateMap({
|
|
732
|
+
hires: true,
|
|
733
|
+
source: id,
|
|
734
|
+
includeContent: true
|
|
735
|
+
})
|
|
736
|
+
};
|
|
737
|
+
});
|
|
738
|
+
const inertJsx = Effect.fn("cssints.inertJsx")(function* (code, id) {
|
|
739
|
+
const jsx = {
|
|
740
|
+
runtime: "classic",
|
|
741
|
+
pragma: "__jsx",
|
|
742
|
+
pragmaFrag: "__jsx"
|
|
743
|
+
};
|
|
744
|
+
return yield* Effect.tryPromise({
|
|
745
|
+
try: () => transformWithOxc(code, id, { jsx }).then((r) => r.code),
|
|
746
|
+
catch: (cause) => new HookError({
|
|
747
|
+
hook: "transform",
|
|
748
|
+
message: `cssints: ${String(cause)}`,
|
|
749
|
+
cause
|
|
750
|
+
})
|
|
751
|
+
});
|
|
752
|
+
});
|
|
753
|
+
const transform = Effect.fn("cssints.transform")(function* (ctx, code, url) {
|
|
754
|
+
const id = url.replace(VERSION, "");
|
|
755
|
+
if (!FILE_RE.test(id) || excluded(id)) return void 0;
|
|
756
|
+
if (!marked(code, id)) {
|
|
757
|
+
if (ctx.environment.name === "client") yield* drop(id);
|
|
758
|
+
return ctx.environment.name === "ssr" && (inner || !build) && /[jt]sx$/.test(id) && !id.includes("node_modules") ? yield* inertJsx(code, id) : void 0;
|
|
759
|
+
}
|
|
760
|
+
if (ctx.environment.name === "ssr" && (inner || !build)) {
|
|
761
|
+
const out = yield* instrument(code, id, false);
|
|
762
|
+
return out && /x$/.test(id) ? yield* inertJsx(out.code, id) : out?.code;
|
|
763
|
+
}
|
|
764
|
+
if (inner) return void 0;
|
|
765
|
+
const parsed = yield* instrument(code, id);
|
|
766
|
+
if (!parsed) return void 0;
|
|
767
|
+
const env = server.environments.ssr;
|
|
768
|
+
runner ??= createServerModuleRunner(env, {
|
|
769
|
+
hmr: false,
|
|
770
|
+
sourcemapInterceptor: "prepareStackTrace",
|
|
771
|
+
evaluator: new DomEvaluator()
|
|
772
|
+
});
|
|
773
|
+
inflight.add(id);
|
|
774
|
+
const watch = (file) => build ? ctx.addWatchFile(file) : void server.watcher.add(file);
|
|
775
|
+
return yield* clientTransform(code, id, parsed, env, (w) => ctx.warn(w), watch).pipe(Effect.ensuring(Effect.sync(() => inflight.delete(id))));
|
|
776
|
+
});
|
|
777
|
+
const startServer = Effect.fn("cssints.buildStart")(function* () {
|
|
778
|
+
server = yield* Effect.tryPromise({
|
|
779
|
+
try: () => createServer({
|
|
780
|
+
configFile: false,
|
|
781
|
+
root,
|
|
782
|
+
logLevel: "warn",
|
|
783
|
+
server: {
|
|
784
|
+
middlewareMode: true,
|
|
785
|
+
watch: null,
|
|
786
|
+
hmr: false
|
|
787
|
+
},
|
|
788
|
+
optimizeDeps: { noDiscovery: true },
|
|
789
|
+
...resolveOf,
|
|
790
|
+
plugins: [cssints({
|
|
791
|
+
inner: true,
|
|
792
|
+
exclude
|
|
793
|
+
})]
|
|
794
|
+
}),
|
|
795
|
+
catch: (cause) => new HookError({
|
|
796
|
+
hook: "buildStart",
|
|
797
|
+
message: `cssints: could not start the evaluation server: ${String(cause)}`,
|
|
798
|
+
cause
|
|
799
|
+
})
|
|
800
|
+
});
|
|
801
|
+
ownServer = true;
|
|
802
|
+
});
|
|
803
|
+
const stopServer = Effect.fn("cssints.closeBundle")(function* () {
|
|
804
|
+
if (!ownServer || !server) return;
|
|
805
|
+
const s = server;
|
|
806
|
+
yield* Effect.tryPromise({
|
|
807
|
+
try: () => s.close(),
|
|
808
|
+
catch: (cause) => new HookError({
|
|
809
|
+
hook: "closeBundle",
|
|
810
|
+
message: `cssints: could not stop the evaluation server: ${String(cause)}`,
|
|
811
|
+
cause
|
|
812
|
+
})
|
|
813
|
+
});
|
|
814
|
+
server = runner = void 0;
|
|
815
|
+
ownServer = false;
|
|
816
|
+
});
|
|
817
|
+
const renderChunk = Effect.fn("cssints.renderChunk")(function* (ctx, chunk) {
|
|
818
|
+
if (inner || !Object.hasOwn(chunk.modules, SHEET)) return null;
|
|
819
|
+
const [css, cssPost] = cssPlugins;
|
|
820
|
+
const text = yield* sheet();
|
|
821
|
+
const via = (plugin, code) => Effect.tryPromise({
|
|
822
|
+
try: () => callTransform(plugin, ctx, code),
|
|
823
|
+
catch: (cause) => new HookError({
|
|
824
|
+
hook: "renderChunk",
|
|
825
|
+
message: `cssints: the sheet failed in Vite's CSS pipeline: ${String(cause)}`,
|
|
826
|
+
cause
|
|
827
|
+
})
|
|
828
|
+
});
|
|
829
|
+
yield* via(cssPost, (yield* via(css, text).pipe(Effect.withSpan("cssints.lightningcss")))?.code ?? text).pipe(Effect.withSpan("cssints.cssPost"));
|
|
830
|
+
return null;
|
|
831
|
+
});
|
|
832
|
+
const emitMaps = Effect.fn("cssints.generateBundle")(function* (ctx, bundle, dir) {
|
|
833
|
+
for (const asset of Object.values(bundle)) {
|
|
834
|
+
if (asset.type !== "asset" || !asset.fileName.endsWith(".css")) continue;
|
|
835
|
+
const text = Predicate.isString(asset.source) ? asset.source : new TextDecoder().decode(asset.source);
|
|
836
|
+
const at = resolve(dir, asset.fileName, "..");
|
|
837
|
+
const map = {
|
|
838
|
+
...sheetMap(text, siteOf, (file) => relative(at, file.replace(/\?.*/, ""))),
|
|
839
|
+
file: basename(asset.fileName)
|
|
840
|
+
};
|
|
841
|
+
if (!map.sources.length) continue;
|
|
842
|
+
const json = Formatter.formatJson(map);
|
|
843
|
+
const url = buildMap === "inline" ? `data:application/json;base64,${Buffer.from(json).toString("base64")}` : `${map.file}.map`;
|
|
844
|
+
if (buildMap !== "inline") yield* Effect.sync(() => ctx.emitFile({
|
|
845
|
+
type: "asset",
|
|
846
|
+
fileName: `${asset.fileName}.map`,
|
|
847
|
+
source: json
|
|
848
|
+
}));
|
|
849
|
+
if (buildMap !== "hidden") asset.source = `${text}\n/*# sourceMappingURL=${url} */`;
|
|
850
|
+
}
|
|
851
|
+
});
|
|
852
|
+
const buildEnd = Effect.fn("cssints.buildEnd")(function* (warn) {
|
|
853
|
+
yield* verifyChecks(() => true).pipe(Effect.catch((e) => locate(e, "", "")), Effect.ensuring(flushWarnings(warn)));
|
|
854
|
+
});
|
|
855
|
+
const hotUpdate = Effect.fn("cssints.hotUpdate")(function* (env, file, modules) {
|
|
856
|
+
if (env.name !== "client") return void 0;
|
|
857
|
+
yield* Effect.sync(() => forgetWarnings([file]));
|
|
858
|
+
const graph = env.moduleGraph;
|
|
859
|
+
const affected = [.../* @__PURE__ */ new Set([...depsOf.get(file) ?? [], ...inflight])].flatMap((id) => graph.getModuleById(id) ?? []);
|
|
860
|
+
yield* Effect.sync(() => affected.forEach((m) => {
|
|
861
|
+
graph.invalidateModule(m);
|
|
862
|
+
if (m.id) forget(m.id);
|
|
863
|
+
}));
|
|
864
|
+
return [...modules, ...affected];
|
|
865
|
+
});
|
|
866
|
+
const main = {
|
|
867
|
+
name: "cssints",
|
|
868
|
+
enforce: "pre",
|
|
869
|
+
config(user) {
|
|
870
|
+
const names = Effect.runSync(packagesOnCssints(resolve(user.root ?? process.cwd())));
|
|
871
|
+
return {
|
|
872
|
+
optimizeDeps: { exclude: names },
|
|
873
|
+
ssr: { noExternal: names }
|
|
874
|
+
};
|
|
875
|
+
},
|
|
876
|
+
api: {
|
|
877
|
+
sheet: (ids) => Effect.runSync(sheet(ids)),
|
|
878
|
+
forgetWarnings: (files) => forgetWarnings(files)
|
|
879
|
+
},
|
|
880
|
+
configResolved(config) {
|
|
881
|
+
build = config.command === "build";
|
|
882
|
+
buildMap = build && !inner && config.build.sourcemap;
|
|
883
|
+
root = config.root;
|
|
884
|
+
if (!inner) rootTargets = Effect.runSync(targets$1(void 0, root));
|
|
885
|
+
const ssr = config.environments.ssr?.resolve;
|
|
886
|
+
resolveOf = {
|
|
887
|
+
resolve: { alias: config.resolve.alias },
|
|
888
|
+
...ssr && { environments: { ssr: { resolve: {
|
|
889
|
+
conditions: ssr.conditions,
|
|
890
|
+
externalConditions: ssr.externalConditions
|
|
891
|
+
} } } }
|
|
892
|
+
};
|
|
893
|
+
cssPlugins = ["vite:css", "vite:css-post"].map((n) => config.plugins.find((p) => p.name === n));
|
|
894
|
+
},
|
|
895
|
+
configureServer(s) {
|
|
896
|
+
server = s;
|
|
897
|
+
if (inner) return;
|
|
898
|
+
s.environments.client.hot.on("cssints:sheet", (v) => {
|
|
899
|
+
if (!s.environments.client.moduleGraph.getModuleById(SHEET)?.transformResult?.code.includes(v)) Effect.runSync(reloadSheet());
|
|
900
|
+
});
|
|
901
|
+
},
|
|
902
|
+
buildStart() {
|
|
903
|
+
if (inner) return;
|
|
904
|
+
if (build) forgetWarnings();
|
|
905
|
+
if (server) return;
|
|
906
|
+
return run(hook("vite.buildStart", root, startServer()));
|
|
907
|
+
},
|
|
908
|
+
buildEnd() {
|
|
909
|
+
if (build && !inner) return run(hook("vite.buildEnd", root, buildEnd((w) => this.warn(w))));
|
|
910
|
+
},
|
|
911
|
+
closeBundle() {
|
|
912
|
+
return run(hook("vite.closeBundle", root, stopServer())).then(() => inner ? void 0 : closeTrace());
|
|
913
|
+
},
|
|
914
|
+
resolveId(id) {
|
|
915
|
+
if (id === SHEET_IMPORT) return SHEET;
|
|
916
|
+
if (id.startsWith("virtual:cssints/runtime/")) return `\0${id}`;
|
|
917
|
+
},
|
|
918
|
+
load(id) {
|
|
919
|
+
if (id === SHEET) {
|
|
920
|
+
if (build) return LAYERS;
|
|
921
|
+
const code = runSync(hook("vite.load", id, sheet()));
|
|
922
|
+
return {
|
|
923
|
+
code,
|
|
924
|
+
map: sheetMap(code, siteOf)
|
|
925
|
+
};
|
|
926
|
+
}
|
|
927
|
+
if (id.startsWith(`\0virtual:cssints/runtime/`)) return runSync(runtimeModule(id.slice(RUNTIME_ID.length + 1)));
|
|
928
|
+
},
|
|
929
|
+
renderChunk(_, chunk) {
|
|
930
|
+
return run(hook("vite.renderChunk", chunk.fileName, renderChunk(this, chunk)));
|
|
931
|
+
},
|
|
932
|
+
generateBundle: {
|
|
933
|
+
order: "post",
|
|
934
|
+
handler(out, bundle) {
|
|
935
|
+
if (buildMap) runSync(hook("vite.generateBundle", root, emitMaps(this, bundle, resolve(root, out.dir ?? "dist"))));
|
|
936
|
+
}
|
|
937
|
+
},
|
|
938
|
+
transform: {
|
|
939
|
+
order: "pre",
|
|
940
|
+
handler(code, id) {
|
|
941
|
+
return run(hook("vite.transform", id, transform(this, code, id).pipe(Effect.catch((e) => locate(e, code, id))), this.environment.name));
|
|
942
|
+
}
|
|
943
|
+
},
|
|
944
|
+
hotUpdate({ file, modules }) {
|
|
945
|
+
return runSync(hook("vite.hotUpdate", file, hotUpdate(this.environment, file, modules)));
|
|
946
|
+
}
|
|
947
|
+
};
|
|
948
|
+
const version = {
|
|
949
|
+
name: "cssints:sheet-version",
|
|
950
|
+
apply: "serve",
|
|
951
|
+
transform: {
|
|
952
|
+
order: "post",
|
|
953
|
+
handler(code, id) {
|
|
954
|
+
if (id === SHEET && this.environment.name === "client") return `${code}\nimport.meta.hot.send("cssints:sheet", ${Formatter.formatJson(hash(code))});`;
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
};
|
|
958
|
+
if (!devtools || inner) return [main, version];
|
|
959
|
+
const dev = devtoolsPlugin(usedBy, callsOf, opencode ? opencode === true ? {} : opencode : void 0);
|
|
960
|
+
return devtools === "build" ? [
|
|
961
|
+
main,
|
|
962
|
+
version,
|
|
963
|
+
dev,
|
|
964
|
+
devtoolsBuildPlugin(usedBy, callsOf)
|
|
965
|
+
] : [
|
|
966
|
+
main,
|
|
967
|
+
version,
|
|
968
|
+
dev
|
|
969
|
+
];
|
|
970
|
+
}
|
|
971
|
+
const callTransform = (plugin, ctx, code) => {
|
|
972
|
+
const t = plugin?.transform;
|
|
973
|
+
const handler = typeof t === "function" ? t : t?.handler;
|
|
974
|
+
return Promise.resolve(handler?.call(ctx, code, SHEET));
|
|
975
|
+
};
|
|
976
|
+
//#endregion
|
|
977
|
+
export { addGlobal, addLayers, cssTarget, cssints as default, globalEntries, instrument, layerEntries, renderSheet, targets };
|