iobroker.mywebui 1.37.21 → 1.37.23

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.
Files changed (31) hide show
  1. package/io-package.json +1 -1
  2. package/package.json +1 -1
  3. package/www/dist/importmaps/importmap-config.js +1 -0
  4. package/www/dist/importmaps/importmap-runtime.js +1 -0
  5. package/www/node_modules/@node-projects/css-parser/LICENSE +11 -0
  6. package/www/node_modules/@node-projects/css-parser/README.md +161 -0
  7. package/www/node_modules/@node-projects/css-parser/dist/CssParseError.d.ts +8 -0
  8. package/www/node_modules/@node-projects/css-parser/dist/CssParseError.js +15 -0
  9. package/www/node_modules/@node-projects/css-parser/dist/CssPosition.d.ts +25 -0
  10. package/www/node_modules/@node-projects/css-parser/dist/CssPosition.js +13 -0
  11. package/www/node_modules/@node-projects/css-parser/dist/index-min.js +56 -0
  12. package/www/node_modules/@node-projects/css-parser/dist/index-min.js.map +7 -0
  13. package/www/node_modules/@node-projects/css-parser/dist/index.d.ts +12 -0
  14. package/www/node_modules/@node-projects/css-parser/dist/index.js +8 -0
  15. package/www/node_modules/@node-projects/css-parser/dist/parse/index.d.ts +8 -0
  16. package/www/node_modules/@node-projects/css-parser/dist/parse/index.js +1293 -0
  17. package/www/node_modules/@node-projects/css-parser/dist/parse/lexer.d.ts +118 -0
  18. package/www/node_modules/@node-projects/css-parser/dist/parse/lexer.js +248 -0
  19. package/www/node_modules/@node-projects/css-parser/dist/stringify/compiler.d.ts +172 -0
  20. package/www/node_modules/@node-projects/css-parser/dist/stringify/compiler.js +732 -0
  21. package/www/node_modules/@node-projects/css-parser/dist/stringify/index.d.ts +5 -0
  22. package/www/node_modules/@node-projects/css-parser/dist/stringify/index.js +5 -0
  23. package/www/node_modules/@node-projects/css-parser/dist/type.d.ts +205 -0
  24. package/www/node_modules/@node-projects/css-parser/dist/type.js +31 -0
  25. package/www/node_modules/@node-projects/css-parser/dist/utils/stringSearch.d.ts +53 -0
  26. package/www/node_modules/@node-projects/css-parser/dist/utils/stringSearch.js +166 -0
  27. package/www/node_modules/@node-projects/css-parser/docs/API.md +362 -0
  28. package/www/node_modules/@node-projects/css-parser/docs/AST.md +417 -0
  29. package/www/node_modules/@node-projects/css-parser/docs/CHANGELOG.md +205 -0
  30. package/www/node_modules/@node-projects/css-parser/docs/EXAMPLES.md +497 -0
  31. package/www/node_modules/@node-projects/css-parser/package.json +66 -0
