zyzz 0.0.9 → 0.0.12
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/variants.d.ts +13 -2
- package/dist/variants.d.ts.map +1 -1
- package/dist/variants.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/variants.ts +35 -2
- 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
|
@@ -663,740 +663,789 @@ export function extract(
|
|
|
663
663
|
}
|
|
664
664
|
}
|
|
665
665
|
|
|
666
|
-
|
|
667
|
-
|
|
666
|
+
function definitions(
|
|
667
|
+
input: unknown,
|
|
668
|
+
headers: readonly string[] = [],
|
|
669
|
+
): { input: unknown; headers: readonly string[] }[] {
|
|
670
|
+
const entries = Object.entries(record(input))
|
|
671
|
+
const groups = new Set(
|
|
672
|
+
entries
|
|
673
|
+
.filter(
|
|
674
|
+
([key]) =>
|
|
675
|
+
key === '@layer' ||
|
|
676
|
+
/^@(media|supports|container|layer)(?=[\t\n\r\f (/])/.test(key),
|
|
677
|
+
)
|
|
678
|
+
.map(([key]) => key),
|
|
679
|
+
)
|
|
680
|
+
const descriptors = entries.filter(([key]) => !groups.has(key))
|
|
681
|
+
const body = Object.fromEntries(descriptors)
|
|
682
|
+
if (!entries.length) return [{ input: body, headers }]
|
|
683
|
+
|
|
684
|
+
// A complete descriptor block occupies its first descriptor's authored position.
|
|
685
|
+
return entries.flatMap(([header, child]) =>
|
|
686
|
+
groups.has(header)
|
|
687
|
+
? definitions(child, [...headers, Condition.normalize(header)])
|
|
688
|
+
: header === descriptors[0]?.[0]
|
|
689
|
+
? [{ input: body, headers }]
|
|
690
|
+
: [],
|
|
691
|
+
)
|
|
692
|
+
}
|
|
668
693
|
|
|
694
|
+
for (const call of scanned.calls) {
|
|
669
695
|
try {
|
|
670
|
-
const
|
|
696
|
+
const argument = value(call.argument)
|
|
671
697
|
if (call.name && !call.exported && !scanned.used.has(call.name)) continue
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
Object.entries(options).some(
|
|
680
|
-
([key, value]) =>
|
|
681
|
-
key !== 'url' &&
|
|
682
|
-
value !== undefined &&
|
|
683
|
-
typeof value !== 'string' &&
|
|
684
|
-
!(key === 'layer' && value === true),
|
|
685
|
-
)
|
|
686
|
-
)
|
|
687
|
-
throw new Error(
|
|
688
|
-
'Expected a stylesheet URL and static import conditions.',
|
|
689
|
-
)
|
|
690
|
-
result.push({
|
|
691
|
-
kind: 'import',
|
|
692
|
-
url: options.url,
|
|
693
|
-
...(options.layer !== undefined
|
|
694
|
-
? { layer: options.layer as string | true }
|
|
695
|
-
: {}),
|
|
696
|
-
...(options.supports !== undefined
|
|
697
|
-
? { supports: options.supports as string }
|
|
698
|
-
: {}),
|
|
699
|
-
...(options.media !== undefined
|
|
700
|
-
? { media: options.media as string }
|
|
701
|
-
: {}),
|
|
702
|
-
})
|
|
703
|
-
} else if (call.kind === 'namespace') {
|
|
704
|
-
const options = record(input)
|
|
705
|
-
if (
|
|
706
|
-
Object.keys(options).some(
|
|
707
|
-
(key) => !['prefix', 'uri'].includes(key),
|
|
708
|
-
) ||
|
|
709
|
-
typeof options.uri !== 'string' ||
|
|
710
|
-
(options.prefix !== undefined &&
|
|
711
|
-
(typeof options.prefix !== 'string' ||
|
|
712
|
-
Identifiers.read(options.prefix) === undefined))
|
|
698
|
+
const contextValue = call.context ? value(call.context) : undefined
|
|
699
|
+
if (
|
|
700
|
+
contextValue !== undefined &&
|
|
701
|
+
Object.keys(record(contextValue)).some((key) => key !== 'id')
|
|
702
|
+
)
|
|
703
|
+
throw new Error(
|
|
704
|
+
'Unknown contribution context option. Use nested at-rule keys for enclosing groups.',
|
|
713
705
|
)
|
|
714
|
-
|
|
715
|
-
|
|
706
|
+
|
|
707
|
+
const inputs = [
|
|
708
|
+
'importCss',
|
|
709
|
+
'namespace',
|
|
710
|
+
'customMedia',
|
|
711
|
+
'layers',
|
|
712
|
+
'global',
|
|
713
|
+
].includes(call.kind)
|
|
714
|
+
? [{ input: argument, headers: [] }]
|
|
715
|
+
: definitions(argument)
|
|
716
|
+
let functionSignature: string | undefined
|
|
717
|
+
for (const { input, headers } of inputs) {
|
|
718
|
+
const before = result.length
|
|
719
|
+
if (call.kind === 'importCss') {
|
|
720
|
+
const options = record(input)
|
|
721
|
+
if (
|
|
722
|
+
Object.keys(options).some(
|
|
723
|
+
(key) => !['layer', 'media', 'supports', 'url'].includes(key),
|
|
724
|
+
) ||
|
|
725
|
+
typeof options.url !== 'string' ||
|
|
726
|
+
Object.entries(options).some(
|
|
727
|
+
([key, value]) =>
|
|
728
|
+
key !== 'url' &&
|
|
729
|
+
value !== undefined &&
|
|
730
|
+
typeof value !== 'string' &&
|
|
731
|
+
!(key === 'layer' && value === true),
|
|
732
|
+
)
|
|
716
733
|
)
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
:
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
734
|
+
throw new Error(
|
|
735
|
+
'Expected a stylesheet URL and static import conditions.',
|
|
736
|
+
)
|
|
737
|
+
result.push({
|
|
738
|
+
kind: 'import',
|
|
739
|
+
url: options.url,
|
|
740
|
+
...(options.layer !== undefined
|
|
741
|
+
? { layer: options.layer as string | true }
|
|
742
|
+
: {}),
|
|
743
|
+
...(options.supports !== undefined
|
|
744
|
+
? { supports: options.supports as string }
|
|
745
|
+
: {}),
|
|
746
|
+
...(options.media !== undefined
|
|
747
|
+
? { media: options.media as string }
|
|
748
|
+
: {}),
|
|
749
|
+
})
|
|
750
|
+
} else if (call.kind === 'namespace') {
|
|
751
|
+
const options = record(input)
|
|
752
|
+
if (
|
|
753
|
+
Object.keys(options).some(
|
|
754
|
+
(key) => !['prefix', 'uri'].includes(key),
|
|
755
|
+
) ||
|
|
756
|
+
typeof options.uri !== 'string' ||
|
|
757
|
+
(options.prefix !== undefined &&
|
|
758
|
+
(typeof options.prefix !== 'string' ||
|
|
759
|
+
Identifiers.read(options.prefix) === undefined))
|
|
743
760
|
)
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
761
|
+
throw new Error(
|
|
762
|
+
'Expected a namespace URI and optional identifier prefix.',
|
|
763
|
+
)
|
|
764
|
+
result.push({
|
|
765
|
+
kind: 'namespace',
|
|
766
|
+
uri: options.uri,
|
|
767
|
+
...(options.prefix !== undefined
|
|
768
|
+
? { prefix: options.prefix as string }
|
|
769
|
+
: {}),
|
|
770
|
+
name: `z-n${scanned.namespace}-${call.start.toString(36)}`,
|
|
771
|
+
})
|
|
772
|
+
} else if (call.kind === 'customMedia') {
|
|
773
|
+
if (typeof input !== 'string' && typeof input !== 'boolean')
|
|
774
|
+
throw new Error('Expected a media query or boolean.')
|
|
775
|
+
if (typeof input === 'string') Descriptors.media(input)
|
|
776
|
+
result.push({ kind: 'custom-media', name: call.name!, query: input })
|
|
777
|
+
} else if (call.kind === 'cssFunction') {
|
|
778
|
+
const options = record(input)
|
|
747
779
|
if (
|
|
748
|
-
Object.keys(
|
|
749
|
-
(key) => !['
|
|
780
|
+
Object.keys(options).some(
|
|
781
|
+
(key) => !['body', 'parameters', 'returns'].includes(key),
|
|
750
782
|
) ||
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
(typeof parameter.syntax !== 'string' ||
|
|
756
|
-
!FunctionSyntax.accepts(parameter.syntax))) ||
|
|
757
|
-
(parameter.default !== undefined &&
|
|
758
|
-
typeof parameter.default !== 'string' &&
|
|
759
|
-
typeof parameter.default !== 'number')
|
|
783
|
+
!Array.isArray(options.parameters) ||
|
|
784
|
+
(options.returns !== undefined &&
|
|
785
|
+
(typeof options.returns !== 'string' ||
|
|
786
|
+
!FunctionSyntax.accepts(options.returns)))
|
|
760
787
|
)
|
|
761
788
|
throw new Error(
|
|
762
|
-
'Expected
|
|
789
|
+
'Expected CSS function parameters, body, and optional return syntax.',
|
|
763
790
|
)
|
|
764
|
-
names
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
791
|
+
const names = new Set<string>()
|
|
792
|
+
const parameters = options.parameters.map((input) => {
|
|
793
|
+
const parameter = record(input)
|
|
794
|
+
if (
|
|
795
|
+
Object.keys(parameter).some(
|
|
796
|
+
(key) => !['default', 'name', 'syntax'].includes(key),
|
|
797
|
+
) ||
|
|
798
|
+
typeof parameter.name !== 'string' ||
|
|
799
|
+
!dashed(parameter.name) ||
|
|
800
|
+
names.has(Identifiers.read(parameter.name)!) ||
|
|
801
|
+
(parameter.syntax !== undefined &&
|
|
802
|
+
(typeof parameter.syntax !== 'string' ||
|
|
803
|
+
!FunctionSyntax.accepts(parameter.syntax))) ||
|
|
804
|
+
(parameter.default !== undefined &&
|
|
805
|
+
typeof parameter.default !== 'string' &&
|
|
806
|
+
typeof parameter.default !== 'number')
|
|
769
807
|
)
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
function body(input: unknown): readonly Block.Entry[] {
|
|
773
|
-
return Object.entries(record(input)).flatMap(
|
|
774
|
-
([key, value]): Block.Entry[] => {
|
|
775
|
-
if (value === undefined) return []
|
|
776
|
-
if (/^@(media|supports|container) /.test(key))
|
|
777
|
-
return [
|
|
778
|
-
{
|
|
779
|
-
kind: 'block',
|
|
780
|
-
header: Condition.normalize(key),
|
|
781
|
-
entries: body(value),
|
|
782
|
-
},
|
|
783
|
-
]
|
|
784
|
-
if (
|
|
785
|
-
(key !== 'result' && !dashed(key)) ||
|
|
786
|
-
(typeof value !== 'string' && typeof value !== 'number')
|
|
808
|
+
throw new Error(
|
|
809
|
+
'Expected unique CSS parameters with supported syntaxes and scalar defaults.',
|
|
787
810
|
)
|
|
788
|
-
|
|
789
|
-
|
|
811
|
+
names.add(Identifiers.read(parameter.name)!)
|
|
812
|
+
if (parameter.default !== undefined)
|
|
813
|
+
Functions.value(
|
|
814
|
+
String(parameter.syntax ?? '*'),
|
|
815
|
+
String(parameter.default),
|
|
816
|
+
)
|
|
817
|
+
return `${parameter.name}${parameter.syntax ? ` ${parameter.syntax === '*' ? 'type(*)' : parameter.syntax}` : ''}${parameter.default !== undefined ? `: ${parameter.default}` : ''}`
|
|
818
|
+
})
|
|
819
|
+
function body(input: unknown): readonly Block.Entry[] {
|
|
820
|
+
return Object.entries(record(input)).flatMap(
|
|
821
|
+
([key, value]): Block.Entry[] => {
|
|
822
|
+
if (value === undefined) return []
|
|
823
|
+
if (/^@(media|supports|container) /.test(key))
|
|
824
|
+
return [
|
|
825
|
+
{
|
|
826
|
+
kind: 'block',
|
|
827
|
+
header: Condition.normalize(key),
|
|
828
|
+
entries: body(value),
|
|
829
|
+
},
|
|
830
|
+
]
|
|
831
|
+
if (
|
|
832
|
+
(key !== 'result' && !dashed(key)) ||
|
|
833
|
+
(typeof value !== 'string' && typeof value !== 'number')
|
|
790
834
|
)
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
835
|
+
throw new Error(
|
|
836
|
+
'CSS function bodies accept result, local variables, and conditional groups.',
|
|
837
|
+
)
|
|
838
|
+
Functions.value('*', String(value))
|
|
839
|
+
return [{ kind: 'descriptor', name: key, value }]
|
|
840
|
+
},
|
|
841
|
+
)
|
|
842
|
+
}
|
|
843
|
+
const signature = JSON.stringify({
|
|
844
|
+
parameters: options.parameters.map((input) => {
|
|
845
|
+
const parameter = record(input)
|
|
846
|
+
return [
|
|
847
|
+
parameter.name,
|
|
848
|
+
parameter.syntax ?? '*',
|
|
849
|
+
parameter.default,
|
|
850
|
+
]
|
|
851
|
+
}),
|
|
852
|
+
returns: options.returns ?? '*',
|
|
853
|
+
})
|
|
854
|
+
if (
|
|
855
|
+
functionSignature !== undefined &&
|
|
856
|
+
functionSignature !== signature
|
|
794
857
|
)
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
})
|
|
804
|
-
} else if (call.kind === 'layers') {
|
|
805
|
-
if (
|
|
806
|
-
!Array.isArray(input) ||
|
|
807
|
-
input.some((value) => typeof value !== 'string')
|
|
808
|
-
)
|
|
809
|
-
throw new Error('Layers require a literal string list.')
|
|
810
|
-
|
|
811
|
-
result.push({ kind: 'layers', names: input })
|
|
812
|
-
} else if (call.kind === 'global') {
|
|
813
|
-
for (const [selector, child] of Object.entries(record(input)))
|
|
858
|
+
throw new Error(
|
|
859
|
+
'Grouped CSS function definitions must use the same parameters and return syntax.',
|
|
860
|
+
)
|
|
861
|
+
functionSignature = signature
|
|
862
|
+
call.function!.parameters =
|
|
863
|
+
options.parameters as readonly cssFunction.Parameter[]
|
|
864
|
+
call.function!.returns = (options.returns ??
|
|
865
|
+
'*') as cssFunction.Syntax
|
|
814
866
|
result.push({
|
|
815
|
-
kind: '
|
|
816
|
-
|
|
817
|
-
|
|
867
|
+
kind: 'block',
|
|
868
|
+
header: `@function ${call.name}(${parameters.join(',')})${options.returns ? ` returns ${options.returns === '*' ? 'type(*)' : options.returns}` : ''}`,
|
|
869
|
+
entries: body(options.body),
|
|
818
870
|
})
|
|
819
|
-
|
|
820
|
-
const declarations = record(input)
|
|
821
|
-
|
|
822
|
-
for (const key of Object.keys(declarations))
|
|
871
|
+
} else if (call.kind === 'layers') {
|
|
823
872
|
if (
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
key !== 'src'
|
|
827
|
-
)
|
|
828
|
-
delete declarations[key]
|
|
829
|
-
|
|
830
|
-
const keys = [
|
|
831
|
-
'fontFeatureSettings',
|
|
832
|
-
'fontVariationSettings',
|
|
833
|
-
'fontFamily',
|
|
834
|
-
'src',
|
|
835
|
-
'fontDisplay',
|
|
836
|
-
'fontStyle',
|
|
837
|
-
'fontWeight',
|
|
838
|
-
'fontStretch',
|
|
839
|
-
'unicodeRange',
|
|
840
|
-
'sizeAdjust',
|
|
841
|
-
'ascentOverride',
|
|
842
|
-
'descentOverride',
|
|
843
|
-
'lineGapOverride',
|
|
844
|
-
]
|
|
845
|
-
if (
|
|
846
|
-
typeof declarations.fontFamily !== 'string' ||
|
|
847
|
-
typeof declarations.src !== 'string' ||
|
|
848
|
-
Object.entries(declarations).some(
|
|
849
|
-
([key, value]) =>
|
|
850
|
-
!keys.includes(key) ||
|
|
851
|
-
(typeof value !== 'string' && typeof value !== 'number'),
|
|
852
|
-
)
|
|
853
|
-
)
|
|
854
|
-
throw new Error(
|
|
855
|
-
'Font faces require family/source and scalar supported descriptors.',
|
|
873
|
+
!Array.isArray(input) ||
|
|
874
|
+
input.some((value) => typeof value !== 'string')
|
|
856
875
|
)
|
|
876
|
+
throw new Error('Layers require a literal string list.')
|
|
877
|
+
|
|
878
|
+
result.push({ kind: 'layers', names: input })
|
|
879
|
+
} else if (call.kind === 'global') {
|
|
880
|
+
for (const [selector, child] of Object.entries(record(input)))
|
|
881
|
+
result.push({
|
|
882
|
+
kind: 'rule',
|
|
883
|
+
selector,
|
|
884
|
+
style: grouping(selector) ? global(child) : style(child),
|
|
885
|
+
})
|
|
886
|
+
} else if (call.kind === 'fontFace') {
|
|
887
|
+
const declarations = record(input)
|
|
857
888
|
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
typeof
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
889
|
+
for (const key of Object.keys(declarations))
|
|
890
|
+
if (
|
|
891
|
+
declarations[key] === undefined &&
|
|
892
|
+
key !== 'fontFamily' &&
|
|
893
|
+
key !== 'src'
|
|
894
|
+
)
|
|
895
|
+
delete declarations[key]
|
|
896
|
+
|
|
897
|
+
const keys = [
|
|
898
|
+
'fontFeatureSettings',
|
|
899
|
+
'fontVariationSettings',
|
|
900
|
+
'fontFamily',
|
|
901
|
+
'src',
|
|
902
|
+
'fontDisplay',
|
|
903
|
+
'fontStyle',
|
|
904
|
+
'fontWeight',
|
|
905
|
+
'fontStretch',
|
|
906
|
+
'unicodeRange',
|
|
907
|
+
'sizeAdjust',
|
|
908
|
+
'ascentOverride',
|
|
909
|
+
'descentOverride',
|
|
910
|
+
'lineGapOverride',
|
|
911
|
+
]
|
|
912
|
+
if (
|
|
913
|
+
typeof declarations.fontFamily !== 'string' ||
|
|
914
|
+
typeof declarations.src !== 'string' ||
|
|
915
|
+
Object.entries(declarations).some(
|
|
916
|
+
([key, value]) =>
|
|
917
|
+
!keys.includes(key) ||
|
|
918
|
+
(typeof value !== 'string' && typeof value !== 'number'),
|
|
919
|
+
)
|
|
886
920
|
)
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
})
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
'bottom-center',
|
|
917
|
-
'bottom-right',
|
|
918
|
-
'bottom-right-corner',
|
|
919
|
-
'left-top',
|
|
920
|
-
'left-middle',
|
|
921
|
-
'left-bottom',
|
|
922
|
-
'right-top',
|
|
923
|
-
'right-middle',
|
|
924
|
-
'right-bottom',
|
|
925
|
-
].map((name) => `@${name}`)
|
|
926
|
-
const properties =
|
|
927
|
-
/^(?!border(?:Collapse|Spacing)$)(?:background|border|font|margin|padding|outline)/
|
|
928
|
-
const names = [
|
|
929
|
-
'color',
|
|
930
|
-
'counterIncrement',
|
|
931
|
-
'counterReset',
|
|
932
|
-
'direction',
|
|
933
|
-
'height',
|
|
934
|
-
'letterSpacing',
|
|
935
|
-
'lineHeight',
|
|
936
|
-
'maxHeight',
|
|
937
|
-
'maxWidth',
|
|
938
|
-
'minHeight',
|
|
939
|
-
'minWidth',
|
|
940
|
-
'quotes',
|
|
941
|
-
'textAlign',
|
|
942
|
-
'textDecoration',
|
|
943
|
-
'textIndent',
|
|
944
|
-
'textTransform',
|
|
945
|
-
'visibility',
|
|
946
|
-
'whiteSpace',
|
|
947
|
-
'width',
|
|
948
|
-
'wordSpacing',
|
|
949
|
-
]
|
|
950
|
-
function body(input: unknown, margin = false): readonly Block.Entry[] {
|
|
951
|
-
return Object.entries(record(input)).flatMap(
|
|
952
|
-
([key, value]): Block.Entry[] => {
|
|
953
|
-
if (value === undefined) return []
|
|
954
|
-
if (!margin && margins.includes(key))
|
|
955
|
-
return [
|
|
956
|
-
{ kind: 'block', header: key, entries: body(value, true) },
|
|
957
|
-
]
|
|
958
|
-
if (
|
|
959
|
-
!margin &&
|
|
960
|
-
['bleed', 'marks', 'pageOrientation', 'size'].includes(key)
|
|
961
|
-
) {
|
|
962
|
-
if (typeof value !== 'string' && typeof value !== 'number')
|
|
963
|
-
throw new Error('Expected a scalar page descriptor.')
|
|
964
|
-
Descriptors.check({
|
|
965
|
-
rule: 'page',
|
|
966
|
-
name: key,
|
|
967
|
-
value: String(value),
|
|
968
|
-
})
|
|
969
|
-
return [
|
|
970
|
-
{
|
|
971
|
-
kind: 'descriptor',
|
|
972
|
-
name: key.replace(
|
|
973
|
-
/[A-Z]/g,
|
|
974
|
-
(letter) => `-${letter.toLowerCase()}`,
|
|
975
|
-
),
|
|
976
|
-
value,
|
|
977
|
-
},
|
|
978
|
-
]
|
|
979
|
-
}
|
|
980
|
-
if (
|
|
981
|
-
!properties.test(key) &&
|
|
982
|
-
!names.includes(key) &&
|
|
983
|
-
!(
|
|
984
|
-
margin &&
|
|
985
|
-
[
|
|
986
|
-
'content',
|
|
987
|
-
'overflow',
|
|
988
|
-
'unicodeBidi',
|
|
989
|
-
'verticalAlign',
|
|
990
|
-
'zIndex',
|
|
991
|
-
].includes(key)
|
|
992
|
-
)
|
|
993
|
-
)
|
|
994
|
-
throw new Error('Unsupported page or page-margin declaration.')
|
|
995
|
-
return [{ kind: 'style', style: style({ [key]: value }) }]
|
|
996
|
-
},
|
|
921
|
+
throw new Error(
|
|
922
|
+
'Font faces require family/source and scalar supported descriptors.',
|
|
923
|
+
)
|
|
924
|
+
|
|
925
|
+
for (const [name, value] of Object.entries(declarations))
|
|
926
|
+
Descriptors.check({ rule: 'font-face', name, value: String(value) })
|
|
927
|
+
result.push({
|
|
928
|
+
kind: 'font-face',
|
|
929
|
+
declarations: declarations as Record<string, string | number>,
|
|
930
|
+
})
|
|
931
|
+
} else if (call.kind === 'property') {
|
|
932
|
+
const options = record(input)
|
|
933
|
+
const names =
|
|
934
|
+
typeof options.name === 'string'
|
|
935
|
+
? Identifiers.list(options.name, 'space')
|
|
936
|
+
: undefined
|
|
937
|
+
if (
|
|
938
|
+
Object.keys(options).some(
|
|
939
|
+
(key) =>
|
|
940
|
+
!['name', 'syntax', 'inherits', 'initialValue'].includes(key),
|
|
941
|
+
) ||
|
|
942
|
+
names?.length !== 1 ||
|
|
943
|
+
!names[0]!.startsWith('--') ||
|
|
944
|
+
names[0]!.length <= 2 ||
|
|
945
|
+
typeof options.syntax !== 'string' ||
|
|
946
|
+
typeof options.inherits !== 'boolean' ||
|
|
947
|
+
(options.initialValue !== undefined &&
|
|
948
|
+
typeof options.initialValue !== 'string' &&
|
|
949
|
+
typeof options.initialValue !== 'number')
|
|
997
950
|
)
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
951
|
+
throw new Error(
|
|
952
|
+
'Expected a native property registration with scalar descriptors.',
|
|
953
|
+
)
|
|
954
|
+
if (options.initialValue !== undefined)
|
|
955
|
+
Properties.initial(String(options.initialValue))
|
|
956
|
+
result.push({
|
|
957
|
+
kind: 'property',
|
|
958
|
+
name: options.name as `--${string}`,
|
|
959
|
+
syntax: options.syntax,
|
|
960
|
+
inherits: options.inherits,
|
|
961
|
+
...(options.initialValue !== undefined
|
|
962
|
+
? { initialValue: options.initialValue as string | number }
|
|
963
|
+
: {}),
|
|
964
|
+
})
|
|
965
|
+
} else if (call.kind === 'page') {
|
|
966
|
+
const options = record(input)
|
|
967
|
+
if (
|
|
968
|
+
Object.keys(options).some(
|
|
969
|
+
(key) => !['descriptors', 'selector'].includes(key),
|
|
970
|
+
) ||
|
|
971
|
+
(options.selector !== undefined &&
|
|
972
|
+
typeof options.selector !== 'string')
|
|
1011
973
|
)
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
974
|
+
throw new Error(
|
|
975
|
+
'Expected page descriptors and an optional selector.',
|
|
976
|
+
)
|
|
977
|
+
const margins = [
|
|
978
|
+
'top-left-corner',
|
|
979
|
+
'top-left',
|
|
980
|
+
'top-center',
|
|
981
|
+
'top-right',
|
|
982
|
+
'top-right-corner',
|
|
983
|
+
'bottom-left-corner',
|
|
984
|
+
'bottom-left',
|
|
985
|
+
'bottom-center',
|
|
986
|
+
'bottom-right',
|
|
987
|
+
'bottom-right-corner',
|
|
988
|
+
'left-top',
|
|
989
|
+
'left-middle',
|
|
990
|
+
'left-bottom',
|
|
991
|
+
'right-top',
|
|
992
|
+
'right-middle',
|
|
993
|
+
'right-bottom',
|
|
994
|
+
].map((name) => `@${name}`)
|
|
995
|
+
const properties =
|
|
996
|
+
/^(?!border(?:Collapse|Spacing)$)(?:background|border|font|margin|padding|outline)/
|
|
997
|
+
const names = [
|
|
998
|
+
'color',
|
|
999
|
+
'counterIncrement',
|
|
1000
|
+
'counterReset',
|
|
1001
|
+
'direction',
|
|
1002
|
+
'height',
|
|
1003
|
+
'letterSpacing',
|
|
1004
|
+
'lineHeight',
|
|
1005
|
+
'maxHeight',
|
|
1006
|
+
'maxWidth',
|
|
1007
|
+
'minHeight',
|
|
1008
|
+
'minWidth',
|
|
1009
|
+
'quotes',
|
|
1010
|
+
'textAlign',
|
|
1011
|
+
'textDecoration',
|
|
1012
|
+
'textIndent',
|
|
1013
|
+
'textTransform',
|
|
1014
|
+
'visibility',
|
|
1015
|
+
'whiteSpace',
|
|
1016
|
+
'width',
|
|
1017
|
+
'wordSpacing',
|
|
1018
|
+
]
|
|
1019
|
+
function body(
|
|
1020
|
+
input: unknown,
|
|
1021
|
+
margin = false,
|
|
1022
|
+
): readonly Block.Entry[] {
|
|
1023
|
+
return Object.entries(record(input)).flatMap(
|
|
1024
|
+
([key, value]): Block.Entry[] => {
|
|
1025
|
+
if (value === undefined) return []
|
|
1026
|
+
if (!margin && margins.includes(key))
|
|
1027
|
+
return [
|
|
1028
|
+
{ kind: 'block', header: key, entries: body(value, true) },
|
|
1029
|
+
]
|
|
1030
|
+
if (
|
|
1031
|
+
!margin &&
|
|
1032
|
+
['bleed', 'marks', 'pageOrientation', 'size'].includes(key)
|
|
1033
|
+
) {
|
|
1034
|
+
if (typeof value !== 'string' && typeof value !== 'number')
|
|
1035
|
+
throw new Error('Expected a scalar page descriptor.')
|
|
1036
|
+
Descriptors.check({
|
|
1037
|
+
rule: 'page',
|
|
1038
|
+
name: key,
|
|
1039
|
+
value: String(value),
|
|
1040
|
+
})
|
|
1041
|
+
return [
|
|
1042
|
+
{
|
|
1043
|
+
kind: 'descriptor',
|
|
1044
|
+
name: key.replace(
|
|
1045
|
+
/[A-Z]/g,
|
|
1046
|
+
(letter) => `-${letter.toLowerCase()}`,
|
|
1047
|
+
),
|
|
1048
|
+
value,
|
|
1049
|
+
},
|
|
1050
|
+
]
|
|
1051
|
+
}
|
|
1052
|
+
if (
|
|
1053
|
+
!properties.test(key) &&
|
|
1054
|
+
!names.includes(key) &&
|
|
1055
|
+
!(
|
|
1056
|
+
margin &&
|
|
1057
|
+
[
|
|
1058
|
+
'content',
|
|
1059
|
+
'overflow',
|
|
1060
|
+
'unicodeBidi',
|
|
1061
|
+
'verticalAlign',
|
|
1062
|
+
'zIndex',
|
|
1063
|
+
].includes(key)
|
|
1064
|
+
)
|
|
1065
|
+
)
|
|
1066
|
+
throw new Error(
|
|
1067
|
+
'Unsupported page or page-margin declaration.',
|
|
1068
|
+
)
|
|
1069
|
+
return [{ kind: 'style', style: style({ [key]: value }) }]
|
|
1070
|
+
},
|
|
1057
1071
|
)
|
|
1058
|
-
throw new Error('Invalid font display descriptor.')
|
|
1059
|
-
entries.push({
|
|
1060
|
-
kind: 'descriptor',
|
|
1061
|
-
name: 'font-display',
|
|
1062
|
-
value: options.fontDisplay,
|
|
1063
|
-
})
|
|
1064
1072
|
}
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
'@swash',
|
|
1078
|
-
].includes(header)
|
|
1073
|
+
result.push({
|
|
1074
|
+
kind: 'block',
|
|
1075
|
+
header: Condition.normalize(
|
|
1076
|
+
`@page${options.selector ? ` ${options.selector}` : ''}`,
|
|
1077
|
+
),
|
|
1078
|
+
entries: body(options.descriptors),
|
|
1079
|
+
})
|
|
1080
|
+
} else if (call.kind === 'fontFeatureValues') {
|
|
1081
|
+
const options = record(input)
|
|
1082
|
+
if (
|
|
1083
|
+
Object.keys(options).some(
|
|
1084
|
+
(key) => !['families', 'features', 'fontDisplay'].includes(key),
|
|
1079
1085
|
)
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
!values.length ||
|
|
1094
|
-
values.length > maximum ||
|
|
1095
|
-
values.some(
|
|
1086
|
+
)
|
|
1087
|
+
throw new Error('Unknown font-feature-values option.')
|
|
1088
|
+
const families = options.families
|
|
1089
|
+
if (
|
|
1090
|
+
typeof families !== 'string' &&
|
|
1091
|
+
(!Array.isArray(families) ||
|
|
1092
|
+
!families.length ||
|
|
1093
|
+
families.some((value) => typeof value !== 'string'))
|
|
1094
|
+
)
|
|
1095
|
+
throw new Error('Expected a font family list.')
|
|
1096
|
+
const familyList = Array.isArray(families)
|
|
1097
|
+
? families
|
|
1098
|
+
.map(
|
|
1096
1099
|
(value) =>
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
+
'"' +
|
|
1101
|
+
Array.from(value as string, (char) => {
|
|
1102
|
+
const code = char.codePointAt(0)!
|
|
1103
|
+
return code < 32 ||
|
|
1104
|
+
code === 127 ||
|
|
1105
|
+
char === '"' ||
|
|
1106
|
+
char === '\\'
|
|
1107
|
+
? `\\${code.toString(16)} `
|
|
1108
|
+
: char
|
|
1109
|
+
}).join('') +
|
|
1110
|
+
'"',
|
|
1100
1111
|
)
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1112
|
+
.join(',')
|
|
1113
|
+
: families
|
|
1114
|
+
// Validate the native prelude before shielding newer body descriptors.
|
|
1115
|
+
Lightning.transform({
|
|
1116
|
+
filename: 'font-feature-values.css',
|
|
1117
|
+
code: new TextEncoder().encode(
|
|
1118
|
+
`@font-feature-values ${familyList} {}`,
|
|
1119
|
+
),
|
|
1120
|
+
})
|
|
1121
|
+
const entries: Block.Entry[] = []
|
|
1122
|
+
for (const key of Object.keys(options)) {
|
|
1123
|
+
if (key === 'fontDisplay' && options.fontDisplay !== undefined) {
|
|
1124
|
+
if (
|
|
1125
|
+
typeof options.fontDisplay !== 'string' ||
|
|
1126
|
+
!['auto', 'block', 'fallback', 'optional', 'swap'].includes(
|
|
1127
|
+
Identifiers.list(options.fontDisplay, 'space')
|
|
1128
|
+
?.join(' ')
|
|
1129
|
+
.replace(/[A-Z]/g, (letter) => letter.toLowerCase()) ?? '',
|
|
1104
1130
|
)
|
|
1105
|
-
return { kind: 'descriptor', name, value: values.join(' ') }
|
|
1106
|
-
})
|
|
1107
|
-
entries.push({ kind: 'block', header, entries: declarations })
|
|
1108
|
-
}
|
|
1109
|
-
}
|
|
1110
|
-
result.push({
|
|
1111
|
-
kind: 'block',
|
|
1112
|
-
header: `@font-feature-values ${familyList}`,
|
|
1113
|
-
entries,
|
|
1114
|
-
})
|
|
1115
|
-
} else if (call.kind === 'viewTransition') {
|
|
1116
|
-
const entries = Object.entries(record(input)).flatMap(
|
|
1117
|
-
([key, value]): Block.Entry[] => {
|
|
1118
|
-
if (value === undefined) return []
|
|
1119
|
-
if (
|
|
1120
|
-
(key !== 'navigation' && key !== 'types') ||
|
|
1121
|
-
typeof value !== 'string' ||
|
|
1122
|
-
(key === 'navigation' &&
|
|
1123
|
-
!['auto', 'none'].includes(
|
|
1124
|
-
Identifiers.list(value, 'space')?.join(' ').toLowerCase() ??
|
|
1125
|
-
'',
|
|
1126
|
-
))
|
|
1127
|
-
)
|
|
1128
|
-
throw new Error(
|
|
1129
|
-
'Expected navigation or types view-transition descriptors.',
|
|
1130
1131
|
)
|
|
1131
|
-
|
|
1132
|
-
|
|
1132
|
+
throw new Error('Invalid font display descriptor.')
|
|
1133
|
+
entries.push({
|
|
1134
|
+
kind: 'descriptor',
|
|
1135
|
+
name: 'font-display',
|
|
1136
|
+
value: options.fontDisplay,
|
|
1137
|
+
})
|
|
1138
|
+
}
|
|
1139
|
+
if (key !== 'features') continue
|
|
1140
|
+
for (const [header, input] of Object.entries(
|
|
1141
|
+
record(options.features),
|
|
1142
|
+
)) {
|
|
1143
|
+
if (input === undefined) continue
|
|
1133
1144
|
if (
|
|
1134
|
-
!
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1145
|
+
![
|
|
1146
|
+
'@annotation',
|
|
1147
|
+
'@character-variant',
|
|
1148
|
+
'@ornaments',
|
|
1149
|
+
'@styleset',
|
|
1150
|
+
'@stylistic',
|
|
1151
|
+
'@swash',
|
|
1152
|
+
].includes(header)
|
|
1153
|
+
)
|
|
1154
|
+
throw new Error('Unknown font feature block.')
|
|
1155
|
+
const declarations: Block.Entry[] = Object.entries(
|
|
1156
|
+
record(input),
|
|
1157
|
+
).map(([name, value]) => {
|
|
1158
|
+
const values = Array.isArray(value) ? value : [value]
|
|
1159
|
+
const maximum =
|
|
1160
|
+
header === '@styleset'
|
|
1161
|
+
? Infinity
|
|
1162
|
+
: header === '@character-variant'
|
|
1163
|
+
? 2
|
|
1164
|
+
: 1
|
|
1165
|
+
if (
|
|
1166
|
+
!identifier(name) ||
|
|
1167
|
+
!values.length ||
|
|
1168
|
+
values.length > maximum ||
|
|
1169
|
+
values.some(
|
|
1170
|
+
(value) =>
|
|
1171
|
+
typeof value !== 'number' ||
|
|
1172
|
+
!Number.isSafeInteger(value) ||
|
|
1173
|
+
value < 0,
|
|
1174
|
+
)
|
|
1146
1175
|
)
|
|
1176
|
+
throw new Error(
|
|
1177
|
+
'Expected feature aliases with nonnegative integer indices.',
|
|
1178
|
+
)
|
|
1179
|
+
return { kind: 'descriptor', name, value: values.join(' ') }
|
|
1180
|
+
})
|
|
1181
|
+
entries.push({ kind: 'block', header, entries: declarations })
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
result.push({
|
|
1185
|
+
kind: 'block',
|
|
1186
|
+
header: `@font-feature-values ${familyList}`,
|
|
1187
|
+
entries,
|
|
1188
|
+
})
|
|
1189
|
+
} else if (call.kind === 'viewTransition') {
|
|
1190
|
+
const entries = Object.entries(record(input)).flatMap(
|
|
1191
|
+
([key, value]): Block.Entry[] => {
|
|
1192
|
+
if (value === undefined) return []
|
|
1193
|
+
if (
|
|
1194
|
+
(key !== 'navigation' && key !== 'types') ||
|
|
1195
|
+
typeof value !== 'string' ||
|
|
1196
|
+
(key === 'navigation' &&
|
|
1197
|
+
!['auto', 'none'].includes(
|
|
1198
|
+
Identifiers.list(value, 'space')?.join(' ').toLowerCase() ??
|
|
1199
|
+
'',
|
|
1200
|
+
))
|
|
1147
1201
|
)
|
|
1148
1202
|
throw new Error(
|
|
1149
|
-
'Expected
|
|
1203
|
+
'Expected navigation or types view-transition descriptors.',
|
|
1150
1204
|
)
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
'marginBlock',
|
|
1176
|
-
'marginBlockEnd',
|
|
1177
|
-
'marginBlockStart',
|
|
1178
|
-
'marginBottom',
|
|
1179
|
-
'marginInline',
|
|
1180
|
-
'marginInlineEnd',
|
|
1181
|
-
'marginInlineStart',
|
|
1182
|
-
'marginLeft',
|
|
1183
|
-
'marginRight',
|
|
1184
|
-
'marginTop',
|
|
1185
|
-
'maxBlockSize',
|
|
1186
|
-
'maxHeight',
|
|
1187
|
-
'maxInlineSize',
|
|
1188
|
-
'maxWidth',
|
|
1189
|
-
'minBlockSize',
|
|
1190
|
-
'minHeight',
|
|
1191
|
-
'minInlineSize',
|
|
1192
|
-
'minWidth',
|
|
1193
|
-
'placeSelf',
|
|
1194
|
-
'positionAnchor',
|
|
1195
|
-
'positionArea',
|
|
1196
|
-
'right',
|
|
1197
|
-
'top',
|
|
1198
|
-
'width',
|
|
1199
|
-
]
|
|
1200
|
-
if (Object.keys(declarations).some((key) => !keys.includes(key)))
|
|
1201
|
-
throw new Error('Unsupported position-try declaration.')
|
|
1202
|
-
const block = style(declarations)
|
|
1203
|
-
if (block.rules || block.declarations.some((value) => value.important))
|
|
1204
|
-
throw new Error(
|
|
1205
|
-
'Position-try forbids nested rules and important declarations.',
|
|
1206
|
-
)
|
|
1207
|
-
result.push({
|
|
1208
|
-
kind: 'rule',
|
|
1209
|
-
selector: `@position-try ${call.name}`,
|
|
1210
|
-
style: block,
|
|
1211
|
-
})
|
|
1212
|
-
} else if (
|
|
1213
|
-
call.kind === 'colorProfile' ||
|
|
1214
|
-
call.kind === 'counterStyle' ||
|
|
1215
|
-
call.kind === 'fontPaletteValues'
|
|
1216
|
-
) {
|
|
1217
|
-
const descriptors = {
|
|
1218
|
-
colorProfile: {
|
|
1219
|
-
rule: 'color-profile',
|
|
1220
|
-
keys: ['components', 'renderingIntent', 'src'],
|
|
1221
|
-
required: ['src'],
|
|
1222
|
-
},
|
|
1223
|
-
counterStyle: {
|
|
1224
|
-
rule: 'counter-style',
|
|
1225
|
-
keys: [
|
|
1226
|
-
'additiveSymbols',
|
|
1227
|
-
'fallback',
|
|
1228
|
-
'negative',
|
|
1229
|
-
'pad',
|
|
1230
|
-
'prefix',
|
|
1231
|
-
'range',
|
|
1232
|
-
'speakAs',
|
|
1233
|
-
'suffix',
|
|
1234
|
-
'symbols',
|
|
1235
|
-
'system',
|
|
1236
|
-
],
|
|
1237
|
-
required: [],
|
|
1238
|
-
},
|
|
1239
|
-
fontPaletteValues: {
|
|
1240
|
-
rule: 'font-palette-values',
|
|
1241
|
-
keys: ['basePalette', 'fontFamily', 'overrideColors'],
|
|
1242
|
-
required: ['fontFamily'],
|
|
1243
|
-
},
|
|
1244
|
-
} as const
|
|
1245
|
-
const definition = descriptors[call.kind]
|
|
1246
|
-
const declarations = record(input)
|
|
1247
|
-
for (const key of Object.keys(declarations))
|
|
1248
|
-
if (declarations[key] === undefined) delete declarations[key]
|
|
1249
|
-
if (
|
|
1250
|
-
definition.required.some(
|
|
1251
|
-
(key) => typeof declarations[key] !== 'string',
|
|
1252
|
-
) ||
|
|
1253
|
-
Object.entries(declarations).some(
|
|
1254
|
-
([key, value]) =>
|
|
1255
|
-
!(definition.keys as readonly string[]).includes(key) ||
|
|
1256
|
-
(typeof value !== 'string' &&
|
|
1257
|
-
!(
|
|
1258
|
-
key === 'basePalette' &&
|
|
1259
|
-
typeof value === 'number' &&
|
|
1260
|
-
Number.isSafeInteger(value) &&
|
|
1261
|
-
value >= 0
|
|
1262
|
-
)),
|
|
1205
|
+
if (key === 'types') {
|
|
1206
|
+
const names = Identifiers.list(value, 'space')
|
|
1207
|
+
if (
|
|
1208
|
+
!names ||
|
|
1209
|
+
names.some(
|
|
1210
|
+
(name) =>
|
|
1211
|
+
[
|
|
1212
|
+
'default',
|
|
1213
|
+
'inherit',
|
|
1214
|
+
'initial',
|
|
1215
|
+
'revert',
|
|
1216
|
+
'revert-layer',
|
|
1217
|
+
'unset',
|
|
1218
|
+
].includes(name.toLowerCase()) ||
|
|
1219
|
+
(name.toLowerCase() === 'none' && names.length !== 1),
|
|
1220
|
+
)
|
|
1221
|
+
)
|
|
1222
|
+
throw new Error(
|
|
1223
|
+
'Expected none or a list of view-transition custom identifiers.',
|
|
1224
|
+
)
|
|
1225
|
+
}
|
|
1226
|
+
Functions.value('*', String(value))
|
|
1227
|
+
return [{ kind: 'descriptor', name: key, value }]
|
|
1228
|
+
},
|
|
1263
1229
|
)
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1230
|
+
result.push({ kind: 'block', header: '@view-transition', entries })
|
|
1231
|
+
} else if (call.kind === 'positionTry') {
|
|
1232
|
+
const declarations = record(input)
|
|
1233
|
+
const keys = [
|
|
1234
|
+
'alignSelf',
|
|
1235
|
+
'blockSize',
|
|
1236
|
+
'bottom',
|
|
1237
|
+
'height',
|
|
1238
|
+
'inlineSize',
|
|
1239
|
+
'inset',
|
|
1240
|
+
'insetBlock',
|
|
1241
|
+
'insetBlockEnd',
|
|
1242
|
+
'insetBlockStart',
|
|
1243
|
+
'insetInline',
|
|
1244
|
+
'insetInlineEnd',
|
|
1245
|
+
'insetInlineStart',
|
|
1246
|
+
'justifySelf',
|
|
1247
|
+
'left',
|
|
1248
|
+
'margin',
|
|
1249
|
+
'marginBlock',
|
|
1250
|
+
'marginBlockEnd',
|
|
1251
|
+
'marginBlockStart',
|
|
1252
|
+
'marginBottom',
|
|
1253
|
+
'marginInline',
|
|
1254
|
+
'marginInlineEnd',
|
|
1255
|
+
'marginInlineStart',
|
|
1256
|
+
'marginLeft',
|
|
1257
|
+
'marginRight',
|
|
1258
|
+
'marginTop',
|
|
1259
|
+
'maxBlockSize',
|
|
1260
|
+
'maxHeight',
|
|
1261
|
+
'maxInlineSize',
|
|
1262
|
+
'maxWidth',
|
|
1263
|
+
'minBlockSize',
|
|
1264
|
+
'minHeight',
|
|
1265
|
+
'minInlineSize',
|
|
1266
|
+
'minWidth',
|
|
1267
|
+
'placeSelf',
|
|
1268
|
+
'positionAnchor',
|
|
1269
|
+
'positionArea',
|
|
1270
|
+
'right',
|
|
1271
|
+
'top',
|
|
1272
|
+
'width',
|
|
1273
|
+
]
|
|
1274
|
+
if (Object.keys(declarations).some((key) => !keys.includes(key)))
|
|
1275
|
+
throw new Error('Unsupported position-try declaration.')
|
|
1276
|
+
const block = style(declarations)
|
|
1277
|
+
if (
|
|
1278
|
+
block.rules ||
|
|
1279
|
+
block.declarations.some((value) => value.important)
|
|
1267
1280
|
)
|
|
1268
|
-
if (call.kind === 'colorProfile') {
|
|
1269
|
-
if (!Identifiers.url(declarations.src as string))
|
|
1270
|
-
throw new Error('Color-profile src requires one URL.')
|
|
1271
|
-
if (typeof declarations.components === 'string') {
|
|
1272
|
-
const names = Identifiers.list(declarations.components, 'comma')
|
|
1273
|
-
if (!names || names.some((name) => name.toLowerCase() === 'none'))
|
|
1274
|
-
throw new Error(
|
|
1275
|
-
'Color-profile components require comma-separated identifiers other than none.',
|
|
1276
|
-
)
|
|
1277
|
-
}
|
|
1278
|
-
if (typeof declarations.renderingIntent === 'string') {
|
|
1279
|
-
const names = Identifiers.list(
|
|
1280
|
-
declarations.renderingIntent,
|
|
1281
|
-
'space',
|
|
1282
|
-
)
|
|
1283
|
-
if (
|
|
1284
|
-
names?.length !== 1 ||
|
|
1285
|
-
![
|
|
1286
|
-
'absolute-colorimetric',
|
|
1287
|
-
'relative-colorimetric',
|
|
1288
|
-
'perceptual',
|
|
1289
|
-
'saturation',
|
|
1290
|
-
].includes(names[0]!.toLowerCase())
|
|
1291
|
-
)
|
|
1292
|
-
throw new Error('Invalid color-profile rendering intent.')
|
|
1293
|
-
}
|
|
1294
|
-
}
|
|
1295
|
-
if (call.kind === 'counterStyle') {
|
|
1296
|
-
const system =
|
|
1297
|
-
typeof declarations.system === 'string'
|
|
1298
|
-
? Lexical.normalize(declarations.system)
|
|
1299
|
-
.trim()
|
|
1300
|
-
.replace(/[A-Z]/g, (letter) => letter.toLowerCase())
|
|
1301
|
-
: 'symbolic'
|
|
1302
|
-
try {
|
|
1303
|
-
Descriptors.check({
|
|
1304
|
-
rule: 'counter-style',
|
|
1305
|
-
name: 'system',
|
|
1306
|
-
value:
|
|
1307
|
-
typeof declarations.system === 'string'
|
|
1308
|
-
? declarations.system
|
|
1309
|
-
: 'symbolic',
|
|
1310
|
-
})
|
|
1311
|
-
} catch {
|
|
1312
1281
|
throw new Error(
|
|
1313
|
-
'
|
|
1282
|
+
'Position-try forbids nested rules and important declarations.',
|
|
1314
1283
|
)
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1284
|
+
result.push({
|
|
1285
|
+
kind: 'rule',
|
|
1286
|
+
selector: `@position-try ${call.name}`,
|
|
1287
|
+
style: block,
|
|
1288
|
+
})
|
|
1289
|
+
} else if (
|
|
1290
|
+
call.kind === 'colorProfile' ||
|
|
1291
|
+
call.kind === 'counterStyle' ||
|
|
1292
|
+
call.kind === 'fontPaletteValues'
|
|
1293
|
+
) {
|
|
1294
|
+
const descriptors = {
|
|
1295
|
+
colorProfile: {
|
|
1296
|
+
rule: 'color-profile',
|
|
1297
|
+
keys: ['components', 'renderingIntent', 'src'],
|
|
1298
|
+
required: ['src'],
|
|
1299
|
+
},
|
|
1300
|
+
counterStyle: {
|
|
1301
|
+
rule: 'counter-style',
|
|
1302
|
+
keys: [
|
|
1303
|
+
'additiveSymbols',
|
|
1304
|
+
'fallback',
|
|
1305
|
+
'negative',
|
|
1306
|
+
'pad',
|
|
1307
|
+
'prefix',
|
|
1308
|
+
'range',
|
|
1309
|
+
'speakAs',
|
|
1310
|
+
'suffix',
|
|
1311
|
+
'symbols',
|
|
1312
|
+
'system',
|
|
1313
|
+
],
|
|
1314
|
+
required: [],
|
|
1315
|
+
},
|
|
1316
|
+
fontPaletteValues: {
|
|
1317
|
+
rule: 'font-palette-values',
|
|
1318
|
+
keys: ['basePalette', 'fontFamily', 'overrideColors'],
|
|
1319
|
+
required: ['fontFamily'],
|
|
1320
|
+
},
|
|
1321
|
+
} as const
|
|
1322
|
+
const definition = descriptors[call.kind]
|
|
1323
|
+
const declarations = record(input)
|
|
1324
|
+
for (const key of Object.keys(declarations))
|
|
1325
|
+
if (declarations[key] === undefined) delete declarations[key]
|
|
1322
1326
|
if (
|
|
1323
|
-
required
|
|
1324
|
-
|
|
1325
|
-
|
|
1327
|
+
definition.required.some(
|
|
1328
|
+
(key) => typeof declarations[key] !== 'string',
|
|
1329
|
+
) ||
|
|
1330
|
+
Object.entries(declarations).some(
|
|
1331
|
+
([key, value]) =>
|
|
1332
|
+
!(definition.keys as readonly string[]).includes(key) ||
|
|
1333
|
+
(typeof value !== 'string' &&
|
|
1334
|
+
!(
|
|
1335
|
+
key === 'basePalette' &&
|
|
1336
|
+
typeof value === 'number' &&
|
|
1337
|
+
Number.isSafeInteger(value) &&
|
|
1338
|
+
value >= 0
|
|
1339
|
+
)),
|
|
1340
|
+
)
|
|
1326
1341
|
)
|
|
1327
1342
|
throw new Error(
|
|
1328
|
-
'
|
|
1343
|
+
'Expected supported scalar descriptors and required fields.',
|
|
1329
1344
|
)
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
name
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1345
|
+
if (call.kind === 'colorProfile') {
|
|
1346
|
+
if (!Identifiers.url(declarations.src as string))
|
|
1347
|
+
throw new Error('Color-profile src requires one URL.')
|
|
1348
|
+
if (typeof declarations.components === 'string') {
|
|
1349
|
+
const names = Identifiers.list(declarations.components, 'comma')
|
|
1350
|
+
if (!names || names.some((name) => name.toLowerCase() === 'none'))
|
|
1351
|
+
throw new Error(
|
|
1352
|
+
'Color-profile components require comma-separated identifiers other than none.',
|
|
1353
|
+
)
|
|
1354
|
+
}
|
|
1355
|
+
if (typeof declarations.renderingIntent === 'string') {
|
|
1356
|
+
const names = Identifiers.list(
|
|
1357
|
+
declarations.renderingIntent,
|
|
1358
|
+
'space',
|
|
1359
|
+
)
|
|
1360
|
+
if (
|
|
1361
|
+
names?.length !== 1 ||
|
|
1362
|
+
![
|
|
1363
|
+
'absolute-colorimetric',
|
|
1364
|
+
'relative-colorimetric',
|
|
1365
|
+
'perceptual',
|
|
1366
|
+
'saturation',
|
|
1367
|
+
].includes(names[0]!.toLowerCase())
|
|
1368
|
+
)
|
|
1369
|
+
throw new Error('Invalid color-profile rendering intent.')
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
if (call.kind === 'counterStyle') {
|
|
1373
|
+
const system =
|
|
1374
|
+
typeof declarations.system === 'string'
|
|
1375
|
+
? Lexical.normalize(declarations.system)
|
|
1376
|
+
.trim()
|
|
1377
|
+
.replace(/[A-Z]/g, (letter) => letter.toLowerCase())
|
|
1378
|
+
: 'symbolic'
|
|
1379
|
+
try {
|
|
1380
|
+
Descriptors.check({
|
|
1381
|
+
rule: 'counter-style',
|
|
1382
|
+
name: 'system',
|
|
1383
|
+
value:
|
|
1384
|
+
typeof declarations.system === 'string'
|
|
1385
|
+
? declarations.system
|
|
1386
|
+
: 'symbolic',
|
|
1387
|
+
})
|
|
1388
|
+
} catch {
|
|
1389
|
+
throw new Error(
|
|
1390
|
+
'Expected a supported counter system, with an integer after fixed.',
|
|
1391
|
+
)
|
|
1392
|
+
}
|
|
1393
|
+
const required =
|
|
1394
|
+
system === 'additive'
|
|
1395
|
+
? 'additiveSymbols'
|
|
1396
|
+
: system.startsWith('extends ')
|
|
1397
|
+
? undefined
|
|
1398
|
+
: 'symbols'
|
|
1399
|
+
if (
|
|
1400
|
+
required &&
|
|
1401
|
+
(typeof declarations[required] !== 'string' ||
|
|
1402
|
+
!(declarations[required] as string).trim())
|
|
1349
1403
|
)
|
|
1404
|
+
throw new Error(
|
|
1405
|
+
'The counter system requires symbols or additiveSymbols.',
|
|
1406
|
+
)
|
|
1407
|
+
}
|
|
1408
|
+
if (call.kind !== 'colorProfile')
|
|
1409
|
+
for (const [name, value] of Object.entries(declarations))
|
|
1410
|
+
Descriptors.check({
|
|
1411
|
+
rule: definition.rule,
|
|
1412
|
+
name,
|
|
1413
|
+
value: String(value),
|
|
1414
|
+
})
|
|
1415
|
+
result.push({
|
|
1416
|
+
kind: 'descriptor',
|
|
1417
|
+
rule: definition.rule,
|
|
1418
|
+
name: call.name!,
|
|
1419
|
+
declarations: declarations as Record<string, string | number>,
|
|
1420
|
+
})
|
|
1421
|
+
} else {
|
|
1422
|
+
const frames = Object.entries(record(input)).map(([stop, input]) => {
|
|
1423
|
+
if (!Keyframes.accepts(stop))
|
|
1424
|
+
throw new Error(
|
|
1425
|
+
'Keyframe stops require from, to, 0–100% offsets, or named timeline percentages.',
|
|
1426
|
+
)
|
|
1350
1427
|
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
)
|
|
1356
|
-
throw new Error(
|
|
1357
|
-
'Keyframes forbid nested rules and important declarations.',
|
|
1428
|
+
const frame = style(input)
|
|
1429
|
+
if (
|
|
1430
|
+
frame.rules ||
|
|
1431
|
+
frame.declarations.some((value) => value.important)
|
|
1358
1432
|
)
|
|
1433
|
+
throw new Error(
|
|
1434
|
+
'Keyframes forbid nested rules and important declarations.',
|
|
1435
|
+
)
|
|
1359
1436
|
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
if (call.exported || scanned.used.has(call.name!))
|
|
1364
|
-
result.push({ kind: 'keyframes', name: call.name!, frames })
|
|
1365
|
-
}
|
|
1366
|
-
const contextValue = call.context ? value(call.context) : undefined
|
|
1367
|
-
if (contextValue !== undefined) {
|
|
1368
|
-
const context = record(contextValue)
|
|
1369
|
-
if (Object.keys(context).some((key) => !['id', 'within'].includes(key)))
|
|
1370
|
-
throw new Error('Unknown contribution context option.')
|
|
1371
|
-
if (call.kind === 'customMedia' && 'within' in context)
|
|
1372
|
-
throw new Error(
|
|
1373
|
-
'Custom media definitions do not accept a within context.',
|
|
1374
|
-
)
|
|
1437
|
+
return { stop, style: frame }
|
|
1438
|
+
})
|
|
1375
1439
|
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
/^@(media|supports|container|layer)(?=[\t\n\r\f (/])/.test(
|
|
1385
|
-
header,
|
|
1386
|
-
)
|
|
1387
|
-
),
|
|
1388
|
-
)
|
|
1389
|
-
)
|
|
1390
|
-
throw new Error('Expected enclosing conditional or layer headers.')
|
|
1391
|
-
const headers = within.map((header: string) =>
|
|
1392
|
-
Condition.normalize(header),
|
|
1393
|
-
)
|
|
1394
|
-
for (let index = before; index < result.length; index++)
|
|
1395
|
-
result[index] = { ...result[index]!, within: headers }
|
|
1440
|
+
if (call.exported || scanned.used.has(call.name!))
|
|
1441
|
+
result.push({ kind: 'keyframes', name: call.name!, frames })
|
|
1442
|
+
}
|
|
1443
|
+
for (let index = before; index < result.length; index++) {
|
|
1444
|
+
if (headers.length)
|
|
1445
|
+
result[index] = { ...result[index]!, within: headers }
|
|
1446
|
+
starts?.push(call.start)
|
|
1447
|
+
}
|
|
1396
1448
|
}
|
|
1397
|
-
|
|
1398
|
-
for (let index = before; index < result.length; index++)
|
|
1399
|
-
starts?.push(call.start)
|
|
1400
1449
|
} catch (error) {
|
|
1401
1450
|
throw new Themes.InvalidError((error as Error).message, call)
|
|
1402
1451
|
}
|