@tbela99/css-parser 0.0.1-alpha3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,302 @@
1
+ import { eq } from '../utils/eq.js';
2
+ import { isNumber } from '../utils/syntax.js';
3
+ import { renderToken } from '../../renderer/render.js';
4
+ import { matchType } from '../utils/type.js';
5
+
6
+ function getTokenType(val) {
7
+ if (val == 'transparent' || val == 'currentcolor') {
8
+ return {
9
+ typ: 'Color',
10
+ val,
11
+ kin: 'lit'
12
+ };
13
+ }
14
+ if (val.endsWith('%')) {
15
+ return {
16
+ typ: 'Perc',
17
+ val: val.slice(0, -1)
18
+ };
19
+ }
20
+ return {
21
+ typ: isNumber(val) ? 'Number' : 'Iden',
22
+ val
23
+ };
24
+ }
25
+ function parseString(val) {
26
+ return val.split(/\s/).map(getTokenType).reduce((acc, curr) => {
27
+ if (acc.length > 0) {
28
+ acc.push({ typ: 'Whitespace' });
29
+ }
30
+ acc.push(curr);
31
+ return acc;
32
+ }, []);
33
+ }
34
+ class PropertyMap {
35
+ config;
36
+ declarations;
37
+ requiredCount;
38
+ pattern;
39
+ constructor(config) {
40
+ const values = Object.values(config.properties);
41
+ this.requiredCount = values.reduce((acc, curr) => curr.required ? ++acc : acc, 0) || values.length;
42
+ this.config = config;
43
+ this.declarations = new Map;
44
+ this.pattern = config.pattern.split(/\s/);
45
+ }
46
+ add(declaration) {
47
+ if (declaration.nam == this.config.shorthand) {
48
+ this.declarations.clear();
49
+ this.declarations.set(declaration.nam, declaration);
50
+ }
51
+ else {
52
+ const separator = this.config.separator;
53
+ // expand shorthand
54
+ if (declaration.nam != this.config.shorthand && this.declarations.has(this.config.shorthand)) {
55
+ const tokens = {};
56
+ const values = [];
57
+ // @ts-ignore
58
+ this.declarations.get(this.config.shorthand).val.slice().reduce((acc, curr) => {
59
+ if (separator != null && separator.typ == curr.typ && eq(separator, curr)) {
60
+ acc.push([]);
61
+ return acc;
62
+ }
63
+ // else {
64
+ // @ts-ignore
65
+ acc.at(-1).push(curr);
66
+ // }
67
+ return acc;
68
+ }, [[]]).
69
+ // @ts-ignore
70
+ reduce((acc, list, current) => {
71
+ values.push(...this.pattern.reduce((acc, property) => {
72
+ // let current: number = 0;
73
+ const props = this.config.properties[property];
74
+ for (let i = 0; i < acc.length; i++) {
75
+ if (acc[i].typ == 'Comment' || acc[i].typ == 'Whitespace') {
76
+ acc.splice(i, 1);
77
+ i--;
78
+ continue;
79
+ }
80
+ if (matchType(acc[i], props)) {
81
+ if ('prefix' in props && props.previous != null && !(props.previous in tokens)) {
82
+ return acc;
83
+ }
84
+ if (!(property in tokens)) {
85
+ tokens[property] = [[acc[i]]];
86
+ }
87
+ else {
88
+ if (current == tokens[property].length) {
89
+ tokens[property].push([acc[i]]);
90
+ // tokens[property][current].push();
91
+ }
92
+ else {
93
+ tokens[property][current].push({ typ: 'Whitespace' }, acc[i]);
94
+ }
95
+ }
96
+ acc.splice(i, 1);
97
+ i--;
98
+ // @ts-ignore
99
+ if ('prefix' in props && acc[i]?.typ == props.prefix.typ) {
100
+ // @ts-ignore
101
+ if (eq(acc[i], this.config.properties[property].prefix)) {
102
+ acc.splice(i, 1);
103
+ i--;
104
+ }
105
+ }
106
+ if (props.multiple) {
107
+ continue;
108
+ }
109
+ return acc;
110
+ }
111
+ else {
112
+ if (property in tokens && tokens[property].length > current) {
113
+ return acc;
114
+ }
115
+ }
116
+ }
117
+ if (property in tokens && tokens[property].length > current) {
118
+ return acc;
119
+ }
120
+ // default
121
+ if (props.default.length > 0) {
122
+ const defaults = parseString(props.default[0]);
123
+ if (!(property in tokens)) {
124
+ tokens[property] = [
125
+ [...defaults
126
+ ]
127
+ ];
128
+ }
129
+ else {
130
+ if (current == tokens[property].length) {
131
+ tokens[property].push([]);
132
+ tokens[property][current].push(...defaults);
133
+ }
134
+ else {
135
+ tokens[property][current].push({ typ: 'Whitespace' }, ...defaults);
136
+ }
137
+ }
138
+ }
139
+ return acc;
140
+ }, list));
141
+ return values;
142
+ }, []);
143
+ if (values.length == 0) {
144
+ this.declarations = Object.entries(tokens).reduce((acc, curr) => {
145
+ acc.set(curr[0], {
146
+ typ: 'Declaration',
147
+ nam: curr[0],
148
+ val: curr[1].reduce((acc, curr) => {
149
+ if (acc.length > 0) {
150
+ acc.push({ ...separator });
151
+ }
152
+ acc.push(...curr);
153
+ return acc;
154
+ }, [])
155
+ });
156
+ return acc;
157
+ }, new Map);
158
+ }
159
+ }
160
+ this.declarations.set(declaration.nam, declaration);
161
+ }
162
+ return this;
163
+ }
164
+ [Symbol.iterator]() {
165
+ let requiredCount = Object.keys(this.config.properties).reduce((acc, curr) => this.declarations.has(curr) && this.config.properties[curr].required ? ++acc : acc, 0);
166
+ if (requiredCount == 0) {
167
+ requiredCount = this.declarations.size;
168
+ }
169
+ if (requiredCount < this.requiredCount) {
170
+ // if (this.declarations.size == 1 && this.declarations.has(this.config.shorthand)) {
171
+ //
172
+ // this.declarations
173
+ // }
174
+ return this.declarations.values();
175
+ }
176
+ let count = 0;
177
+ const separator = this.config.separator;
178
+ const tokens = {};
179
+ // @ts-ignore
180
+ const valid = Object.entries(this.config.properties).reduce((acc, curr) => {
181
+ if (!this.declarations.has(curr[0])) {
182
+ if (curr[1].required) {
183
+ acc.push(curr[0]);
184
+ }
185
+ return acc;
186
+ }
187
+ let current = 0;
188
+ const props = this.config.properties[curr[0]];
189
+ // @ts-ignore
190
+ for (const val of this.declarations.get(curr[0]).val) {
191
+ if (separator != null && separator.typ == val.typ && eq(separator, val)) {
192
+ current++;
193
+ if (tokens[curr[0]].length == current) {
194
+ tokens[curr[0]].push([]);
195
+ }
196
+ continue;
197
+ }
198
+ if (val.typ == 'Whitespace' || val.typ == 'Comment') {
199
+ continue;
200
+ }
201
+ if (props.multiple && props.separator != null && props.separator.typ == val.typ && eq(val, props.separator)) {
202
+ continue;
203
+ }
204
+ if (matchType(val, curr[1])) {
205
+ if (!(curr[0] in tokens)) {
206
+ tokens[curr[0]] = [[]];
207
+ }
208
+ // is default value
209
+ tokens[curr[0]][current].push(val);
210
+ continue;
211
+ }
212
+ acc.push(curr[0]);
213
+ break;
214
+ }
215
+ if (count == 0) {
216
+ count = current;
217
+ }
218
+ return acc;
219
+ }, []);
220
+ if (valid.length > 0 || Object.values(tokens).every(v => v.every(v => v.length == count))) {
221
+ return this.declarations.values();
222
+ }
223
+ const values = Object.entries(tokens).reduce((acc, curr) => {
224
+ const props = this.config.properties[curr[0]];
225
+ for (let i = 0; i < curr[1].length; i++) {
226
+ if (acc.length == i) {
227
+ acc.push([]);
228
+ }
229
+ let values = curr[1][i].reduce((acc, curr) => {
230
+ if (acc.length > 0) {
231
+ acc.push({ typ: 'Whitespace' });
232
+ }
233
+ acc.push(curr);
234
+ return acc;
235
+ }, []);
236
+ if (props.default.includes(curr[1][i].reduce((acc, curr) => acc + renderToken(curr) + ' ', '').trimEnd())) {
237
+ continue;
238
+ }
239
+ values = values.filter((val) => {
240
+ if (val.typ == 'Whitespace' || val.typ == 'Comment') {
241
+ return false;
242
+ }
243
+ return !(val.typ == 'Iden' && props.default.includes(val.val));
244
+ });
245
+ if (values.length > 0) {
246
+ if ('mapping' in props) {
247
+ // @ts-ignore
248
+ if (!('constraints' in props) || !('max' in props.constraints) || values.length <= props.constraints.mapping.max) {
249
+ let i = values.length;
250
+ while (i--) {
251
+ // @ts-ignore
252
+ if (values[i].typ == 'Iden' && values[i].val in props.mapping) {
253
+ // @ts-ignore
254
+ values.splice(i, 1, ...parseString(props.mapping[values[i].val]));
255
+ }
256
+ }
257
+ }
258
+ }
259
+ if ('prefix' in props) {
260
+ // @ts-ignore
261
+ acc[i].push({ ...props.prefix });
262
+ }
263
+ else if (acc[i].length > 0) {
264
+ acc[i].push({ typ: 'Whitespace' });
265
+ }
266
+ acc[i].push(...values.reduce((acc, curr) => {
267
+ if (acc.length > 0) {
268
+ // @ts-ignore
269
+ acc.push({ ...(props.separator ?? { typ: 'Whitespace' }) });
270
+ }
271
+ // @ts-ignore
272
+ acc.push(curr);
273
+ return acc;
274
+ }, []));
275
+ }
276
+ }
277
+ return acc;
278
+ }, []).reduce((acc, curr) => {
279
+ if (acc.length > 0) {
280
+ acc.push({ ...separator });
281
+ }
282
+ if (curr.length == 0) {
283
+ curr.push(...this.config.default[0].split(/\s/).map(getTokenType).reduce((acc, curr) => {
284
+ if (acc.length > 0) {
285
+ acc.push({ typ: 'Whitespace' });
286
+ }
287
+ acc.push(curr);
288
+ return acc;
289
+ }, []));
290
+ }
291
+ acc.push(...curr);
292
+ return acc;
293
+ }, []);
294
+ return [{
295
+ typ: 'Declaration',
296
+ nam: this.config.shorthand,
297
+ val: values
298
+ }][Symbol.iterator]();
299
+ }
300
+ }
301
+
302
+ export { PropertyMap };
@@ -0,0 +1,179 @@
1
+ import { eq } from '../utils/eq.js';
2
+ import { isLength } from '../utils/syntax.js';
3
+
4
+ class PropertySet {
5
+ config;
6
+ declarations;
7
+ constructor(config) {
8
+ this.config = config;
9
+ this.declarations = new Map;
10
+ }
11
+ add(declaration) {
12
+ if (declaration.nam == this.config.shorthand) {
13
+ this.declarations.clear();
14
+ this.declarations.set(declaration.nam, declaration);
15
+ }
16
+ else {
17
+ // expand shorthand
18
+ if (declaration.nam != this.config.shorthand && this.declarations.has(this.config.shorthand)) {
19
+ let isValid = true;
20
+ let current = -1;
21
+ const tokens = [];
22
+ // @ts-ignore
23
+ for (let token of this.declarations.get(this.config.shorthand).val) {
24
+ if (this.config.types.includes(token.typ) || (token.typ == 'Number' && token.val == '0' &&
25
+ (this.config.types.includes('Length') ||
26
+ this.config.types.includes('Angle') ||
27
+ this.config.types.includes('Dimension')))) {
28
+ if (tokens.length == 0) {
29
+ tokens.push([]);
30
+ current++;
31
+ }
32
+ tokens[current].push(token);
33
+ continue;
34
+ }
35
+ if (token.typ != 'Whitespace' && token.typ != 'Comment') {
36
+ if (token.typ == 'Iden' && this.config.keywords.includes(token.val)) {
37
+ tokens[current].push(token);
38
+ }
39
+ if (token.typ == 'Literal' && token.val == this.config.separator) {
40
+ tokens.push([]);
41
+ current++;
42
+ continue;
43
+ }
44
+ isValid = false;
45
+ break;
46
+ }
47
+ }
48
+ if (isValid && tokens.length > 0) {
49
+ this.declarations.delete(this.config.shorthand);
50
+ for (const values of tokens) {
51
+ this.config.properties.forEach((property, index) => {
52
+ // if (property == declaration.nam) {
53
+ //
54
+ // return;
55
+ // }
56
+ if (!this.declarations.has(property)) {
57
+ this.declarations.set(property, {
58
+ typ: 'Declaration',
59
+ nam: property,
60
+ val: []
61
+ });
62
+ }
63
+ while (index > 0 && index >= values.length) {
64
+ if (index > 1) {
65
+ index %= 2;
66
+ }
67
+ else {
68
+ index = 0;
69
+ break;
70
+ }
71
+ }
72
+ // @ts-ignore
73
+ const val = this.declarations.get(property).val;
74
+ if (val.length > 0) {
75
+ val.push({ typ: 'Whitespace' });
76
+ }
77
+ val.push({ ...values[index] });
78
+ });
79
+ }
80
+ }
81
+ this.declarations.set(declaration.nam, declaration);
82
+ return this;
83
+ }
84
+ // declaration.chi = declaration.chi.reduce((acc: Token[], token: Token) => {
85
+ //
86
+ // if (this.config.types.includes(token.typ) || ('0' == (<DimensionToken>token).chi && (
87
+ // this.config.types.includes('Length') ||
88
+ // this.config.types.includes('Angle') ||
89
+ // this.config.types.includes('Dimension'))) || (token.typ == 'Iden' && this.config.keywords.includes(token.chi))) {
90
+ //
91
+ // acc.push(token);
92
+ // }
93
+ //
94
+ // return acc;
95
+ // }, <Token[]>[]);
96
+ this.declarations.set(declaration.nam, declaration);
97
+ }
98
+ return this;
99
+ }
100
+ [Symbol.iterator]() {
101
+ let iterator;
102
+ const declarations = this.declarations;
103
+ if (declarations.size < this.config.properties.length || this.config.properties.some((property, index) => {
104
+ return !declarations.has(property) || (index > 0 &&
105
+ // @ts-ignore
106
+ declarations.get(property).val.length != declarations.get(this.config.properties[Math.floor(index / 2)]).val.length);
107
+ })) {
108
+ iterator = declarations.values();
109
+ }
110
+ else {
111
+ const values = [];
112
+ this.config.properties.forEach((property) => {
113
+ let index = 0;
114
+ // @ts-ignore
115
+ for (const token of this.declarations.get(property).val) {
116
+ if (token.typ == 'Whitespace') {
117
+ continue;
118
+ }
119
+ if (values.length == index) {
120
+ values.push([]);
121
+ }
122
+ values[index].push(token);
123
+ index++;
124
+ }
125
+ });
126
+ for (const value of values) {
127
+ let i = value.length;
128
+ while (i-- > 1) {
129
+ const t = value[i];
130
+ const k = value[i == 1 ? 0 : i % 2];
131
+ if (t.val == k.val && t.val == '0') {
132
+ if ((t.typ == 'Number' && isLength(k)) ||
133
+ (k.typ == 'Number' && isLength(t)) ||
134
+ (isLength(k) || isLength(t))) {
135
+ value.splice(i, 1);
136
+ continue;
137
+ }
138
+ }
139
+ if (eq(t, k)) {
140
+ value.splice(i, 1);
141
+ continue;
142
+ }
143
+ break;
144
+ }
145
+ }
146
+ iterator = [{
147
+ typ: 'Declaration',
148
+ nam: this.config.shorthand,
149
+ val: values.reduce((acc, curr) => {
150
+ if (curr.length > 1) {
151
+ const k = curr.length * 2 - 1;
152
+ let i = 1;
153
+ while (i < k) {
154
+ curr.splice(i, 0, { typ: 'Whitespace' });
155
+ i += 2;
156
+ }
157
+ }
158
+ if (acc.length > 0) {
159
+ acc.push({ typ: 'Literal', val: this.config.separator });
160
+ }
161
+ acc.push(...curr);
162
+ return acc;
163
+ }, [])
164
+ }][Symbol.iterator]();
165
+ return {
166
+ next() {
167
+ return iterator.next();
168
+ }
169
+ };
170
+ }
171
+ return {
172
+ next() {
173
+ return iterator.next();
174
+ }
175
+ };
176
+ }
177
+ }
178
+
179
+ export { PropertySet };