regexcss 0.1.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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 maekoya
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 all
13
+ 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 OF OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,7 @@
1
+ # regexcss
2
+
3
+ > 🚧 README is being rewritten. Documentation coming soon.
4
+
5
+ ## License
6
+
7
+ MIT © 2026 maekoya
@@ -0,0 +1,174 @@
1
+ //#region src/extractor/tokenize.ts
2
+ const DEFAULT_TOKEN_RE = /[\w:.\-/]+/g;
3
+ const defaultExtractor = (code) => {
4
+ const matches = code.matchAll(DEFAULT_TOKEN_RE);
5
+ const out = [];
6
+ for (const m of matches) out.push(m[0]);
7
+ return out;
8
+ };
9
+ //#endregion
10
+ //#region src/core/escape.ts
11
+ const NEEDS_ESCAPE = /[!"#$%&'()*+,./:;<=>?@[\\\]^`{|}~]/g;
12
+ const escapeSelector = (raw) => {
13
+ return raw.replace(NEEDS_ESCAPE, (m) => `\\${m}`);
14
+ };
15
+ //#endregion
16
+ //#region src/core/layer.ts
17
+ const SEG = String.raw`(?:[A-Za-z_]|-[A-Za-z_-])[A-Za-z0-9_-]*`;
18
+ const LAYER_NAME_RE = new RegExp(String.raw`^${SEG}(?:\.${SEG})*$`);
19
+ const renderLayer = (css, layerName) => {
20
+ if (!layerName) return css;
21
+ if (!LAYER_NAME_RE.test(layerName)) throw new Error(`Invalid @layer name ${JSON.stringify(layerName)}: expected dot-separated CSS identifiers (letters, digits, "-", "_"), each segment starting with a letter, "-" or "_".`);
22
+ if (css.length === 0) return css;
23
+ return `@layer ${layerName} {\n${css.split("\n").map((line) => line.length > 0 ? ` ${line}` : line).join("\n")}\n}`;
24
+ };
25
+ //#endregion
26
+ //#region src/core/rules.ts
27
+ const matchRule = (matcher, rules, ctx) => {
28
+ for (const [re, handler] of rules) {
29
+ const m = matcher.match(re);
30
+ if (!m) continue;
31
+ const result = handler(m, ctx);
32
+ if (result) return result;
33
+ }
34
+ };
35
+ //#endregion
36
+ //#region src/core/stringify.ts
37
+ const camelToKebab = (prop) => {
38
+ if (prop.startsWith("--")) return prop;
39
+ return prop.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
40
+ };
41
+ const stringifyDeclarations = (css) => {
42
+ const lines = [];
43
+ for (const [key, value] of Object.entries(css)) lines.push(`${camelToKebab(key)}: ${value};`);
44
+ return lines.join(" ");
45
+ };
46
+ //#endregion
47
+ //#region src/core/variants.ts
48
+ const applyVariantChain = (raw, variants) => {
49
+ let current = raw;
50
+ const chain = [];
51
+ const seen = /* @__PURE__ */ new Set();
52
+ while (true) {
53
+ if (seen.has(current)) break;
54
+ seen.add(current);
55
+ let progressed = false;
56
+ for (const [re, handler] of variants) {
57
+ const m = current.match(re);
58
+ if (!m) continue;
59
+ const result = handler(m, current);
60
+ if (!result) continue;
61
+ chain.push(result);
62
+ current = result.matcher;
63
+ progressed = true;
64
+ break;
65
+ }
66
+ if (!progressed) break;
67
+ }
68
+ return {
69
+ matcher: current,
70
+ chain
71
+ };
72
+ };
73
+ //#endregion
74
+ //#region src/core/generator.ts
75
+ const resolveConfig = (user) => ({
76
+ rules: user.rules,
77
+ variants: user.variants ?? [],
78
+ layerName: user.layerName,
79
+ prefix: user.prefix ?? "",
80
+ customMedia: user.customMedia ?? {},
81
+ content: user.content ?? { include: [] },
82
+ extractor: user.extractor ?? defaultExtractor
83
+ });
84
+ const renderCustomMedia = (cm) => {
85
+ const entries = Object.entries(cm);
86
+ if (entries.length === 0) return "";
87
+ return entries.map(([name, query]) => `@custom-media ${name} ${query};`).join("\n");
88
+ };
89
+ const buildSelector = (raw, chain) => {
90
+ let sel = `.${escapeSelector(raw)}`;
91
+ for (const v of chain) if (v.selector) sel = v.selector(sel);
92
+ return sel;
93
+ };
94
+ const collectParents = (chain) => {
95
+ const parents = [];
96
+ for (const v of chain) if (v.parent) parents.push(v.parent);
97
+ return parents;
98
+ };
99
+ const groupBlocks = (blocks) => {
100
+ const grouped = /* @__PURE__ */ new Map();
101
+ for (const b of blocks) {
102
+ const key = b.parents.join("\0");
103
+ let arr = grouped.get(key);
104
+ if (!arr) {
105
+ arr = [];
106
+ grouped.set(key, arr);
107
+ }
108
+ arr.push(b);
109
+ }
110
+ const parts = [];
111
+ for (const [key, bs] of grouped) {
112
+ const parents = key === "" ? [] : key.split("\0");
113
+ const inner = bs.map((b) => `${b.selector} { ${b.decls} }`).join("\n");
114
+ parts.push(wrapNested(parents, inner));
115
+ }
116
+ return parts.join("\n\n");
117
+ };
118
+ const wrapNested = (parents, inner) => {
119
+ if (parents.length === 0) return inner;
120
+ let acc = inner;
121
+ for (let i = parents.length - 1; i >= 0; i--) {
122
+ const indented = acc.split("\n").map((l) => l.length > 0 ? ` ${l}` : l).join("\n");
123
+ acc = `${parents[i]} {\n${indented}\n}`;
124
+ }
125
+ return acc;
126
+ };
127
+ const createGenerator = (userConfig) => {
128
+ const config = resolveConfig(userConfig);
129
+ const generate = async (tokens, options) => {
130
+ const seen = /* @__PURE__ */ new Set();
131
+ const matched = /* @__PURE__ */ new Set();
132
+ const blocks = [];
133
+ for (const raw of tokens) {
134
+ if (seen.has(raw)) continue;
135
+ seen.add(raw);
136
+ let matcherInput = raw;
137
+ if (config.prefix !== "") {
138
+ if (!raw.startsWith(config.prefix)) continue;
139
+ matcherInput = raw.slice(config.prefix.length);
140
+ }
141
+ const { matcher, chain } = applyVariantChain(matcherInput, config.variants);
142
+ const ctx = {
143
+ rawSelector: raw,
144
+ currentSelector: matcher,
145
+ variants: chain
146
+ };
147
+ const css = matchRule(matcher, config.rules, ctx);
148
+ if (!css) continue;
149
+ const decls = stringifyDeclarations(css);
150
+ if (decls.length === 0) continue;
151
+ blocks.push({
152
+ raw,
153
+ selector: buildSelector(raw, chain),
154
+ parents: collectParents(chain),
155
+ decls
156
+ });
157
+ matched.add(raw);
158
+ }
159
+ const layered = renderLayer(groupBlocks(blocks), options?.layerName ?? config.layerName);
160
+ const cmDecl = renderCustomMedia(config.customMedia);
161
+ return {
162
+ css: cmDecl ? layered ? `${cmDecl}\n\n${layered}` : cmDecl : layered,
163
+ matched
164
+ };
165
+ };
166
+ return {
167
+ generate,
168
+ config
169
+ };
170
+ };
171
+ //#endregion
172
+ export { defaultExtractor as n, createGenerator as t };
173
+
174
+ //# sourceMappingURL=generator-D6K3x9Hv.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generator-D6K3x9Hv.mjs","names":[],"sources":["../src/extractor/tokenize.ts","../src/core/escape.ts","../src/core/layer.ts","../src/core/rules.ts","../src/core/stringify.ts","../src/core/variants.ts","../src/core/generator.ts"],"sourcesContent":["const DEFAULT_TOKEN_RE = /[\\w:.\\-/]+/g;\n\nexport const defaultExtractor = (code: string): string[] => {\n const matches = code.matchAll(DEFAULT_TOKEN_RE);\n const out: string[] = [];\n for (const m of matches) out.push(m[0]);\n return out;\n};\n","const NEEDS_ESCAPE = /[!\"#$%&'()*+,./:;<=>?@[\\\\\\]^`{|}~]/g;\n\nexport const escapeSelector = (raw: string): string => {\n return raw.replace(NEEDS_ESCAPE, (m) => `\\\\${m}`);\n};\n","// One CSS-ident segment: starts with a letter/`_`, or `-` followed by a\n// letter/`_`/`-` (so `-webkit` and `--foo` are fine, but `-1` and a lone `-`\n// are not — a digit may never start an ident). Stays ASCII-only on purpose;\n// this is a typo guard, not a full CSS tokenizer (escapes / non-ASCII are out\n// of scope). Dots join segments for nested layers, e.g. `website.utilities`.\nconst SEG = String.raw`(?:[A-Za-z_]|-[A-Za-z_-])[A-Za-z0-9_-]*`;\n// Valid `@layer` name: dot-separated CSS identifiers. Guards against typos /\n// stray characters that would otherwise emit broken or unintended CSS.\nconst LAYER_NAME_RE = new RegExp(String.raw`^${SEG}(?:\\.${SEG})*$`);\n\n// Wrap a CSS body in `@layer <name> { ... }`. Validates the name whenever one is\n// given (even for an empty body, so config typos surface immediately). Returns\n// the body unchanged when `layerName` is falsy or — for a valid name — empty.\nexport const renderLayer = (css: string, layerName: string | undefined): string => {\n if (!layerName) return css;\n if (!LAYER_NAME_RE.test(layerName)) {\n throw new Error(\n `Invalid @layer name ${JSON.stringify(layerName)}: expected dot-separated CSS identifiers (letters, digits, \"-\", \"_\"), each segment starting with a letter, \"-\" or \"_\".`,\n );\n }\n if (css.length === 0) return css;\n const indented = css\n .split(\"\\n\")\n .map((line) => (line.length > 0 ? ` ${line}` : line))\n .join(\"\\n\");\n return `@layer ${layerName} {\\n${indented}\\n}`;\n};\n","import type { CSSObject, Rule, RuleContext } from \"../types.ts\";\n\nexport const matchRule = (matcher: string, rules: Rule[], ctx: RuleContext): CSSObject | undefined => {\n for (const [re, handler] of rules) {\n const m = matcher.match(re);\n if (!m) continue;\n const result = handler(m, ctx);\n if (result) return result;\n }\n return undefined;\n};\n","import type { CSSObject } from \"../types.ts\";\n\nconst camelToKebab = (prop: string): string => {\n if (prop.startsWith(\"--\")) return prop;\n return prop.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);\n};\n\nexport const stringifyDeclarations = (css: CSSObject): string => {\n const lines: string[] = [];\n for (const [key, value] of Object.entries(css)) {\n lines.push(`${camelToKebab(key)}: ${value};`);\n }\n return lines.join(\" \");\n};\n","import type { Variant, VariantHandlerResult } from \"../types.ts\";\n\nexport interface VariantChainResult {\n matcher: string;\n chain: VariantHandlerResult[];\n}\n\nexport const applyVariantChain = (raw: string, variants: Variant[]): VariantChainResult => {\n let current = raw;\n const chain: VariantHandlerResult[] = [];\n const seen = new Set<string>();\n\n while (true) {\n if (seen.has(current)) break;\n seen.add(current);\n\n let progressed = false;\n for (const [re, handler] of variants) {\n const m = current.match(re);\n if (!m) continue;\n const result = handler(m, current);\n if (!result) continue;\n chain.push(result);\n current = result.matcher;\n progressed = true;\n break;\n }\n if (!progressed) break;\n }\n\n return { matcher: current, chain };\n};\n","import { defaultExtractor } from \"../extractor/tokenize.ts\";\nimport type {\n GenerateOptions,\n GenerateResult,\n Generator,\n ResolvedConfig,\n UserConfig,\n VariantHandlerResult,\n} from \"../types.ts\";\nimport { escapeSelector } from \"./escape.ts\";\nimport { renderLayer } from \"./layer.ts\";\nimport { matchRule } from \"./rules.ts\";\nimport { stringifyDeclarations } from \"./stringify.ts\";\nimport { applyVariantChain } from \"./variants.ts\";\n\ninterface Block {\n raw: string;\n selector: string;\n parents: string[];\n decls: string;\n}\n\nconst resolveConfig = (user: UserConfig): ResolvedConfig => ({\n rules: user.rules,\n variants: user.variants ?? [],\n layerName: user.layerName,\n prefix: user.prefix ?? \"\",\n customMedia: user.customMedia ?? {},\n content: user.content ?? { include: [] },\n extractor: user.extractor ?? defaultExtractor,\n});\n\nconst renderCustomMedia = (cm: Record<string, string>): string => {\n const entries = Object.entries(cm);\n if (entries.length === 0) return \"\";\n return entries.map(([name, query]) => `@custom-media ${name} ${query};`).join(\"\\n\");\n};\n\nconst buildSelector = (raw: string, chain: VariantHandlerResult[]): string => {\n let sel = `.${escapeSelector(raw)}`;\n for (const v of chain) {\n if (v.selector) sel = v.selector(sel);\n }\n return sel;\n};\n\nconst collectParents = (chain: VariantHandlerResult[]): string[] => {\n const parents: string[] = [];\n for (const v of chain) {\n if (v.parent) parents.push(v.parent);\n }\n return parents;\n};\n\nconst groupBlocks = (blocks: Block[]): string => {\n const grouped = new Map<string, Block[]>();\n for (const b of blocks) {\n const key = b.parents.join(\"\u0000\");\n let arr = grouped.get(key);\n if (!arr) {\n arr = [];\n grouped.set(key, arr);\n }\n arr.push(b);\n }\n\n const parts: string[] = [];\n for (const [key, bs] of grouped) {\n const parents = key === \"\" ? [] : key.split(\"\u0000\");\n const inner = bs.map((b) => `${b.selector} { ${b.decls} }`).join(\"\\n\");\n parts.push(wrapNested(parents, inner));\n }\n return parts.join(\"\\n\\n\");\n};\n\nconst wrapNested = (parents: string[], inner: string): string => {\n if (parents.length === 0) return inner;\n let acc = inner;\n for (let i = parents.length - 1; i >= 0; i--) {\n const indented = acc\n .split(\"\\n\")\n .map((l) => (l.length > 0 ? ` ${l}` : l))\n .join(\"\\n\");\n acc = `${parents[i]} {\\n${indented}\\n}`;\n }\n return acc;\n};\n\nexport const createGenerator = (userConfig: UserConfig): Generator => {\n const config = resolveConfig(userConfig);\n\n const generate = async (tokens: Iterable<string>, options?: GenerateOptions): Promise<GenerateResult> => {\n const seen = new Set<string>();\n const matched = new Set<string>();\n const blocks: Block[] = [];\n\n for (const raw of tokens) {\n if (seen.has(raw)) continue;\n seen.add(raw);\n\n let matcherInput = raw;\n if (config.prefix !== \"\") {\n if (!raw.startsWith(config.prefix)) continue;\n matcherInput = raw.slice(config.prefix.length);\n }\n\n const { matcher, chain } = applyVariantChain(matcherInput, config.variants);\n const ctx = {\n rawSelector: raw,\n currentSelector: matcher,\n variants: chain,\n };\n const css = matchRule(matcher, config.rules, ctx);\n if (!css) continue;\n\n const decls = stringifyDeclarations(css);\n if (decls.length === 0) continue;\n\n blocks.push({\n raw,\n selector: buildSelector(raw, chain),\n parents: collectParents(chain),\n decls,\n });\n matched.add(raw);\n }\n\n const body = groupBlocks(blocks);\n const effectiveLayerName = options?.layerName ?? config.layerName;\n const layered = renderLayer(body, effectiveLayerName);\n const cmDecl = renderCustomMedia(config.customMedia);\n const css = cmDecl ? (layered ? `${cmDecl}\\n\\n${layered}` : cmDecl) : layered;\n return { css, matched };\n };\n\n return { generate, config };\n};\n"],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ import { d as Variant } from "./types-jVjPo8bk.mjs";
2
+
3
+ //#region src/helpers.d.ts
4
+ declare const rem: (n: string | number, factor?: number) => string;
5
+ declare const px: (n: string | number) => string;
6
+ declare const em: (n: string | number) => string;
7
+ declare const pct: (n: string | number) => string;
8
+ declare const vw: (n: string | number) => string;
9
+ declare const vh: (n: string | number) => string;
10
+ /**
11
+ * Build a {@link Variant} from a prefix plus optional selector / parent transforms.
12
+ *
13
+ * - `selector`: string suffix (e.g. `":hover"`) — appended to the generated class selector.
14
+ * Or a function `(s) => string` for complex shapes (e.g. `(s) => `.group:hover ${s}``).
15
+ * - `parent`: at-rule that wraps the rule (e.g. `"@media (min-width: 768px)"`,
16
+ * `"@media (any-hover: hover)"`, `"@container (width > 30em)"`).
17
+ *
18
+ * The prefix is treated literally — regex meta characters in it are escaped.
19
+ *
20
+ * @example
21
+ * createVariant("md", { parent: "@media (min-width: 768px)" })
22
+ * createVariant("hover", { selector: ":hover" })
23
+ * createVariant("hover", { selector: ":hover", parent: "@media (any-hover: hover)" })
24
+ * createVariant("group-hover", { selector: (s) => `.group:hover ${s}` })
25
+ */
26
+ declare const createVariant: (prefix: string, options: {
27
+ selector?: string | ((s: string) => string);
28
+ parent?: string;
29
+ }) => Variant;
30
+ declare const parseCustomMedia: (cssText: string) => Record<string, string>;
31
+ declare const loadCustomMedia: (path: string) => Record<string, string>;
32
+ //#endregion
33
+ export { createVariant, em, loadCustomMedia, parseCustomMedia, pct, px, rem, vh, vw };
34
+ //# sourceMappingURL=helpers.d.mts.map
@@ -0,0 +1,50 @@
1
+ import { readFileSync } from "node:fs";
2
+ //#region src/helpers.ts
3
+ const rem = (n, factor = 4) => `${Number(n) / factor}rem`;
4
+ const px = (n) => `${Number(n)}px`;
5
+ const em = (n) => `${Number(n)}em`;
6
+ const pct = (n) => `${Number(n)}%`;
7
+ const vw = (n) => `${Number(n)}vw`;
8
+ const vh = (n) => `${Number(n)}vh`;
9
+ const escapeRegExp = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
10
+ /**
11
+ * Build a {@link Variant} from a prefix plus optional selector / parent transforms.
12
+ *
13
+ * - `selector`: string suffix (e.g. `":hover"`) — appended to the generated class selector.
14
+ * Or a function `(s) => string` for complex shapes (e.g. `(s) => `.group:hover ${s}``).
15
+ * - `parent`: at-rule that wraps the rule (e.g. `"@media (min-width: 768px)"`,
16
+ * `"@media (any-hover: hover)"`, `"@container (width > 30em)"`).
17
+ *
18
+ * The prefix is treated literally — regex meta characters in it are escaped.
19
+ *
20
+ * @example
21
+ * createVariant("md", { parent: "@media (min-width: 768px)" })
22
+ * createVariant("hover", { selector: ":hover" })
23
+ * createVariant("hover", { selector: ":hover", parent: "@media (any-hover: hover)" })
24
+ * createVariant("group-hover", { selector: (s) => `.group:hover ${s}` })
25
+ */
26
+ const createVariant = (prefix, options) => {
27
+ const { selector, parent } = options;
28
+ const selectorFn = typeof selector === "string" ? (s) => `${s}${selector}` : selector;
29
+ return [new RegExp(`^${escapeRegExp(prefix)}:`), (_, raw) => ({
30
+ matcher: raw.slice(prefix.length + 1),
31
+ ...selectorFn ? { selector: selectorFn } : {},
32
+ ...parent ? { parent } : {}
33
+ })];
34
+ };
35
+ const BLOCK_COMMENT_RE = /\/\*[\s\S]*?\*\//g;
36
+ const CUSTOM_MEDIA_RE = /@custom-media\s+(--[\w-]+)\s+([^;]+);/g;
37
+ const parseCustomMedia = (cssText) => {
38
+ const stripped = cssText.replace(BLOCK_COMMENT_RE, "");
39
+ const result = {};
40
+ for (const m of stripped.matchAll(CUSTOM_MEDIA_RE)) {
41
+ const [, name, query] = m;
42
+ if (name && query) result[name] = query.trim();
43
+ }
44
+ return result;
45
+ };
46
+ const loadCustomMedia = (path) => parseCustomMedia(readFileSync(path, "utf-8"));
47
+ //#endregion
48
+ export { createVariant, em, loadCustomMedia, parseCustomMedia, pct, px, rem, vh, vw };
49
+
50
+ //# sourceMappingURL=helpers.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.mjs","names":[],"sources":["../src/helpers.ts"],"sourcesContent":["// Optional helpers. Import from 'regexcss/helpers'.\n\nimport { readFileSync } from \"node:fs\";\nimport type { Variant } from \"./types.ts\";\n\n// --- unit helpers ---\n\nexport const rem = (n: string | number, factor = 4): string => `${Number(n) / factor}rem`;\n\nexport const px = (n: string | number): string => `${Number(n)}px`;\n\nexport const em = (n: string | number): string => `${Number(n)}em`;\n\nexport const pct = (n: string | number): string => `${Number(n)}%`;\n\nexport const vw = (n: string | number): string => `${Number(n)}vw`;\n\nexport const vh = (n: string | number): string => `${Number(n)}vh`;\n\n// --- variant helper ---\n\n// Escape regex meta characters so a user-supplied prefix is treated literally.\nconst escapeRegExp = (s: string): string => s.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n\n/**\n * Build a {@link Variant} from a prefix plus optional selector / parent transforms.\n *\n * - `selector`: string suffix (e.g. `\":hover\"`) — appended to the generated class selector.\n * Or a function `(s) => string` for complex shapes (e.g. `(s) => `.group:hover ${s}``).\n * - `parent`: at-rule that wraps the rule (e.g. `\"@media (min-width: 768px)\"`,\n * `\"@media (any-hover: hover)\"`, `\"@container (width > 30em)\"`).\n *\n * The prefix is treated literally — regex meta characters in it are escaped.\n *\n * @example\n * createVariant(\"md\", { parent: \"@media (min-width: 768px)\" })\n * createVariant(\"hover\", { selector: \":hover\" })\n * createVariant(\"hover\", { selector: \":hover\", parent: \"@media (any-hover: hover)\" })\n * createVariant(\"group-hover\", { selector: (s) => `.group:hover ${s}` })\n */\nexport const createVariant = (\n prefix: string,\n options: {\n selector?: string | ((s: string) => string);\n parent?: string;\n },\n): Variant => {\n const { selector, parent } = options;\n const selectorFn = typeof selector === \"string\" ? (s: string) => `${s}${selector}` : selector;\n return [\n new RegExp(`^${escapeRegExp(prefix)}:`),\n (_, raw) => ({\n matcher: raw.slice(prefix.length + 1),\n ...(selectorFn ? { selector: selectorFn } : {}),\n ...(parent ? { parent } : {}),\n }),\n ];\n};\n\n// --- @custom-media parsers ---\n\n// Extracts `@custom-media --name (query);` declarations from a CSS source.\n// CSS block comments (`/* ... */`) are stripped before parsing to avoid\n// false positives inside commented-out lines. Returns a `{ \"--name\": \"(query)\" }`\n// map ready to pass to `defineConfig({ customMedia: ... })`.\nconst BLOCK_COMMENT_RE = /\\/\\*[\\s\\S]*?\\*\\//g;\nconst CUSTOM_MEDIA_RE = /@custom-media\\s+(--[\\w-]+)\\s+([^;]+);/g;\n\nexport const parseCustomMedia = (cssText: string): Record<string, string> => {\n const stripped = cssText.replace(BLOCK_COMMENT_RE, \"\");\n const result: Record<string, string> = {};\n for (const m of stripped.matchAll(CUSTOM_MEDIA_RE)) {\n const [, name, query] = m;\n if (name && query) result[name] = query.trim();\n }\n return result;\n};\n\n// Convenience: read a CSS file from disk and parse its `@custom-media` decls.\n// Node-only. Pass an absolute path (resolve relative paths with `node:path`).\nexport const loadCustomMedia = (path: string): Record<string, string> => parseCustomMedia(readFileSync(path, \"utf-8\"));\n"],"mappings":";;AAOA,MAAa,OAAO,GAAoB,SAAS,MAAc,GAAG,OAAO,CAAC,IAAI,OAAO;AAErF,MAAa,MAAM,MAA+B,GAAG,OAAO,CAAC,EAAE;AAE/D,MAAa,MAAM,MAA+B,GAAG,OAAO,CAAC,EAAE;AAE/D,MAAa,OAAO,MAA+B,GAAG,OAAO,CAAC,EAAE;AAEhE,MAAa,MAAM,MAA+B,GAAG,OAAO,CAAC,EAAE;AAE/D,MAAa,MAAM,MAA+B,GAAG,OAAO,CAAC,EAAE;AAK/D,MAAM,gBAAgB,MAAsB,EAAE,QAAQ,uBAAuB,MAAM;;;;;;;;;;;;;;;;;AAkBnF,MAAa,iBACX,QACA,YAIY;CACZ,MAAM,EAAE,UAAU,WAAW;CAC7B,MAAM,aAAa,OAAO,aAAa,YAAY,MAAc,GAAG,IAAI,aAAa;CACrF,OAAO,CACL,IAAI,OAAO,IAAI,aAAa,MAAM,EAAE,EAAE,IACrC,GAAG,SAAS;EACX,SAAS,IAAI,MAAM,OAAO,SAAS,CAAC;EACpC,GAAI,aAAa,EAAE,UAAU,WAAW,IAAI,CAAC;EAC7C,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;CAC7B,EACF;AACF;AAQA,MAAM,mBAAmB;AACzB,MAAM,kBAAkB;AAExB,MAAa,oBAAoB,YAA4C;CAC3E,MAAM,WAAW,QAAQ,QAAQ,kBAAkB,EAAE;CACrD,MAAM,SAAiC,CAAC;CACxC,KAAK,MAAM,KAAK,SAAS,SAAS,eAAe,GAAG;EAClD,MAAM,GAAG,MAAM,SAAS;EACxB,IAAI,QAAQ,OAAO,OAAO,QAAQ,MAAM,KAAK;CAC/C;CACA,OAAO;AACT;AAIA,MAAa,mBAAmB,SAAyC,iBAAiB,aAAa,MAAM,OAAO,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { a as Generator, c as RuleContext, d as Variant, f as VariantHandler, i as GenerateResult, l as RuleHandler, n as ContentConfig, o as ResolvedConfig, p as VariantHandlerResult, r as GenerateOptions, s as Rule, t as CSSObject, u as UserConfig } from "./types-jVjPo8bk.mjs";
2
+
3
+ //#region src/config/define.d.ts
4
+ declare const defineConfig: (config: UserConfig) => UserConfig;
5
+ //#endregion
6
+ //#region src/core/generator.d.ts
7
+ declare const createGenerator: (userConfig: UserConfig) => Generator;
8
+ //#endregion
9
+ //#region src/extractor/tokenize.d.ts
10
+ declare const defaultExtractor: (code: string) => string[];
11
+ //#endregion
12
+ export { type CSSObject, type ContentConfig, type GenerateOptions, type GenerateResult, type Generator, type ResolvedConfig, type Rule, type RuleContext, type RuleHandler, type UserConfig, type Variant, type VariantHandler, type VariantHandlerResult, createGenerator, defaultExtractor, defineConfig };
13
+ //# sourceMappingURL=index.d.mts.map
package/dist/index.mjs ADDED
@@ -0,0 +1,7 @@
1
+ import { n as defaultExtractor, t as createGenerator } from "./generator-D6K3x9Hv.mjs";
2
+ //#region src/config/define.ts
3
+ const defineConfig = (config) => config;
4
+ //#endregion
5
+ export { createGenerator, defaultExtractor, defineConfig };
6
+
7
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/config/define.ts"],"sourcesContent":["import type { UserConfig } from \"../types.ts\";\n\nexport const defineConfig = (config: UserConfig): UserConfig => config;\n"],"mappings":";;AAEA,MAAa,gBAAgB,WAAmC"}
@@ -0,0 +1,118 @@
1
+ import { s as Rule } from "./types-jVjPo8bk.mjs";
2
+
3
+ //#region src/preset/rules/color/background-color.d.ts
4
+ declare const backgroundColorRules: Rule[];
5
+ //#endregion
6
+ //#region src/preset/rules/color/index.d.ts
7
+ declare const colorRules: Rule[];
8
+ //#endregion
9
+ //#region src/preset/rules/flexbox-grid/align-content.d.ts
10
+ declare const alignContentRules: Rule[];
11
+ //#endregion
12
+ //#region src/preset/rules/flexbox-grid/align-items.d.ts
13
+ declare const alignItemsRules: Rule[];
14
+ //#endregion
15
+ //#region src/preset/rules/flexbox-grid/align-self.d.ts
16
+ declare const alignSelfRules: Rule[];
17
+ //#endregion
18
+ //#region src/preset/rules/flexbox-grid/gap.d.ts
19
+ declare const gapRules: Rule[];
20
+ //#endregion
21
+ //#region src/preset/rules/flexbox-grid/grid-template-columns.d.ts
22
+ declare const gridTemplateColumnsRules: Rule[];
23
+ //#endregion
24
+ //#region src/preset/rules/flexbox-grid/grid-template-rows.d.ts
25
+ declare const gridTemplateRowsRules: Rule[];
26
+ //#endregion
27
+ //#region src/preset/rules/flexbox-grid/justify-content.d.ts
28
+ declare const justifyContentRules: Rule[];
29
+ //#endregion
30
+ //#region src/preset/rules/flexbox-grid/justify-items.d.ts
31
+ declare const justifyItemsRules: Rule[];
32
+ //#endregion
33
+ //#region src/preset/rules/flexbox-grid/justify-self.d.ts
34
+ declare const justifySelfRules: Rule[];
35
+ //#endregion
36
+ //#region src/preset/rules/flexbox-grid/order.d.ts
37
+ declare const orderRules: Rule[];
38
+ //#endregion
39
+ //#region src/preset/rules/flexbox-grid/index.d.ts
40
+ declare const flexboxGridRules: Rule[];
41
+ //#endregion
42
+ //#region src/preset/rules/layout/display.d.ts
43
+ declare const displayRules: Rule[];
44
+ //#endregion
45
+ //#region src/preset/rules/layout/object-fit.d.ts
46
+ declare const objectFitRules: Rule[];
47
+ //#endregion
48
+ //#region src/preset/rules/layout/object-position.d.ts
49
+ declare const objectPositionRules: Rule[];
50
+ //#endregion
51
+ //#region src/preset/rules/layout/overflow.d.ts
52
+ declare const overflowRules: Rule[];
53
+ //#endregion
54
+ //#region src/preset/rules/layout/overscroll.d.ts
55
+ declare const overscrollRules: Rule[];
56
+ //#endregion
57
+ //#region src/preset/rules/layout/position.d.ts
58
+ declare const positionRules: Rule[];
59
+ //#endregion
60
+ //#region src/preset/rules/layout/z-index.d.ts
61
+ declare const zIndexRules: Rule[];
62
+ //#endregion
63
+ //#region src/preset/rules/layout/index.d.ts
64
+ declare const layoutRules: Rule[];
65
+ //#endregion
66
+ //#region src/preset/rules/spacing/margin.d.ts
67
+ declare const marginRules: Rule[];
68
+ //#endregion
69
+ //#region src/preset/rules/spacing/padding.d.ts
70
+ declare const paddingRules: Rule[];
71
+ //#endregion
72
+ //#region src/preset/rules/spacing/index.d.ts
73
+ declare const spacingRules: Rule[];
74
+ //#endregion
75
+ //#region src/preset/rules/typography/font-family.d.ts
76
+ declare const fontFamilyRules: Rule[];
77
+ //#endregion
78
+ //#region src/preset/rules/typography/font-style.d.ts
79
+ declare const fontStyleRules: Rule[];
80
+ //#endregion
81
+ //#region src/preset/rules/typography/font-variant-numeric.d.ts
82
+ declare const fontVariantNumericRules: Rule[];
83
+ //#endregion
84
+ //#region src/preset/rules/typography/font-weight.d.ts
85
+ declare const fontWeightRules: Rule[];
86
+ //#endregion
87
+ //#region src/preset/rules/typography/line-clamp.d.ts
88
+ declare const lineClampRules: Rule[];
89
+ //#endregion
90
+ //#region src/preset/rules/typography/text-align.d.ts
91
+ declare const textAlignRules: Rule[];
92
+ //#endregion
93
+ //#region src/preset/rules/typography/text-decoration-line.d.ts
94
+ declare const textDecorationLineRules: Rule[];
95
+ //#endregion
96
+ //#region src/preset/rules/typography/text-overflow.d.ts
97
+ declare const textOverflowRules: Rule[];
98
+ //#endregion
99
+ //#region src/preset/rules/typography/text-transform.d.ts
100
+ declare const textTransformRules: Rule[];
101
+ //#endregion
102
+ //#region src/preset/rules/typography/text-wrap.d.ts
103
+ declare const textWrapRules: Rule[];
104
+ //#endregion
105
+ //#region src/preset/rules/typography/vertical-align.d.ts
106
+ declare const verticalAlignRules: Rule[];
107
+ //#endregion
108
+ //#region src/preset/rules/typography/white-space.d.ts
109
+ declare const whiteSpaceRules: Rule[];
110
+ //#endregion
111
+ //#region src/preset/rules/typography/word-break.d.ts
112
+ declare const wordBreakRules: Rule[];
113
+ //#endregion
114
+ //#region src/preset/rules/typography/index.d.ts
115
+ declare const typographyRules: Rule[];
116
+ //#endregion
117
+ export { alignContentRules, alignItemsRules, alignSelfRules, backgroundColorRules, colorRules, displayRules, flexboxGridRules, fontFamilyRules, fontStyleRules, fontVariantNumericRules, fontWeightRules, gapRules, gridTemplateColumnsRules, gridTemplateRowsRules, justifyContentRules, justifyItemsRules, justifySelfRules, layoutRules, lineClampRules, marginRules, objectFitRules, objectPositionRules, orderRules, overflowRules, overscrollRules, paddingRules, positionRules, spacingRules, textAlignRules, textDecorationLineRules, textOverflowRules, textTransformRules, textWrapRules, typographyRules, verticalAlignRules, whiteSpaceRules, wordBreakRules, zIndexRules };
118
+ //# sourceMappingURL=preset.d.mts.map