@@ -0,0 +1,1293 @@
1
+ import CssParseError from '../CssParseError.js';
2
+ import Position from '../CssPosition.js';
3
+ import { CssTypes, } from '../type.js';
4
+ import { indexOfArrayWithBracketAndQuoteSupport, splitWithBracketAndQuoteSupport, } from '../utils/stringSearch.js';
5
+ import { Ch_AT, Ch_CLOSE, Ch_SLASH, Ch_STAR, Lexer } from './lexer.js';
6
+ // http://www.w3.org/TR/CSS21/grammar.html
7
+ // https://github.com/visionmedia/css-parse/pull/49#issuecomment-30088027
8
+ // New rule => https://www.w3.org/TR/CSS22/syndata.html#comments
9
+ // [^] is equivalent to [.\n\r]
10
+ const commentRegex = /\/\*[^]*?(?:\*\/|$)/g;
11
+ // ─── Sticky regexes (y-flag) ────────────────────────────────────────────────
12
+ // Using sticky regexes matched against the full input string avoids
13
+ // creating a temporary substring on every `matchRegex` call.
14
+ const re_comment = /\/\*[^]*?\*\//y;
15
+ const re_propName = /(\*?[-#/*\\\w]+(\[[0-9a-z_-]+\])?)\s*/y;
16
+ const re_keyframeValue = /((\d+\.\d+|\.\d+|\d+)%?|[a-z]+)\s*/y;
17
+ const re_keyframesName = /@([-\w]+)?keyframes\s*/y;
18
+ const re_identifier = /([-\w]+)\s*/y;
19
+ const re_supports = /@supports *([^{]+)/y;
20
+ const re_host = /@host\s*/y;
21
+ const re_container = /@container *([^{]+)/y;
22
+ const re_layer = /@layer *([^{;@]+)/y;
23
+ const re_media = /@media *([^{]+)/y;
24
+ const re_customMedia = /@custom-media\s+(--\S+)\s+([^{;\s][^{;]*);/y;
25
+ const re_page = /@page */y;
26
+ const re_document = /@([-\w]+)?document *([^{]+)/y;
27
+ const re_fontFace = /@font-face\s*/y;
28
+ const re_property = /@property\s+(--[-\w]+)\s*/y;
29
+ const re_counterStyle = /@counter-style\s+([-\w]+)\s*/y;
30
+ const re_fontFeatureValues = /@font-feature-values\s+([^{]+)/y;
31
+ const re_scope = /@scope\s*([^{]*)/y;
32
+ const re_viewTransition = /@view-transition\s*/y;
33
+ const re_positionTry = /@position-try\s+(--[-\w]+)\s*/y;
34
+ const re_startingStyle = /@starting-style\s*/y;
35
+ const re_genericAtRule = /@([-\w]+)\s*/y;
36
+ // Pre-compiled page margin box regex (moved to module scope to avoid re-creation)
37
+ const pageMarginBoxNames = [
38
+ 'top-left-corner',
39
+ 'top-left',
40
+ 'top-center',
41
+ 'top-right',
42
+ 'top-right-corner',
43
+ 'bottom-left-corner',
44
+ 'bottom-left',
45
+ 'bottom-center',
46
+ 'bottom-right',
47
+ 'bottom-right-corner',
48
+ 'left-top',
49
+ 'left-middle',
50
+ 'left-bottom',
51
+ 'right-top',
52
+ 'right-middle',
53
+ 'right-bottom',
54
+ ];
55
+ const re_pageMarginBox = new RegExp(`@(${pageMarginBoxNames.join('|')})(?![\\w-])\\s*`, 'y');
56
+ // Pre-compiled non-block at-rule regexes.
57
+ // NOTE: these patterns are inherited from the original _compileAtRule factory.
58
+ const re_atImport = /@import\s*((?::?[^;'"]|"(?:\\"|[^"])*?"|'(?:\\'|[^'])*?')+)(?:;|$)/y;
59
+ const re_atCharset = /@charset\s*((?::?[^;'"]|"(?:\\"|[^"])*?"|'(?:\\'|[^'])*?')+)(?:;|$)/y;
60
+ const re_atNamespace = /@namespace\s*((?::?[^;'"]|"(?:\\"|[^"])*?"|'(?:\\'|[^'])*?')+)(?:;|$)/y;
61
+ export const parse = (css, options) => {
62
+ options = options || {};
63
+ const lexer = new Lexer(css);
64
+ const preserveFormatting = options.preserveFormatting ?? false;
65
+ /**
66
+ * Insert whitespace AST nodes between sibling nodes in an array.
67
+ * Uses position offsets from the source to compute whitespace text.
68
+ */
69
+ function insertWhitespace(nodes, containerStart, containerEnd) {
70
+ if (!preserveFormatting) {
71
+ return nodes;
72
+ }
73
+ const result = [];
74
+ let cursor = containerStart;
75
+ for (const node of nodes) {
76
+ const start = node.position?.start?.offset;
77
+ if (start != null && start > cursor) {
78
+ const wsText = css.slice(cursor, start);
79
+ if (wsText) {
80
+ result.push({ type: CssTypes.whitespace, value: wsText });
81
+ }
82
+ }
83
+ result.push(node);
84
+ const end = node.position?.end?.offset;
85
+ if (end != null) {
86
+ cursor = end;
87
+ }
88
+ }
89
+ if (cursor < containerEnd) {
90
+ const wsText = css.slice(cursor, containerEnd);
91
+ if (wsText) {
92
+ result.push({ type: CssTypes.whitespace, value: wsText });
93
+ }
94
+ }
95
+ return result;
96
+ }
97
+ /**
98
+ * Mark position and patch `node.position`.
99
+ */
100
+ function position() {
101
+ const start = preserveFormatting
102
+ ? { ...lexer.getPosition(), offset: lexer.pos }
103
+ : lexer.getPosition();
104
+ return (node) => {
105
+ const end = preserveFormatting
106
+ ? { ...lexer.getPosition(), offset: lexer.pos }
107
+ : lexer.getPosition();
108
+ node.position = new Position(start, end, options?.source || '');
109
+ lexer.skipWhitespace();
110
+ return node;
111
+ };
112
+ }
113
+ /**
114
+ * Error `msg`.
115
+ */
116
+ const errorsList = [];
117
+ function error(msg) {
118
+ const err = new CssParseError(options?.source || '', msg, lexer.lineno, lexer.column, lexer.remaining);
119
+ if (options?.silent) {
120
+ errorsList.push(err);
121
+ }
122
+ else {
123
+ throw err;
124
+ }
125
+ }
126
+ /**
127
+ * Parse stylesheet.
128
+ */
129
+ function stylesheet() {
130
+ const rulesList = rules();
131
+ const result = {
132
+ type: CssTypes.stylesheet,
133
+ stylesheet: {
134
+ source: options?.source,
135
+ rules: insertWhitespace(rulesList, 0, css.length),
136
+ parsingErrors: errorsList,
137
+ },
138
+ };
139
+ return result;
140
+ }
141
+ /**
142
+ * Opening brace.
143
+ */
144
+ function open() {
145
+ return lexer.tryOpenBrace();
146
+ }
147
+ /**
148
+ * Track brace position and call open().
149
+ */
150
+ function openWithPos() {
151
+ const afterOpen = lexer.pos + 1;
152
+ return { ok: lexer.tryOpenBrace(), afterOpen };
153
+ }
154
+ /**
155
+ * Closing brace.
156
+ */
157
+ function close() {
158
+ return lexer.tryCloseBrace();
159
+ }
160
+ /**
161
+ * Parse ruleset.
162
+ */
163
+ function rules() {
164
+ let node;
165
+ const rules = [];
166
+ lexer.skipWhitespace();
167
+ comments(rules);
168
+ while (lexer.hasMore) {
169
+ if (lexer.charCodeAt() === Ch_CLOSE) {
170
+ if (options?.silent) {
171
+ // Skip stray closing braces at top level
172
+ error("extra '}'");
173
+ lexer.consume(1);
174
+ lexer.skipWhitespace();
175
+ comments(rules);
176
+ continue;
177
+ }
178
+ break;
179
+ }
180
+ node = atRule() || rule();
181
+ if (node) {
182
+ rules.push(node);
183
+ comments(rules);
184
+ }
185
+ else {
186
+ if (options?.silent) {
187
+ // Skip unrecognized character to recover
188
+ lexer.consume(1);
189
+ lexer.skipWhitespace();
190
+ comments(rules);
191
+ continue;
192
+ }
193
+ break;
194
+ }
195
+ }
196
+ return rules;
197
+ }
198
+ /**
199
+ * Parse whitespace.
200
+ */
201
+ function whitespace() {
202
+ lexer.skipWhitespace();
203
+ }
204
+ /**
205
+ * Parse comments;
206
+ */
207
+ function comments(rules) {
208
+ rules = rules || [];
209
+ let c = comment();
210
+ while (c) {
211
+ rules.push(c);
212
+ c = comment();
213
+ }
214
+ return rules;
215
+ }
216
+ /**
217
+ * Parse comment.
218
+ */
219
+ function comment() {
220
+ const pos = position();
221
+ if (lexer.charCodeAt() !== Ch_SLASH || lexer.charCodeAt(1) !== Ch_STAR) {
222
+ return;
223
+ }
224
+ const m = lexer.matchRegex(re_comment);
225
+ if (!m) {
226
+ return error('End of comment missing');
227
+ }
228
+ return pos({
229
+ type: CssTypes.comment,
230
+ comment: m[0].slice(2, -2),
231
+ });
232
+ }
233
+ /**
234
+ * Parse selector.
235
+ */
236
+ function selector() {
237
+ const absPos = indexOfArrayWithBracketAndQuoteSupport(lexer.input, ['{'], lexer.pos);
238
+ if (absPos === -1 || absPos === lexer.pos) {
239
+ return;
240
+ }
241
+ const selectorStr = lexer.consumeTo(absPos);
242
+ // remove comment in selector;
243
+ const res = trim(selectorStr).replace(commentRegex, '');
244
+ return splitWithBracketAndQuoteSupport(res, [',']).map((v) => trim(v));
245
+ }
246
+ /**
247
+ * Parse declaration.
248
+ */
249
+ function declaration() {
250
+ const pos = position();
251
+ const declStart = preserveFormatting ? lexer.pos : 0;
252
+ // prop
253
+ const propMatch = lexer.matchRegex(re_propName);
254
+ if (!propMatch) {
255
+ return;
256
+ }
257
+ const propValue = trim(propMatch[0]);
258
+ const propClean = propValue.replace(commentRegex, '');
259
+ // :
260
+ if (!lexer.tryColon()) {
261
+ return error("property missing ':'");
262
+ }
263
+ const afterColon = preserveFormatting ? lexer.pos : 0;
264
+ // val
265
+ let value = '';
266
+ let rawValText = '';
267
+ const absEndPos = indexOfArrayWithBracketAndQuoteSupport(lexer.input, [';', '}'], lexer.pos);
268
+ if (absEndPos !== -1) {
269
+ rawValText = lexer.consumeTo(absEndPos);
270
+ value = trim(rawValText).replace(commentRegex, '');
271
+ }
272
+ const ret = pos({
273
+ type: CssTypes.declaration,
274
+ property: propClean,
275
+ value: value,
276
+ ...(preserveFormatting
277
+ ? {
278
+ rawBetween: css.slice(declStart + propClean.length, afterColon),
279
+ rawValue: rawValText,
280
+ }
281
+ : {}),
282
+ });
283
+ // ;
284
+ lexer.skipSemicolonAndWhitespace();
285
+ return ret;
286
+ }
287
+ /**
288
+ * Parse declarations (without nesting support).
289
+ * Used by @font-face, @page, keyframes.
290
+ * Returns { decls, afterOpen, beforeClose } when preserveFormatting is true.
291
+ */
292
+ function declarations() {
293
+ const afterOpen = preserveFormatting ? lexer.pos + 1 : 0;
294
+ if (!open()) {
295
+ error("missing '{'");
296
+ return;
297
+ }
298
+ const decls = [];
299
+ comments(decls);
300
+ // declarations
301
+ let decl = declaration();
302
+ while (decl) {
303
+ decls.push(decl);
304
+ comments(decls);
305
+ decl = declaration();
306
+ }
307
+ // In silent mode, try to recover from errors by skipping to next semicolon
308
+ while (options?.silent &&
309
+ lexer.hasMore &&
310
+ lexer.charCodeAt() !== Ch_CLOSE) {
311
+ const semiPos = lexer.input.indexOf(';', lexer.pos);
312
+ const bracePos = lexer.input.indexOf('}', lexer.pos);
313
+ if (semiPos !== -1 && (bracePos === -1 || semiPos < bracePos)) {
314
+ lexer.consumeTo(semiPos + 1);
315
+ whitespace();
316
+ comments(decls);
317
+ decl = declaration();
318
+ while (decl) {
319
+ decls.push(decl);
320
+ comments(decls);
321
+ decl = declaration();
322
+ }
323
+ }
324
+ else {
325
+ break;
326
+ }
327
+ }
328
+ const beforeClose = preserveFormatting ? lexer.pos : 0;
329
+ if (!close()) {
330
+ error("missing '}'");
331
+ return;
332
+ }
333
+ return {
334
+ decls: insertWhitespace(decls, afterOpen, beforeClose),
335
+ afterOpen,
336
+ beforeClose,
337
+ };
338
+ }
339
+ /**
340
+ * Check if the current position looks like a nested rule
341
+ * ('{' appears before ';' and '}' at the top level).
342
+ */
343
+ function looksLikeNestedRule() {
344
+ const pos = lexer.pos;
345
+ const bracePos = indexOfArrayWithBracketAndQuoteSupport(lexer.input, ['{'], pos);
346
+ if (bracePos === -1) {
347
+ return false;
348
+ }
349
+ const semiPos = indexOfArrayWithBracketAndQuoteSupport(lexer.input, [';'], pos);
350
+ const closePos = indexOfArrayWithBracketAndQuoteSupport(lexer.input, ['}'], pos);
351
+ if (semiPos !== -1 && semiPos < bracePos) {
352
+ return false;
353
+ }
354
+ if (closePos !== -1 && closePos < bracePos) {
355
+ return false;
356
+ }
357
+ return true;
358
+ }
359
+ /**
360
+ * Parse rule body with CSS nesting support.
361
+ * Handles declarations, comments, nested rules, and nested at-rules.
362
+ */
363
+ function ruleBody() {
364
+ const items = [];
365
+ const afterOpen = preserveFormatting ? lexer.pos + 1 : 0;
366
+ if (!open()) {
367
+ error("missing '{'");
368
+ return;
369
+ }
370
+ comments(items);
371
+ while (lexer.hasMore && lexer.charCodeAt() !== Ch_CLOSE) {
372
+ // nested at-rule
373
+ if (lexer.charCodeAt() === Ch_AT) {
374
+ const ar = atRule();
375
+ if (ar) {
376
+ items.push(ar);
377
+ comments(items);
378
+ continue;
379
+ }
380
+ }
381
+ // nested rule ('{' comes before ';' and '}')
382
+ if (looksLikeNestedRule()) {
383
+ const nestedR = rule();
384
+ if (nestedR) {
385
+ items.push(nestedR);
386
+ comments(items);
387
+ continue;
388
+ }
389
+ }
390
+ // declaration
391
+ const decl = declaration();
392
+ if (decl) {
393
+ items.push(decl);
394
+ comments(items);
395
+ continue;
396
+ }
397
+ // nothing matched — skip to next semicolon or closing brace to recover
398
+ if (options?.silent) {
399
+ const semiPos = lexer.input.indexOf(';', lexer.pos);
400
+ const bracePos = lexer.input.indexOf('}', lexer.pos);
401
+ if (semiPos !== -1 && (bracePos === -1 || semiPos < bracePos)) {
402
+ lexer.consumeTo(semiPos + 1);
403
+ whitespace();
404
+ comments(items);
405
+ continue;
406
+ }
407
+ }
408
+ break;
409
+ }
410
+ const beforeClose = preserveFormatting ? lexer.pos : 0;
411
+ if (!close()) {
412
+ error("missing '}'");
413
+ return;
414
+ }
415
+ return {
416
+ items: insertWhitespace(items, afterOpen, beforeClose),
417
+ afterOpen,
418
+ beforeClose,
419
+ };
420
+ }
421
+ /**
422
+ * Parse rules, declarations, and nested rules.
423
+ * Used by block at-rules (media, supports, etc.) to support
424
+ * both top-level rules and declarations when nested inside a rule.
425
+ */
426
+ function rulesOrDeclarations(afterOpen) {
427
+ const items = [];
428
+ whitespace();
429
+ comments(items);
430
+ while (lexer.hasMore && lexer.charCodeAt() !== Ch_CLOSE) {
431
+ // at-rule
432
+ if (lexer.charCodeAt() === Ch_AT) {
433
+ const ar = atRule();
434
+ if (ar) {
435
+ items.push(ar);
436
+ comments(items);
437
+ continue;
438
+ }
439
+ }
440
+ // nested rule ('{' comes before ';' and '}')
441
+ if (looksLikeNestedRule()) {
442
+ const r = rule();
443
+ if (r) {
444
+ items.push(r);
445
+ comments(items);
446
+ continue;
447
+ }
448
+ }
449
+ // declaration
450
+ const decl = declaration();
451
+ if (decl) {
452
+ items.push(decl);
453
+ comments(items);
454
+ continue;
455
+ }
456
+ // nothing matched — skip to next semicolon or closing brace to recover
457
+ if (options?.silent) {
458
+ const semiPos = lexer.input.indexOf(';', lexer.pos);
459
+ const bracePos = lexer.input.indexOf('}', lexer.pos);
460
+ if (semiPos !== -1 && (bracePos === -1 || semiPos < bracePos)) {
461
+ lexer.consumeTo(semiPos + 1);
462
+ whitespace();
463
+ comments(items);
464
+ continue;
465
+ }
466
+ }
467
+ break;
468
+ }
469
+ if (preserveFormatting && afterOpen != null) {
470
+ const beforeClose = lexer.pos;
471
+ return insertWhitespace(items, afterOpen, beforeClose);
472
+ }
473
+ return items;
474
+ }
475
+ /**
476
+ * Parse keyframe.
477
+ */
478
+ function keyframe() {
479
+ const vals = [];
480
+ const pos = position();
481
+ const kfStart = preserveFormatting ? lexer.pos : 0;
482
+ let m = lexer.matchRegex(re_keyframeValue);
483
+ while (m) {
484
+ vals.push(m[1]);
485
+ lexer.tryCommaAndWhitespace();
486
+ m = lexer.matchRegex(re_keyframeValue);
487
+ }
488
+ if (!vals.length) {
489
+ return;
490
+ }
491
+ const braceOffset = preserveFormatting ? lexer.pos : 0;
492
+ const parsed = declarations();
493
+ if (!parsed)
494
+ return;
495
+ return pos({
496
+ type: CssTypes.keyframe,
497
+ values: vals,
498
+ declarations: parsed.decls,
499
+ ...(preserveFormatting
500
+ ? { rawPrelude: css.slice(kfStart, braceOffset) }
501
+ : {}),
502
+ });
503
+ }
504
+ /**
505
+ * Parse keyframes.
506
+ */
507
+ function atKeyframes() {
508
+ const pos = position();
509
+ const kfStart = preserveFormatting ? lexer.pos : 0;
510
+ const m1 = lexer.matchRegex(re_keyframesName);
511
+ if (!m1) {
512
+ return;
513
+ }
514
+ const vendor = m1[1];
515
+ // identifier
516
+ const m2 = lexer.matchRegex(re_identifier);
517
+ if (!m2) {
518
+ return error('@keyframes missing name');
519
+ }
520
+ const name = m2[1];
521
+ const braceOffset = preserveFormatting ? lexer.pos : 0;
522
+ const afterOpen = preserveFormatting ? lexer.pos + 1 : 0;
523
+ if (!open()) {
524
+ return error("@keyframes missing '{'");
525
+ }
526
+ const frames = comments();
527
+ let frame = keyframe();
528
+ while (frame) {
529
+ frames.push(frame);
530
+ comments(frames);
531
+ frame = keyframe();
532
+ }
533
+ const beforeClose = preserveFormatting ? lexer.pos : 0;
534
+ if (!close()) {
535
+ return error("@keyframes missing '}'");
536
+ }
537
+ return pos({
538
+ type: CssTypes.keyframes,
539
+ name: name,
540
+ vendor: vendor,
541
+ keyframes: insertWhitespace(frames, afterOpen, beforeClose),
542
+ ...(preserveFormatting
543
+ ? { rawPrelude: css.slice(kfStart, braceOffset) }
544
+ : {}),
545
+ });
546
+ }
547
+ /**
548
+ * Parse supports.
549
+ */
550
+ function atSupports() {
551
+ const pos = position();
552
+ const atStart = preserveFormatting ? lexer.pos : 0;
553
+ const m = lexer.matchRegex(re_supports);
554
+ if (!m) {
555
+ return;
556
+ }
557
+ const supports = trim(m[1]);
558
+ const braceOffset = preserveFormatting ? lexer.pos : 0;
559
+ const { ok: opened, afterOpen } = openWithPos();
560
+ if (!opened) {
561
+ return error("@supports missing '{'");
562
+ }
563
+ const style = rulesOrDeclarations(preserveFormatting ? afterOpen : undefined);
564
+ if (!close()) {
565
+ return error("@supports missing '}'");
566
+ }
567
+ return pos({
568
+ type: CssTypes.supports,
569
+ supports: supports,
570
+ rules: style,
571
+ ...(preserveFormatting
572
+ ? { rawPrelude: css.slice(atStart, braceOffset) }
573
+ : {}),
574
+ });
575
+ }
576
+ /**
577
+ * Parse host.
578
+ */
579
+ function atHost() {
580
+ const pos = position();
581
+ const atStart = preserveFormatting ? lexer.pos : 0;
582
+ const m = lexer.matchRegex(re_host);
583
+ if (!m) {
584
+ return;
585
+ }
586
+ const braceOffset = preserveFormatting ? lexer.pos : 0;
587
+ const { ok: opened, afterOpen } = openWithPos();
588
+ if (!opened) {
589
+ return error("@host missing '{'");
590
+ }
591
+ const style = rulesOrDeclarations(preserveFormatting ? afterOpen : undefined);
592
+ if (!close()) {
593
+ return error("@host missing '}'");
594
+ }
595
+ return pos({
596
+ type: CssTypes.host,
597
+ rules: style,
598
+ ...(preserveFormatting
599
+ ? { rawPrelude: css.slice(atStart, braceOffset) }
600
+ : {}),
601
+ });
602
+ }
603
+ /**
604
+ * Parse container.
605
+ */
606
+ function atContainer() {
607
+ const pos = position();
608
+ const atStart = preserveFormatting ? lexer.pos : 0;
609
+ const m = lexer.matchRegex(re_container);
610
+ if (!m) {
611
+ return;
612
+ }
613
+ const container = trim(m[1]);
614
+ const braceOffset = preserveFormatting ? lexer.pos : 0;
615
+ const { ok: opened, afterOpen } = openWithPos();
616
+ if (!opened) {
617
+ return error("@container missing '{'");
618
+ }
619
+ const style = rulesOrDeclarations(preserveFormatting ? afterOpen : undefined);
620
+ if (!close()) {
621
+ return error("@container missing '}'");
622
+ }
623
+ return pos({
624
+ type: CssTypes.container,
625
+ container: container,
626
+ rules: style,
627
+ ...(preserveFormatting
628
+ ? { rawPrelude: css.slice(atStart, braceOffset) }
629
+ : {}),
630
+ });
631
+ }
632
+ /**
633
+ * Parse layer.
634
+ */
635
+ function atLayer() {
636
+ const pos = position();
637
+ const atStart = preserveFormatting ? lexer.pos : 0;
638
+ const m = lexer.matchRegex(re_layer);
639
+ if (!m) {
640
+ return;
641
+ }
642
+ const layer = trim(m[1]);
643
+ const braceOffset = preserveFormatting ? lexer.pos : 0;
644
+ const { ok: opened, afterOpen } = openWithPos();
645
+ if (!opened) {
646
+ // Statement form: @layer name;
647
+ // Consume the semicolon so position end includes it
648
+ if (lexer.charCodeAt() === 59) {
649
+ // 59 = ';'
650
+ lexer.consume(1);
651
+ }
652
+ const rawSrc = preserveFormatting
653
+ ? css.slice(atStart, lexer.pos)
654
+ : undefined;
655
+ return pos({
656
+ type: CssTypes.layer,
657
+ layer: layer,
658
+ ...(rawSrc ? { rawSource: rawSrc } : {}),
659
+ });
660
+ }
661
+ const style = rulesOrDeclarations(preserveFormatting ? afterOpen : undefined);
662
+ if (!close()) {
663
+ return error("@layer missing '}'");
664
+ }
665
+ return pos({
666
+ type: CssTypes.layer,
667
+ layer: layer,
668
+ rules: style,
669
+ ...(preserveFormatting
670
+ ? { rawPrelude: css.slice(atStart, braceOffset) }
671
+ : {}),
672
+ });
673
+ }
674
+ /**
675
+ * Parse media.
676
+ */
677
+ function atMedia() {
678
+ const pos = position();
679
+ const atStart = preserveFormatting ? lexer.pos : 0;
680
+ const m = lexer.matchRegex(re_media);
681
+ if (!m) {
682
+ return;
683
+ }
684
+ const media = trim(m[1]);
685
+ const braceOffset = preserveFormatting ? lexer.pos : 0;
686
+ const { ok: opened, afterOpen } = openWithPos();
687
+ if (!opened) {
688
+ return error("@media missing '{'");
689
+ }
690
+ const style = rulesOrDeclarations(preserveFormatting ? afterOpen : undefined);
691
+ if (!close()) {
692
+ return error("@media missing '}'");
693
+ }
694
+ return pos({
695
+ type: CssTypes.media,
696
+ media: media,
697
+ rules: style,
698
+ ...(preserveFormatting
699
+ ? { rawPrelude: css.slice(atStart, braceOffset) }
700
+ : {}),
701
+ });
702
+ }
703
+ /**
704
+ * Parse custom-media.
705
+ */
706
+ function atCustomMedia() {
707
+ const pos = position();
708
+ const atStart = preserveFormatting ? lexer.pos : 0;
709
+ const m = lexer.matchRegex(re_customMedia);
710
+ if (!m) {
711
+ return;
712
+ }
713
+ const rawSrc = preserveFormatting
714
+ ? css.slice(atStart, lexer.pos)
715
+ : undefined;
716
+ return pos({
717
+ type: CssTypes.customMedia,
718
+ name: trim(m[1]),
719
+ media: trim(m[2]),
720
+ ...(rawSrc ? { rawSource: rawSrc } : {}),
721
+ });
722
+ }
723
+ /**
724
+ * Parse @page margin box at-rules (@top-left, @bottom-right, @left-middle, etc.).
725
+ */
726
+ function atPageMarginBox() {
727
+ const pos = position();
728
+ const atStart = preserveFormatting ? lexer.pos : 0;
729
+ const m = lexer.matchRegex(re_pageMarginBox);
730
+ if (!m) {
731
+ return;
732
+ }
733
+ const name = m[1];
734
+ const braceOffset = preserveFormatting ? lexer.pos : 0;
735
+ const afterOpen = preserveFormatting ? lexer.pos + 1 : 0;
736
+ if (!open()) {
737
+ return error(`@${name} missing '{'`);
738
+ }
739
+ const decls = comments();
740
+ let decl = declaration();
741
+ while (decl) {
742
+ decls.push(decl);
743
+ comments(decls);
744
+ decl = declaration();
745
+ }
746
+ const beforeClose = preserveFormatting ? lexer.pos : 0;
747
+ if (!close()) {
748
+ return error(`@${name} missing '}'`);
749
+ }
750
+ return pos({
751
+ type: CssTypes.pageMarginBox,
752
+ name: name,
753
+ declarations: insertWhitespace(decls, afterOpen, beforeClose),
754
+ ...(preserveFormatting
755
+ ? { rawPrelude: css.slice(atStart, braceOffset) }
756
+ : {}),
757
+ });
758
+ }
759
+ /**
760
+ * Parse paged media.
761
+ */
762
+ function atPage() {
763
+ const pos = position();
764
+ const atStart = preserveFormatting ? lexer.pos : 0;
765
+ const m = lexer.matchRegex(re_page);
766
+ if (!m) {
767
+ return;
768
+ }
769
+ const sel = selector() || [];
770
+ const braceOffset = preserveFormatting ? lexer.pos : 0;
771
+ const afterOpen = preserveFormatting ? lexer.pos + 1 : 0;
772
+ if (!open()) {
773
+ return error("@page missing '{'");
774
+ }
775
+ const decls = [];
776
+ comments(decls);
777
+ // declarations and nested at-rules (margin boxes)
778
+ while (lexer.hasMore && lexer.charCodeAt() !== Ch_CLOSE) {
779
+ if (lexer.charCodeAt() === Ch_AT) {
780
+ const ar = atRule();
781
+ if (ar) {
782
+ decls.push(ar);
783
+ comments(decls);
784
+ continue;
785
+ }
786
+ }
787
+ const decl = declaration();
788
+ if (decl) {
789
+ decls.push(decl);
790
+ comments(decls);
791
+ continue;
792
+ }
793
+ break;
794
+ }
795
+ const beforeClose = preserveFormatting ? lexer.pos : 0;
796
+ if (!close()) {
797
+ return error("@page missing '}'");
798
+ }
799
+ return pos({
800
+ type: CssTypes.page,
801
+ selectors: sel,
802
+ declarations: insertWhitespace(decls, afterOpen, beforeClose),
803
+ ...(preserveFormatting
804
+ ? { rawPrelude: css.slice(atStart, braceOffset) }
805
+ : {}),
806
+ });
807
+ }
808
+ /**
809
+ * Parse document.
810
+ */
811
+ function atDocument() {
812
+ const pos = position();
813
+ const atStart = preserveFormatting ? lexer.pos : 0;
814
+ const m = lexer.matchRegex(re_document);
815
+ if (!m) {
816
+ return;
817
+ }
818
+ const vendor = trim(m[1]);
819
+ const doc = trim(m[2]);
820
+ const braceOffset = preserveFormatting ? lexer.pos : 0;
821
+ const { ok: opened, afterOpen } = openWithPos();
822
+ if (!opened) {
823
+ return error("@document missing '{'");
824
+ }
825
+ const style = rulesOrDeclarations(preserveFormatting ? afterOpen : undefined);
826
+ if (!close()) {
827
+ return error("@document missing '}'");
828
+ }
829
+ return pos({
830
+ type: CssTypes.document,
831
+ document: doc,
832
+ vendor: vendor,
833
+ rules: style,
834
+ ...(preserveFormatting
835
+ ? { rawPrelude: css.slice(atStart, braceOffset) }
836
+ : {}),
837
+ });
838
+ }
839
+ /**
840
+ * Parse font-face.
841
+ */
842
+ function atFontFace() {
843
+ const pos = position();
844
+ const atStart = preserveFormatting ? lexer.pos : 0;
845
+ const m = lexer.matchRegex(re_fontFace);
846
+ if (!m) {
847
+ return;
848
+ }
849
+ const braceOffset = preserveFormatting ? lexer.pos : 0;
850
+ const afterOpen = preserveFormatting ? lexer.pos + 1 : 0;
851
+ if (!open()) {
852
+ return error("@font-face missing '{'");
853
+ }
854
+ const decls = comments();
855
+ // declarations
856
+ let decl = declaration();
857
+ while (decl) {
858
+ decls.push(decl);
859
+ comments(decls);
860
+ decl = declaration();
861
+ }
862
+ const beforeClose = preserveFormatting ? lexer.pos : 0;
863
+ if (!close()) {
864
+ return error("@font-face missing '}'");
865
+ }
866
+ return pos({
867
+ type: CssTypes.fontFace,
868
+ declarations: insertWhitespace(decls, afterOpen, beforeClose),
869
+ ...(preserveFormatting
870
+ ? { rawPrelude: css.slice(atStart, braceOffset) }
871
+ : {}),
872
+ });
873
+ }
874
+ /**
875
+ * Parse @property.
876
+ */
877
+ function atProperty() {
878
+ const pos = position();
879
+ const atStart = preserveFormatting ? lexer.pos : 0;
880
+ const m = lexer.matchRegex(re_property);
881
+ if (!m) {
882
+ return;
883
+ }
884
+ const name = m[1];
885
+ const braceOffset = preserveFormatting ? lexer.pos : 0;
886
+ const afterOpen = preserveFormatting ? lexer.pos + 1 : 0;
887
+ if (!open()) {
888
+ return error("@property missing '{'");
889
+ }
890
+ const decls = comments();
891
+ let decl = declaration();
892
+ while (decl) {
893
+ decls.push(decl);
894
+ comments(decls);
895
+ decl = declaration();
896
+ }
897
+ const beforeClose = preserveFormatting ? lexer.pos : 0;
898
+ if (!close()) {
899
+ return error("@property missing '}'");
900
+ }
901
+ return pos({
902
+ type: CssTypes.property,
903
+ name: name,
904
+ declarations: insertWhitespace(decls, afterOpen, beforeClose),
905
+ ...(preserveFormatting
906
+ ? { rawPrelude: css.slice(atStart, braceOffset) }
907
+ : {}),
908
+ });
909
+ }
910
+ /**
911
+ * Parse @counter-style.
912
+ */
913
+ function atCounterStyle() {
914
+ const pos = position();
915
+ const atStart = preserveFormatting ? lexer.pos : 0;
916
+ const m = lexer.matchRegex(re_counterStyle);
917
+ if (!m) {
918
+ return;
919
+ }
920
+ const name = m[1];
921
+ const braceOffset = preserveFormatting ? lexer.pos : 0;
922
+ const afterOpen = preserveFormatting ? lexer.pos + 1 : 0;
923
+ if (!open()) {
924
+ return error("@counter-style missing '{'");
925
+ }
926
+ const decls = comments();
927
+ let decl = declaration();
928
+ while (decl) {
929
+ decls.push(decl);
930
+ comments(decls);
931
+ decl = declaration();
932
+ }
933
+ const beforeClose = preserveFormatting ? lexer.pos : 0;
934
+ if (!close()) {
935
+ return error("@counter-style missing '}'");
936
+ }
937
+ return pos({
938
+ type: CssTypes.counterStyle,
939
+ name: name,
940
+ declarations: insertWhitespace(decls, afterOpen, beforeClose),
941
+ ...(preserveFormatting
942
+ ? { rawPrelude: css.slice(atStart, braceOffset) }
943
+ : {}),
944
+ });
945
+ }
946
+ /**
947
+ * Parse @font-feature-values.
948
+ */
949
+ function atFontFeatureValues() {
950
+ const pos = position();
951
+ const atStart = preserveFormatting ? lexer.pos : 0;
952
+ const m = lexer.matchRegex(re_fontFeatureValues);
953
+ if (!m) {
954
+ return;
955
+ }
956
+ const fontFamily = trim(m[1]);
957
+ const braceOffset = preserveFormatting ? lexer.pos : 0;
958
+ const { ok: opened, afterOpen } = openWithPos();
959
+ if (!opened) {
960
+ return error("@font-feature-values missing '{'");
961
+ }
962
+ const style = rulesOrDeclarations(preserveFormatting ? afterOpen : undefined);
963
+ if (!close()) {
964
+ return error("@font-feature-values missing '}'");
965
+ }
966
+ return pos({
967
+ type: CssTypes.fontFeatureValues,
968
+ fontFamily: fontFamily,
969
+ rules: style,
970
+ ...(preserveFormatting
971
+ ? { rawPrelude: css.slice(atStart, braceOffset) }
972
+ : {}),
973
+ });
974
+ }
975
+ /**
976
+ * Parse @scope.
977
+ */
978
+ function atScope() {
979
+ const pos = position();
980
+ const atStart = preserveFormatting ? lexer.pos : 0;
981
+ const m = lexer.matchRegex(re_scope);
982
+ if (!m) {
983
+ return;
984
+ }
985
+ const scope = trim(m[1]);
986
+ const braceOffset = preserveFormatting ? lexer.pos : 0;
987
+ const { ok: opened, afterOpen } = openWithPos();
988
+ if (!opened) {
989
+ return error("@scope missing '{'");
990
+ }
991
+ const style = rulesOrDeclarations(preserveFormatting ? afterOpen : undefined);
992
+ if (!close()) {
993
+ return error("@scope missing '}'");
994
+ }
995
+ return pos({
996
+ type: CssTypes.scope,
997
+ scope: scope,
998
+ rules: style,
999
+ ...(preserveFormatting
1000
+ ? { rawPrelude: css.slice(atStart, braceOffset) }
1001
+ : {}),
1002
+ });
1003
+ }
1004
+ /**
1005
+ * Parse @view-transition.
1006
+ */
1007
+ function atViewTransition() {
1008
+ const pos = position();
1009
+ const atStart = preserveFormatting ? lexer.pos : 0;
1010
+ const m = lexer.matchRegex(re_viewTransition);
1011
+ if (!m) {
1012
+ return;
1013
+ }
1014
+ const braceOffset = preserveFormatting ? lexer.pos : 0;
1015
+ const afterOpen = preserveFormatting ? lexer.pos + 1 : 0;
1016
+ if (!open()) {
1017
+ return error("@view-transition missing '{'");
1018
+ }
1019
+ const decls = comments();
1020
+ let decl = declaration();
1021
+ while (decl) {
1022
+ decls.push(decl);
1023
+ comments(decls);
1024
+ decl = declaration();
1025
+ }
1026
+ const beforeClose = preserveFormatting ? lexer.pos : 0;
1027
+ if (!close()) {
1028
+ return error("@view-transition missing '}'");
1029
+ }
1030
+ return pos({
1031
+ type: CssTypes.viewTransition,
1032
+ declarations: insertWhitespace(decls, afterOpen, beforeClose),
1033
+ ...(preserveFormatting
1034
+ ? { rawPrelude: css.slice(atStart, braceOffset) }
1035
+ : {}),
1036
+ });
1037
+ }
1038
+ /**
1039
+ * Parse @position-try.
1040
+ */
1041
+ function atPositionTry() {
1042
+ const pos = position();
1043
+ const atStart = preserveFormatting ? lexer.pos : 0;
1044
+ const m = lexer.matchRegex(re_positionTry);
1045
+ if (!m) {
1046
+ return;
1047
+ }
1048
+ const name = m[1];
1049
+ const braceOffset = preserveFormatting ? lexer.pos : 0;
1050
+ const afterOpen = preserveFormatting ? lexer.pos + 1 : 0;
1051
+ if (!open()) {
1052
+ return error("@position-try missing '{'");
1053
+ }
1054
+ const decls = comments();
1055
+ let decl = declaration();
1056
+ while (decl) {
1057
+ decls.push(decl);
1058
+ comments(decls);
1059
+ decl = declaration();
1060
+ }
1061
+ const beforeClose = preserveFormatting ? lexer.pos : 0;
1062
+ if (!close()) {
1063
+ return error("@position-try missing '}'");
1064
+ }
1065
+ return pos({
1066
+ type: CssTypes.positionTry,
1067
+ name: name,
1068
+ declarations: insertWhitespace(decls, afterOpen, beforeClose),
1069
+ ...(preserveFormatting
1070
+ ? { rawPrelude: css.slice(atStart, braceOffset) }
1071
+ : {}),
1072
+ });
1073
+ }
1074
+ /**
1075
+ * Parse starting style.
1076
+ */
1077
+ function atStartingStyle() {
1078
+ const pos = position();
1079
+ const atStart = preserveFormatting ? lexer.pos : 0;
1080
+ const m = lexer.matchRegex(re_startingStyle);
1081
+ if (!m) {
1082
+ return;
1083
+ }
1084
+ const braceOffset = preserveFormatting ? lexer.pos : 0;
1085
+ const { ok: opened, afterOpen } = openWithPos();
1086
+ if (!opened) {
1087
+ return error("@starting-style missing '{'");
1088
+ }
1089
+ const style = rulesOrDeclarations(preserveFormatting ? afterOpen : undefined);
1090
+ if (!close()) {
1091
+ return error("@starting-style missing '}'");
1092
+ }
1093
+ return pos({
1094
+ type: CssTypes.startingStyle,
1095
+ rules: style,
1096
+ ...(preserveFormatting
1097
+ ? { rawPrelude: css.slice(atStart, braceOffset) }
1098
+ : {}),
1099
+ });
1100
+ }
1101
+ /**
1102
+ * Parse import
1103
+ */
1104
+ function atImport() {
1105
+ const pos = position();
1106
+ const atStart = preserveFormatting ? lexer.pos : 0;
1107
+ const m = lexer.matchRegex(re_atImport);
1108
+ if (!m) {
1109
+ return;
1110
+ }
1111
+ const rawSrc = preserveFormatting
1112
+ ? css.slice(atStart, lexer.pos)
1113
+ : undefined;
1114
+ return pos({
1115
+ type: CssTypes.import,
1116
+ import: m[1].trim(),
1117
+ ...(rawSrc ? { rawSource: rawSrc } : {}),
1118
+ });
1119
+ }
1120
+ /**
1121
+ * Parse charset
1122
+ */
1123
+ function atCharset() {
1124
+ const pos = position();
1125
+ const atStart = preserveFormatting ? lexer.pos : 0;
1126
+ const m = lexer.matchRegex(re_atCharset);
1127
+ if (!m) {
1128
+ return;
1129
+ }
1130
+ const rawSrc = preserveFormatting
1131
+ ? css.slice(atStart, lexer.pos)
1132
+ : undefined;
1133
+ return pos({
1134
+ type: CssTypes.charset,
1135
+ charset: m[1].trim(),
1136
+ ...(rawSrc ? { rawSource: rawSrc } : {}),
1137
+ });
1138
+ }
1139
+ /**
1140
+ * Parse namespace
1141
+ */
1142
+ function atNamespace() {
1143
+ const pos = position();
1144
+ const atStart = preserveFormatting ? lexer.pos : 0;
1145
+ const m = lexer.matchRegex(re_atNamespace);
1146
+ if (!m) {
1147
+ return;
1148
+ }
1149
+ const rawSrc = preserveFormatting
1150
+ ? css.slice(atStart, lexer.pos)
1151
+ : undefined;
1152
+ return pos({
1153
+ type: CssTypes.namespace,
1154
+ namespace: m[1].trim(),
1155
+ ...(rawSrc ? { rawSource: rawSrc } : {}),
1156
+ });
1157
+ }
1158
+ /**
1159
+ * Parse generic/unknown at-rule (fallback for any unrecognized at-rule).
1160
+ * Handles both block at-rules (@scope { ... }) and statement at-rules (@foo ...;).
1161
+ */
1162
+ function atGeneric() {
1163
+ const pos = position();
1164
+ const atStart = preserveFormatting ? lexer.pos : 0;
1165
+ const m = lexer.matchRegex(re_genericAtRule);
1166
+ if (!m) {
1167
+ return;
1168
+ }
1169
+ const name = m[1];
1170
+ // Capture prelude (everything between the name and '{' or ';')
1171
+ let prelude = '';
1172
+ const preludeEnd = indexOfArrayWithBracketAndQuoteSupport(lexer.input, ['{', ';'], lexer.pos);
1173
+ if (preludeEnd !== -1 && preludeEnd > lexer.pos) {
1174
+ prelude = trim(lexer.consumeTo(preludeEnd));
1175
+ }
1176
+ // Block at-rule
1177
+ const braceOffset = preserveFormatting ? lexer.pos : 0;
1178
+ const { ok: opened, afterOpen } = openWithPos();
1179
+ if (opened) {
1180
+ const style = rulesOrDeclarations(preserveFormatting ? afterOpen : undefined);
1181
+ if (!close()) {
1182
+ return error(`@${name} missing '}'`);
1183
+ }
1184
+ return pos({
1185
+ type: CssTypes.atRule,
1186
+ name: name,
1187
+ prelude: prelude,
1188
+ rules: style,
1189
+ ...(preserveFormatting
1190
+ ? { rawPrelude: css.slice(atStart, braceOffset) }
1191
+ : {}),
1192
+ });
1193
+ }
1194
+ // Statement at-rule (ends with ';')
1195
+ lexer.skipSemicolonAndWhitespace();
1196
+ return pos({
1197
+ type: CssTypes.atRule,
1198
+ name: name,
1199
+ prelude: prelude,
1200
+ });
1201
+ }
1202
+ /**
1203
+ * Parse at rule.
1204
+ */
1205
+ function atRule() {
1206
+ if (lexer.charCodeAt() !== Ch_AT) {
1207
+ return;
1208
+ }
1209
+ return (atKeyframes() ||
1210
+ atMedia() ||
1211
+ atCustomMedia() ||
1212
+ atSupports() ||
1213
+ atImport() ||
1214
+ atCharset() ||
1215
+ atNamespace() ||
1216
+ atDocument() ||
1217
+ atPage() ||
1218
+ atHost() ||
1219
+ atFontFace() ||
1220
+ atFontFeatureValues() ||
1221
+ atContainer() ||
1222
+ atStartingStyle() ||
1223
+ atLayer() ||
1224
+ atProperty() ||
1225
+ atCounterStyle() ||
1226
+ atScope() ||
1227
+ atViewTransition() ||
1228
+ atPositionTry() ||
1229
+ atPageMarginBox() ||
1230
+ atGeneric());
1231
+ }
1232
+ /**
1233
+ * Parse rule.
1234
+ */
1235
+ function rule() {
1236
+ const pos = position();
1237
+ const ruleStart = preserveFormatting ? lexer.pos : 0;
1238
+ const sel = selector();
1239
+ if (!sel) {
1240
+ return error('selector missing');
1241
+ }
1242
+ const braceOffset = preserveFormatting ? lexer.pos : 0;
1243
+ comments();
1244
+ const body = ruleBody();
1245
+ return pos({
1246
+ type: CssTypes.rule,
1247
+ selectors: sel,
1248
+ declarations: body?.items || [],
1249
+ ...(preserveFormatting
1250
+ ? { rawPrelude: css.slice(ruleStart, braceOffset) }
1251
+ : {}),
1252
+ });
1253
+ }
1254
+ return addParent(stylesheet());
1255
+ };
1256
+ /**
1257
+ * Trim `str`.
1258
+ */
1259
+ function trim(str) {
1260
+ return str ? str.trim() : '';
1261
+ }
1262
+ /**
1263
+ * Adds non-enumerable parent node reference to each node.
1264
+ * Only recurses into array and object properties that can contain child nodes,
1265
+ * skipping primitive values and known leaf objects (Position, etc.).
1266
+ */
1267
+ function addParent(obj, parent) {
1268
+ const isNode = obj && typeof obj.type === 'string';
1269
+ const childParent = isNode ? obj : parent;
1270
+ for (const k in obj) {
1271
+ const value = obj[k];
1272
+ if (Array.isArray(value)) {
1273
+ for (let i = 0; i < value.length; i++) {
1274
+ addParent(value[i], childParent);
1275
+ }
1276
+ }
1277
+ else if (value &&
1278
+ typeof value === 'object' &&
1279
+ !(value instanceof Position)) {
1280
+ addParent(value, childParent);
1281
+ }
1282
+ }
1283
+ if (isNode) {
1284
+ Object.defineProperty(obj, 'parent', {
1285
+ configurable: true,
1286
+ writable: true,
1287
+ enumerable: false,
1288
+ value: parent || null,
1289
+ });
1290
+ }
1291
+ return obj;
1292
+ }
1293
+ export default parse;