zyzz 0.0.18 → 0.0.20
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 +9 -9
- package/dist/Config.d.ts +1 -0
- package/dist/Config.d.ts.map +1 -1
- package/dist/Config.js.map +1 -1
- package/dist/Vars.d.ts +22 -15
- package/dist/Vars.d.ts.map +1 -1
- package/dist/Vars.js +26 -0
- package/dist/Vars.js.map +1 -1
- package/dist/cli/index.js +5 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/compiler/Source.d.ts.map +1 -1
- package/dist/compiler/Source.js +3 -0
- package/dist/compiler/Source.js.map +1 -1
- package/dist/compiler/internal/Configurations.d.ts.map +1 -1
- package/dist/compiler/internal/Configurations.js +3 -0
- package/dist/compiler/internal/Configurations.js.map +1 -1
- package/dist/compiler/internal/Contract.d.ts.map +1 -1
- package/dist/compiler/internal/Contract.js +30 -4
- package/dist/compiler/internal/Contract.js.map +1 -1
- package/dist/compiler/internal/Themes.d.ts.map +1 -1
- package/dist/compiler/internal/Themes.js +83 -23
- package/dist/compiler/internal/Themes.js.map +1 -1
- package/dist/default.d.ts +7 -11
- package/dist/default.d.ts.map +1 -1
- package/dist/default.js +4 -5
- package/dist/default.js.map +2 -2
- package/dist/default.js.zyzz.json +1 -1
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -1
- package/dist/internal/Token.d.ts +11 -2
- package/dist/internal/Token.d.ts.map +1 -1
- package/dist/internal/Token.js +2 -0
- package/dist/internal/Token.js.map +1 -1
- package/dist/internal/VariableSets.d.ts.map +1 -1
- package/dist/internal/VariableSets.js +18 -1
- package/dist/internal/VariableSets.js.map +1 -1
- package/dist/node/Host.d.ts +2 -0
- package/dist/node/Host.d.ts.map +1 -1
- package/dist/node/Host.js +7 -0
- package/dist/node/Host.js.map +1 -1
- package/dist/oxlint/index.d.ts +6 -0
- package/dist/oxlint/index.d.ts.map +1 -0
- package/dist/oxlint/index.js +18 -0
- package/dist/oxlint/index.js.map +1 -0
- package/dist/oxlint/internal/Bindings.d.ts +20 -0
- package/dist/oxlint/internal/Bindings.d.ts.map +1 -0
- package/dist/oxlint/internal/Bindings.js +203 -0
- package/dist/oxlint/internal/Bindings.js.map +1 -0
- package/dist/oxlint/internal/Declarations.d.ts +19 -0
- package/dist/oxlint/internal/Declarations.d.ts.map +1 -0
- package/dist/oxlint/internal/Declarations.js +114 -0
- package/dist/oxlint/internal/Declarations.js.map +1 -0
- package/dist/oxlint/rules/noConflictingProps.d.ts +5 -0
- package/dist/oxlint/rules/noConflictingProps.d.ts.map +1 -0
- package/dist/oxlint/rules/noConflictingProps.js +45 -0
- package/dist/oxlint/rules/noConflictingProps.js.map +1 -0
- package/dist/oxlint/rules/noUnused.d.ts +5 -0
- package/dist/oxlint/rules/noUnused.d.ts.map +1 -0
- package/dist/oxlint/rules/noUnused.js +62 -0
- package/dist/oxlint/rules/noUnused.js.map +1 -0
- package/dist/oxlint/rules/restrictedProperties.d.ts +5 -0
- package/dist/oxlint/rules/restrictedProperties.d.ts.map +1 -0
- package/dist/oxlint/rules/restrictedProperties.js +82 -0
- package/dist/oxlint/rules/restrictedProperties.js.map +1 -0
- package/dist/oxlint/rules/useLogicalProperties.d.ts +5 -0
- package/dist/oxlint/rules/useLogicalProperties.d.ts.map +1 -0
- package/dist/oxlint/rules/useLogicalProperties.js +76 -0
- package/dist/oxlint/rules/useLogicalProperties.js.map +1 -0
- package/dist/oxlint/rules/validStyles.d.ts +5 -0
- package/dist/oxlint/rules/validStyles.d.ts.map +1 -0
- package/dist/oxlint/rules/validStyles.js +75 -0
- package/dist/oxlint/rules/validStyles.js.map +1 -0
- package/dist/react-native/StyleSheet.js +2 -0
- package/dist/react-native/StyleSheet.js.map +1 -1
- package/dist/runtime/Composition.d.ts +1 -1
- package/dist/runtime/ConditionalRecipe.d.ts +1 -1
- package/dist/runtime/PayloadRecipe.d.ts +1 -1
- package/dist/runtime/Recipe.d.ts +1 -1
- package/dist/styleFunction.d.ts +1 -1
- package/dist/styleFunction.d.ts.map +1 -1
- package/dist/styleFunction.js.map +1 -1
- package/dist/variants.d.ts +14 -6
- package/dist/variants.d.ts.map +1 -1
- package/dist/variants.js.map +1 -1
- package/dist/vite/index.d.ts +2 -0
- package/dist/vite/index.d.ts.map +1 -1
- package/dist/vite/index.js +75 -30
- package/dist/vite/index.js.map +1 -1
- package/dist/web/internal/Themes.d.ts.map +1 -1
- package/dist/web/internal/Themes.js +4 -0
- package/dist/web/internal/Themes.js.map +1 -1
- package/package.json +7 -1
- package/src/Config.ts +5 -0
- package/src/Vars.ts +88 -29
- package/src/cli/index.ts +5 -0
- package/src/compiler/Source.ts +3 -0
- package/src/compiler/internal/Configurations.ts +3 -0
- package/src/compiler/internal/Contract.ts +47 -4
- package/src/compiler/internal/Themes.ts +109 -34
- package/src/default.ts +8 -10
- package/src/index.ts +15 -0
- package/src/internal/Authoring.ts +1 -1
- package/src/internal/Token.ts +39 -11
- package/src/internal/VariableSets.ts +25 -1
- package/src/node/Host.ts +19 -0
- package/src/oxlint/index.ts +21 -0
- package/src/oxlint/internal/Bindings.ts +270 -0
- package/src/oxlint/internal/Declarations.ts +137 -0
- package/src/oxlint/rules/noConflictingProps.ts +52 -0
- package/src/oxlint/rules/noUnused.ts +67 -0
- package/src/oxlint/rules/restrictedProperties.ts +92 -0
- package/src/oxlint/rules/useLogicalProperties.ts +81 -0
- package/src/oxlint/rules/validStyles.ts +88 -0
- package/src/react-native/StyleSheet.ts +6 -0
- package/src/styleFunction.ts +1 -3
- package/src/variants.ts +38 -16
- package/src/vite/index.ts +94 -33
- package/src/web/internal/Themes.ts +4 -0
package/src/vite/index.ts
CHANGED
|
@@ -69,6 +69,7 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
69
69
|
const sourceEntrypoints = new Set<string>()
|
|
70
70
|
const identities = new Map<string, string>()
|
|
71
71
|
const lazyImports = new WeakMap<Parser.ParseResult, string[]>()
|
|
72
|
+
let directories: readonly string[]
|
|
72
73
|
let root: string
|
|
73
74
|
|
|
74
75
|
function snapshot(environment: Environment) {
|
|
@@ -94,12 +95,33 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
94
95
|
function sourceId(file: string) {
|
|
95
96
|
let id = identities.get(file)
|
|
96
97
|
if (!id) {
|
|
97
|
-
|
|
98
|
+
const directory = sourceRoot(file) ?? root
|
|
99
|
+
const namespace =
|
|
100
|
+
directory === root
|
|
101
|
+
? 'app'
|
|
102
|
+
: `include-${directories.indexOf(directory) - 1}`
|
|
103
|
+
id = `${namespace}/${Path.relative(directory, file).split(Path.sep).join('/')}`
|
|
98
104
|
identities.set(file, id)
|
|
99
105
|
}
|
|
100
106
|
return id
|
|
101
107
|
}
|
|
102
108
|
|
|
109
|
+
// Included directories have portable namespaces rather than traversal IDs.
|
|
110
|
+
function sourceFile(id: string) {
|
|
111
|
+
const offset = id.indexOf('/')
|
|
112
|
+
const namespace = id.slice(0, offset)
|
|
113
|
+
const directory = (() => {
|
|
114
|
+
if (namespace === 'app') return root
|
|
115
|
+
if (/^include-\d+$/.test(namespace))
|
|
116
|
+
return directories[Number(namespace.slice(8)) + 1]
|
|
117
|
+
return undefined
|
|
118
|
+
})()
|
|
119
|
+
|
|
120
|
+
return directory === undefined
|
|
121
|
+
? undefined
|
|
122
|
+
: Path.join(directory, id.slice(offset + 1))
|
|
123
|
+
}
|
|
124
|
+
|
|
103
125
|
function resource(id: string) {
|
|
104
126
|
const query = id.split('?')[1]?.split('#')[0]
|
|
105
127
|
|
|
@@ -119,17 +141,28 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
119
141
|
if (sourceEntrypoints.has(normalize(id))) return true
|
|
120
142
|
// Ids carrying foreign queries are Vite resources such as inline-module proxies, not source.
|
|
121
143
|
if (resource(id)) return false
|
|
122
|
-
const relative = Path.relative(root, id)
|
|
123
144
|
|
|
124
145
|
return (
|
|
125
146
|
Path.isAbsolute(id) &&
|
|
126
|
-
|
|
127
|
-
!relative.split(Path.sep).includes('node_modules') &&
|
|
147
|
+
sourceRoot(id) !== undefined &&
|
|
128
148
|
/\.[cm]?[jt]sx?$/.test(id) &&
|
|
129
|
-
!/\.(?:d|test|test-d|bench)\.[cm]?[jt]sx?$/.test(id)
|
|
149
|
+
!/\.(?:d|test|test-d|bench|bench-d)\.[cm]?[jt]sx?$/.test(id)
|
|
130
150
|
)
|
|
131
151
|
}
|
|
132
152
|
|
|
153
|
+
function sourceRoot(file: string) {
|
|
154
|
+
return directories.find((directory) => {
|
|
155
|
+
const relative = Path.relative(directory, file)
|
|
156
|
+
|
|
157
|
+
return (
|
|
158
|
+
relative !== '..' &&
|
|
159
|
+
!relative.startsWith(`..${Path.sep}`) &&
|
|
160
|
+
!Path.isAbsolute(relative) &&
|
|
161
|
+
!relative.split(Path.sep).includes('node_modules')
|
|
162
|
+
)
|
|
163
|
+
})
|
|
164
|
+
}
|
|
165
|
+
|
|
133
166
|
function discover(environment: Environment, host: Host) {
|
|
134
167
|
let pending = discoveries.get(environment)
|
|
135
168
|
|
|
@@ -137,10 +170,14 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
137
170
|
pending = (async () => {
|
|
138
171
|
const sources = new Map<string, string>()
|
|
139
172
|
const eagerFiles = new Set<string>()
|
|
173
|
+
const visited = new Set<string>()
|
|
140
174
|
|
|
141
175
|
contributionFiles.set(environment, eagerFiles)
|
|
142
176
|
|
|
143
177
|
async function collect(directory: string): Promise<void> {
|
|
178
|
+
if (visited.has(directory)) return
|
|
179
|
+
visited.add(directory)
|
|
180
|
+
|
|
144
181
|
for (const item of await Fs.readdir(directory, {
|
|
145
182
|
withFileTypes: true,
|
|
146
183
|
})) {
|
|
@@ -163,7 +200,7 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
163
200
|
const file = Path.join(directory, item.name)
|
|
164
201
|
|
|
165
202
|
if (item.isDirectory()) await collect(file)
|
|
166
|
-
else if (item.isFile() && eager(file)) {
|
|
203
|
+
else if (item.isFile() && eager(file, environment)) {
|
|
167
204
|
host.watch(file)
|
|
168
205
|
|
|
169
206
|
const source = await Fs.readFile(file, 'utf8')
|
|
@@ -175,7 +212,7 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
175
212
|
}
|
|
176
213
|
}
|
|
177
214
|
|
|
178
|
-
await collect(
|
|
215
|
+
for (const directory of directories) await collect(directory)
|
|
179
216
|
|
|
180
217
|
return sources
|
|
181
218
|
})()
|
|
@@ -185,10 +222,17 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
185
222
|
return pending
|
|
186
223
|
}
|
|
187
224
|
|
|
188
|
-
function eager(file: string) {
|
|
225
|
+
function eager(file: string, environment: Environment) {
|
|
189
226
|
return (
|
|
190
227
|
eligible(file) &&
|
|
191
|
-
|
|
228
|
+
file !== environment.config.configFile &&
|
|
229
|
+
!environment.config.configFileDependencies.includes(file) &&
|
|
230
|
+
// Server entrypoints must not contribute to the client stylesheet scan.
|
|
231
|
+
!(
|
|
232
|
+
environment.config.consumer === 'client' &&
|
|
233
|
+
/\.server\.[cm]?[jt]sx?$/.test(file)
|
|
234
|
+
) &&
|
|
235
|
+
!Path.relative(sourceRoot(file)!, file)
|
|
192
236
|
.split(Path.sep)
|
|
193
237
|
.some((part) =>
|
|
194
238
|
['test', 'tests', '__tests__', 'fixtures', '__fixtures__'].includes(
|
|
@@ -323,7 +367,7 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
323
367
|
}
|
|
324
368
|
|
|
325
369
|
const pending = discoveries.get(environment)
|
|
326
|
-
if (!pending || !eager(file)) return
|
|
370
|
+
if (!pending || !eager(file, environment)) return
|
|
327
371
|
|
|
328
372
|
const sources = await pending
|
|
329
373
|
|
|
@@ -733,7 +777,7 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
733
777
|
map: {
|
|
734
778
|
...output.map,
|
|
735
779
|
sources: output.map.sources.map((source) =>
|
|
736
|
-
source === null ? null :
|
|
780
|
+
source === null ? null : (sourceFile(source) ?? source),
|
|
737
781
|
),
|
|
738
782
|
},
|
|
739
783
|
}
|
|
@@ -773,7 +817,7 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
773
817
|
let line = 0
|
|
774
818
|
|
|
775
819
|
for (const [id, output] of Object.entries(result.modules)) {
|
|
776
|
-
if (!connected.has(
|
|
820
|
+
if (!connected.has(sourceFile(id)!)) continue
|
|
777
821
|
if (!output.css) continue
|
|
778
822
|
|
|
779
823
|
for (const mapping of Mapping.allMappings(
|
|
@@ -788,7 +832,7 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
788
832
|
const location = {
|
|
789
833
|
generated,
|
|
790
834
|
original: mapping.original,
|
|
791
|
-
source:
|
|
835
|
+
source: sourceFile(mapping.source) ?? mapping.source,
|
|
792
836
|
}
|
|
793
837
|
|
|
794
838
|
if (mapping.name === undefined) Mapping.addMapping(map, location)
|
|
@@ -800,7 +844,7 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
800
844
|
if (source !== null)
|
|
801
845
|
Mapping.setSourceContent(
|
|
802
846
|
map,
|
|
803
|
-
|
|
847
|
+
sourceFile(source) ?? source,
|
|
804
848
|
output.cssMap.sourcesContent?.[index] ?? null,
|
|
805
849
|
)
|
|
806
850
|
|
|
@@ -808,7 +852,6 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
808
852
|
line += output.css.split('\n').length
|
|
809
853
|
}
|
|
810
854
|
|
|
811
|
-
const appRoot = await Fs.realpath(root)
|
|
812
855
|
const owners = new Map<string, string>()
|
|
813
856
|
|
|
814
857
|
for (const id of new Set(Object.values(result.sharedAssetOwners ?? {}))) {
|
|
@@ -839,11 +882,9 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
839
882
|
const raw = target.split(/[?#]/)[0]!
|
|
840
883
|
|
|
841
884
|
const identity = result.sharedAssetOwners?.[key]
|
|
842
|
-
const path =
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
? decodeURIComponent(raw)
|
|
846
|
-
: undefined
|
|
885
|
+
const path =
|
|
886
|
+
sourceFile(decodeURIComponent(raw)) ??
|
|
887
|
+
(Path.isAbsolute(raw) ? decodeURIComponent(raw) : undefined)
|
|
847
888
|
if (!path) throw new Error('Asset path escapes the Vite graph.')
|
|
848
889
|
|
|
849
890
|
const asset = await (async () => {
|
|
@@ -852,11 +893,12 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
852
893
|
} catch (error) {
|
|
853
894
|
if (
|
|
854
895
|
(error as NodeJS.ErrnoException).code !== 'ENOENT' ||
|
|
855
|
-
!identity
|
|
896
|
+
!identity ||
|
|
897
|
+
!sourceFile(identity)
|
|
856
898
|
)
|
|
857
899
|
throw error
|
|
858
900
|
|
|
859
|
-
const importer =
|
|
901
|
+
const importer = sourceFile(identity)!
|
|
860
902
|
const specifier = Path.relative(Path.dirname(importer), path)
|
|
861
903
|
.split(Path.sep)
|
|
862
904
|
.join('/')
|
|
@@ -872,11 +914,12 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
872
914
|
})()
|
|
873
915
|
const file = asset.file
|
|
874
916
|
|
|
875
|
-
const owner =
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
917
|
+
const owner =
|
|
918
|
+
identity && sourceFile(identity)
|
|
919
|
+
? sourceRoot(sourceFile(identity)!)
|
|
920
|
+
: identity
|
|
921
|
+
? owners.get(identity)
|
|
922
|
+
: undefined
|
|
880
923
|
|
|
881
924
|
const relative = owner ? Path.relative(owner, file) : '..'
|
|
882
925
|
if (
|
|
@@ -961,7 +1004,7 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
961
1004
|
) as Mapping.EncodedSourceMap
|
|
962
1005
|
|
|
963
1006
|
sharedMap.sources = sharedMap.sources.map((source) =>
|
|
964
|
-
source
|
|
1007
|
+
source === null ? null : (sourceFile(source) ?? source),
|
|
965
1008
|
)
|
|
966
1009
|
|
|
967
1010
|
const output = result.modules[sourceId(entry.file)]!
|
|
@@ -982,7 +1025,7 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
982
1025
|
map: {
|
|
983
1026
|
...output.map,
|
|
984
1027
|
sources: output.map.sources.map((source) =>
|
|
985
|
-
source === null ? null :
|
|
1028
|
+
source === null ? null : (sourceFile(source) ?? source),
|
|
986
1029
|
),
|
|
987
1030
|
},
|
|
988
1031
|
}
|
|
@@ -1219,6 +1262,9 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
1219
1262
|
},
|
|
1220
1263
|
},
|
|
1221
1264
|
configureServer(server) {
|
|
1265
|
+
// Directory watches belong to the server, not module import dependencies.
|
|
1266
|
+
server.watcher.add(directories.slice(1))
|
|
1267
|
+
|
|
1222
1268
|
server.middlewares.use((request, response, next) => {
|
|
1223
1269
|
const path = new URL(request.url ?? '/', 'http://localhost').pathname
|
|
1224
1270
|
const file = assets.get(path)
|
|
@@ -1236,8 +1282,21 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
1236
1282
|
}, next)
|
|
1237
1283
|
})
|
|
1238
1284
|
},
|
|
1239
|
-
configResolved(config) {
|
|
1240
|
-
root = config.root
|
|
1285
|
+
async configResolved(config) {
|
|
1286
|
+
root = await Fs.realpath(config.root)
|
|
1287
|
+
directories = [
|
|
1288
|
+
root,
|
|
1289
|
+
...(await Promise.all(
|
|
1290
|
+
(options.include ?? []).map(async (directory) => {
|
|
1291
|
+
const file = await Fs.realpath(Path.resolve(root, directory))
|
|
1292
|
+
if (!(await Fs.stat(file)).isDirectory())
|
|
1293
|
+
throw new Error(
|
|
1294
|
+
`Zyzz include paths must be directories: ${directory}`,
|
|
1295
|
+
)
|
|
1296
|
+
return file
|
|
1297
|
+
}),
|
|
1298
|
+
)),
|
|
1299
|
+
]
|
|
1241
1300
|
if (native) return
|
|
1242
1301
|
const lightning = (config.css.lightningcss ??= {})
|
|
1243
1302
|
lightning.include =
|
|
@@ -1336,7 +1395,7 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
1336
1395
|
|
|
1337
1396
|
const state = entries(this.environment)
|
|
1338
1397
|
const first = [...state.values()].find(
|
|
1339
|
-
(entry) => entry.files.has(file) || eager(file),
|
|
1398
|
+
(entry) => entry.files.has(file) || eager(file, this.environment),
|
|
1340
1399
|
)
|
|
1341
1400
|
if (!first && !removed.get(this.environment)?.has(file)) return modules
|
|
1342
1401
|
|
|
@@ -1374,7 +1433,7 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
1374
1433
|
if (type === 'delete') ids.add(cssId(file))
|
|
1375
1434
|
|
|
1376
1435
|
for (const entry of entries(this.environment).values()) {
|
|
1377
|
-
if (!entry.files.has(file) && !eager(file)) continue
|
|
1436
|
+
if (!entry.files.has(file) && !eager(file, this.environment)) continue
|
|
1378
1437
|
|
|
1379
1438
|
// Theme scopes affect CSS even when Vite's JavaScript import was erased.
|
|
1380
1439
|
if (
|
|
@@ -1635,6 +1694,8 @@ export declare namespace zyzz {
|
|
|
1635
1694
|
type Options = {
|
|
1636
1695
|
/** False retains authored calls and requires explicit identities where needed. */
|
|
1637
1696
|
readonly compiler?: boolean | undefined
|
|
1697
|
+
/** Additional source directories, absolute or relative to the Vite root. */
|
|
1698
|
+
readonly include?: readonly string[] | undefined
|
|
1638
1699
|
/** Native context captured at creation. Disables CSS delivery and initialization scripts. */
|
|
1639
1700
|
readonly native?: Graph.compile.Options['native']
|
|
1640
1701
|
/** Include the CSS reset. Defaults to false. */
|
|
@@ -220,6 +220,10 @@ export function create() {
|
|
|
220
220
|
owner?: Token.Contract,
|
|
221
221
|
): string {
|
|
222
222
|
if (Token.is(value)) return serialize(value)
|
|
223
|
+
if (Token.isExpression(value))
|
|
224
|
+
return value.parts
|
|
225
|
+
.map((part) => (typeof part === 'string' ? part : serialize(part)))
|
|
226
|
+
.join('')
|
|
223
227
|
if (typeof value !== 'object') return String(value)
|
|
224
228
|
if ('default' in value) {
|
|
225
229
|
// Separate fallback properties preserve extensions and resolve references within each scope.
|