@react-hive/honey-css 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +211 -0
- package/dist/LICENSE +21 -0
- package/dist/README.md +211 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.dev.cjs +386 -0
- package/dist/index.dev.cjs.map +1 -0
- package/dist/index.mjs +2 -0
- package/dist/index.mjs.map +1 -0
- package/dist/tokenize-css.d.ts +24 -0
- package/dist/types.d.ts +22 -0
- package/package.json +81 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 React Hive
|
|
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,211 @@
|
|
|
1
|
+
# @react-hive/honey-css
|
|
2
|
+
|
|
3
|
+
A lightweight CSS tokenizer + parser that produces a minimal AST for custom CSS processing.
|
|
4
|
+
|
|
5
|
+
This package is designed as a small foundation for building **CSS transformers**, **preprocessors**, and **CSS-in-JS tooling** β without pulling in heavyweight dependencies like PostCSS.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## β¨ Why honey-css?
|
|
10
|
+
|
|
11
|
+
Most CSS parsers today are extremely powerful⦠and extremely complex.
|
|
12
|
+
|
|
13
|
+
They solve *everything*, but sometimes you only need:
|
|
14
|
+
|
|
15
|
+
- a small tokenizer
|
|
16
|
+
- a predictable AST
|
|
17
|
+
- support for nested rules
|
|
18
|
+
- a clean base for custom transformations
|
|
19
|
+
|
|
20
|
+
**honey-css** focuses on the sweet spot:
|
|
21
|
+
|
|
22
|
+
- π― Small surface area
|
|
23
|
+
- π― Predictable output
|
|
24
|
+
- π³ Minimal AST structure
|
|
25
|
+
- π§© Easy to extend
|
|
26
|
+
- β‘ Perfect for custom styling engines
|
|
27
|
+
|
|
28
|
+
If you're building your own styling layer or transformer pipeline, this gives you the core building blocks β without unnecessary overhead.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## β¨ Features
|
|
33
|
+
|
|
34
|
+
- β
Tokenizes raw CSS into structured tokens
|
|
35
|
+
- β
Parses tokens into a minimal developer-friendly AST
|
|
36
|
+
- β
Supports nested rules and nested at-rules
|
|
37
|
+
- β
Handles common real-world CSS syntax:
|
|
38
|
+
- declarations (`color: red;`)
|
|
39
|
+
- selectors (`.btn:hover {}`)
|
|
40
|
+
- at-rules (`@media (...) {}`)
|
|
41
|
+
- params groups (`url(...)`, `var(...)`)
|
|
42
|
+
- quoted strings (`content: "hello"`)
|
|
43
|
+
- block comments (`/* ... */`)
|
|
44
|
+
- β
Tiny, fast, and easy to extend
|
|
45
|
+
- β
Built for CSS-in-JS engines and custom compilers
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## π¦ Installation
|
|
50
|
+
|
|
51
|
+
Install with pnpm (recommended):
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pnpm add @react-hive/honey-css
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## π Quick Start
|
|
58
|
+
|
|
59
|
+
Tokenizing CSS
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
import { tokenizeCss } from "@react-hive/honey-css";
|
|
63
|
+
|
|
64
|
+
const tokens = tokenizeCss(`
|
|
65
|
+
.btn {
|
|
66
|
+
color: red;
|
|
67
|
+
padding: 12px;
|
|
68
|
+
}
|
|
69
|
+
`);
|
|
70
|
+
|
|
71
|
+
console.log(tokens);
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Output:
|
|
75
|
+
|
|
76
|
+
```json
|
|
77
|
+
[
|
|
78
|
+
{ type: "text", value: ".btn" },
|
|
79
|
+
{ type: "braceOpen" },
|
|
80
|
+
|
|
81
|
+
{ type: "text", value: "color" },
|
|
82
|
+
{ type: "colon" },
|
|
83
|
+
{ type: "text", value: "red" },
|
|
84
|
+
{ type: "semicolon" },
|
|
85
|
+
|
|
86
|
+
{ type: "text", value: "padding" },
|
|
87
|
+
{ type: "colon" },
|
|
88
|
+
{ type: "text", value: "12px" },
|
|
89
|
+
{ type: "semicolon" },
|
|
90
|
+
|
|
91
|
+
{ type: "braceClose" }
|
|
92
|
+
]
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Parsing CSS into AST
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
import { parseCss } from "@react-hive/honey-css";
|
|
99
|
+
|
|
100
|
+
const ast = parseCss(`
|
|
101
|
+
.btn {
|
|
102
|
+
color: red;
|
|
103
|
+
}
|
|
104
|
+
`);
|
|
105
|
+
|
|
106
|
+
console.log(ast);
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Output:
|
|
110
|
+
|
|
111
|
+
```json
|
|
112
|
+
{
|
|
113
|
+
type: "stylesheet",
|
|
114
|
+
body: [
|
|
115
|
+
{
|
|
116
|
+
type: "rule",
|
|
117
|
+
selector: ".btn",
|
|
118
|
+
body: [
|
|
119
|
+
{
|
|
120
|
+
type: "declaration",
|
|
121
|
+
prop: "color",
|
|
122
|
+
value: "red"
|
|
123
|
+
}
|
|
124
|
+
]
|
|
125
|
+
}
|
|
126
|
+
]
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## π³ AST Overview
|
|
131
|
+
|
|
132
|
+
The AST is intentionally minimal and easy to traverse.
|
|
133
|
+
|
|
134
|
+
**Stylesheet Root**
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
{
|
|
138
|
+
type: "stylesheet",
|
|
139
|
+
body: HoneyCssNode[]
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
**Declaration Node**
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
{
|
|
147
|
+
type: "declaration",
|
|
148
|
+
prop: "padding",
|
|
149
|
+
value: "12px"
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Represents:
|
|
154
|
+
```
|
|
155
|
+
padding: 12px;
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
**Rule Node**
|
|
159
|
+
|
|
160
|
+
```
|
|
161
|
+
{
|
|
162
|
+
type: "rule",
|
|
163
|
+
selector: ".child:hover",
|
|
164
|
+
body: [...]
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Represents:
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
.child:hover {
|
|
172
|
+
opacity: 0.5;
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**At-Rule Node**
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
{
|
|
180
|
+
type: "atRule",
|
|
181
|
+
name: "media",
|
|
182
|
+
params: "(max-width: 768px)",
|
|
183
|
+
body: [...]
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Represents:
|
|
188
|
+
|
|
189
|
+
```
|
|
190
|
+
@media (max-width: 768px) {
|
|
191
|
+
color: red;
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## π― Use Cases
|
|
196
|
+
|
|
197
|
+
The **honey-css** is a great fit for:
|
|
198
|
+
|
|
199
|
+
- CSS-in-JS compilers
|
|
200
|
+
- Custom at-rule processors
|
|
201
|
+
- Design system engines
|
|
202
|
+
- Lightweight CSS preprocessors
|
|
203
|
+
- AST-based transformations
|
|
204
|
+
|
|
205
|
+
It is not intended to fully replace PostCSS or implement the full CSS specification β itβs a focused foundation.
|
|
206
|
+
|
|
207
|
+
## π License
|
|
208
|
+
|
|
209
|
+
MIT Β© Mike Aliinyk
|
|
210
|
+
|
|
211
|
+
Part of the **[React Hive](https://github.com/React-Hive)** ecosystem π
|
package/dist/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 React Hive
|
|
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/dist/README.md
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# @react-hive/honey-css
|
|
2
|
+
|
|
3
|
+
A lightweight CSS tokenizer + parser that produces a minimal AST for custom CSS processing.
|
|
4
|
+
|
|
5
|
+
This package is designed as a small foundation for building **CSS transformers**, **preprocessors**, and **CSS-in-JS tooling** β without pulling in heavyweight dependencies like PostCSS.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## β¨ Why honey-css?
|
|
10
|
+
|
|
11
|
+
Most CSS parsers today are extremely powerful⦠and extremely complex.
|
|
12
|
+
|
|
13
|
+
They solve *everything*, but sometimes you only need:
|
|
14
|
+
|
|
15
|
+
- a small tokenizer
|
|
16
|
+
- a predictable AST
|
|
17
|
+
- support for nested rules
|
|
18
|
+
- a clean base for custom transformations
|
|
19
|
+
|
|
20
|
+
**honey-css** focuses on the sweet spot:
|
|
21
|
+
|
|
22
|
+
- π― Small surface area
|
|
23
|
+
- π― Predictable output
|
|
24
|
+
- π³ Minimal AST structure
|
|
25
|
+
- π§© Easy to extend
|
|
26
|
+
- β‘ Perfect for custom styling engines
|
|
27
|
+
|
|
28
|
+
If you're building your own styling layer or transformer pipeline, this gives you the core building blocks β without unnecessary overhead.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## β¨ Features
|
|
33
|
+
|
|
34
|
+
- β
Tokenizes raw CSS into structured tokens
|
|
35
|
+
- β
Parses tokens into a minimal developer-friendly AST
|
|
36
|
+
- β
Supports nested rules and nested at-rules
|
|
37
|
+
- β
Handles common real-world CSS syntax:
|
|
38
|
+
- declarations (`color: red;`)
|
|
39
|
+
- selectors (`.btn:hover {}`)
|
|
40
|
+
- at-rules (`@media (...) {}`)
|
|
41
|
+
- params groups (`url(...)`, `var(...)`)
|
|
42
|
+
- quoted strings (`content: "hello"`)
|
|
43
|
+
- block comments (`/* ... */`)
|
|
44
|
+
- β
Tiny, fast, and easy to extend
|
|
45
|
+
- β
Built for CSS-in-JS engines and custom compilers
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## π¦ Installation
|
|
50
|
+
|
|
51
|
+
Install with pnpm (recommended):
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pnpm add @react-hive/honey-css
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## π Quick Start
|
|
58
|
+
|
|
59
|
+
Tokenizing CSS
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
import { tokenizeCss } from "@react-hive/honey-css";
|
|
63
|
+
|
|
64
|
+
const tokens = tokenizeCss(`
|
|
65
|
+
.btn {
|
|
66
|
+
color: red;
|
|
67
|
+
padding: 12px;
|
|
68
|
+
}
|
|
69
|
+
`);
|
|
70
|
+
|
|
71
|
+
console.log(tokens);
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Output:
|
|
75
|
+
|
|
76
|
+
```json
|
|
77
|
+
[
|
|
78
|
+
{ type: "text", value: ".btn" },
|
|
79
|
+
{ type: "braceOpen" },
|
|
80
|
+
|
|
81
|
+
{ type: "text", value: "color" },
|
|
82
|
+
{ type: "colon" },
|
|
83
|
+
{ type: "text", value: "red" },
|
|
84
|
+
{ type: "semicolon" },
|
|
85
|
+
|
|
86
|
+
{ type: "text", value: "padding" },
|
|
87
|
+
{ type: "colon" },
|
|
88
|
+
{ type: "text", value: "12px" },
|
|
89
|
+
{ type: "semicolon" },
|
|
90
|
+
|
|
91
|
+
{ type: "braceClose" }
|
|
92
|
+
]
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Parsing CSS into AST
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
import { parseCss } from "@react-hive/honey-css";
|
|
99
|
+
|
|
100
|
+
const ast = parseCss(`
|
|
101
|
+
.btn {
|
|
102
|
+
color: red;
|
|
103
|
+
}
|
|
104
|
+
`);
|
|
105
|
+
|
|
106
|
+
console.log(ast);
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Output:
|
|
110
|
+
|
|
111
|
+
```json
|
|
112
|
+
{
|
|
113
|
+
type: "stylesheet",
|
|
114
|
+
body: [
|
|
115
|
+
{
|
|
116
|
+
type: "rule",
|
|
117
|
+
selector: ".btn",
|
|
118
|
+
body: [
|
|
119
|
+
{
|
|
120
|
+
type: "declaration",
|
|
121
|
+
prop: "color",
|
|
122
|
+
value: "red"
|
|
123
|
+
}
|
|
124
|
+
]
|
|
125
|
+
}
|
|
126
|
+
]
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## π³ AST Overview
|
|
131
|
+
|
|
132
|
+
The AST is intentionally minimal and easy to traverse.
|
|
133
|
+
|
|
134
|
+
**Stylesheet Root**
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
{
|
|
138
|
+
type: "stylesheet",
|
|
139
|
+
body: HoneyCssNode[]
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
**Declaration Node**
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
{
|
|
147
|
+
type: "declaration",
|
|
148
|
+
prop: "padding",
|
|
149
|
+
value: "12px"
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Represents:
|
|
154
|
+
```
|
|
155
|
+
padding: 12px;
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
**Rule Node**
|
|
159
|
+
|
|
160
|
+
```
|
|
161
|
+
{
|
|
162
|
+
type: "rule",
|
|
163
|
+
selector: ".child:hover",
|
|
164
|
+
body: [...]
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Represents:
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
.child:hover {
|
|
172
|
+
opacity: 0.5;
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**At-Rule Node**
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
{
|
|
180
|
+
type: "atRule",
|
|
181
|
+
name: "media",
|
|
182
|
+
params: "(max-width: 768px)",
|
|
183
|
+
body: [...]
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Represents:
|
|
188
|
+
|
|
189
|
+
```
|
|
190
|
+
@media (max-width: 768px) {
|
|
191
|
+
color: red;
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## π― Use Cases
|
|
196
|
+
|
|
197
|
+
The **honey-css** is a great fit for:
|
|
198
|
+
|
|
199
|
+
- CSS-in-JS compilers
|
|
200
|
+
- Custom at-rule processors
|
|
201
|
+
- Design system engines
|
|
202
|
+
- Lightweight CSS preprocessors
|
|
203
|
+
- AST-based transformations
|
|
204
|
+
|
|
205
|
+
It is not intended to fully replace PostCSS or implement the full CSS specification β itβs a focused foundation.
|
|
206
|
+
|
|
207
|
+
## π License
|
|
208
|
+
|
|
209
|
+
MIT Β© Mike Aliinyk
|
|
210
|
+
|
|
211
|
+
Part of the **[React Hive](https://github.com/React-Hive)** ecosystem π
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
(()=>{"use strict";var e={d:(t,n)=>{for(var r in n)e.o(n,r)&&!e.o(t,r)&&Object.defineProperty(t,r,{enumerable:!0,get:n[r]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r:e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}},t={};e.r(t),e.d(t,{tokenizeCss:()=>r});const n=e=>"{"===e||"}"===e||":"===e||";"===e||"@"===e||"("===e||'"'===e||"'"===e||"/"===e,r=e=>{const t=[];let r=0;const o=()=>r>=e.length,i=()=>o()?void 0:e[r],u=()=>r+1>=e.length?void 0:e[r+1],f=()=>{for(;;){const e=i();if(!e||!/\s/.test(e))return;r++}},s=()=>{if("/"!==i()||"*"!==u())return!1;for(r+=2;!o();){if("*"===i()&&"/"===u())return r+=2,!0;r++}return!0},c=()=>{const e=i();if(!e)return"";r++;let t="";for(;!o();){const n=i();if(!n)break;if("\\"===n){t+=n,r++;const e=i();e&&(t+=e,r++);continue}if(n===e){r++;break}t+=n,r++}return t},p=()=>{let e=0,t="";for(;!o();){const n=i();if(!n)break;if("("===n&&e++,")"===n&&e--,t+=n,r++,0===e)break}return t},a=()=>{let e="";for(;!o();){const t=i();if(!t)break;if(n(t))break;e+=t,r++}return e.trim()};for(;!o()&&(f(),!o());){if(s())continue;const e=i();if(!e)break;if("{"===e){t.push({type:"braceOpen"}),r++;continue}if("}"===e){t.push({type:"braceClose"}),r++;continue}if(":"===e){t.push({type:"colon"}),r++;continue}if(";"===e){t.push({type:"semicolon"}),r++;continue}if("@"===e){t.push({type:"at"}),r++;continue}if("("===e){t.push({type:"params",value:p()});continue}if('"'===e||"'"===e){t.push({type:"string",value:c()});continue}const n=a();n?t.push({type:"text",value:n}):r++}return t};module.exports=t})();
|
|
2
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","mappings":"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","sources":["webpack://@react-hive/honey-css/webpack/bootstrap","webpack://@react-hive/honey-css/webpack/runtime/define property getters","webpack://@react-hive/honey-css/webpack/runtime/hasOwnProperty shorthand","webpack://@react-hive/honey-css/webpack/runtime/make namespace object","webpack://@react-hive/honey-css/./src/tokenize-css.ts"],"sourcesContent":["// The require scope\nvar __webpack_require__ = {};\n\n","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import { HoneyCssToken } from '~/types';\n\n/**\n * Determines whether a character should terminate a plain text read.\n *\n * These characters represent structural boundaries in CSS:\n * - Blocks: `{` `}`\n * - Declarations: `:` `;`\n * - At-rules: `@`\n * - Params: `(`\n * - Strings: `'` `\"`\n * - Comments: `/`\n */\nconst isBoundaryChar = (ch: string): boolean =>\n ch === '{' ||\n ch === '}' ||\n ch === ':' ||\n ch === ';' ||\n ch === '@' ||\n ch === '(' ||\n ch === '\"' ||\n ch === \"'\" ||\n ch === '/';\n\n/**\n * Tokenizes a CSS-like input string into a sequence of Honey CSS tokens.\n *\n * This tokenizer is intentionally lightweight and designed for parsing\n * Honey-specific CSS extensions such as:\n *\n * - Custom at-rules: `@honey-media (...) { ... }`\n * - Nested selectors: `&:hover { ... }`\n * - CSS variables: `--primary-color: red;`\n *\n * Supported syntax:\n * - Braces: `{` `}`\n * - Colons and semicolons: `:` `;`\n * - At-rule marker: `@`\n * - Parentheses groups: `(sm:down)`\n * - Quoted strings: `\"...\"`, `'...'`\n * - Block comments: `/* ... *\\/`\n *\n * @param input - Raw CSS string to tokenize.\n *\n * @returns An ordered array of tokens.\n */\nexport const tokenizeCss = (input: string): HoneyCssToken[] => {\n const tokens: HoneyCssToken[] = [];\n\n let index = 0;\n\n const isEof = (): boolean => index >= input.length;\n\n /**\n * Returns the current character without consuming it.\n */\n const peek = (): string | undefined => (isEof() ? undefined : input[index]);\n\n /**\n * Returns the next character without consuming it.\n */\n const peekNext = (): string | undefined =>\n index + 1 >= input.length ? undefined : input[index + 1];\n\n /**\n * Advances the cursor past any whitespace characters.\n */\n const skipWhitespace = () => {\n while (true) {\n const ch = peek();\n\n if (!ch || !/\\s/.test(ch)) {\n return;\n }\n\n index++;\n }\n };\n\n /**\n * Skips CSS block comments of the form:\n *\n * ```css\n * /* comment *\\/\n * ```\n *\n * If the comment is unterminated, tokenization stops safely.\n *\n * @returns `true` if a comment was skipped.\n */\n const skipComment = (): boolean => {\n if (peek() !== '/' || peekNext() !== '*') {\n return false;\n }\n\n index += 2; // skip \"/*\"\n\n while (!isEof()) {\n if (peek() === '*' && peekNext() === '/') {\n index += 2; // skip \"*/\"\n\n return true;\n }\n\n index++;\n }\n\n return true;\n };\n\n /**\n * Reads a quoted string token.\n *\n * Supports:\n * - Double quotes: `\"text\"`\n * - Single quotes: `'text'`\n * - Escaped characters: `\"a\\\\\\\"b\"`\n *\n * @returns The unwrapped string contents.\n */\n const readString = (): string => {\n const quote = peek();\n if (!quote) {\n return '';\n }\n\n index++; // skip opening quote\n let result = '';\n\n while (!isEof()) {\n const ch = peek();\n if (!ch) {\n break;\n }\n\n // Handle escape sequences\n if (ch === '\\\\') {\n result += ch;\n index++;\n\n const escaped = peek();\n if (escaped) {\n result += escaped;\n index++;\n }\n\n continue;\n }\n\n // Closing quote\n if (ch === quote) {\n index++;\n break;\n }\n\n result += ch;\n index++;\n }\n\n return result;\n };\n\n /**\n * Reads a balanced parentheses group.\n *\n * Examples:\n * - `(sm:down)`\n * - `(min-width: calc(100% - 1px))`\n *\n * Nested parentheses are supported.\n *\n * @returns The full params string including parentheses.\n */\n const readParamsGroup = (): string => {\n let depth = 0;\n let result = '';\n\n while (!isEof()) {\n const ch = peek();\n if (!ch) {\n break;\n }\n\n if (ch === '(') {\n depth++;\n }\n\n if (ch === ')') {\n depth--;\n }\n\n result += ch;\n index++;\n\n if (depth === 0) {\n break;\n }\n }\n\n return result;\n };\n\n /**\n * Reads plain text until a boundary character is reached.\n *\n * This is used for:\n * - Selectors (`.btn`, `&:hover`)\n * - Property names (`color`)\n * - Values (`red`, `12px`)\n *\n * @returns Trimmed text content.\n */\n const readText = (): string => {\n let result = '';\n\n while (!isEof()) {\n const ch = peek();\n if (!ch) {\n break;\n }\n\n if (isBoundaryChar(ch)) {\n break;\n }\n\n result += ch;\n index++;\n }\n\n return result.trim();\n };\n\n // ============================\n // Main Token Loop\n // ============================\n while (!isEof()) {\n skipWhitespace();\n\n if (isEof()) {\n break;\n }\n\n if (skipComment()) {\n continue;\n }\n\n const ch = peek();\n if (!ch) {\n break;\n }\n\n if (ch === '{') {\n tokens.push({\n type: 'braceOpen',\n });\n\n index++;\n continue;\n }\n\n if (ch === '}') {\n tokens.push({\n type: 'braceClose',\n });\n\n index++;\n continue;\n }\n\n if (ch === ':') {\n tokens.push({\n type: 'colon',\n });\n\n index++;\n continue;\n }\n\n if (ch === ';') {\n tokens.push({\n type: 'semicolon',\n });\n\n index++;\n continue;\n }\n\n if (ch === '@') {\n tokens.push({\n type: 'at',\n });\n\n index++;\n continue;\n }\n\n // Params group\n if (ch === '(') {\n tokens.push({\n type: 'params',\n value: readParamsGroup(),\n });\n\n continue;\n }\n\n // Strings\n if (ch === '\"' || ch === \"'\") {\n tokens.push({\n type: 'string',\n value: readString(),\n });\n\n continue;\n }\n\n // Text chunk\n const value = readText();\n if (value) {\n tokens.push({\n type: 'text',\n value,\n });\n } else {\n // Safety fallback to prevent infinite loops\n index++;\n }\n }\n\n return tokens;\n};\n"],"names":["__webpack_require__","exports","definition","key","o","Object","defineProperty","enumerable","get","obj","prop","prototype","hasOwnProperty","call","Symbol","toStringTag","value","isBoundaryChar","ch","tokenizeCss","input","tokens","index","isEof","length","peek","undefined","peekNext","skipWhitespace","test","skipComment","readString","quote","result","escaped","readParamsGroup","depth","readText","trim","push","type"],"sourceRoot":""}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
/******/ (() => { // webpackBootstrap
|
|
2
|
+
/******/ "use strict";
|
|
3
|
+
/******/ var __webpack_modules__ = ({
|
|
4
|
+
|
|
5
|
+
/***/ "./src/tokenize-css.ts"
|
|
6
|
+
/*!*****************************!*\
|
|
7
|
+
!*** ./src/tokenize-css.ts ***!
|
|
8
|
+
\*****************************/
|
|
9
|
+
(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
10
|
+
|
|
11
|
+
__webpack_require__.r(__webpack_exports__);
|
|
12
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
13
|
+
/* harmony export */ tokenizeCss: () => (/* binding */ tokenizeCss)
|
|
14
|
+
/* harmony export */ });
|
|
15
|
+
/**
|
|
16
|
+
* Determines whether a character should terminate a plain text read.
|
|
17
|
+
*
|
|
18
|
+
* These characters represent structural boundaries in CSS:
|
|
19
|
+
* - Blocks: `{` `}`
|
|
20
|
+
* - Declarations: `:` `;`
|
|
21
|
+
* - At-rules: `@`
|
|
22
|
+
* - Params: `(`
|
|
23
|
+
* - Strings: `'` `"`
|
|
24
|
+
* - Comments: `/`
|
|
25
|
+
*/
|
|
26
|
+
const isBoundaryChar = (ch) => ch === '{' ||
|
|
27
|
+
ch === '}' ||
|
|
28
|
+
ch === ':' ||
|
|
29
|
+
ch === ';' ||
|
|
30
|
+
ch === '@' ||
|
|
31
|
+
ch === '(' ||
|
|
32
|
+
ch === '"' ||
|
|
33
|
+
ch === "'" ||
|
|
34
|
+
ch === '/';
|
|
35
|
+
/**
|
|
36
|
+
* Tokenizes a CSS-like input string into a sequence of Honey CSS tokens.
|
|
37
|
+
*
|
|
38
|
+
* This tokenizer is intentionally lightweight and designed for parsing
|
|
39
|
+
* Honey-specific CSS extensions such as:
|
|
40
|
+
*
|
|
41
|
+
* - Custom at-rules: `@honey-media (...) { ... }`
|
|
42
|
+
* - Nested selectors: `&:hover { ... }`
|
|
43
|
+
* - CSS variables: `--primary-color: red;`
|
|
44
|
+
*
|
|
45
|
+
* Supported syntax:
|
|
46
|
+
* - Braces: `{` `}`
|
|
47
|
+
* - Colons and semicolons: `:` `;`
|
|
48
|
+
* - At-rule marker: `@`
|
|
49
|
+
* - Parentheses groups: `(sm:down)`
|
|
50
|
+
* - Quoted strings: `"..."`, `'...'`
|
|
51
|
+
* - Block comments: `/* ... *\/`
|
|
52
|
+
*
|
|
53
|
+
* @param input - Raw CSS string to tokenize.
|
|
54
|
+
*
|
|
55
|
+
* @returns An ordered array of tokens.
|
|
56
|
+
*/
|
|
57
|
+
const tokenizeCss = (input) => {
|
|
58
|
+
const tokens = [];
|
|
59
|
+
let index = 0;
|
|
60
|
+
const isEof = () => index >= input.length;
|
|
61
|
+
/**
|
|
62
|
+
* Returns the current character without consuming it.
|
|
63
|
+
*/
|
|
64
|
+
const peek = () => (isEof() ? undefined : input[index]);
|
|
65
|
+
/**
|
|
66
|
+
* Returns the next character without consuming it.
|
|
67
|
+
*/
|
|
68
|
+
const peekNext = () => index + 1 >= input.length ? undefined : input[index + 1];
|
|
69
|
+
/**
|
|
70
|
+
* Advances the cursor past any whitespace characters.
|
|
71
|
+
*/
|
|
72
|
+
const skipWhitespace = () => {
|
|
73
|
+
while (true) {
|
|
74
|
+
const ch = peek();
|
|
75
|
+
if (!ch || !/\s/.test(ch)) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
index++;
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* Skips CSS block comments of the form:
|
|
83
|
+
*
|
|
84
|
+
* ```css
|
|
85
|
+
* /* comment *\/
|
|
86
|
+
* ```
|
|
87
|
+
*
|
|
88
|
+
* If the comment is unterminated, tokenization stops safely.
|
|
89
|
+
*
|
|
90
|
+
* @returns `true` if a comment was skipped.
|
|
91
|
+
*/
|
|
92
|
+
const skipComment = () => {
|
|
93
|
+
if (peek() !== '/' || peekNext() !== '*') {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
index += 2; // skip "/*"
|
|
97
|
+
while (!isEof()) {
|
|
98
|
+
if (peek() === '*' && peekNext() === '/') {
|
|
99
|
+
index += 2; // skip "*/"
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
index++;
|
|
103
|
+
}
|
|
104
|
+
return true;
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* Reads a quoted string token.
|
|
108
|
+
*
|
|
109
|
+
* Supports:
|
|
110
|
+
* - Double quotes: `"text"`
|
|
111
|
+
* - Single quotes: `'text'`
|
|
112
|
+
* - Escaped characters: `"a\\\"b"`
|
|
113
|
+
*
|
|
114
|
+
* @returns The unwrapped string contents.
|
|
115
|
+
*/
|
|
116
|
+
const readString = () => {
|
|
117
|
+
const quote = peek();
|
|
118
|
+
if (!quote) {
|
|
119
|
+
return '';
|
|
120
|
+
}
|
|
121
|
+
index++; // skip opening quote
|
|
122
|
+
let result = '';
|
|
123
|
+
while (!isEof()) {
|
|
124
|
+
const ch = peek();
|
|
125
|
+
if (!ch) {
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
// Handle escape sequences
|
|
129
|
+
if (ch === '\\') {
|
|
130
|
+
result += ch;
|
|
131
|
+
index++;
|
|
132
|
+
const escaped = peek();
|
|
133
|
+
if (escaped) {
|
|
134
|
+
result += escaped;
|
|
135
|
+
index++;
|
|
136
|
+
}
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
// Closing quote
|
|
140
|
+
if (ch === quote) {
|
|
141
|
+
index++;
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
result += ch;
|
|
145
|
+
index++;
|
|
146
|
+
}
|
|
147
|
+
return result;
|
|
148
|
+
};
|
|
149
|
+
/**
|
|
150
|
+
* Reads a balanced parentheses group.
|
|
151
|
+
*
|
|
152
|
+
* Examples:
|
|
153
|
+
* - `(sm:down)`
|
|
154
|
+
* - `(min-width: calc(100% - 1px))`
|
|
155
|
+
*
|
|
156
|
+
* Nested parentheses are supported.
|
|
157
|
+
*
|
|
158
|
+
* @returns The full params string including parentheses.
|
|
159
|
+
*/
|
|
160
|
+
const readParamsGroup = () => {
|
|
161
|
+
let depth = 0;
|
|
162
|
+
let result = '';
|
|
163
|
+
while (!isEof()) {
|
|
164
|
+
const ch = peek();
|
|
165
|
+
if (!ch) {
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
if (ch === '(') {
|
|
169
|
+
depth++;
|
|
170
|
+
}
|
|
171
|
+
if (ch === ')') {
|
|
172
|
+
depth--;
|
|
173
|
+
}
|
|
174
|
+
result += ch;
|
|
175
|
+
index++;
|
|
176
|
+
if (depth === 0) {
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return result;
|
|
181
|
+
};
|
|
182
|
+
/**
|
|
183
|
+
* Reads plain text until a boundary character is reached.
|
|
184
|
+
*
|
|
185
|
+
* This is used for:
|
|
186
|
+
* - Selectors (`.btn`, `&:hover`)
|
|
187
|
+
* - Property names (`color`)
|
|
188
|
+
* - Values (`red`, `12px`)
|
|
189
|
+
*
|
|
190
|
+
* @returns Trimmed text content.
|
|
191
|
+
*/
|
|
192
|
+
const readText = () => {
|
|
193
|
+
let result = '';
|
|
194
|
+
while (!isEof()) {
|
|
195
|
+
const ch = peek();
|
|
196
|
+
if (!ch) {
|
|
197
|
+
break;
|
|
198
|
+
}
|
|
199
|
+
if (isBoundaryChar(ch)) {
|
|
200
|
+
break;
|
|
201
|
+
}
|
|
202
|
+
result += ch;
|
|
203
|
+
index++;
|
|
204
|
+
}
|
|
205
|
+
return result.trim();
|
|
206
|
+
};
|
|
207
|
+
// ============================
|
|
208
|
+
// Main Token Loop
|
|
209
|
+
// ============================
|
|
210
|
+
while (!isEof()) {
|
|
211
|
+
skipWhitespace();
|
|
212
|
+
if (isEof()) {
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
if (skipComment()) {
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
const ch = peek();
|
|
219
|
+
if (!ch) {
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
if (ch === '{') {
|
|
223
|
+
tokens.push({
|
|
224
|
+
type: 'braceOpen',
|
|
225
|
+
});
|
|
226
|
+
index++;
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
if (ch === '}') {
|
|
230
|
+
tokens.push({
|
|
231
|
+
type: 'braceClose',
|
|
232
|
+
});
|
|
233
|
+
index++;
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
if (ch === ':') {
|
|
237
|
+
tokens.push({
|
|
238
|
+
type: 'colon',
|
|
239
|
+
});
|
|
240
|
+
index++;
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
if (ch === ';') {
|
|
244
|
+
tokens.push({
|
|
245
|
+
type: 'semicolon',
|
|
246
|
+
});
|
|
247
|
+
index++;
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
if (ch === '@') {
|
|
251
|
+
tokens.push({
|
|
252
|
+
type: 'at',
|
|
253
|
+
});
|
|
254
|
+
index++;
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
// Params group
|
|
258
|
+
if (ch === '(') {
|
|
259
|
+
tokens.push({
|
|
260
|
+
type: 'params',
|
|
261
|
+
value: readParamsGroup(),
|
|
262
|
+
});
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
265
|
+
// Strings
|
|
266
|
+
if (ch === '"' || ch === "'") {
|
|
267
|
+
tokens.push({
|
|
268
|
+
type: 'string',
|
|
269
|
+
value: readString(),
|
|
270
|
+
});
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
// Text chunk
|
|
274
|
+
const value = readText();
|
|
275
|
+
if (value) {
|
|
276
|
+
tokens.push({
|
|
277
|
+
type: 'text',
|
|
278
|
+
value,
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
// Safety fallback to prevent infinite loops
|
|
283
|
+
index++;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return tokens;
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
/***/ },
|
|
291
|
+
|
|
292
|
+
/***/ "./src/types.ts"
|
|
293
|
+
/*!**********************!*\
|
|
294
|
+
!*** ./src/types.ts ***!
|
|
295
|
+
\**********************/
|
|
296
|
+
(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
297
|
+
|
|
298
|
+
__webpack_require__.r(__webpack_exports__);
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
/***/ }
|
|
303
|
+
|
|
304
|
+
/******/ });
|
|
305
|
+
/************************************************************************/
|
|
306
|
+
/******/ // The module cache
|
|
307
|
+
/******/ var __webpack_module_cache__ = {};
|
|
308
|
+
/******/
|
|
309
|
+
/******/ // The require function
|
|
310
|
+
/******/ function __webpack_require__(moduleId) {
|
|
311
|
+
/******/ // Check if module is in cache
|
|
312
|
+
/******/ var cachedModule = __webpack_module_cache__[moduleId];
|
|
313
|
+
/******/ if (cachedModule !== undefined) {
|
|
314
|
+
/******/ return cachedModule.exports;
|
|
315
|
+
/******/ }
|
|
316
|
+
/******/ // Check if module exists (development only)
|
|
317
|
+
/******/ if (__webpack_modules__[moduleId] === undefined) {
|
|
318
|
+
/******/ var e = new Error("Cannot find module '" + moduleId + "'");
|
|
319
|
+
/******/ e.code = 'MODULE_NOT_FOUND';
|
|
320
|
+
/******/ throw e;
|
|
321
|
+
/******/ }
|
|
322
|
+
/******/ // Create a new module (and put it into the cache)
|
|
323
|
+
/******/ var module = __webpack_module_cache__[moduleId] = {
|
|
324
|
+
/******/ // no module.id needed
|
|
325
|
+
/******/ // no module.loaded needed
|
|
326
|
+
/******/ exports: {}
|
|
327
|
+
/******/ };
|
|
328
|
+
/******/
|
|
329
|
+
/******/ // Execute the module function
|
|
330
|
+
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
|
|
331
|
+
/******/
|
|
332
|
+
/******/ // Return the exports of the module
|
|
333
|
+
/******/ return module.exports;
|
|
334
|
+
/******/ }
|
|
335
|
+
/******/
|
|
336
|
+
/************************************************************************/
|
|
337
|
+
/******/ /* webpack/runtime/define property getters */
|
|
338
|
+
/******/ (() => {
|
|
339
|
+
/******/ // define getter functions for harmony exports
|
|
340
|
+
/******/ __webpack_require__.d = (exports, definition) => {
|
|
341
|
+
/******/ for(var key in definition) {
|
|
342
|
+
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
|
|
343
|
+
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
|
|
344
|
+
/******/ }
|
|
345
|
+
/******/ }
|
|
346
|
+
/******/ };
|
|
347
|
+
/******/ })();
|
|
348
|
+
/******/
|
|
349
|
+
/******/ /* webpack/runtime/hasOwnProperty shorthand */
|
|
350
|
+
/******/ (() => {
|
|
351
|
+
/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
|
|
352
|
+
/******/ })();
|
|
353
|
+
/******/
|
|
354
|
+
/******/ /* webpack/runtime/make namespace object */
|
|
355
|
+
/******/ (() => {
|
|
356
|
+
/******/ // define __esModule on exports
|
|
357
|
+
/******/ __webpack_require__.r = (exports) => {
|
|
358
|
+
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
|
|
359
|
+
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
360
|
+
/******/ }
|
|
361
|
+
/******/ Object.defineProperty(exports, '__esModule', { value: true });
|
|
362
|
+
/******/ };
|
|
363
|
+
/******/ })();
|
|
364
|
+
/******/
|
|
365
|
+
/************************************************************************/
|
|
366
|
+
var __webpack_exports__ = {};
|
|
367
|
+
// This entry needs to be wrapped in an IIFE because it needs to be isolated against other modules in the chunk.
|
|
368
|
+
(() => {
|
|
369
|
+
/*!**********************!*\
|
|
370
|
+
!*** ./src/index.ts ***!
|
|
371
|
+
\**********************/
|
|
372
|
+
__webpack_require__.r(__webpack_exports__);
|
|
373
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
374
|
+
/* harmony export */ tokenizeCss: () => (/* reexport safe */ _tokenize_css__WEBPACK_IMPORTED_MODULE_1__.tokenizeCss)
|
|
375
|
+
/* harmony export */ });
|
|
376
|
+
/* harmony import */ var _types__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./types */ "./src/types.ts");
|
|
377
|
+
/* harmony import */ var _tokenize_css__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./tokenize-css */ "./src/tokenize-css.ts");
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
})();
|
|
382
|
+
|
|
383
|
+
module.exports = __webpack_exports__;
|
|
384
|
+
/******/ })()
|
|
385
|
+
;
|
|
386
|
+
//# sourceMappingURL=index.dev.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.dev.cjs","mappings":"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","sources":["webpack://@react-hive/honey-css/./src/tokenize-css.ts","webpack://@react-hive/honey-css/./src/types.ts","webpack://@react-hive/honey-css/webpack/bootstrap","webpack://@react-hive/honey-css/webpack/runtime/define property getters","webpack://@react-hive/honey-css/webpack/runtime/hasOwnProperty shorthand","webpack://@react-hive/honey-css/webpack/runtime/make namespace object","webpack://@react-hive/honey-css/./src/index.ts"],"sourcesContent":["import { HoneyCssToken } from '~/types';\n\n/**\n * Determines whether a character should terminate a plain text read.\n *\n * These characters represent structural boundaries in CSS:\n * - Blocks: `{` `}`\n * - Declarations: `:` `;`\n * - At-rules: `@`\n * - Params: `(`\n * - Strings: `'` `\"`\n * - Comments: `/`\n */\nconst isBoundaryChar = (ch: string): boolean =>\n ch === '{' ||\n ch === '}' ||\n ch === ':' ||\n ch === ';' ||\n ch === '@' ||\n ch === '(' ||\n ch === '\"' ||\n ch === \"'\" ||\n ch === '/';\n\n/**\n * Tokenizes a CSS-like input string into a sequence of Honey CSS tokens.\n *\n * This tokenizer is intentionally lightweight and designed for parsing\n * Honey-specific CSS extensions such as:\n *\n * - Custom at-rules: `@honey-media (...) { ... }`\n * - Nested selectors: `&:hover { ... }`\n * - CSS variables: `--primary-color: red;`\n *\n * Supported syntax:\n * - Braces: `{` `}`\n * - Colons and semicolons: `:` `;`\n * - At-rule marker: `@`\n * - Parentheses groups: `(sm:down)`\n * - Quoted strings: `\"...\"`, `'...'`\n * - Block comments: `/* ... *\\/`\n *\n * @param input - Raw CSS string to tokenize.\n *\n * @returns An ordered array of tokens.\n */\nexport const tokenizeCss = (input: string): HoneyCssToken[] => {\n const tokens: HoneyCssToken[] = [];\n\n let index = 0;\n\n const isEof = (): boolean => index >= input.length;\n\n /**\n * Returns the current character without consuming it.\n */\n const peek = (): string | undefined => (isEof() ? undefined : input[index]);\n\n /**\n * Returns the next character without consuming it.\n */\n const peekNext = (): string | undefined =>\n index + 1 >= input.length ? undefined : input[index + 1];\n\n /**\n * Advances the cursor past any whitespace characters.\n */\n const skipWhitespace = () => {\n while (true) {\n const ch = peek();\n\n if (!ch || !/\\s/.test(ch)) {\n return;\n }\n\n index++;\n }\n };\n\n /**\n * Skips CSS block comments of the form:\n *\n * ```css\n * /* comment *\\/\n * ```\n *\n * If the comment is unterminated, tokenization stops safely.\n *\n * @returns `true` if a comment was skipped.\n */\n const skipComment = (): boolean => {\n if (peek() !== '/' || peekNext() !== '*') {\n return false;\n }\n\n index += 2; // skip \"/*\"\n\n while (!isEof()) {\n if (peek() === '*' && peekNext() === '/') {\n index += 2; // skip \"*/\"\n\n return true;\n }\n\n index++;\n }\n\n return true;\n };\n\n /**\n * Reads a quoted string token.\n *\n * Supports:\n * - Double quotes: `\"text\"`\n * - Single quotes: `'text'`\n * - Escaped characters: `\"a\\\\\\\"b\"`\n *\n * @returns The unwrapped string contents.\n */\n const readString = (): string => {\n const quote = peek();\n if (!quote) {\n return '';\n }\n\n index++; // skip opening quote\n let result = '';\n\n while (!isEof()) {\n const ch = peek();\n if (!ch) {\n break;\n }\n\n // Handle escape sequences\n if (ch === '\\\\') {\n result += ch;\n index++;\n\n const escaped = peek();\n if (escaped) {\n result += escaped;\n index++;\n }\n\n continue;\n }\n\n // Closing quote\n if (ch === quote) {\n index++;\n break;\n }\n\n result += ch;\n index++;\n }\n\n return result;\n };\n\n /**\n * Reads a balanced parentheses group.\n *\n * Examples:\n * - `(sm:down)`\n * - `(min-width: calc(100% - 1px))`\n *\n * Nested parentheses are supported.\n *\n * @returns The full params string including parentheses.\n */\n const readParamsGroup = (): string => {\n let depth = 0;\n let result = '';\n\n while (!isEof()) {\n const ch = peek();\n if (!ch) {\n break;\n }\n\n if (ch === '(') {\n depth++;\n }\n\n if (ch === ')') {\n depth--;\n }\n\n result += ch;\n index++;\n\n if (depth === 0) {\n break;\n }\n }\n\n return result;\n };\n\n /**\n * Reads plain text until a boundary character is reached.\n *\n * This is used for:\n * - Selectors (`.btn`, `&:hover`)\n * - Property names (`color`)\n * - Values (`red`, `12px`)\n *\n * @returns Trimmed text content.\n */\n const readText = (): string => {\n let result = '';\n\n while (!isEof()) {\n const ch = peek();\n if (!ch) {\n break;\n }\n\n if (isBoundaryChar(ch)) {\n break;\n }\n\n result += ch;\n index++;\n }\n\n return result.trim();\n };\n\n // ============================\n // Main Token Loop\n // ============================\n while (!isEof()) {\n skipWhitespace();\n\n if (isEof()) {\n break;\n }\n\n if (skipComment()) {\n continue;\n }\n\n const ch = peek();\n if (!ch) {\n break;\n }\n\n if (ch === '{') {\n tokens.push({\n type: 'braceOpen',\n });\n\n index++;\n continue;\n }\n\n if (ch === '}') {\n tokens.push({\n type: 'braceClose',\n });\n\n index++;\n continue;\n }\n\n if (ch === ':') {\n tokens.push({\n type: 'colon',\n });\n\n index++;\n continue;\n }\n\n if (ch === ';') {\n tokens.push({\n type: 'semicolon',\n });\n\n index++;\n continue;\n }\n\n if (ch === '@') {\n tokens.push({\n type: 'at',\n });\n\n index++;\n continue;\n }\n\n // Params group\n if (ch === '(') {\n tokens.push({\n type: 'params',\n value: readParamsGroup(),\n });\n\n continue;\n }\n\n // Strings\n if (ch === '\"' || ch === \"'\") {\n tokens.push({\n type: 'string',\n value: readString(),\n });\n\n continue;\n }\n\n // Text chunk\n const value = readText();\n if (value) {\n tokens.push({\n type: 'text',\n value,\n });\n } else {\n // Safety fallback to prevent infinite loops\n index++;\n }\n }\n\n return tokens;\n};\n","/**\n * All supported token types produced by the Honey CSS tokenizer.\n *\n * These tokens represent the minimal syntax units needed for parsing:\n * - Structural braces (`{` / `}`)\n * - Punctuation (`:` / `;`)\n * - At-rules (`@`)\n * - Parenthesized groups (`(...)`)\n * - Strings (`\"...\"`, `'...'`)\n * - Plain text chunks (selectors, property names, values)\n */\nexport type HoneyCssTokenType =\n | 'braceOpen'\n | 'braceClose'\n | 'colon'\n | 'semicolon'\n | 'at'\n | 'params'\n | 'string'\n | 'text';\n\n/**\n * A single token produced by {@link tokenizeCss}.\n *\n * Some token types (like `text`, `params`, `string`) include a `value`,\n * while punctuation tokens do not.\n */\nexport type HoneyCssToken = {\n type: HoneyCssTokenType;\n value?: string;\n};","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Check if module exists (development only)\n\tif (__webpack_modules__[moduleId] === undefined) {\n\t\tvar e = new Error(\"Cannot find module '\" + moduleId + \"'\");\n\t\te.code = 'MODULE_NOT_FOUND';\n\t\tthrow e;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","export * from './types'\nexport * from './tokenize-css'"],"names":[],"sourceRoot":""}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const t=t=>"{"===t||"}"===t||":"===t||";"===t||"@"===t||"("===t||'"'===t||"'"===t||"/"===t,e=e=>{const n=[];let r=0;const i=()=>r>=e.length,o=()=>i()?void 0:e[r],u=()=>r+1>=e.length?void 0:e[r+1],f=()=>{for(;;){const t=o();if(!t||!/\s/.test(t))return;r++}},s=()=>{if("/"!==o()||"*"!==u())return!1;for(r+=2;!i();){if("*"===o()&&"/"===u())return r+=2,!0;r++}return!0},c=()=>{const t=o();if(!t)return"";r++;let e="";for(;!i();){const n=o();if(!n)break;if("\\"===n){e+=n,r++;const t=o();t&&(e+=t,r++);continue}if(n===t){r++;break}e+=n,r++}return e},p=()=>{let t=0,e="";for(;!i();){const n=o();if(!n)break;if("("===n&&t++,")"===n&&t--,e+=n,r++,0===t)break}return e},a=()=>{let e="";for(;!i();){const n=o();if(!n)break;if(t(n))break;e+=n,r++}return e.trim()};for(;!i()&&(f(),!i());){if(s())continue;const t=o();if(!t)break;if("{"===t){n.push({type:"braceOpen"}),r++;continue}if("}"===t){n.push({type:"braceClose"}),r++;continue}if(":"===t){n.push({type:"colon"}),r++;continue}if(";"===t){n.push({type:"semicolon"}),r++;continue}if("@"===t){n.push({type:"at"}),r++;continue}if("("===t){n.push({type:"params",value:p()});continue}if('"'===t||"'"===t){n.push({type:"string",value:c()});continue}const e=a();e?n.push({type:"text",value:e}):r++}return n};export{e as tokenizeCss};
|
|
2
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","mappings":"AAaA,MAAMA,EAAkBC,GACf,MAAPA,GACO,MAAPA,GACO,MAAPA,GACO,MAAPA,GACO,MAAPA,GACO,MAAPA,GACO,MAAPA,GACO,MAAPA,GACO,MAAPA,EAwBWC,EAAeC,IAC1B,MAAMC,EAA0B,GAEhC,IAAIC,EAAQ,EAEZ,MAAMC,EAAQ,IAAeD,GAASF,EAAMI,OAKtCC,EAAO,IAA2BF,SAAUG,EAAYN,EAAME,GAK9DK,EAAW,IACfL,EAAQ,GAAKF,EAAMI,YAASE,EAAYN,EAAME,EAAQ,GAKlDM,EAAiB,KACrB,OAAa,CACX,MAAMV,EAAKO,IAEX,IAAKP,IAAO,KAAKW,KAAKX,GACpB,OAGFI,GACF,GAcIQ,EAAc,KAClB,GAAe,MAAXL,KAAiC,MAAfE,IACpB,OAAO,EAKT,IAFAL,GAAS,GAEDC,KAAS,CACf,GAAe,MAAXE,KAAiC,MAAfE,IAGpB,OAFAL,GAAS,GAEF,EAGTA,GACF,CAEA,OAAO,GAaHS,EAAa,KACjB,MAAMC,EAAQP,IACd,IAAKO,EACH,MAAO,GAGTV,IACA,IAAIW,EAAS,GAEb,MAAQV,KAAS,CACf,MAAML,EAAKO,IACX,IAAKP,EACH,MAIF,GAAW,OAAPA,EAAa,CACfe,GAAUf,EACVI,IAEA,MAAMY,EAAUT,IACZS,IACFD,GAAUC,EACVZ,KAGF,QACF,CAGA,GAAIJ,IAAOc,EAAO,CAChBV,IACA,KACF,CAEAW,GAAUf,EACVI,GACF,CAEA,OAAOW,GAcHE,EAAkB,KACtB,IAAIC,EAAQ,EACRH,EAAS,GAEb,MAAQV,KAAS,CACf,MAAML,EAAKO,IACX,IAAKP,EACH,MAcF,GAXW,MAAPA,GACFkB,IAGS,MAAPlB,GACFkB,IAGFH,GAAUf,EACVI,IAEc,IAAVc,EACF,KAEJ,CAEA,OAAOH,GAaHI,EAAW,KACf,IAAIJ,EAAS,GAEb,MAAQV,KAAS,CACf,MAAML,EAAKO,IACX,IAAKP,EACH,MAGF,GAAID,EAAeC,GACjB,MAGFe,GAAUf,EACVI,GACF,CAEA,OAAOW,EAAOK,QAMhB,MAAQf,MACNK,KAEIL,MAHW,CAOf,GAAIO,IACF,SAGF,MAAMZ,EAAKO,IACX,IAAKP,EACH,MAGF,GAAW,MAAPA,EAAY,CACdG,EAAOkB,KAAK,CACVC,KAAM,cAGRlB,IACA,QACF,CAEA,GAAW,MAAPJ,EAAY,CACdG,EAAOkB,KAAK,CACVC,KAAM,eAGRlB,IACA,QACF,CAEA,GAAW,MAAPJ,EAAY,CACdG,EAAOkB,KAAK,CACVC,KAAM,UAGRlB,IACA,QACF,CAEA,GAAW,MAAPJ,EAAY,CACdG,EAAOkB,KAAK,CACVC,KAAM,cAGRlB,IACA,QACF,CAEA,GAAW,MAAPJ,EAAY,CACdG,EAAOkB,KAAK,CACVC,KAAM,OAGRlB,IACA,QACF,CAGA,GAAW,MAAPJ,EAAY,CACdG,EAAOkB,KAAK,CACVC,KAAM,SACNC,MAAON,MAGT,QACF,CAGA,GAAW,MAAPjB,GAAqB,MAAPA,EAAY,CAC5BG,EAAOkB,KAAK,CACVC,KAAM,SACNC,MAAOV,MAGT,QACF,CAGA,MAAMU,EAAQJ,IACVI,EACFpB,EAAOkB,KAAK,CACVC,KAAM,OACNC,UAIFnB,GAEJ,CAEA,OAAOD,U","sources":["webpack://@react-hive/honey-css/./src/tokenize-css.ts"],"sourcesContent":["import { HoneyCssToken } from '~/types';\n\n/**\n * Determines whether a character should terminate a plain text read.\n *\n * These characters represent structural boundaries in CSS:\n * - Blocks: `{` `}`\n * - Declarations: `:` `;`\n * - At-rules: `@`\n * - Params: `(`\n * - Strings: `'` `\"`\n * - Comments: `/`\n */\nconst isBoundaryChar = (ch: string): boolean =>\n ch === '{' ||\n ch === '}' ||\n ch === ':' ||\n ch === ';' ||\n ch === '@' ||\n ch === '(' ||\n ch === '\"' ||\n ch === \"'\" ||\n ch === '/';\n\n/**\n * Tokenizes a CSS-like input string into a sequence of Honey CSS tokens.\n *\n * This tokenizer is intentionally lightweight and designed for parsing\n * Honey-specific CSS extensions such as:\n *\n * - Custom at-rules: `@honey-media (...) { ... }`\n * - Nested selectors: `&:hover { ... }`\n * - CSS variables: `--primary-color: red;`\n *\n * Supported syntax:\n * - Braces: `{` `}`\n * - Colons and semicolons: `:` `;`\n * - At-rule marker: `@`\n * - Parentheses groups: `(sm:down)`\n * - Quoted strings: `\"...\"`, `'...'`\n * - Block comments: `/* ... *\\/`\n *\n * @param input - Raw CSS string to tokenize.\n *\n * @returns An ordered array of tokens.\n */\nexport const tokenizeCss = (input: string): HoneyCssToken[] => {\n const tokens: HoneyCssToken[] = [];\n\n let index = 0;\n\n const isEof = (): boolean => index >= input.length;\n\n /**\n * Returns the current character without consuming it.\n */\n const peek = (): string | undefined => (isEof() ? undefined : input[index]);\n\n /**\n * Returns the next character without consuming it.\n */\n const peekNext = (): string | undefined =>\n index + 1 >= input.length ? undefined : input[index + 1];\n\n /**\n * Advances the cursor past any whitespace characters.\n */\n const skipWhitespace = () => {\n while (true) {\n const ch = peek();\n\n if (!ch || !/\\s/.test(ch)) {\n return;\n }\n\n index++;\n }\n };\n\n /**\n * Skips CSS block comments of the form:\n *\n * ```css\n * /* comment *\\/\n * ```\n *\n * If the comment is unterminated, tokenization stops safely.\n *\n * @returns `true` if a comment was skipped.\n */\n const skipComment = (): boolean => {\n if (peek() !== '/' || peekNext() !== '*') {\n return false;\n }\n\n index += 2; // skip \"/*\"\n\n while (!isEof()) {\n if (peek() === '*' && peekNext() === '/') {\n index += 2; // skip \"*/\"\n\n return true;\n }\n\n index++;\n }\n\n return true;\n };\n\n /**\n * Reads a quoted string token.\n *\n * Supports:\n * - Double quotes: `\"text\"`\n * - Single quotes: `'text'`\n * - Escaped characters: `\"a\\\\\\\"b\"`\n *\n * @returns The unwrapped string contents.\n */\n const readString = (): string => {\n const quote = peek();\n if (!quote) {\n return '';\n }\n\n index++; // skip opening quote\n let result = '';\n\n while (!isEof()) {\n const ch = peek();\n if (!ch) {\n break;\n }\n\n // Handle escape sequences\n if (ch === '\\\\') {\n result += ch;\n index++;\n\n const escaped = peek();\n if (escaped) {\n result += escaped;\n index++;\n }\n\n continue;\n }\n\n // Closing quote\n if (ch === quote) {\n index++;\n break;\n }\n\n result += ch;\n index++;\n }\n\n return result;\n };\n\n /**\n * Reads a balanced parentheses group.\n *\n * Examples:\n * - `(sm:down)`\n * - `(min-width: calc(100% - 1px))`\n *\n * Nested parentheses are supported.\n *\n * @returns The full params string including parentheses.\n */\n const readParamsGroup = (): string => {\n let depth = 0;\n let result = '';\n\n while (!isEof()) {\n const ch = peek();\n if (!ch) {\n break;\n }\n\n if (ch === '(') {\n depth++;\n }\n\n if (ch === ')') {\n depth--;\n }\n\n result += ch;\n index++;\n\n if (depth === 0) {\n break;\n }\n }\n\n return result;\n };\n\n /**\n * Reads plain text until a boundary character is reached.\n *\n * This is used for:\n * - Selectors (`.btn`, `&:hover`)\n * - Property names (`color`)\n * - Values (`red`, `12px`)\n *\n * @returns Trimmed text content.\n */\n const readText = (): string => {\n let result = '';\n\n while (!isEof()) {\n const ch = peek();\n if (!ch) {\n break;\n }\n\n if (isBoundaryChar(ch)) {\n break;\n }\n\n result += ch;\n index++;\n }\n\n return result.trim();\n };\n\n // ============================\n // Main Token Loop\n // ============================\n while (!isEof()) {\n skipWhitespace();\n\n if (isEof()) {\n break;\n }\n\n if (skipComment()) {\n continue;\n }\n\n const ch = peek();\n if (!ch) {\n break;\n }\n\n if (ch === '{') {\n tokens.push({\n type: 'braceOpen',\n });\n\n index++;\n continue;\n }\n\n if (ch === '}') {\n tokens.push({\n type: 'braceClose',\n });\n\n index++;\n continue;\n }\n\n if (ch === ':') {\n tokens.push({\n type: 'colon',\n });\n\n index++;\n continue;\n }\n\n if (ch === ';') {\n tokens.push({\n type: 'semicolon',\n });\n\n index++;\n continue;\n }\n\n if (ch === '@') {\n tokens.push({\n type: 'at',\n });\n\n index++;\n continue;\n }\n\n // Params group\n if (ch === '(') {\n tokens.push({\n type: 'params',\n value: readParamsGroup(),\n });\n\n continue;\n }\n\n // Strings\n if (ch === '\"' || ch === \"'\") {\n tokens.push({\n type: 'string',\n value: readString(),\n });\n\n continue;\n }\n\n // Text chunk\n const value = readText();\n if (value) {\n tokens.push({\n type: 'text',\n value,\n });\n } else {\n // Safety fallback to prevent infinite loops\n index++;\n }\n }\n\n return tokens;\n};\n"],"names":["isBoundaryChar","ch","tokenizeCss","input","tokens","index","isEof","length","peek","undefined","peekNext","skipWhitespace","test","skipComment","readString","quote","result","escaped","readParamsGroup","depth","readText","trim","push","type","value"],"sourceRoot":""}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { HoneyCssToken } from '~/types';
|
|
2
|
+
/**
|
|
3
|
+
* Tokenizes a CSS-like input string into a sequence of Honey CSS tokens.
|
|
4
|
+
*
|
|
5
|
+
* This tokenizer is intentionally lightweight and designed for parsing
|
|
6
|
+
* Honey-specific CSS extensions such as:
|
|
7
|
+
*
|
|
8
|
+
* - Custom at-rules: `@honey-media (...) { ... }`
|
|
9
|
+
* - Nested selectors: `&:hover { ... }`
|
|
10
|
+
* - CSS variables: `--primary-color: red;`
|
|
11
|
+
*
|
|
12
|
+
* Supported syntax:
|
|
13
|
+
* - Braces: `{` `}`
|
|
14
|
+
* - Colons and semicolons: `:` `;`
|
|
15
|
+
* - At-rule marker: `@`
|
|
16
|
+
* - Parentheses groups: `(sm:down)`
|
|
17
|
+
* - Quoted strings: `"..."`, `'...'`
|
|
18
|
+
* - Block comments: `/* ... *\/`
|
|
19
|
+
*
|
|
20
|
+
* @param input - Raw CSS string to tokenize.
|
|
21
|
+
*
|
|
22
|
+
* @returns An ordered array of tokens.
|
|
23
|
+
*/
|
|
24
|
+
export declare const tokenizeCss: (input: string) => HoneyCssToken[];
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* All supported token types produced by the Honey CSS tokenizer.
|
|
3
|
+
*
|
|
4
|
+
* These tokens represent the minimal syntax units needed for parsing:
|
|
5
|
+
* - Structural braces (`{` / `}`)
|
|
6
|
+
* - Punctuation (`:` / `;`)
|
|
7
|
+
* - At-rules (`@`)
|
|
8
|
+
* - Parenthesized groups (`(...)`)
|
|
9
|
+
* - Strings (`"..."`, `'...'`)
|
|
10
|
+
* - Plain text chunks (selectors, property names, values)
|
|
11
|
+
*/
|
|
12
|
+
export type HoneyCssTokenType = 'braceOpen' | 'braceClose' | 'colon' | 'semicolon' | 'at' | 'params' | 'string' | 'text';
|
|
13
|
+
/**
|
|
14
|
+
* A single token produced by {@link tokenizeCss}.
|
|
15
|
+
*
|
|
16
|
+
* Some token types (like `text`, `params`, `string`) include a `value`,
|
|
17
|
+
* while punctuation tokens do not.
|
|
18
|
+
*/
|
|
19
|
+
export type HoneyCssToken = {
|
|
20
|
+
type: HoneyCssTokenType;
|
|
21
|
+
value?: string;
|
|
22
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@react-hive/honey-css",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A lightweight CSS tokenizer and parser that produces a simple AST for custom CSS processing.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"css",
|
|
7
|
+
"parser",
|
|
8
|
+
"tokenizer",
|
|
9
|
+
"ast",
|
|
10
|
+
"css-ast",
|
|
11
|
+
"css-in-js",
|
|
12
|
+
"compiler",
|
|
13
|
+
"transformer",
|
|
14
|
+
"react-hive",
|
|
15
|
+
"honey-style"
|
|
16
|
+
],
|
|
17
|
+
"homepage": "https://github.com/React-Hive/honey-css",
|
|
18
|
+
"bugs": {
|
|
19
|
+
"url": "https://github.com/React-Hive/honey-css/issues"
|
|
20
|
+
},
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "https://github.com/React-Hive/honey-css.git"
|
|
24
|
+
},
|
|
25
|
+
"author": "Mike Aliinyk <m.aliynik@gmail.com>",
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"type": "module",
|
|
28
|
+
"main": "./dist/index.cjs",
|
|
29
|
+
"module": "./dist/index.mjs",
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"exports": {
|
|
32
|
+
".": {
|
|
33
|
+
"types": "./dist/index.d.ts",
|
|
34
|
+
"import": "./dist/index.mjs",
|
|
35
|
+
"require": "./dist/index.cjs"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"files": [
|
|
39
|
+
"dist",
|
|
40
|
+
"!dist/**/__mocks__",
|
|
41
|
+
"!dist/**/__tests__",
|
|
42
|
+
"!dist/**/jest*"
|
|
43
|
+
],
|
|
44
|
+
"publishConfig": {
|
|
45
|
+
"access": "public"
|
|
46
|
+
},
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": ">=18"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@eslint/js": "9.39.1",
|
|
52
|
+
"@mdx-js/loader": "3.1.1",
|
|
53
|
+
"@types/jest": "29.5.14",
|
|
54
|
+
"@types/node": "22.19.1",
|
|
55
|
+
"copy-webpack-plugin": "13.0.1",
|
|
56
|
+
"eslint": "9.39.1",
|
|
57
|
+
"eslint-plugin-react": "7.37.5",
|
|
58
|
+
"jest": "29.7.0",
|
|
59
|
+
"prettier": "3.6.2",
|
|
60
|
+
"ts-jest": "29.4.4",
|
|
61
|
+
"ts-loader": "9.5.4",
|
|
62
|
+
"typescript": "5.9.3",
|
|
63
|
+
"typescript-eslint": "8.47.0",
|
|
64
|
+
"webpack": "5.105.2",
|
|
65
|
+
"webpack-cli": "6.0.1"
|
|
66
|
+
},
|
|
67
|
+
"jest": {
|
|
68
|
+
"preset": "ts-jest",
|
|
69
|
+
"testMatch": [
|
|
70
|
+
"**/src/**/*.spec.ts"
|
|
71
|
+
],
|
|
72
|
+
"moduleNameMapper": {
|
|
73
|
+
"^~/(.*)$": "<rootDir>/src/$1"
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
"scripts": {
|
|
77
|
+
"clean": "rm -rf dist coverage",
|
|
78
|
+
"build": "webpack --config webpack.config.mjs",
|
|
79
|
+
"test": "jest --coverage"
|
|
80
|
+
}
|
|
81
|
+
}
|