zyzz 0.0.9 → 0.0.11
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/README.md +1 -1
- package/dist/Style.js +2 -2
- package/dist/Style.js.map +1 -1
- package/dist/Vars.d.ts +2 -2
- package/dist/Vars.d.ts.map +1 -1
- package/dist/Vars.js.map +1 -1
- package/dist/compiler/Source.d.ts.map +1 -1
- package/dist/compiler/Source.js +10 -0
- package/dist/compiler/Source.js.map +1 -1
- package/dist/compiler/internal/Contract.d.ts.map +1 -1
- package/dist/compiler/internal/Contract.js +11 -6
- package/dist/compiler/internal/Contract.js.map +1 -1
- package/dist/compiler/internal/Contributions.d.ts.map +1 -1
- package/dist/compiler/internal/Contributions.js +592 -556
- package/dist/compiler/internal/Contributions.js.map +1 -1
- package/dist/compiler/internal/Expression.d.ts +4 -0
- package/dist/compiler/internal/Expression.d.ts.map +1 -1
- package/dist/compiler/internal/Expression.js +45 -0
- package/dist/compiler/internal/Expression.js.map +1 -1
- package/dist/compiler/internal/RecipeConditions.js +2 -2
- package/dist/compiler/internal/RecipeConditions.js.map +1 -1
- package/dist/compiler/internal/Themes.d.ts.map +1 -1
- package/dist/compiler/internal/Themes.js +2 -0
- package/dist/compiler/internal/Themes.js.map +1 -1
- package/dist/default.d.ts +75 -19
- package/dist/default.d.ts.map +1 -1
- package/dist/default.js +76 -11
- package/dist/default.js.map +2 -2
- package/dist/default.js.zyzz.json +1 -1
- package/dist/internal/Condition.d.ts +1 -1
- package/dist/internal/Condition.d.ts.map +1 -1
- package/dist/internal/Configuration.js +2 -2
- package/dist/internal/Configuration.js.map +1 -1
- package/dist/internal/Query.d.ts +2 -2
- package/dist/internal/Query.d.ts.map +1 -1
- package/dist/internal/Query.js +1 -1
- package/dist/internal/Query.js.map +1 -1
- package/dist/internal/Theme.d.ts +4 -4
- package/dist/internal/Theme.d.ts.map +1 -1
- package/dist/internal/Theme.js +6 -6
- package/dist/internal/Theme.js.map +1 -1
- package/dist/internal/Token.d.ts +185 -2
- package/dist/internal/Token.d.ts.map +1 -1
- package/dist/internal/Token.js +236 -23
- package/dist/internal/Token.js.map +1 -1
- package/dist/internal/VariableSets.d.ts.map +1 -1
- package/dist/internal/VariableSets.js +9 -6
- package/dist/internal/VariableSets.js.map +1 -1
- package/dist/unplugin/index.d.ts.map +1 -1
- package/dist/unplugin/index.js +14 -0
- package/dist/unplugin/index.js.map +1 -1
- package/dist/web/colorProfile.d.ts +9 -5
- package/dist/web/colorProfile.d.ts.map +1 -1
- package/dist/web/colorProfile.js.map +1 -1
- package/dist/web/counterStyle.d.ts +13 -9
- package/dist/web/counterStyle.d.ts.map +1 -1
- package/dist/web/counterStyle.js.map +1 -1
- package/dist/web/cssFunction.d.ts +19 -14
- package/dist/web/cssFunction.d.ts.map +1 -1
- package/dist/web/cssFunction.js.map +1 -1
- package/dist/web/fontFace.d.ts +6 -1
- package/dist/web/fontFace.d.ts.map +1 -1
- package/dist/web/fontFace.js.map +1 -1
- package/dist/web/fontFeatureValues.d.ts +11 -7
- package/dist/web/fontFeatureValues.d.ts.map +1 -1
- package/dist/web/fontFeatureValues.js.map +1 -1
- package/dist/web/fontPaletteValues.d.ts +8 -3
- package/dist/web/fontPaletteValues.d.ts.map +1 -1
- package/dist/web/fontPaletteValues.js.map +1 -1
- package/dist/web/internal/Context.d.ts +3 -3
- package/dist/web/internal/Context.d.ts.map +1 -1
- package/dist/web/keyframes.d.ts +7 -3
- package/dist/web/keyframes.d.ts.map +1 -1
- package/dist/web/keyframes.js.map +1 -1
- package/dist/web/page.d.ts +11 -4
- package/dist/web/page.d.ts.map +1 -1
- package/dist/web/page.js.map +1 -1
- package/dist/web/positionTry.d.ts +6 -1
- package/dist/web/positionTry.d.ts.map +1 -1
- package/dist/web/positionTry.js.map +1 -1
- package/dist/web/property.d.ts +10 -5
- package/dist/web/property.d.ts.map +1 -1
- package/dist/web/property.js.map +1 -1
- package/dist/web/viewTransition.d.ts +10 -6
- package/dist/web/viewTransition.d.ts.map +1 -1
- package/dist/web/viewTransition.js.map +1 -1
- package/package.json +1 -1
- package/src/Style.ts +2 -2
- package/src/Vars.ts +2 -3
- package/src/compiler/Source.ts +19 -0
- package/src/compiler/internal/Contract.ts +19 -8
- package/src/compiler/internal/Contributions.ts +734 -685
- package/src/compiler/internal/Expression.ts +57 -0
- package/src/compiler/internal/RecipeConditions.ts +2 -2
- package/src/compiler/internal/Themes.ts +2 -0
- package/src/default.ts +175 -30
- package/src/internal/Condition.ts +3 -3
- package/src/internal/Configuration.ts +2 -2
- package/src/internal/Query.ts +3 -3
- package/src/internal/Theme.ts +12 -12
- package/src/internal/Token.ts +253 -33
- package/src/internal/VariableSets.ts +28 -25
- package/src/unplugin/index.ts +14 -0
- package/src/web/colorProfile.ts +25 -10
- package/src/web/counterStyle.ts +29 -14
- package/src/web/cssFunction.ts +47 -24
- package/src/web/fontFace.ts +16 -3
- package/src/web/fontFeatureValues.ts +35 -18
- package/src/web/fontPaletteValues.ts +25 -11
- package/src/web/internal/Context.ts +9 -3
- package/src/web/keyframes.ts +24 -9
- package/src/web/page.ts +22 -5
- package/src/web/positionTry.ts +20 -5
- package/src/web/property.ts +23 -9
- package/src/web/viewTransition.ts +28 -13
|
@@ -445,585 +445,621 @@ export function extract(scanned, tokens, starts, resolve = Expression.unwrap) {
|
|
|
445
445
|
})),
|
|
446
446
|
};
|
|
447
447
|
}
|
|
448
|
+
function definitions(input, headers = []) {
|
|
449
|
+
const entries = Object.entries(record(input));
|
|
450
|
+
const groups = new Set(entries
|
|
451
|
+
.filter(([key]) => key === '@layer' ||
|
|
452
|
+
/^@(media|supports|container|layer)(?=[\t\n\r\f (/])/.test(key))
|
|
453
|
+
.map(([key]) => key));
|
|
454
|
+
const descriptors = entries.filter(([key]) => !groups.has(key));
|
|
455
|
+
const body = Object.fromEntries(descriptors);
|
|
456
|
+
if (!entries.length)
|
|
457
|
+
return [{ input: body, headers }];
|
|
458
|
+
// A complete descriptor block occupies its first descriptor's authored position.
|
|
459
|
+
return entries.flatMap(([header, child]) => groups.has(header)
|
|
460
|
+
? definitions(child, [...headers, Condition.normalize(header)])
|
|
461
|
+
: header === descriptors[0]?.[0]
|
|
462
|
+
? [{ input: body, headers }]
|
|
463
|
+
: []);
|
|
464
|
+
}
|
|
448
465
|
for (const call of scanned.calls) {
|
|
449
|
-
const before = result.length;
|
|
450
466
|
try {
|
|
451
|
-
const
|
|
467
|
+
const argument = value(call.argument);
|
|
452
468
|
if (call.name && !call.exported && !scanned.used.has(call.name))
|
|
453
469
|
continue;
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
(
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
name: `z-n${scanned.namespace}-${call.start.toString(36)}`,
|
|
492
|
-
});
|
|
493
|
-
}
|
|
494
|
-
else if (call.kind === 'customMedia') {
|
|
495
|
-
if (typeof input !== 'string' && typeof input !== 'boolean')
|
|
496
|
-
throw new Error('Expected a media query or boolean.');
|
|
497
|
-
if (typeof input === 'string')
|
|
498
|
-
Descriptors.media(input);
|
|
499
|
-
result.push({ kind: 'custom-media', name: call.name, query: input });
|
|
500
|
-
}
|
|
501
|
-
else if (call.kind === 'cssFunction') {
|
|
502
|
-
const options = record(input);
|
|
503
|
-
if (Object.keys(options).some((key) => !['body', 'parameters', 'returns'].includes(key)) ||
|
|
504
|
-
!Array.isArray(options.parameters) ||
|
|
505
|
-
(options.returns !== undefined &&
|
|
506
|
-
(typeof options.returns !== 'string' ||
|
|
507
|
-
!FunctionSyntax.accepts(options.returns))))
|
|
508
|
-
throw new Error('Expected CSS function parameters, body, and optional return syntax.');
|
|
509
|
-
const names = new Set();
|
|
510
|
-
const parameters = options.parameters.map((input) => {
|
|
511
|
-
const parameter = record(input);
|
|
512
|
-
if (Object.keys(parameter).some((key) => !['default', 'name', 'syntax'].includes(key)) ||
|
|
513
|
-
typeof parameter.name !== 'string' ||
|
|
514
|
-
!dashed(parameter.name) ||
|
|
515
|
-
names.has(Identifiers.read(parameter.name)) ||
|
|
516
|
-
(parameter.syntax !== undefined &&
|
|
517
|
-
(typeof parameter.syntax !== 'string' ||
|
|
518
|
-
!FunctionSyntax.accepts(parameter.syntax))) ||
|
|
519
|
-
(parameter.default !== undefined &&
|
|
520
|
-
typeof parameter.default !== 'string' &&
|
|
521
|
-
typeof parameter.default !== 'number'))
|
|
522
|
-
throw new Error('Expected unique CSS parameters with supported syntaxes and scalar defaults.');
|
|
523
|
-
names.add(Identifiers.read(parameter.name));
|
|
524
|
-
if (parameter.default !== undefined)
|
|
525
|
-
Functions.value(String(parameter.syntax ?? '*'), String(parameter.default));
|
|
526
|
-
return `${parameter.name}${parameter.syntax ? ` ${parameter.syntax === '*' ? 'type(*)' : parameter.syntax}` : ''}${parameter.default !== undefined ? `: ${parameter.default}` : ''}`;
|
|
527
|
-
});
|
|
528
|
-
function body(input) {
|
|
529
|
-
return Object.entries(record(input)).flatMap(([key, value]) => {
|
|
530
|
-
if (value === undefined)
|
|
531
|
-
return [];
|
|
532
|
-
if (/^@(media|supports|container) /.test(key))
|
|
533
|
-
return [
|
|
534
|
-
{
|
|
535
|
-
kind: 'block',
|
|
536
|
-
header: Condition.normalize(key),
|
|
537
|
-
entries: body(value),
|
|
538
|
-
},
|
|
539
|
-
];
|
|
540
|
-
if ((key !== 'result' && !dashed(key)) ||
|
|
541
|
-
(typeof value !== 'string' && typeof value !== 'number'))
|
|
542
|
-
throw new Error('CSS function bodies accept result, local variables, and conditional groups.');
|
|
543
|
-
Functions.value('*', String(value));
|
|
544
|
-
return [{ kind: 'descriptor', name: key, value }];
|
|
470
|
+
const contextValue = call.context ? value(call.context) : undefined;
|
|
471
|
+
if (contextValue !== undefined &&
|
|
472
|
+
Object.keys(record(contextValue)).some((key) => key !== 'id'))
|
|
473
|
+
throw new Error('Unknown contribution context option. Use nested at-rule keys for enclosing groups.');
|
|
474
|
+
const inputs = [
|
|
475
|
+
'importCss',
|
|
476
|
+
'namespace',
|
|
477
|
+
'customMedia',
|
|
478
|
+
'layers',
|
|
479
|
+
'global',
|
|
480
|
+
].includes(call.kind)
|
|
481
|
+
? [{ input: argument, headers: [] }]
|
|
482
|
+
: definitions(argument);
|
|
483
|
+
let functionSignature;
|
|
484
|
+
for (const { input, headers } of inputs) {
|
|
485
|
+
const before = result.length;
|
|
486
|
+
if (call.kind === 'importCss') {
|
|
487
|
+
const options = record(input);
|
|
488
|
+
if (Object.keys(options).some((key) => !['layer', 'media', 'supports', 'url'].includes(key)) ||
|
|
489
|
+
typeof options.url !== 'string' ||
|
|
490
|
+
Object.entries(options).some(([key, value]) => key !== 'url' &&
|
|
491
|
+
value !== undefined &&
|
|
492
|
+
typeof value !== 'string' &&
|
|
493
|
+
!(key === 'layer' && value === true)))
|
|
494
|
+
throw new Error('Expected a stylesheet URL and static import conditions.');
|
|
495
|
+
result.push({
|
|
496
|
+
kind: 'import',
|
|
497
|
+
url: options.url,
|
|
498
|
+
...(options.layer !== undefined
|
|
499
|
+
? { layer: options.layer }
|
|
500
|
+
: {}),
|
|
501
|
+
...(options.supports !== undefined
|
|
502
|
+
? { supports: options.supports }
|
|
503
|
+
: {}),
|
|
504
|
+
...(options.media !== undefined
|
|
505
|
+
? { media: options.media }
|
|
506
|
+
: {}),
|
|
545
507
|
});
|
|
546
508
|
}
|
|
547
|
-
call.
|
|
548
|
-
options
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
}
|
|
556
|
-
else if (call.kind === 'layers') {
|
|
557
|
-
if (!Array.isArray(input) ||
|
|
558
|
-
input.some((value) => typeof value !== 'string'))
|
|
559
|
-
throw new Error('Layers require a literal string list.');
|
|
560
|
-
result.push({ kind: 'layers', names: input });
|
|
561
|
-
}
|
|
562
|
-
else if (call.kind === 'global') {
|
|
563
|
-
for (const [selector, child] of Object.entries(record(input)))
|
|
509
|
+
else if (call.kind === 'namespace') {
|
|
510
|
+
const options = record(input);
|
|
511
|
+
if (Object.keys(options).some((key) => !['prefix', 'uri'].includes(key)) ||
|
|
512
|
+
typeof options.uri !== 'string' ||
|
|
513
|
+
(options.prefix !== undefined &&
|
|
514
|
+
(typeof options.prefix !== 'string' ||
|
|
515
|
+
Identifiers.read(options.prefix) === undefined)))
|
|
516
|
+
throw new Error('Expected a namespace URI and optional identifier prefix.');
|
|
564
517
|
result.push({
|
|
565
|
-
kind: '
|
|
566
|
-
|
|
567
|
-
|
|
518
|
+
kind: 'namespace',
|
|
519
|
+
uri: options.uri,
|
|
520
|
+
...(options.prefix !== undefined
|
|
521
|
+
? { prefix: options.prefix }
|
|
522
|
+
: {}),
|
|
523
|
+
name: `z-n${scanned.namespace}-${call.start.toString(36)}`,
|
|
568
524
|
});
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
if (
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
'
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
...(options.initialValue !== undefined
|
|
627
|
-
? { initialValue: options.initialValue }
|
|
628
|
-
: {}),
|
|
629
|
-
});
|
|
630
|
-
}
|
|
631
|
-
else if (call.kind === 'page') {
|
|
632
|
-
const options = record(input);
|
|
633
|
-
if (Object.keys(options).some((key) => !['descriptors', 'selector'].includes(key)) ||
|
|
634
|
-
(options.selector !== undefined &&
|
|
635
|
-
typeof options.selector !== 'string'))
|
|
636
|
-
throw new Error('Expected page descriptors and an optional selector.');
|
|
637
|
-
const margins = [
|
|
638
|
-
'top-left-corner',
|
|
639
|
-
'top-left',
|
|
640
|
-
'top-center',
|
|
641
|
-
'top-right',
|
|
642
|
-
'top-right-corner',
|
|
643
|
-
'bottom-left-corner',
|
|
644
|
-
'bottom-left',
|
|
645
|
-
'bottom-center',
|
|
646
|
-
'bottom-right',
|
|
647
|
-
'bottom-right-corner',
|
|
648
|
-
'left-top',
|
|
649
|
-
'left-middle',
|
|
650
|
-
'left-bottom',
|
|
651
|
-
'right-top',
|
|
652
|
-
'right-middle',
|
|
653
|
-
'right-bottom',
|
|
654
|
-
].map((name) => `@${name}`);
|
|
655
|
-
const properties = /^(?!border(?:Collapse|Spacing)$)(?:background|border|font|margin|padding|outline)/;
|
|
656
|
-
const names = [
|
|
657
|
-
'color',
|
|
658
|
-
'counterIncrement',
|
|
659
|
-
'counterReset',
|
|
660
|
-
'direction',
|
|
661
|
-
'height',
|
|
662
|
-
'letterSpacing',
|
|
663
|
-
'lineHeight',
|
|
664
|
-
'maxHeight',
|
|
665
|
-
'maxWidth',
|
|
666
|
-
'minHeight',
|
|
667
|
-
'minWidth',
|
|
668
|
-
'quotes',
|
|
669
|
-
'textAlign',
|
|
670
|
-
'textDecoration',
|
|
671
|
-
'textIndent',
|
|
672
|
-
'textTransform',
|
|
673
|
-
'visibility',
|
|
674
|
-
'whiteSpace',
|
|
675
|
-
'width',
|
|
676
|
-
'wordSpacing',
|
|
677
|
-
];
|
|
678
|
-
function body(input, margin = false) {
|
|
679
|
-
return Object.entries(record(input)).flatMap(([key, value]) => {
|
|
680
|
-
if (value === undefined)
|
|
681
|
-
return [];
|
|
682
|
-
if (!margin && margins.includes(key))
|
|
683
|
-
return [
|
|
684
|
-
{ kind: 'block', header: key, entries: body(value, true) },
|
|
685
|
-
];
|
|
686
|
-
if (!margin &&
|
|
687
|
-
['bleed', 'marks', 'pageOrientation', 'size'].includes(key)) {
|
|
688
|
-
if (typeof value !== 'string' && typeof value !== 'number')
|
|
689
|
-
throw new Error('Expected a scalar page descriptor.');
|
|
690
|
-
Descriptors.check({
|
|
691
|
-
rule: 'page',
|
|
692
|
-
name: key,
|
|
693
|
-
value: String(value),
|
|
694
|
-
});
|
|
525
|
+
}
|
|
526
|
+
else if (call.kind === 'customMedia') {
|
|
527
|
+
if (typeof input !== 'string' && typeof input !== 'boolean')
|
|
528
|
+
throw new Error('Expected a media query or boolean.');
|
|
529
|
+
if (typeof input === 'string')
|
|
530
|
+
Descriptors.media(input);
|
|
531
|
+
result.push({ kind: 'custom-media', name: call.name, query: input });
|
|
532
|
+
}
|
|
533
|
+
else if (call.kind === 'cssFunction') {
|
|
534
|
+
const options = record(input);
|
|
535
|
+
if (Object.keys(options).some((key) => !['body', 'parameters', 'returns'].includes(key)) ||
|
|
536
|
+
!Array.isArray(options.parameters) ||
|
|
537
|
+
(options.returns !== undefined &&
|
|
538
|
+
(typeof options.returns !== 'string' ||
|
|
539
|
+
!FunctionSyntax.accepts(options.returns))))
|
|
540
|
+
throw new Error('Expected CSS function parameters, body, and optional return syntax.');
|
|
541
|
+
const names = new Set();
|
|
542
|
+
const parameters = options.parameters.map((input) => {
|
|
543
|
+
const parameter = record(input);
|
|
544
|
+
if (Object.keys(parameter).some((key) => !['default', 'name', 'syntax'].includes(key)) ||
|
|
545
|
+
typeof parameter.name !== 'string' ||
|
|
546
|
+
!dashed(parameter.name) ||
|
|
547
|
+
names.has(Identifiers.read(parameter.name)) ||
|
|
548
|
+
(parameter.syntax !== undefined &&
|
|
549
|
+
(typeof parameter.syntax !== 'string' ||
|
|
550
|
+
!FunctionSyntax.accepts(parameter.syntax))) ||
|
|
551
|
+
(parameter.default !== undefined &&
|
|
552
|
+
typeof parameter.default !== 'string' &&
|
|
553
|
+
typeof parameter.default !== 'number'))
|
|
554
|
+
throw new Error('Expected unique CSS parameters with supported syntaxes and scalar defaults.');
|
|
555
|
+
names.add(Identifiers.read(parameter.name));
|
|
556
|
+
if (parameter.default !== undefined)
|
|
557
|
+
Functions.value(String(parameter.syntax ?? '*'), String(parameter.default));
|
|
558
|
+
return `${parameter.name}${parameter.syntax ? ` ${parameter.syntax === '*' ? 'type(*)' : parameter.syntax}` : ''}${parameter.default !== undefined ? `: ${parameter.default}` : ''}`;
|
|
559
|
+
});
|
|
560
|
+
function body(input) {
|
|
561
|
+
return Object.entries(record(input)).flatMap(([key, value]) => {
|
|
562
|
+
if (value === undefined)
|
|
563
|
+
return [];
|
|
564
|
+
if (/^@(media|supports|container) /.test(key))
|
|
565
|
+
return [
|
|
566
|
+
{
|
|
567
|
+
kind: 'block',
|
|
568
|
+
header: Condition.normalize(key),
|
|
569
|
+
entries: body(value),
|
|
570
|
+
},
|
|
571
|
+
];
|
|
572
|
+
if ((key !== 'result' && !dashed(key)) ||
|
|
573
|
+
(typeof value !== 'string' && typeof value !== 'number'))
|
|
574
|
+
throw new Error('CSS function bodies accept result, local variables, and conditional groups.');
|
|
575
|
+
Functions.value('*', String(value));
|
|
576
|
+
return [{ kind: 'descriptor', name: key, value }];
|
|
577
|
+
});
|
|
578
|
+
}
|
|
579
|
+
const signature = JSON.stringify({
|
|
580
|
+
parameters: options.parameters.map((input) => {
|
|
581
|
+
const parameter = record(input);
|
|
695
582
|
return [
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
value,
|
|
700
|
-
},
|
|
583
|
+
parameter.name,
|
|
584
|
+
parameter.syntax ?? '*',
|
|
585
|
+
parameter.default,
|
|
701
586
|
];
|
|
702
|
-
}
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
587
|
+
}),
|
|
588
|
+
returns: options.returns ?? '*',
|
|
589
|
+
});
|
|
590
|
+
if (functionSignature !== undefined &&
|
|
591
|
+
functionSignature !== signature)
|
|
592
|
+
throw new Error('Grouped CSS function definitions must use the same parameters and return syntax.');
|
|
593
|
+
functionSignature = signature;
|
|
594
|
+
call.function.parameters =
|
|
595
|
+
options.parameters;
|
|
596
|
+
call.function.returns = (options.returns ??
|
|
597
|
+
'*');
|
|
598
|
+
result.push({
|
|
599
|
+
kind: 'block',
|
|
600
|
+
header: `@function ${call.name}(${parameters.join(',')})${options.returns ? ` returns ${options.returns === '*' ? 'type(*)' : options.returns}` : ''}`,
|
|
601
|
+
entries: body(options.body),
|
|
715
602
|
});
|
|
716
603
|
}
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
(!Array.isArray(families) ||
|
|
730
|
-
!families.length ||
|
|
731
|
-
families.some((value) => typeof value !== 'string')))
|
|
732
|
-
throw new Error('Expected a font family list.');
|
|
733
|
-
const familyList = Array.isArray(families)
|
|
734
|
-
? families
|
|
735
|
-
.map((value) => '"' +
|
|
736
|
-
Array.from(value, (char) => {
|
|
737
|
-
const code = char.codePointAt(0);
|
|
738
|
-
return code < 32 ||
|
|
739
|
-
code === 127 ||
|
|
740
|
-
char === '"' ||
|
|
741
|
-
char === '\\'
|
|
742
|
-
? `\\${code.toString(16)} `
|
|
743
|
-
: char;
|
|
744
|
-
}).join('') +
|
|
745
|
-
'"')
|
|
746
|
-
.join(',')
|
|
747
|
-
: families;
|
|
748
|
-
// Validate the native prelude before shielding newer body descriptors.
|
|
749
|
-
Lightning.transform({
|
|
750
|
-
filename: 'font-feature-values.css',
|
|
751
|
-
code: new TextEncoder().encode(`@font-feature-values ${familyList} {}`),
|
|
752
|
-
});
|
|
753
|
-
const entries = [];
|
|
754
|
-
for (const key of Object.keys(options)) {
|
|
755
|
-
if (key === 'fontDisplay' && options.fontDisplay !== undefined) {
|
|
756
|
-
if (typeof options.fontDisplay !== 'string' ||
|
|
757
|
-
!['auto', 'block', 'fallback', 'optional', 'swap'].includes(Identifiers.list(options.fontDisplay, 'space')
|
|
758
|
-
?.join(' ')
|
|
759
|
-
.replace(/[A-Z]/g, (letter) => letter.toLowerCase()) ?? ''))
|
|
760
|
-
throw new Error('Invalid font display descriptor.');
|
|
761
|
-
entries.push({
|
|
762
|
-
kind: 'descriptor',
|
|
763
|
-
name: 'font-display',
|
|
764
|
-
value: options.fontDisplay,
|
|
604
|
+
else if (call.kind === 'layers') {
|
|
605
|
+
if (!Array.isArray(input) ||
|
|
606
|
+
input.some((value) => typeof value !== 'string'))
|
|
607
|
+
throw new Error('Layers require a literal string list.');
|
|
608
|
+
result.push({ kind: 'layers', names: input });
|
|
609
|
+
}
|
|
610
|
+
else if (call.kind === 'global') {
|
|
611
|
+
for (const [selector, child] of Object.entries(record(input)))
|
|
612
|
+
result.push({
|
|
613
|
+
kind: 'rule',
|
|
614
|
+
selector,
|
|
615
|
+
style: grouping(selector) ? global(child) : style(child),
|
|
765
616
|
});
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
for (const
|
|
770
|
-
if (
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
617
|
+
}
|
|
618
|
+
else if (call.kind === 'fontFace') {
|
|
619
|
+
const declarations = record(input);
|
|
620
|
+
for (const key of Object.keys(declarations))
|
|
621
|
+
if (declarations[key] === undefined &&
|
|
622
|
+
key !== 'fontFamily' &&
|
|
623
|
+
key !== 'src')
|
|
624
|
+
delete declarations[key];
|
|
625
|
+
const keys = [
|
|
626
|
+
'fontFeatureSettings',
|
|
627
|
+
'fontVariationSettings',
|
|
628
|
+
'fontFamily',
|
|
629
|
+
'src',
|
|
630
|
+
'fontDisplay',
|
|
631
|
+
'fontStyle',
|
|
632
|
+
'fontWeight',
|
|
633
|
+
'fontStretch',
|
|
634
|
+
'unicodeRange',
|
|
635
|
+
'sizeAdjust',
|
|
636
|
+
'ascentOverride',
|
|
637
|
+
'descentOverride',
|
|
638
|
+
'lineGapOverride',
|
|
639
|
+
];
|
|
640
|
+
if (typeof declarations.fontFamily !== 'string' ||
|
|
641
|
+
typeof declarations.src !== 'string' ||
|
|
642
|
+
Object.entries(declarations).some(([key, value]) => !keys.includes(key) ||
|
|
643
|
+
(typeof value !== 'string' && typeof value !== 'number')))
|
|
644
|
+
throw new Error('Font faces require family/source and scalar supported descriptors.');
|
|
645
|
+
for (const [name, value] of Object.entries(declarations))
|
|
646
|
+
Descriptors.check({ rule: 'font-face', name, value: String(value) });
|
|
647
|
+
result.push({
|
|
648
|
+
kind: 'font-face',
|
|
649
|
+
declarations: declarations,
|
|
650
|
+
});
|
|
651
|
+
}
|
|
652
|
+
else if (call.kind === 'property') {
|
|
653
|
+
const options = record(input);
|
|
654
|
+
const names = typeof options.name === 'string'
|
|
655
|
+
? Identifiers.list(options.name, 'space')
|
|
656
|
+
: undefined;
|
|
657
|
+
if (Object.keys(options).some((key) => !['name', 'syntax', 'inherits', 'initialValue'].includes(key)) ||
|
|
658
|
+
names?.length !== 1 ||
|
|
659
|
+
!names[0].startsWith('--') ||
|
|
660
|
+
names[0].length <= 2 ||
|
|
661
|
+
typeof options.syntax !== 'string' ||
|
|
662
|
+
typeof options.inherits !== 'boolean' ||
|
|
663
|
+
(options.initialValue !== undefined &&
|
|
664
|
+
typeof options.initialValue !== 'string' &&
|
|
665
|
+
typeof options.initialValue !== 'number'))
|
|
666
|
+
throw new Error('Expected a native property registration with scalar descriptors.');
|
|
667
|
+
if (options.initialValue !== undefined)
|
|
668
|
+
Properties.initial(String(options.initialValue));
|
|
669
|
+
result.push({
|
|
670
|
+
kind: 'property',
|
|
671
|
+
name: options.name,
|
|
672
|
+
syntax: options.syntax,
|
|
673
|
+
inherits: options.inherits,
|
|
674
|
+
...(options.initialValue !== undefined
|
|
675
|
+
? { initialValue: options.initialValue }
|
|
676
|
+
: {}),
|
|
677
|
+
});
|
|
678
|
+
}
|
|
679
|
+
else if (call.kind === 'page') {
|
|
680
|
+
const options = record(input);
|
|
681
|
+
if (Object.keys(options).some((key) => !['descriptors', 'selector'].includes(key)) ||
|
|
682
|
+
(options.selector !== undefined &&
|
|
683
|
+
typeof options.selector !== 'string'))
|
|
684
|
+
throw new Error('Expected page descriptors and an optional selector.');
|
|
685
|
+
const margins = [
|
|
686
|
+
'top-left-corner',
|
|
687
|
+
'top-left',
|
|
688
|
+
'top-center',
|
|
689
|
+
'top-right',
|
|
690
|
+
'top-right-corner',
|
|
691
|
+
'bottom-left-corner',
|
|
692
|
+
'bottom-left',
|
|
693
|
+
'bottom-center',
|
|
694
|
+
'bottom-right',
|
|
695
|
+
'bottom-right-corner',
|
|
696
|
+
'left-top',
|
|
697
|
+
'left-middle',
|
|
698
|
+
'left-bottom',
|
|
699
|
+
'right-top',
|
|
700
|
+
'right-middle',
|
|
701
|
+
'right-bottom',
|
|
702
|
+
].map((name) => `@${name}`);
|
|
703
|
+
const properties = /^(?!border(?:Collapse|Spacing)$)(?:background|border|font|margin|padding|outline)/;
|
|
704
|
+
const names = [
|
|
705
|
+
'color',
|
|
706
|
+
'counterIncrement',
|
|
707
|
+
'counterReset',
|
|
708
|
+
'direction',
|
|
709
|
+
'height',
|
|
710
|
+
'letterSpacing',
|
|
711
|
+
'lineHeight',
|
|
712
|
+
'maxHeight',
|
|
713
|
+
'maxWidth',
|
|
714
|
+
'minHeight',
|
|
715
|
+
'minWidth',
|
|
716
|
+
'quotes',
|
|
717
|
+
'textAlign',
|
|
718
|
+
'textDecoration',
|
|
719
|
+
'textIndent',
|
|
720
|
+
'textTransform',
|
|
721
|
+
'visibility',
|
|
722
|
+
'whiteSpace',
|
|
723
|
+
'width',
|
|
724
|
+
'wordSpacing',
|
|
725
|
+
];
|
|
726
|
+
function body(input, margin = false) {
|
|
727
|
+
return Object.entries(record(input)).flatMap(([key, value]) => {
|
|
728
|
+
if (value === undefined)
|
|
729
|
+
return [];
|
|
730
|
+
if (!margin && margins.includes(key))
|
|
731
|
+
return [
|
|
732
|
+
{ kind: 'block', header: key, entries: body(value, true) },
|
|
733
|
+
];
|
|
734
|
+
if (!margin &&
|
|
735
|
+
['bleed', 'marks', 'pageOrientation', 'size'].includes(key)) {
|
|
736
|
+
if (typeof value !== 'string' && typeof value !== 'number')
|
|
737
|
+
throw new Error('Expected a scalar page descriptor.');
|
|
738
|
+
Descriptors.check({
|
|
739
|
+
rule: 'page',
|
|
740
|
+
name: key,
|
|
741
|
+
value: String(value),
|
|
742
|
+
});
|
|
743
|
+
return [
|
|
744
|
+
{
|
|
745
|
+
kind: 'descriptor',
|
|
746
|
+
name: key.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`),
|
|
747
|
+
value,
|
|
748
|
+
},
|
|
749
|
+
];
|
|
750
|
+
}
|
|
751
|
+
if (!properties.test(key) &&
|
|
752
|
+
!names.includes(key) &&
|
|
753
|
+
!(margin &&
|
|
754
|
+
[
|
|
755
|
+
'content',
|
|
756
|
+
'overflow',
|
|
757
|
+
'unicodeBidi',
|
|
758
|
+
'verticalAlign',
|
|
759
|
+
'zIndex',
|
|
760
|
+
].includes(key)))
|
|
761
|
+
throw new Error('Unsupported page or page-margin declaration.');
|
|
762
|
+
return [{ kind: 'style', style: style({ [key]: value }) }];
|
|
796
763
|
});
|
|
797
|
-
entries.push({ kind: 'block', header, entries: declarations });
|
|
798
764
|
}
|
|
765
|
+
result.push({
|
|
766
|
+
kind: 'block',
|
|
767
|
+
header: Condition.normalize(`@page${options.selector ? ` ${options.selector}` : ''}`),
|
|
768
|
+
entries: body(options.descriptors),
|
|
769
|
+
});
|
|
799
770
|
}
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
}
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
'width',
|
|
877
|
-
];
|
|
878
|
-
if (Object.keys(declarations).some((key) => !keys.includes(key)))
|
|
879
|
-
throw new Error('Unsupported position-try declaration.');
|
|
880
|
-
const block = style(declarations);
|
|
881
|
-
if (block.rules || block.declarations.some((value) => value.important))
|
|
882
|
-
throw new Error('Position-try forbids nested rules and important declarations.');
|
|
883
|
-
result.push({
|
|
884
|
-
kind: 'rule',
|
|
885
|
-
selector: `@position-try ${call.name}`,
|
|
886
|
-
style: block,
|
|
887
|
-
});
|
|
888
|
-
}
|
|
889
|
-
else if (call.kind === 'colorProfile' ||
|
|
890
|
-
call.kind === 'counterStyle' ||
|
|
891
|
-
call.kind === 'fontPaletteValues') {
|
|
892
|
-
const descriptors = {
|
|
893
|
-
colorProfile: {
|
|
894
|
-
rule: 'color-profile',
|
|
895
|
-
keys: ['components', 'renderingIntent', 'src'],
|
|
896
|
-
required: ['src'],
|
|
897
|
-
},
|
|
898
|
-
counterStyle: {
|
|
899
|
-
rule: 'counter-style',
|
|
900
|
-
keys: [
|
|
901
|
-
'additiveSymbols',
|
|
902
|
-
'fallback',
|
|
903
|
-
'negative',
|
|
904
|
-
'pad',
|
|
905
|
-
'prefix',
|
|
906
|
-
'range',
|
|
907
|
-
'speakAs',
|
|
908
|
-
'suffix',
|
|
909
|
-
'symbols',
|
|
910
|
-
'system',
|
|
911
|
-
],
|
|
912
|
-
required: [],
|
|
913
|
-
},
|
|
914
|
-
fontPaletteValues: {
|
|
915
|
-
rule: 'font-palette-values',
|
|
916
|
-
keys: ['basePalette', 'fontFamily', 'overrideColors'],
|
|
917
|
-
required: ['fontFamily'],
|
|
918
|
-
},
|
|
919
|
-
};
|
|
920
|
-
const definition = descriptors[call.kind];
|
|
921
|
-
const declarations = record(input);
|
|
922
|
-
for (const key of Object.keys(declarations))
|
|
923
|
-
if (declarations[key] === undefined)
|
|
924
|
-
delete declarations[key];
|
|
925
|
-
if (definition.required.some((key) => typeof declarations[key] !== 'string') ||
|
|
926
|
-
Object.entries(declarations).some(([key, value]) => !definition.keys.includes(key) ||
|
|
927
|
-
(typeof value !== 'string' &&
|
|
928
|
-
!(key === 'basePalette' &&
|
|
929
|
-
typeof value === 'number' &&
|
|
930
|
-
Number.isSafeInteger(value) &&
|
|
931
|
-
value >= 0))))
|
|
932
|
-
throw new Error('Expected supported scalar descriptors and required fields.');
|
|
933
|
-
if (call.kind === 'colorProfile') {
|
|
934
|
-
if (!Identifiers.url(declarations.src))
|
|
935
|
-
throw new Error('Color-profile src requires one URL.');
|
|
936
|
-
if (typeof declarations.components === 'string') {
|
|
937
|
-
const names = Identifiers.list(declarations.components, 'comma');
|
|
938
|
-
if (!names || names.some((name) => name.toLowerCase() === 'none'))
|
|
939
|
-
throw new Error('Color-profile components require comma-separated identifiers other than none.');
|
|
940
|
-
}
|
|
941
|
-
if (typeof declarations.renderingIntent === 'string') {
|
|
942
|
-
const names = Identifiers.list(declarations.renderingIntent, 'space');
|
|
943
|
-
if (names?.length !== 1 ||
|
|
944
|
-
![
|
|
945
|
-
'absolute-colorimetric',
|
|
946
|
-
'relative-colorimetric',
|
|
947
|
-
'perceptual',
|
|
948
|
-
'saturation',
|
|
949
|
-
].includes(names[0].toLowerCase()))
|
|
950
|
-
throw new Error('Invalid color-profile rendering intent.');
|
|
771
|
+
else if (call.kind === 'fontFeatureValues') {
|
|
772
|
+
const options = record(input);
|
|
773
|
+
if (Object.keys(options).some((key) => !['families', 'features', 'fontDisplay'].includes(key)))
|
|
774
|
+
throw new Error('Unknown font-feature-values option.');
|
|
775
|
+
const families = options.families;
|
|
776
|
+
if (typeof families !== 'string' &&
|
|
777
|
+
(!Array.isArray(families) ||
|
|
778
|
+
!families.length ||
|
|
779
|
+
families.some((value) => typeof value !== 'string')))
|
|
780
|
+
throw new Error('Expected a font family list.');
|
|
781
|
+
const familyList = Array.isArray(families)
|
|
782
|
+
? families
|
|
783
|
+
.map((value) => '"' +
|
|
784
|
+
Array.from(value, (char) => {
|
|
785
|
+
const code = char.codePointAt(0);
|
|
786
|
+
return code < 32 ||
|
|
787
|
+
code === 127 ||
|
|
788
|
+
char === '"' ||
|
|
789
|
+
char === '\\'
|
|
790
|
+
? `\\${code.toString(16)} `
|
|
791
|
+
: char;
|
|
792
|
+
}).join('') +
|
|
793
|
+
'"')
|
|
794
|
+
.join(',')
|
|
795
|
+
: families;
|
|
796
|
+
// Validate the native prelude before shielding newer body descriptors.
|
|
797
|
+
Lightning.transform({
|
|
798
|
+
filename: 'font-feature-values.css',
|
|
799
|
+
code: new TextEncoder().encode(`@font-feature-values ${familyList} {}`),
|
|
800
|
+
});
|
|
801
|
+
const entries = [];
|
|
802
|
+
for (const key of Object.keys(options)) {
|
|
803
|
+
if (key === 'fontDisplay' && options.fontDisplay !== undefined) {
|
|
804
|
+
if (typeof options.fontDisplay !== 'string' ||
|
|
805
|
+
!['auto', 'block', 'fallback', 'optional', 'swap'].includes(Identifiers.list(options.fontDisplay, 'space')
|
|
806
|
+
?.join(' ')
|
|
807
|
+
.replace(/[A-Z]/g, (letter) => letter.toLowerCase()) ?? ''))
|
|
808
|
+
throw new Error('Invalid font display descriptor.');
|
|
809
|
+
entries.push({
|
|
810
|
+
kind: 'descriptor',
|
|
811
|
+
name: 'font-display',
|
|
812
|
+
value: options.fontDisplay,
|
|
813
|
+
});
|
|
814
|
+
}
|
|
815
|
+
if (key !== 'features')
|
|
816
|
+
continue;
|
|
817
|
+
for (const [header, input] of Object.entries(record(options.features))) {
|
|
818
|
+
if (input === undefined)
|
|
819
|
+
continue;
|
|
820
|
+
if (![
|
|
821
|
+
'@annotation',
|
|
822
|
+
'@character-variant',
|
|
823
|
+
'@ornaments',
|
|
824
|
+
'@styleset',
|
|
825
|
+
'@stylistic',
|
|
826
|
+
'@swash',
|
|
827
|
+
].includes(header))
|
|
828
|
+
throw new Error('Unknown font feature block.');
|
|
829
|
+
const declarations = Object.entries(record(input)).map(([name, value]) => {
|
|
830
|
+
const values = Array.isArray(value) ? value : [value];
|
|
831
|
+
const maximum = header === '@styleset'
|
|
832
|
+
? Infinity
|
|
833
|
+
: header === '@character-variant'
|
|
834
|
+
? 2
|
|
835
|
+
: 1;
|
|
836
|
+
if (!identifier(name) ||
|
|
837
|
+
!values.length ||
|
|
838
|
+
values.length > maximum ||
|
|
839
|
+
values.some((value) => typeof value !== 'number' ||
|
|
840
|
+
!Number.isSafeInteger(value) ||
|
|
841
|
+
value < 0))
|
|
842
|
+
throw new Error('Expected feature aliases with nonnegative integer indices.');
|
|
843
|
+
return { kind: 'descriptor', name, value: values.join(' ') };
|
|
844
|
+
});
|
|
845
|
+
entries.push({ kind: 'block', header, entries: declarations });
|
|
846
|
+
}
|
|
951
847
|
}
|
|
848
|
+
result.push({
|
|
849
|
+
kind: 'block',
|
|
850
|
+
header: `@font-feature-values ${familyList}`,
|
|
851
|
+
entries,
|
|
852
|
+
});
|
|
853
|
+
}
|
|
854
|
+
else if (call.kind === 'viewTransition') {
|
|
855
|
+
const entries = Object.entries(record(input)).flatMap(([key, value]) => {
|
|
856
|
+
if (value === undefined)
|
|
857
|
+
return [];
|
|
858
|
+
if ((key !== 'navigation' && key !== 'types') ||
|
|
859
|
+
typeof value !== 'string' ||
|
|
860
|
+
(key === 'navigation' &&
|
|
861
|
+
!['auto', 'none'].includes(Identifiers.list(value, 'space')?.join(' ').toLowerCase() ??
|
|
862
|
+
'')))
|
|
863
|
+
throw new Error('Expected navigation or types view-transition descriptors.');
|
|
864
|
+
if (key === 'types') {
|
|
865
|
+
const names = Identifiers.list(value, 'space');
|
|
866
|
+
if (!names ||
|
|
867
|
+
names.some((name) => [
|
|
868
|
+
'default',
|
|
869
|
+
'inherit',
|
|
870
|
+
'initial',
|
|
871
|
+
'revert',
|
|
872
|
+
'revert-layer',
|
|
873
|
+
'unset',
|
|
874
|
+
].includes(name.toLowerCase()) ||
|
|
875
|
+
(name.toLowerCase() === 'none' && names.length !== 1)))
|
|
876
|
+
throw new Error('Expected none or a list of view-transition custom identifiers.');
|
|
877
|
+
}
|
|
878
|
+
Functions.value('*', String(value));
|
|
879
|
+
return [{ kind: 'descriptor', name: key, value }];
|
|
880
|
+
});
|
|
881
|
+
result.push({ kind: 'block', header: '@view-transition', entries });
|
|
882
|
+
}
|
|
883
|
+
else if (call.kind === 'positionTry') {
|
|
884
|
+
const declarations = record(input);
|
|
885
|
+
const keys = [
|
|
886
|
+
'alignSelf',
|
|
887
|
+
'blockSize',
|
|
888
|
+
'bottom',
|
|
889
|
+
'height',
|
|
890
|
+
'inlineSize',
|
|
891
|
+
'inset',
|
|
892
|
+
'insetBlock',
|
|
893
|
+
'insetBlockEnd',
|
|
894
|
+
'insetBlockStart',
|
|
895
|
+
'insetInline',
|
|
896
|
+
'insetInlineEnd',
|
|
897
|
+
'insetInlineStart',
|
|
898
|
+
'justifySelf',
|
|
899
|
+
'left',
|
|
900
|
+
'margin',
|
|
901
|
+
'marginBlock',
|
|
902
|
+
'marginBlockEnd',
|
|
903
|
+
'marginBlockStart',
|
|
904
|
+
'marginBottom',
|
|
905
|
+
'marginInline',
|
|
906
|
+
'marginInlineEnd',
|
|
907
|
+
'marginInlineStart',
|
|
908
|
+
'marginLeft',
|
|
909
|
+
'marginRight',
|
|
910
|
+
'marginTop',
|
|
911
|
+
'maxBlockSize',
|
|
912
|
+
'maxHeight',
|
|
913
|
+
'maxInlineSize',
|
|
914
|
+
'maxWidth',
|
|
915
|
+
'minBlockSize',
|
|
916
|
+
'minHeight',
|
|
917
|
+
'minInlineSize',
|
|
918
|
+
'minWidth',
|
|
919
|
+
'placeSelf',
|
|
920
|
+
'positionAnchor',
|
|
921
|
+
'positionArea',
|
|
922
|
+
'right',
|
|
923
|
+
'top',
|
|
924
|
+
'width',
|
|
925
|
+
];
|
|
926
|
+
if (Object.keys(declarations).some((key) => !keys.includes(key)))
|
|
927
|
+
throw new Error('Unsupported position-try declaration.');
|
|
928
|
+
const block = style(declarations);
|
|
929
|
+
if (block.rules ||
|
|
930
|
+
block.declarations.some((value) => value.important))
|
|
931
|
+
throw new Error('Position-try forbids nested rules and important declarations.');
|
|
932
|
+
result.push({
|
|
933
|
+
kind: 'rule',
|
|
934
|
+
selector: `@position-try ${call.name}`,
|
|
935
|
+
style: block,
|
|
936
|
+
});
|
|
952
937
|
}
|
|
953
|
-
if (call.kind === '
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
938
|
+
else if (call.kind === 'colorProfile' ||
|
|
939
|
+
call.kind === 'counterStyle' ||
|
|
940
|
+
call.kind === 'fontPaletteValues') {
|
|
941
|
+
const descriptors = {
|
|
942
|
+
colorProfile: {
|
|
943
|
+
rule: 'color-profile',
|
|
944
|
+
keys: ['components', 'renderingIntent', 'src'],
|
|
945
|
+
required: ['src'],
|
|
946
|
+
},
|
|
947
|
+
counterStyle: {
|
|
961
948
|
rule: 'counter-style',
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
949
|
+
keys: [
|
|
950
|
+
'additiveSymbols',
|
|
951
|
+
'fallback',
|
|
952
|
+
'negative',
|
|
953
|
+
'pad',
|
|
954
|
+
'prefix',
|
|
955
|
+
'range',
|
|
956
|
+
'speakAs',
|
|
957
|
+
'suffix',
|
|
958
|
+
'symbols',
|
|
959
|
+
'system',
|
|
960
|
+
],
|
|
961
|
+
required: [],
|
|
962
|
+
},
|
|
963
|
+
fontPaletteValues: {
|
|
964
|
+
rule: 'font-palette-values',
|
|
965
|
+
keys: ['basePalette', 'fontFamily', 'overrideColors'],
|
|
966
|
+
required: ['fontFamily'],
|
|
967
|
+
},
|
|
968
|
+
};
|
|
969
|
+
const definition = descriptors[call.kind];
|
|
970
|
+
const declarations = record(input);
|
|
971
|
+
for (const key of Object.keys(declarations))
|
|
972
|
+
if (declarations[key] === undefined)
|
|
973
|
+
delete declarations[key];
|
|
974
|
+
if (definition.required.some((key) => typeof declarations[key] !== 'string') ||
|
|
975
|
+
Object.entries(declarations).some(([key, value]) => !definition.keys.includes(key) ||
|
|
976
|
+
(typeof value !== 'string' &&
|
|
977
|
+
!(key === 'basePalette' &&
|
|
978
|
+
typeof value === 'number' &&
|
|
979
|
+
Number.isSafeInteger(value) &&
|
|
980
|
+
value >= 0))))
|
|
981
|
+
throw new Error('Expected supported scalar descriptors and required fields.');
|
|
982
|
+
if (call.kind === 'colorProfile') {
|
|
983
|
+
if (!Identifiers.url(declarations.src))
|
|
984
|
+
throw new Error('Color-profile src requires one URL.');
|
|
985
|
+
if (typeof declarations.components === 'string') {
|
|
986
|
+
const names = Identifiers.list(declarations.components, 'comma');
|
|
987
|
+
if (!names || names.some((name) => name.toLowerCase() === 'none'))
|
|
988
|
+
throw new Error('Color-profile components require comma-separated identifiers other than none.');
|
|
989
|
+
}
|
|
990
|
+
if (typeof declarations.renderingIntent === 'string') {
|
|
991
|
+
const names = Identifiers.list(declarations.renderingIntent, 'space');
|
|
992
|
+
if (names?.length !== 1 ||
|
|
993
|
+
![
|
|
994
|
+
'absolute-colorimetric',
|
|
995
|
+
'relative-colorimetric',
|
|
996
|
+
'perceptual',
|
|
997
|
+
'saturation',
|
|
998
|
+
].includes(names[0].toLowerCase()))
|
|
999
|
+
throw new Error('Invalid color-profile rendering intent.');
|
|
1000
|
+
}
|
|
967
1001
|
}
|
|
968
|
-
|
|
969
|
-
|
|
1002
|
+
if (call.kind === 'counterStyle') {
|
|
1003
|
+
const system = typeof declarations.system === 'string'
|
|
1004
|
+
? Lexical.normalize(declarations.system)
|
|
1005
|
+
.trim()
|
|
1006
|
+
.replace(/[A-Z]/g, (letter) => letter.toLowerCase())
|
|
1007
|
+
: 'symbolic';
|
|
1008
|
+
try {
|
|
1009
|
+
Descriptors.check({
|
|
1010
|
+
rule: 'counter-style',
|
|
1011
|
+
name: 'system',
|
|
1012
|
+
value: typeof declarations.system === 'string'
|
|
1013
|
+
? declarations.system
|
|
1014
|
+
: 'symbolic',
|
|
1015
|
+
});
|
|
1016
|
+
}
|
|
1017
|
+
catch {
|
|
1018
|
+
throw new Error('Expected a supported counter system, with an integer after fixed.');
|
|
1019
|
+
}
|
|
1020
|
+
const required = system === 'additive'
|
|
1021
|
+
? 'additiveSymbols'
|
|
1022
|
+
: system.startsWith('extends ')
|
|
1023
|
+
? undefined
|
|
1024
|
+
: 'symbols';
|
|
1025
|
+
if (required &&
|
|
1026
|
+
(typeof declarations[required] !== 'string' ||
|
|
1027
|
+
!declarations[required].trim()))
|
|
1028
|
+
throw new Error('The counter system requires symbols or additiveSymbols.');
|
|
970
1029
|
}
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
1030
|
+
if (call.kind !== 'colorProfile')
|
|
1031
|
+
for (const [name, value] of Object.entries(declarations))
|
|
1032
|
+
Descriptors.check({
|
|
1033
|
+
rule: definition.rule,
|
|
1034
|
+
name,
|
|
1035
|
+
value: String(value),
|
|
1036
|
+
});
|
|
1037
|
+
result.push({
|
|
1038
|
+
kind: 'descriptor',
|
|
1039
|
+
rule: definition.rule,
|
|
1040
|
+
name: call.name,
|
|
1041
|
+
declarations: declarations,
|
|
1042
|
+
});
|
|
1043
|
+
}
|
|
1044
|
+
else {
|
|
1045
|
+
const frames = Object.entries(record(input)).map(([stop, input]) => {
|
|
1046
|
+
if (!Keyframes.accepts(stop))
|
|
1047
|
+
throw new Error('Keyframe stops require from, to, 0–100% offsets, or named timeline percentages.');
|
|
1048
|
+
const frame = style(input);
|
|
1049
|
+
if (frame.rules ||
|
|
1050
|
+
frame.declarations.some((value) => value.important))
|
|
1051
|
+
throw new Error('Keyframes forbid nested rules and important declarations.');
|
|
1052
|
+
return { stop, style: frame };
|
|
1053
|
+
});
|
|
1054
|
+
if (call.exported || scanned.used.has(call.name))
|
|
1055
|
+
result.push({ kind: 'keyframes', name: call.name, frames });
|
|
1056
|
+
}
|
|
1057
|
+
for (let index = before; index < result.length; index++) {
|
|
1058
|
+
if (headers.length)
|
|
1059
|
+
result[index] = { ...result[index], within: headers };
|
|
1060
|
+
starts?.push(call.start);
|
|
980
1061
|
}
|
|
981
|
-
if (call.kind !== 'colorProfile')
|
|
982
|
-
for (const [name, value] of Object.entries(declarations))
|
|
983
|
-
Descriptors.check({
|
|
984
|
-
rule: definition.rule,
|
|
985
|
-
name,
|
|
986
|
-
value: String(value),
|
|
987
|
-
});
|
|
988
|
-
result.push({
|
|
989
|
-
kind: 'descriptor',
|
|
990
|
-
rule: definition.rule,
|
|
991
|
-
name: call.name,
|
|
992
|
-
declarations: declarations,
|
|
993
|
-
});
|
|
994
|
-
}
|
|
995
|
-
else {
|
|
996
|
-
const frames = Object.entries(record(input)).map(([stop, input]) => {
|
|
997
|
-
if (!Keyframes.accepts(stop))
|
|
998
|
-
throw new Error('Keyframe stops require from, to, 0–100% offsets, or named timeline percentages.');
|
|
999
|
-
const frame = style(input);
|
|
1000
|
-
if (frame.rules ||
|
|
1001
|
-
frame.declarations.some((value) => value.important))
|
|
1002
|
-
throw new Error('Keyframes forbid nested rules and important declarations.');
|
|
1003
|
-
return { stop, style: frame };
|
|
1004
|
-
});
|
|
1005
|
-
if (call.exported || scanned.used.has(call.name))
|
|
1006
|
-
result.push({ kind: 'keyframes', name: call.name, frames });
|
|
1007
|
-
}
|
|
1008
|
-
const contextValue = call.context ? value(call.context) : undefined;
|
|
1009
|
-
if (contextValue !== undefined) {
|
|
1010
|
-
const context = record(contextValue);
|
|
1011
|
-
if (Object.keys(context).some((key) => !['id', 'within'].includes(key)))
|
|
1012
|
-
throw new Error('Unknown contribution context option.');
|
|
1013
|
-
if (call.kind === 'customMedia' && 'within' in context)
|
|
1014
|
-
throw new Error('Custom media definitions do not accept a within context.');
|
|
1015
|
-
const within = context.within ?? [];
|
|
1016
|
-
if (!Array.isArray(within) ||
|
|
1017
|
-
within.some((header) => typeof header !== 'string' ||
|
|
1018
|
-
!(header === '@layer' ||
|
|
1019
|
-
/^@(media|supports|container|layer)(?=[\t\n\r\f (/])/.test(header))))
|
|
1020
|
-
throw new Error('Expected enclosing conditional or layer headers.');
|
|
1021
|
-
const headers = within.map((header) => Condition.normalize(header));
|
|
1022
|
-
for (let index = before; index < result.length; index++)
|
|
1023
|
-
result[index] = { ...result[index], within: headers };
|
|
1024
1062
|
}
|
|
1025
|
-
for (let index = before; index < result.length; index++)
|
|
1026
|
-
starts?.push(call.start);
|
|
1027
1063
|
}
|
|
1028
1064
|
catch (error) {
|
|
1029
1065
|
throw new Themes.InvalidError(error.message, call);
|