zyzz 0.0.19 → 0.0.21
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/Style.d.ts +7 -0
- package/dist/Style.d.ts.map +1 -1
- package/dist/Style.js +1 -5
- package/dist/Style.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/Graph.d.ts +3 -0
- package/dist/compiler/Graph.d.ts.map +1 -1
- package/dist/compiler/Graph.js +44 -37
- package/dist/compiler/Graph.js.map +1 -1
- package/dist/compiler/Source.d.ts +4 -0
- package/dist/compiler/Source.d.ts.map +1 -1
- package/dist/compiler/Source.js +66 -6
- package/dist/compiler/Source.js.map +1 -1
- package/dist/compiler/Transform.d.ts +4 -1
- package/dist/compiler/Transform.d.ts.map +1 -1
- package/dist/compiler/Transform.js +32 -46
- package/dist/compiler/Transform.js.map +1 -1
- package/dist/compiler/internal/Catalogs.d.ts.map +1 -1
- package/dist/compiler/internal/Catalogs.js +6 -1
- package/dist/compiler/internal/Catalogs.js.map +1 -1
- package/dist/compiler/internal/Compositions.d.ts.map +1 -1
- package/dist/compiler/internal/Compositions.js +5 -0
- package/dist/compiler/internal/Compositions.js.map +1 -1
- package/dist/compiler/internal/Configurations.d.ts.map +1 -1
- package/dist/compiler/internal/Configurations.js +5 -1
- package/dist/compiler/internal/Configurations.js.map +1 -1
- package/dist/compiler/internal/Contract.d.ts +4 -1
- package/dist/compiler/internal/Contract.d.ts.map +1 -1
- package/dist/compiler/internal/Contract.js +73 -138
- 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 +1 -3
- package/dist/compiler/internal/Contributions.js.map +1 -1
- package/dist/compiler/internal/Dynamic.d.ts +1 -1
- package/dist/compiler/internal/Dynamic.d.ts.map +1 -1
- package/dist/compiler/internal/Dynamic.js +5 -5
- package/dist/compiler/internal/Dynamic.js.map +1 -1
- package/dist/compiler/internal/Names.d.ts +5 -0
- package/dist/compiler/internal/Names.d.ts.map +1 -0
- package/dist/compiler/internal/Names.js +37 -0
- package/dist/compiler/internal/Names.js.map +1 -0
- package/dist/compiler/internal/Selectors.d.ts +1 -1
- package/dist/compiler/internal/Selectors.d.ts.map +1 -1
- package/dist/compiler/internal/Selectors.js +5 -2
- package/dist/compiler/internal/Selectors.js.map +1 -1
- package/dist/compiler/internal/Stylesheets.js +2 -2
- package/dist/compiler/internal/Stylesheets.js.map +1 -1
- package/dist/compiler/internal/Themes.d.ts.map +1 -1
- package/dist/compiler/internal/Themes.js +85 -24
- package/dist/compiler/internal/Themes.js.map +1 -1
- package/dist/compiler/internal/Vars.d.ts +2 -0
- package/dist/compiler/internal/Vars.d.ts.map +1 -1
- package/dist/compiler/internal/Vars.js +7 -1
- package/dist/compiler/internal/Vars.js.map +1 -1
- package/dist/default.d.ts +11 -15
- package/dist/default.d.ts.map +1 -1
- package/dist/default.js +13 -14
- 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/Authoring.d.ts.map +1 -1
- package/dist/internal/Authoring.js +8 -3
- package/dist/internal/Authoring.js.map +1 -1
- package/dist/internal/Binding.d.ts +4 -0
- package/dist/internal/Binding.d.ts.map +1 -1
- package/dist/internal/Binding.js +2 -0
- package/dist/internal/Binding.js.map +1 -1
- package/dist/internal/Configuration.d.ts +2 -2
- package/dist/internal/Configuration.d.ts.map +1 -1
- package/dist/internal/Configuration.js +4 -2
- package/dist/internal/Configuration.js.map +1 -1
- package/dist/internal/Identity.d.ts +3 -3
- package/dist/internal/Identity.d.ts.map +1 -1
- package/dist/internal/Identity.js +11 -9
- package/dist/internal/Identity.js.map +1 -1
- package/dist/internal/Theme.js +2 -2
- package/dist/internal/Theme.js.map +1 -1
- package/dist/internal/Token.d.ts +16 -3
- package/dist/internal/Token.d.ts.map +1 -1
- package/dist/internal/Token.js +11 -2
- package/dist/internal/Token.js.map +1 -1
- package/dist/internal/VariableSets.d.ts.map +1 -1
- package/dist/internal/VariableSets.js +19 -2
- 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 +9 -0
- package/dist/node/Host.js.map +1 -1
- 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/variable.js +1 -1
- package/dist/variable.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 +111 -42
- package/dist/vite/index.js.map +1 -1
- package/dist/web/Css.d.ts +7 -2
- package/dist/web/Css.d.ts.map +1 -1
- package/dist/web/Css.js +46 -39
- package/dist/web/Css.js.map +1 -1
- package/dist/web/internal/ClassName.d.ts +13 -2
- package/dist/web/internal/ClassName.d.ts.map +1 -1
- package/dist/web/internal/ClassName.js +17 -30
- package/dist/web/internal/ClassName.js.map +1 -1
- package/dist/web/internal/Themes.d.ts +3 -0
- package/dist/web/internal/Themes.d.ts.map +1 -1
- package/dist/web/internal/Themes.js +52 -24
- package/dist/web/internal/Themes.js.map +1 -1
- package/package.json +1 -1
- package/src/Config.ts +5 -0
- package/src/Style.ts +4 -1
- package/src/Vars.ts +88 -29
- package/src/cli/index.ts +5 -0
- package/src/compiler/Graph.ts +60 -46
- package/src/compiler/Source.ts +86 -5
- package/src/compiler/Transform.ts +42 -60
- package/src/compiler/internal/Catalogs.ts +9 -1
- package/src/compiler/internal/Compositions.ts +7 -0
- package/src/compiler/internal/Configurations.ts +5 -1
- package/src/compiler/internal/Contract.ts +104 -239
- package/src/compiler/internal/Contributions.ts +1 -5
- package/src/compiler/internal/Dynamic.ts +14 -9
- package/src/compiler/internal/Names.ts +48 -0
- package/src/compiler/internal/Selectors.ts +6 -1
- package/src/compiler/internal/Stylesheets.ts +2 -2
- package/src/compiler/internal/Themes.ts +115 -35
- package/src/compiler/internal/Vars.ts +9 -1
- package/src/default.ts +17 -20
- package/src/index.ts +15 -0
- package/src/internal/Authoring.ts +9 -3
- package/src/internal/Binding.ts +5 -0
- package/src/internal/Configuration.ts +7 -4
- package/src/internal/Identity.ts +14 -12
- package/src/internal/Theme.ts +2 -2
- package/src/internal/Token.ts +52 -12
- package/src/internal/VariableSets.ts +26 -2
- package/src/node/Host.ts +22 -0
- package/src/react-native/StyleSheet.ts +6 -0
- package/src/styleFunction.ts +1 -3
- package/src/variable.ts +1 -1
- package/src/variants.ts +38 -16
- package/src/vite/index.ts +137 -51
- package/src/web/Css.ts +83 -49
- package/src/web/internal/ClassName.ts +31 -36
- package/src/web/internal/Themes.ts +79 -29
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 =
|
|
@@ -1332,11 +1391,16 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
1332
1391
|
await updateDiscovery(this.environment, file, change.event)
|
|
1333
1392
|
},
|
|
1334
1393
|
async hotUpdate({ file, modules, timestamp, type, server }) {
|
|
1335
|
-
await updateDiscovery(this.environment, file, type)
|
|
1336
|
-
|
|
1337
1394
|
const state = entries(this.environment)
|
|
1395
|
+
const previous = [...state.values()].map((entry) => ({
|
|
1396
|
+
code: entry.code,
|
|
1397
|
+
file: entry.file,
|
|
1398
|
+
imports: entry.imports,
|
|
1399
|
+
}))
|
|
1400
|
+
|
|
1401
|
+
await updateDiscovery(this.environment, file, type)
|
|
1338
1402
|
const first = [...state.values()].find(
|
|
1339
|
-
(entry) => entry.files.has(file) || eager(file),
|
|
1403
|
+
(entry) => entry.files.has(file) || eager(file, this.environment),
|
|
1340
1404
|
)
|
|
1341
1405
|
if (!first && !removed.get(this.environment)?.has(file)) return modules
|
|
1342
1406
|
|
|
@@ -1358,31 +1422,51 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
1358
1422
|
true,
|
|
1359
1423
|
).catch(() => undefined)
|
|
1360
1424
|
: undefined
|
|
1361
|
-
const
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
entry.
|
|
1425
|
+
const javascriptChanged = await (async () => {
|
|
1426
|
+
if (!output) return true
|
|
1427
|
+
|
|
1428
|
+
// Portable build adapters share this module and do not require Vite.
|
|
1429
|
+
const { transformWithOxc } = await import('vite')
|
|
1430
|
+
const changed = await Promise.all(
|
|
1431
|
+
previous.map(async (entry) => {
|
|
1432
|
+
const code = output.modules[sourceId(entry.file)]?.code
|
|
1433
|
+
if (
|
|
1434
|
+
entry.imports !==
|
|
1369
1435
|
JSON.stringify(output.imports[sourceId(entry.file)])
|
|
1370
|
-
|
|
1371
|
-
|
|
1436
|
+
)
|
|
1437
|
+
return true
|
|
1438
|
+
if (entry.code === code) return false
|
|
1439
|
+
if (entry.code === undefined || code === undefined) return true
|
|
1440
|
+
|
|
1441
|
+
// Generated type assertions can change without changing runtime bindings.
|
|
1442
|
+
const [before, after] = await Promise.all([
|
|
1443
|
+
transformWithOxc(entry.code, entry.file, { sourcemap: false }),
|
|
1444
|
+
transformWithOxc(code, entry.file, { sourcemap: false }),
|
|
1445
|
+
])
|
|
1446
|
+
return before.code !== after.code
|
|
1447
|
+
}),
|
|
1448
|
+
)
|
|
1449
|
+
return changed.some(Boolean)
|
|
1450
|
+
})()
|
|
1451
|
+
// Compiler-only inputs have watch edges, but their stylesheets update separately.
|
|
1452
|
+
const affected = new Set(
|
|
1453
|
+
modules.filter(
|
|
1454
|
+
(module) =>
|
|
1455
|
+
javascriptChanged ||
|
|
1456
|
+
(module.id
|
|
1457
|
+
? !output?.modules[sourceId(module.id)]
|
|
1458
|
+
: module.type !== 'asset'),
|
|
1459
|
+
),
|
|
1372
1460
|
)
|
|
1373
1461
|
const ids = new Set<string>()
|
|
1374
1462
|
if (type === 'delete') ids.add(cssId(file))
|
|
1375
1463
|
|
|
1376
1464
|
for (const entry of entries(this.environment).values()) {
|
|
1377
|
-
if (!entry.files.has(file) && !eager(file)) continue
|
|
1465
|
+
if (!entry.files.has(file) && !eager(file, this.environment)) continue
|
|
1378
1466
|
|
|
1379
1467
|
// Theme scopes affect CSS even when Vite's JavaScript import was erased.
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
entry.code !== output.modules[sourceId(entry.file)]?.code ||
|
|
1383
|
-
entry.imports !== JSON.stringify(output.imports[sourceId(entry.file)])
|
|
1384
|
-
)
|
|
1385
|
-
ids.add(entry.file)
|
|
1468
|
+
// Rewritten importers can lose a source edge, so changed bindings must update together.
|
|
1469
|
+
if (javascriptChanged) ids.add(entry.file)
|
|
1386
1470
|
ids.add(cssId(entry.file))
|
|
1387
1471
|
ids.add(sharedId)
|
|
1388
1472
|
}
|
|
@@ -1635,6 +1719,8 @@ export declare namespace zyzz {
|
|
|
1635
1719
|
type Options = {
|
|
1636
1720
|
/** False retains authored calls and requires explicit identities where needed. */
|
|
1637
1721
|
readonly compiler?: boolean | undefined
|
|
1722
|
+
/** Additional source directories, absolute or relative to the Vite root. */
|
|
1723
|
+
readonly include?: readonly string[] | undefined
|
|
1638
1724
|
/** Native context captured at creation. Disables CSS delivery and initialization scripts. */
|
|
1639
1725
|
readonly native?: Graph.compile.Options['native']
|
|
1640
1726
|
/** Include the CSS reset. Defaults to false. */
|
package/src/web/Css.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import * as Targets from '../internal/Targets.js'
|
|
6
6
|
import * as ClassName from './internal/ClassName.js'
|
|
7
|
+
import * as Identity from '../internal/Identity.js'
|
|
7
8
|
import * as Contributions from './internal/Contributions.js'
|
|
8
9
|
import * as Binding from '../internal/Binding.js'
|
|
9
10
|
import * as Cascade from '../internal/Cascade.js'
|
|
@@ -33,6 +34,7 @@ export function compile<
|
|
|
33
34
|
>(
|
|
34
35
|
options: compile.Options<name, themeName>,
|
|
35
36
|
): compile.ReturnType<name, themeName> {
|
|
37
|
+
const labels = options[ClassName.labels] ?? options.styles[ClassName.labels]
|
|
36
38
|
options = {
|
|
37
39
|
...options,
|
|
38
40
|
styles: { styles: options.styles.styles.map(Targets.web) },
|
|
@@ -417,6 +419,8 @@ export function compile<
|
|
|
417
419
|
|
|
418
420
|
const identities = new Map<string, string>()
|
|
419
421
|
const rules = new Map<string, string>()
|
|
422
|
+
type ConditionalRule = { conditions: readonly string[]; value: string }
|
|
423
|
+
const conditionalRules = new Map<string, ConditionalRule>()
|
|
420
424
|
const identical = new Map<string, string>()
|
|
421
425
|
const explicitBodies = new Map<string, string>()
|
|
422
426
|
const selectors = new Map<string, string>()
|
|
@@ -470,12 +474,18 @@ export function compile<
|
|
|
470
474
|
|
|
471
475
|
const names: string[] = explicit === undefined ? [] : [explicit]
|
|
472
476
|
let ordinal = 0
|
|
473
|
-
const
|
|
474
|
-
const
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
function emit(
|
|
477
|
+
const cssName = labels?.[style.name]?.name ?? encode(style.name)
|
|
478
|
+
const cssNamespace =
|
|
479
|
+
labels?.[style.name]?.namespace ??
|
|
480
|
+
(options.scope ? Identity.name(options.scope) : undefined)
|
|
481
|
+
|
|
482
|
+
function emit(
|
|
483
|
+
body: string,
|
|
484
|
+
label: string,
|
|
485
|
+
shared: boolean,
|
|
486
|
+
output = mode,
|
|
487
|
+
conditional?: ConditionalRule,
|
|
488
|
+
) {
|
|
479
489
|
if (!body) return
|
|
480
490
|
|
|
481
491
|
const independent =
|
|
@@ -483,12 +493,8 @@ export function compile<
|
|
|
483
493
|
!options.development &&
|
|
484
494
|
output === mode &&
|
|
485
495
|
options.composition === 'independent'
|
|
486
|
-
const key =
|
|
487
|
-
|
|
488
|
-
const reusable =
|
|
489
|
-
explicit === undefined &&
|
|
490
|
-
!options.development &&
|
|
491
|
-
(shared || independent)
|
|
496
|
+
const key = JSON.stringify([cssNamespace, output, body])
|
|
497
|
+
const reusable = explicit === undefined && (shared || independent)
|
|
492
498
|
const previous = reusable ? identical.get(key) : undefined
|
|
493
499
|
if (previous && !names.includes(previous)) {
|
|
494
500
|
names.push(previous)
|
|
@@ -498,43 +504,23 @@ export function compile<
|
|
|
498
504
|
if (previous) shared = false
|
|
499
505
|
|
|
500
506
|
// Contextual slots preserve authored ordering; development names survive value edits.
|
|
501
|
-
const
|
|
502
|
-
const slot = options.development ? (slots.get(label) ?? 0) : ordinalSlot
|
|
503
|
-
slots.set(label, slot + 1)
|
|
507
|
+
const slot = ordinal++
|
|
504
508
|
const identity = (() => {
|
|
505
509
|
if (explicit !== undefined)
|
|
506
510
|
return `${explicit}-${mode}-${encode(label)}-${slot}`
|
|
507
|
-
if (
|
|
508
|
-
output === 'grouped' &&
|
|
509
|
-
mode === 'grouped' &&
|
|
510
|
-
!options.development &&
|
|
511
|
-
options.composition === 'independent'
|
|
512
|
-
)
|
|
513
|
-
return `g_${rules.size.toString(36)}`
|
|
514
511
|
if (output === 'grouped' && mode === 'grouped') {
|
|
515
|
-
|
|
516
|
-
const scope =
|
|
517
|
-
options.development && options.scope
|
|
518
|
-
? `_m${encode(options.scope)}`
|
|
519
|
-
: ''
|
|
520
|
-
return `g-${encode(name)}${scope}${slot ? `_s${slot}` : ''}`
|
|
512
|
+
return `z-${cssNamespace ? `${cssNamespace}-` : ''}${cssName}${slot ? `__${slot}` : ''}`
|
|
521
513
|
}
|
|
522
514
|
return ClassName.create({
|
|
523
515
|
body,
|
|
524
|
-
context:
|
|
525
|
-
|
|
526
|
-
? JSON.stringify([
|
|
527
|
-
options.scope,
|
|
528
|
-
mode,
|
|
529
|
-
options.development ? developmentName : style.name,
|
|
530
|
-
])
|
|
531
|
-
: options.scope,
|
|
516
|
+
context: !shared ? cssName : undefined,
|
|
517
|
+
namespace: cssNamespace,
|
|
532
518
|
property: label,
|
|
533
|
-
slot: !shared
|
|
534
|
-
stable: options.development,
|
|
519
|
+
slot: !shared ? slot : undefined,
|
|
535
520
|
})
|
|
536
521
|
})()
|
|
537
|
-
const owner =
|
|
522
|
+
const owner =
|
|
523
|
+
mode === 'atomic' && !shared ? `${style.name}:${slot}` : undefined
|
|
538
524
|
if (
|
|
539
525
|
(rules.has(identity) && rules.get(identity) !== body) ||
|
|
540
526
|
(owner !== undefined &&
|
|
@@ -543,12 +529,19 @@ export function compile<
|
|
|
543
529
|
)
|
|
544
530
|
diagnostics.push({
|
|
545
531
|
code: 'identity_collision',
|
|
546
|
-
message:
|
|
532
|
+
message:
|
|
533
|
+
'Generated class names conflict. Supply distinct config or style ids.',
|
|
547
534
|
path: [style.name],
|
|
548
535
|
})
|
|
549
536
|
|
|
550
537
|
if (owner !== undefined) identities.set(identity, owner)
|
|
551
538
|
rules.set(identity, body)
|
|
539
|
+
if (
|
|
540
|
+
conditional?.conditions.some((condition) =>
|
|
541
|
+
/^@(media|supports)\b/.test(condition),
|
|
542
|
+
)
|
|
543
|
+
)
|
|
544
|
+
conditionalRules.set(identity, conditional)
|
|
552
545
|
if (explicit !== undefined) selectors.set(identity, explicit)
|
|
553
546
|
else {
|
|
554
547
|
if (reusable) identical.set(key, identity)
|
|
@@ -611,7 +604,7 @@ export function compile<
|
|
|
611
604
|
!nestedComposition &&
|
|
612
605
|
!conditions.length &&
|
|
613
606
|
groups.get(conflict(property)) !== false
|
|
614
|
-
emit(body, property, shared)
|
|
607
|
+
emit(body, property, shared, mode, { conditions, value })
|
|
615
608
|
}
|
|
616
609
|
}
|
|
617
610
|
|
|
@@ -673,7 +666,7 @@ export function compile<
|
|
|
673
666
|
options.schemes ?? false,
|
|
674
667
|
options[Themes.shared],
|
|
675
668
|
)
|
|
676
|
-
: { classes: Object.freeze({}), css: '', resources: [] }
|
|
669
|
+
: { classes: Object.freeze({}), css: '', resources: [], rules: [] }
|
|
677
670
|
} catch (error) {
|
|
678
671
|
throw new CompileError([
|
|
679
672
|
{
|
|
@@ -686,20 +679,57 @@ export function compile<
|
|
|
686
679
|
|
|
687
680
|
const scopedCss = [
|
|
688
681
|
scopes.css,
|
|
689
|
-
...[...rules].map(
|
|
690
|
-
|
|
691
|
-
|
|
682
|
+
...[...rules].map((entry) => {
|
|
683
|
+
const [name, body] = entry
|
|
684
|
+
const selector = `.${ClassName.selector(selectors.get(name) ?? name)}`
|
|
685
|
+
const conditional = conditionalRules.get(name)
|
|
686
|
+
if (
|
|
687
|
+
!conditional ||
|
|
688
|
+
conditional.conditions.some(
|
|
689
|
+
(condition) =>
|
|
690
|
+
condition.startsWith('@') &&
|
|
691
|
+
!/^@(media|supports)\b/.test(condition),
|
|
692
|
+
)
|
|
693
|
+
)
|
|
694
|
+
return `${selector}{${body}}`
|
|
695
|
+
|
|
696
|
+
// Inactive conditions must surround the class rather than leave a matched empty wrapper.
|
|
697
|
+
const conditions = conditional.conditions.filter((condition) =>
|
|
698
|
+
condition.startsWith('@'),
|
|
699
|
+
)
|
|
700
|
+
const nested = conditional.conditions
|
|
701
|
+
.filter((condition) => !condition.startsWith('@'))
|
|
702
|
+
.reduceRight(
|
|
703
|
+
(body, condition) => `${condition}{${body}}`,
|
|
704
|
+
conditional.value,
|
|
705
|
+
)
|
|
706
|
+
return conditions.reduceRight(
|
|
707
|
+
(body, condition) => `${condition}{${body}}`,
|
|
708
|
+
`${selector}{${nested}}`,
|
|
709
|
+
)
|
|
710
|
+
}),
|
|
692
711
|
]
|
|
693
712
|
.filter(Boolean)
|
|
694
713
|
.join('\n')
|
|
695
714
|
|
|
696
|
-
|
|
715
|
+
const result = {
|
|
697
716
|
...(scopes.resources.length ? { [Themes.shared]: scopes.resources } : {}),
|
|
698
717
|
...(contributionCss ? { contributionCss, scopedCss } : {}),
|
|
718
|
+
[ClassName.rules]: Object.freeze({
|
|
719
|
+
...Object.fromEntries(rules),
|
|
720
|
+
...Object.fromEntries(
|
|
721
|
+
scopes.rules.map((rule) => [
|
|
722
|
+
`@scope:${rule.selector.slice(1)}:${Identity.name(rule.property)}:${Identity.name(JSON.stringify(rule.conditions))}`,
|
|
723
|
+
rule.value,
|
|
724
|
+
]),
|
|
725
|
+
),
|
|
726
|
+
}),
|
|
699
727
|
classes: Object.freeze(classes),
|
|
700
728
|
css: [contributionCss, scopedCss].filter(Boolean).join('\n'),
|
|
701
729
|
vars: scopes.classes as Readonly<Record<themeName, string>>,
|
|
702
|
-
}
|
|
730
|
+
}
|
|
731
|
+
Object.defineProperty(result, ClassName.rules, { enumerable: false })
|
|
732
|
+
return Object.freeze(result)
|
|
703
733
|
}
|
|
704
734
|
|
|
705
735
|
/** Input and output contracts for literal compilation. */
|
|
@@ -714,6 +744,8 @@ export declare namespace compile {
|
|
|
714
744
|
> = {
|
|
715
745
|
/** Separates generated token rules for hosts with independent CSS resources. */
|
|
716
746
|
readonly [Themes.shared]?: 'all' | 'defaults' | undefined
|
|
747
|
+
/** Readable source bindings and consumer-owned configuration namespaces. */
|
|
748
|
+
readonly [ClassName.labels]?: ClassName.Labels | undefined
|
|
717
749
|
/** Fixed class identities used by CSS-only consumers. */
|
|
718
750
|
readonly names?: Readonly<Record<string, string>> | undefined
|
|
719
751
|
/**
|
|
@@ -726,14 +758,14 @@ export declare namespace compile {
|
|
|
726
758
|
/** CSS representation; atomic declarations are the default. */
|
|
727
759
|
readonly cssOutput?: 'atomic' | 'grouped' | undefined
|
|
728
760
|
readonly composition?: 'independent' | 'ordered' | undefined
|
|
729
|
-
/**
|
|
761
|
+
/** Retains live definitions for development updates. */
|
|
730
762
|
readonly development?: boolean | undefined
|
|
731
763
|
/**
|
|
732
764
|
* Emit the `color-scheme` selection classes. Set by modules whose runtime
|
|
733
765
|
* helpers can apply a scheme, so lowered `light-dark()` resolves there.
|
|
734
766
|
*/
|
|
735
767
|
readonly schemes?: boolean | undefined
|
|
736
|
-
/**
|
|
768
|
+
/** Explicit consumer-owned namespace for independently delivered stylesheets. */
|
|
737
769
|
readonly scope?: string | undefined
|
|
738
770
|
/** Ordered definitions; no themes or source adapter is required. */
|
|
739
771
|
readonly styles: Style.Definition<name>
|
|
@@ -748,6 +780,8 @@ export declare namespace compile {
|
|
|
748
780
|
name extends string = string,
|
|
749
781
|
themeName extends string = string,
|
|
750
782
|
> = {
|
|
783
|
+
/** Exact emitted rule bodies retained for graph-wide collision diagnostics. */
|
|
784
|
+
readonly [ClassName.rules]: Readonly<Record<string, string>>
|
|
751
785
|
/** Shared token resources omitted from this module's stylesheet. */
|
|
752
786
|
readonly [Themes.shared]?: readonly Themes.Resource[] | undefined
|
|
753
787
|
/** Contribution text separated for graph-wide hoisting. */
|