lightningcss-tailwindcss 0.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 ice breaker
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 OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,105 @@
1
+ # lightningcss-tailwindcss
2
+
3
+ Lightning CSS AST utilities for analyzing Tailwind CSS syntax.
4
+
5
+ ## Overview
6
+
7
+ This package provides a Tailwind-oriented analysis layer on top of **Lightning CSS AST**.
8
+
9
+ It extracts:
10
+
11
+ - `@apply` utility candidates
12
+ - `theme(...)` calls
13
+ - Tailwind import directives
14
+ - utility selectors declared in authored stylesheets
15
+ - basic Tailwind version hints from parsed syntax
16
+ - parser warnings emitted while Lightning CSS recovers invalid or custom syntax
17
+
18
+ This package is useful when your tooling already depends on Lightning CSS AST and you want to inspect Tailwind-related syntax without switching to PostCSS.
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ pnpm add -D lightningcss-tailwindcss
24
+ ```
25
+
26
+ ## When To Use This Package
27
+
28
+ Use `lightningcss-tailwindcss` when:
29
+
30
+ - your pipeline already uses `lightningcss`
31
+ - you want a fast Rust-backed parser with JS visitor access
32
+ - you are comfortable with recovered/normalized AST output
33
+
34
+ Use `postcss-tailwindcss` instead when:
35
+
36
+ - you need more permissive authored-source parsing
37
+ - you want direct PostCSS node references
38
+ - you need project-aware Tailwind runtime/config resolution
39
+
40
+ ## API
41
+
42
+ - `parseTailwindCss(input)`
43
+ - `detectTailwindVersion(input)`
44
+ - `collectApplyCandidates(input)`
45
+ - `collectThemeCalls(input)`
46
+ - `collectImportDirectives(input)`
47
+ - `collectUtilitySelectors(input)`
48
+ - `analyzeTailwindCss(input)`
49
+
50
+ ## Example
51
+
52
+ ```ts
53
+ import { analyzeTailwindCss } from 'lightningcss-tailwindcss'
54
+
55
+ const css = `
56
+ @import "tailwindcss" source(none) prefix(tw);
57
+
58
+ .button {
59
+ @apply flex hover:bg-red-500;
60
+ color: theme(colors.gray.900 / 75%);
61
+ }
62
+ `
63
+
64
+ const result = analyzeTailwindCss(css)
65
+
66
+ console.log(result.version)
67
+ console.log(result.applyCandidates.map(item => item.candidate))
68
+ console.log(result.warnings)
69
+ ```
70
+
71
+ ## Return Shape
72
+
73
+ `analyzeTailwindCss()` returns:
74
+
75
+ ```ts
76
+ interface TailwindAnalysis {
77
+ version: 3 | 4 | 'unknown'
78
+ applyCandidates: UtilityCandidate[]
79
+ themeCalls: ThemeCall[]
80
+ importDirectives: TailwindImportDirective[]
81
+ utilitySelectors: UtilitySelector[]
82
+ warnings: LightningWarning[]
83
+ }
84
+ ```
85
+
86
+ Unlike the PostCSS version, this package returns Lightning CSS AST fragments and `loc` data rather than PostCSS nodes.
87
+
88
+ ## Parsing Behavior
89
+
90
+ This package relies on Lightning CSS `transform()` with `errorRecovery: true`.
91
+
92
+ That means:
93
+
94
+ - unsupported Tailwind syntax may still be preserved in recovered form
95
+ - parser warnings are expected for some Tailwind-specific constructs
96
+ - v4 `@import "tailwindcss" source(...) prefix(...)` is analyzable even if Lightning CSS treats parts of it as recovered tokens
97
+
98
+ ## Important Differences From `postcss-tailwindcss`
99
+
100
+ - No Tailwind runtime resolution helpers
101
+ - No PostCSS node references
102
+ - More normalized AST output
103
+ - Better fit for tools that already consume Lightning CSS visitors
104
+
105
+ If you need to inspect the consuming project's installed Tailwind runtime or config file, use `postcss-tailwindcss`.
package/README.zh.md ADDED
@@ -0,0 +1,101 @@
1
+ # lightningcss-tailwindcss
2
+
3
+ 用于分析 Tailwind CSS 语法的 Lightning CSS AST 工具集。
4
+
5
+ ## 概览
6
+
7
+ 这个包是在 **Lightning CSS AST** 之上做的一层 Tailwind 语法分析能力。
8
+
9
+ 它可以提取:
10
+
11
+ - `@apply` 中的 utility candidate
12
+ - `theme(...)` 调用
13
+ - Tailwind import 指令
14
+ - 手写样式中声明的 utility selector
15
+ - 基于语法信号推断的 Tailwind 版本
16
+ - Lightning CSS 在容错解析过程中产生的 warning
17
+
18
+ 如果你的工具链本身已经依赖 Lightning CSS AST,而你又想分析 Tailwind 相关语法,这个包会比较合适。
19
+
20
+ ## 安装
21
+
22
+ ```bash
23
+ pnpm add -D lightningcss-tailwindcss
24
+ ```
25
+
26
+ ## 适用场景
27
+
28
+ 推荐在这些情况下使用 `lightningcss-tailwindcss`:
29
+
30
+ - 你的分析流程已经基于 `lightningcss`
31
+ - 你希望用 Rust 驱动的解析器 + JS visitor
32
+ - 你可以接受“恢复后”的 AST 输出
33
+
34
+ 如果你需要更宽松的源码级解析、PostCSS 节点引用,或者需要解析使用方项目的 Tailwind 安装与配置,请使用 `postcss-tailwindcss`。
35
+
36
+ ## API
37
+
38
+ - `parseTailwindCss(input)`
39
+ - `detectTailwindVersion(input)`
40
+ - `collectApplyCandidates(input)`
41
+ - `collectThemeCalls(input)`
42
+ - `collectImportDirectives(input)`
43
+ - `collectUtilitySelectors(input)`
44
+ - `analyzeTailwindCss(input)`
45
+
46
+ ## 示例
47
+
48
+ ```ts
49
+ import { analyzeTailwindCss } from 'lightningcss-tailwindcss'
50
+
51
+ const css = `
52
+ @import "tailwindcss" source(none) prefix(tw);
53
+
54
+ .button {
55
+ @apply flex hover:bg-red-500;
56
+ color: theme(colors.gray.900 / 75%);
57
+ }
58
+ `
59
+
60
+ const result = analyzeTailwindCss(css)
61
+
62
+ console.log(result.version)
63
+ console.log(result.applyCandidates.map(item => item.candidate))
64
+ console.log(result.warnings)
65
+ ```
66
+
67
+ ## 返回结果
68
+
69
+ `analyzeTailwindCss()` 返回:
70
+
71
+ ```ts
72
+ interface TailwindAnalysis {
73
+ version: 3 | 4 | 'unknown'
74
+ applyCandidates: UtilityCandidate[]
75
+ themeCalls: ThemeCall[]
76
+ importDirectives: TailwindImportDirective[]
77
+ utilitySelectors: UtilitySelector[]
78
+ warnings: LightningWarning[]
79
+ }
80
+ ```
81
+
82
+ 和 PostCSS 版本不同,这里返回的是 Lightning CSS AST 片段与 `loc` 信息,而不是 PostCSS 节点对象。
83
+
84
+ ## 解析特性
85
+
86
+ 这个包内部依赖 Lightning CSS 的 `transform()`,并开启了 `errorRecovery: true`。
87
+
88
+ 这意味着:
89
+
90
+ - 某些 Tailwind 扩展语法会以“容错恢复”的形式保留下来
91
+ - 对部分 Tailwind 特有写法出现 warning 是预期行为
92
+ - v4 的 `@import "tailwindcss" source(...) prefix(...)` 仍然可以被分析,即使 Lightning CSS 不会把它完全当成标准语法
93
+
94
+ ## 与 `postcss-tailwindcss` 的区别
95
+
96
+ - 不提供 Tailwind 运行时/配置解析能力
97
+ - 不返回 PostCSS 节点
98
+ - AST 结果更偏“规范化输出”
99
+ - 更适合已经基于 Lightning CSS visitor 的工具
100
+
101
+ 如果你还需要感知使用方项目里真实安装的 Tailwind 版本和配置文件位置,应该选 `postcss-tailwindcss`。
@@ -0,0 +1,60 @@
1
+ import { ImportRule, Location2, Selector, StyleSheet, UnknownAtRule } from "lightningcss";
2
+
3
+ //#region src/index.d.ts
4
+ type TailwindVersion = 3 | 4 | 'unknown';
5
+ interface LightningWarning {
6
+ message: string;
7
+ type: string;
8
+ loc?: {
9
+ filename?: string;
10
+ line: number;
11
+ column: number;
12
+ };
13
+ }
14
+ interface ParseTailwindCssResult {
15
+ stylesheet: StyleSheet;
16
+ warnings: LightningWarning[];
17
+ }
18
+ interface UtilityCandidate {
19
+ candidate: string;
20
+ ruleName: string;
21
+ loc: UnknownAtRule['loc'];
22
+ }
23
+ interface ThemeCall {
24
+ raw: string;
25
+ path: string;
26
+ opacity: string | null;
27
+ functionName: string;
28
+ }
29
+ interface TailwindImportDirective {
30
+ importTarget: string;
31
+ functions: Array<{
32
+ name: string;
33
+ value: string;
34
+ }>;
35
+ hasLayerKeyword: boolean;
36
+ mediaQuery: string | null;
37
+ loc: ImportRule['loc'];
38
+ }
39
+ interface UtilitySelector {
40
+ className: string;
41
+ selector: Selector;
42
+ loc: Location2;
43
+ }
44
+ interface TailwindAnalysis {
45
+ version: TailwindVersion;
46
+ applyCandidates: UtilityCandidate[];
47
+ themeCalls: ThemeCall[];
48
+ importDirectives: TailwindImportDirective[];
49
+ utilitySelectors: UtilitySelector[];
50
+ warnings: LightningWarning[];
51
+ }
52
+ declare function parseTailwindCss(input: string): ParseTailwindCssResult;
53
+ declare function detectTailwindVersion(input: string): TailwindVersion;
54
+ declare function collectApplyCandidates(input: string): UtilityCandidate[];
55
+ declare function collectThemeCalls(input: string): ThemeCall[];
56
+ declare function collectImportDirectives(input: string): TailwindImportDirective[];
57
+ declare function collectUtilitySelectors(input: string): UtilitySelector[];
58
+ declare function analyzeTailwindCss(input: string): TailwindAnalysis;
59
+ //#endregion
60
+ export { LightningWarning, ParseTailwindCssResult, TailwindAnalysis, TailwindImportDirective, TailwindVersion, ThemeCall, UtilityCandidate, UtilitySelector, analyzeTailwindCss, collectApplyCandidates, collectImportDirectives, collectThemeCalls, collectUtilitySelectors, detectTailwindVersion, parseTailwindCss };
package/dist/index.js ADDED
@@ -0,0 +1,310 @@
1
+ import { Buffer } from "node:buffer";
2
+ import { transform } from "lightningcss";
3
+ //#region src/index.ts
4
+ const WHITESPACE_RE = /\s/;
5
+ function tokenToString(token) {
6
+ switch (token.type) {
7
+ case "ident":
8
+ case "at-keyword":
9
+ case "hash":
10
+ case "id-hash":
11
+ case "white-space":
12
+ case "comment":
13
+ case "string":
14
+ case "unquoted-url":
15
+ case "delim":
16
+ case "bad-string":
17
+ case "bad-url": return token.value;
18
+ case "number": return String(token.value);
19
+ case "percentage": return `${token.value * 100}%`;
20
+ case "dimension": return `${token.value}${token.unit}`;
21
+ case "colon": return ":";
22
+ case "semicolon": return ";";
23
+ case "comma": return ",";
24
+ case "include-match": return "~=";
25
+ case "dash-match": return "|=";
26
+ case "prefix-match": return "^=";
27
+ case "suffix-match": return "$=";
28
+ case "substring-match": return "*=";
29
+ case "cdo": return "<!--";
30
+ case "cdc": return "-->";
31
+ case "function": return `${token.value}(`;
32
+ case "parenthesis-block": return "(";
33
+ case "square-bracket-block": return "[";
34
+ case "curly-bracket-block": return "{";
35
+ case "close-parenthesis": return ")";
36
+ case "close-square-bracket": return "]";
37
+ case "close-curly-bracket": return "}";
38
+ default: return "";
39
+ }
40
+ }
41
+ function tokenOrValueListToString(nodes) {
42
+ let output = "";
43
+ for (const [index, node] of nodes.entries()) {
44
+ const rendered = tokenOrValueToString(node);
45
+ if (node.type === "token" && node.value.type === "number" && index > 0) {
46
+ const previous = nodes[index - 1];
47
+ if (previous && previous.type === "token" && previous.value.type === "ident") {
48
+ const numericValue = node.value.value;
49
+ const normalized = numericValue > 0 && numericValue < 1 ? String(Math.round(numericValue * 1e3)) : rendered;
50
+ output += `.${normalized}`;
51
+ continue;
52
+ }
53
+ }
54
+ output += rendered;
55
+ }
56
+ return output;
57
+ }
58
+ function tokenOrValueToString(node) {
59
+ switch (node.type) {
60
+ case "token": return tokenToString(node.value);
61
+ case "function": return `${node.value.name}(${tokenOrValueListToString(node.value.arguments)})`;
62
+ case "dashed-ident":
63
+ case "animation-name": return String(node.value);
64
+ case "length": return `${node.value.value}${node.value.unit}`;
65
+ case "angle": return `${node.value.value}${node.value.type}`;
66
+ case "time": return `${node.value.value}${node.value.type === "seconds" ? "s" : "ms"}`;
67
+ case "resolution": return `${node.value.value}${node.value.type}`;
68
+ case "url": return `url(${String(node.value.url)})`;
69
+ case "var": return `var(${String(node.value.name)})`;
70
+ case "env": return `env(${String(node.value.name)})`;
71
+ case "color":
72
+ case "unresolved-color": return JSON.stringify(node.value);
73
+ default: return "";
74
+ }
75
+ }
76
+ function splitCandidateList(input) {
77
+ const candidates = [];
78
+ let current = "";
79
+ let bracketDepth = 0;
80
+ let parenDepth = 0;
81
+ let quote = null;
82
+ let escaped = false;
83
+ for (const char of input) {
84
+ if (escaped) {
85
+ current += char;
86
+ escaped = false;
87
+ continue;
88
+ }
89
+ if (char === "\\") {
90
+ current += char;
91
+ escaped = true;
92
+ continue;
93
+ }
94
+ if (quote) {
95
+ current += char;
96
+ if (char === quote) quote = null;
97
+ continue;
98
+ }
99
+ if (char === "\"" || char === "'") {
100
+ current += char;
101
+ quote = char;
102
+ continue;
103
+ }
104
+ if (char === "[") {
105
+ bracketDepth += 1;
106
+ current += char;
107
+ continue;
108
+ }
109
+ if (char === "]") {
110
+ bracketDepth = Math.max(0, bracketDepth - 1);
111
+ current += char;
112
+ continue;
113
+ }
114
+ if (char === "(") {
115
+ parenDepth += 1;
116
+ current += char;
117
+ continue;
118
+ }
119
+ if (char === ")") {
120
+ parenDepth = Math.max(0, parenDepth - 1);
121
+ current += char;
122
+ continue;
123
+ }
124
+ if (WHITESPACE_RE.test(char) && bracketDepth === 0 && parenDepth === 0) {
125
+ const value = current.trim();
126
+ if (value) candidates.push(value);
127
+ current = "";
128
+ continue;
129
+ }
130
+ current += char;
131
+ }
132
+ const last = current.trim();
133
+ if (last) candidates.push(last);
134
+ return candidates;
135
+ }
136
+ function parseThemeArgument(raw) {
137
+ let bracketDepth = 0;
138
+ let parenDepth = 0;
139
+ let slashIndex = -1;
140
+ for (let i = 0; i < raw.length; i += 1) {
141
+ const char = raw[i];
142
+ if (char === "[") bracketDepth += 1;
143
+ else if (char === "]") bracketDepth = Math.max(0, bracketDepth - 1);
144
+ else if (char === "(") parenDepth += 1;
145
+ else if (char === ")") parenDepth = Math.max(0, parenDepth - 1);
146
+ else if (char === "/" && bracketDepth === 0 && parenDepth === 0) {
147
+ slashIndex = i;
148
+ break;
149
+ }
150
+ }
151
+ if (slashIndex === -1) return {
152
+ path: raw.trim(),
153
+ opacity: null
154
+ };
155
+ return {
156
+ path: raw.slice(0, slashIndex).trim(),
157
+ opacity: raw.slice(slashIndex + 1).trim() || null
158
+ };
159
+ }
160
+ function parseWithLightningCss(input) {
161
+ let stylesheetRef;
162
+ const result = transform({
163
+ filename: "input.css",
164
+ code: Buffer.from(input),
165
+ errorRecovery: true,
166
+ visitor: { StyleSheet(stylesheet) {
167
+ stylesheetRef = stylesheet;
168
+ } }
169
+ });
170
+ if (!stylesheetRef) throw new Error("Failed to capture Lightning CSS stylesheet");
171
+ return {
172
+ stylesheet: stylesheetRef,
173
+ warnings: result.warnings.map((warning) => ({
174
+ message: warning.message,
175
+ type: warning.type,
176
+ loc: warning.loc
177
+ }))
178
+ };
179
+ }
180
+ function parseTailwindCss(input) {
181
+ return parseWithLightningCss(input);
182
+ }
183
+ function walkRules(rules, visit) {
184
+ for (const rule of rules) {
185
+ visit(rule);
186
+ if (rule.type === "style") walkRules(rule.value.rules ?? [], visit);
187
+ else if (rule.type === "media" || rule.type === "supports" || rule.type === "container" || rule.type === "scope" || rule.type === "starting-style" || rule.type === "layer-block") walkRules(rule.value.rules, visit);
188
+ }
189
+ }
190
+ function detectTailwindVersion(input) {
191
+ const { stylesheet } = parseWithLightningCss(input);
192
+ let hasV3 = false;
193
+ let hasV4 = false;
194
+ walkRules(stylesheet.rules, (rule) => {
195
+ if (rule.type === "import") {
196
+ if (rule.value.url.includes("tailwindcss")) hasV4 = true;
197
+ return;
198
+ }
199
+ if (rule.type !== "unknown") return;
200
+ if (["tailwind", "config"].includes(rule.value.name)) hasV3 = true;
201
+ if ([
202
+ "theme",
203
+ "source",
204
+ "utility",
205
+ "variant",
206
+ "custom-variant",
207
+ "plugin",
208
+ "reference"
209
+ ].includes(rule.value.name)) hasV4 = true;
210
+ });
211
+ if (hasV4) return 4;
212
+ if (hasV3) return 3;
213
+ return "unknown";
214
+ }
215
+ function collectApplyCandidates(input) {
216
+ const { stylesheet } = parseWithLightningCss(input);
217
+ const candidates = [];
218
+ walkRules(stylesheet.rules, (rule) => {
219
+ if (rule.type !== "unknown" || rule.value.name !== "apply") return;
220
+ const prelude = tokenOrValueListToString(rule.value.prelude);
221
+ for (const candidate of splitCandidateList(prelude)) candidates.push({
222
+ candidate,
223
+ ruleName: rule.value.name,
224
+ loc: rule.value.loc
225
+ });
226
+ });
227
+ return candidates;
228
+ }
229
+ function collectThemeCalls(input) {
230
+ const calls = [];
231
+ transform({
232
+ filename: "input.css",
233
+ code: Buffer.from(input),
234
+ errorRecovery: true,
235
+ visitor: { Function: { theme(fn) {
236
+ const raw = tokenOrValueListToString(fn.arguments).trim();
237
+ const { path, opacity } = parseThemeArgument(raw);
238
+ calls.push({
239
+ raw,
240
+ path,
241
+ opacity,
242
+ functionName: fn.name
243
+ });
244
+ } } }
245
+ });
246
+ return calls;
247
+ }
248
+ function collectImportDirectives(input) {
249
+ const { stylesheet } = parseWithLightningCss(input);
250
+ const directives = [];
251
+ walkRules(stylesheet.rules, (rule) => {
252
+ if (rule.type !== "import" || !rule.value.url.includes("tailwindcss")) return;
253
+ const condition = rule.value.media?.mediaQueries[0]?.condition;
254
+ const tokens = condition?.type === "unknown" ? condition.value : [];
255
+ const functions = tokens.filter((item) => item.type === "function").filter((item) => [
256
+ "source",
257
+ "prefix",
258
+ "layer",
259
+ "supports"
260
+ ].includes(item.value.name)).map((item) => ({
261
+ name: item.value.name,
262
+ value: tokenOrValueListToString(item.value.arguments).trim()
263
+ }));
264
+ const mediaQuery = tokenOrValueListToString(tokens.filter((item) => {
265
+ return !(item.type === "function" && [
266
+ "source",
267
+ "prefix",
268
+ "layer",
269
+ "supports"
270
+ ].includes(item.value.name));
271
+ })).trim() || null;
272
+ directives.push({
273
+ importTarget: rule.value.url,
274
+ functions,
275
+ hasLayerKeyword: Boolean(rule.value.layer),
276
+ mediaQuery,
277
+ loc: rule.value.loc
278
+ });
279
+ });
280
+ return directives;
281
+ }
282
+ function collectUtilitySelectors(input) {
283
+ const { stylesheet } = parseWithLightningCss(input);
284
+ const selectors = [];
285
+ walkRules(stylesheet.rules, (rule) => {
286
+ if (rule.type !== "style") return;
287
+ for (const selector of rule.value.selectors) for (const component of selector) {
288
+ if (component.type !== "class") continue;
289
+ selectors.push({
290
+ className: component.name,
291
+ selector,
292
+ loc: rule.value.loc
293
+ });
294
+ }
295
+ });
296
+ return selectors;
297
+ }
298
+ function analyzeTailwindCss(input) {
299
+ const parsed = parseWithLightningCss(input);
300
+ return {
301
+ version: detectTailwindVersion(input),
302
+ applyCandidates: collectApplyCandidates(input),
303
+ themeCalls: collectThemeCalls(input),
304
+ importDirectives: collectImportDirectives(input),
305
+ utilitySelectors: collectUtilitySelectors(input),
306
+ warnings: parsed.warnings
307
+ };
308
+ }
309
+ //#endregion
310
+ export { analyzeTailwindCss, collectApplyCandidates, collectImportDirectives, collectThemeCalls, collectUtilitySelectors, detectTailwindVersion, parseTailwindCss };
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "lightningcss-tailwindcss",
3
+ "type": "module",
4
+ "version": "0.0.0",
5
+ "description": "Lightning CSS AST utilities for analyzing Tailwind CSS syntax",
6
+ "author": "ice breaker <1324318532@qq.com>",
7
+ "license": "MIT",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/sonofmagic/dev-configs.git",
11
+ "directory": "packages/lightningcss-tailwindcss"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/sonofmagic/dev-configs/issues"
15
+ },
16
+ "keywords": [
17
+ "dev-configs",
18
+ "icebreakers",
19
+ "lightningcss",
20
+ "tailwindcss"
21
+ ],
22
+ "sideEffects": false,
23
+ "exports": {
24
+ ".": {
25
+ "types": "./dist/index.d.ts",
26
+ "default": "./dist/index.js"
27
+ },
28
+ "./package.json": "./package.json"
29
+ },
30
+ "main": "./dist/index.js",
31
+ "module": "./dist/index.js",
32
+ "types": "./dist/index.d.ts",
33
+ "files": [
34
+ "README.md",
35
+ "README.zh.md",
36
+ "dist"
37
+ ],
38
+ "dependencies": {
39
+ "lightningcss": "^1.31.1"
40
+ },
41
+ "publishConfig": {
42
+ "access": "public",
43
+ "registry": "https://registry.npmjs.org"
44
+ },
45
+ "scripts": {
46
+ "dev": "tsdown --watch --sourcemap",
47
+ "build": "tsdown",
48
+ "test": "vitest run",
49
+ "test:dev": "vitest",
50
+ "release": "pnpm publish",
51
+ "sync": "cnpm sync lightningcss-tailwindcss",
52
+ "typecheck": "tsc --noEmit"
53
+ }
54
+ }