zyzz 0.0.3 → 0.0.5
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 +34 -19
- package/dist/Config.d.ts +16 -167
- package/dist/Config.d.ts.map +1 -1
- package/dist/Config.js +7 -246
- package/dist/Config.js.map +1 -1
- package/dist/Style.d.ts +15 -12
- package/dist/Style.d.ts.map +1 -1
- package/dist/Style.js +51 -26
- package/dist/Style.js.map +1 -1
- package/dist/Vars.d.ts +114 -0
- package/dist/Vars.d.ts.map +1 -0
- package/dist/Vars.js +42 -0
- package/dist/Vars.js.map +1 -0
- package/dist/compiler/Graph.js +11 -8
- package/dist/compiler/Graph.js.map +1 -1
- package/dist/compiler/Native.d.ts +5 -5
- package/dist/compiler/Native.d.ts.map +1 -1
- package/dist/compiler/Native.js +21 -21
- package/dist/compiler/Native.js.map +1 -1
- package/dist/compiler/Source.d.ts +8 -6
- package/dist/compiler/Source.d.ts.map +1 -1
- package/dist/compiler/Source.js +47 -14
- package/dist/compiler/Source.js.map +1 -1
- package/dist/compiler/Transform.d.ts +1 -1
- package/dist/compiler/Transform.d.ts.map +1 -1
- package/dist/compiler/Transform.js +58 -22
- package/dist/compiler/Transform.js.map +1 -1
- package/dist/compiler/internal/Compositions.d.ts +5 -0
- package/dist/compiler/internal/Compositions.d.ts.map +1 -1
- package/dist/compiler/internal/Compositions.js +22 -3
- 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 +73 -12
- package/dist/compiler/internal/Configurations.js.map +1 -1
- package/dist/compiler/internal/Contract.d.ts +1 -1
- package/dist/compiler/internal/Contract.d.ts.map +1 -1
- package/dist/compiler/internal/Contract.js +155 -13
- package/dist/compiler/internal/Contract.js.map +1 -1
- package/dist/compiler/internal/Contributions.js +1 -1
- package/dist/compiler/internal/Contributions.js.map +1 -1
- package/dist/compiler/internal/Dynamic.js +1 -1
- package/dist/compiler/internal/Dynamic.js.map +1 -1
- package/dist/compiler/internal/Expression.d.ts +3 -0
- package/dist/compiler/internal/Expression.d.ts.map +1 -1
- package/dist/compiler/internal/Expression.js +21 -0
- package/dist/compiler/internal/Expression.js.map +1 -1
- package/dist/compiler/internal/Identifiers.d.ts +1 -1
- package/dist/compiler/internal/Identifiers.d.ts.map +1 -1
- package/dist/compiler/internal/Identifiers.js +2 -2
- package/dist/compiler/internal/Identifiers.js.map +1 -1
- package/dist/compiler/internal/NativeBindings.d.ts +1 -1
- package/dist/compiler/internal/NativeBindings.d.ts.map +1 -1
- package/dist/compiler/internal/NativeBindings.js +3 -3
- package/dist/compiler/internal/NativeBindings.js.map +1 -1
- package/dist/compiler/internal/PackedStyles.d.ts +1 -1
- package/dist/compiler/internal/PackedStyles.d.ts.map +1 -1
- package/dist/compiler/internal/PackedStyles.js +15 -25
- package/dist/compiler/internal/PackedStyles.js.map +1 -1
- package/dist/compiler/internal/Recipes.js +1 -1
- package/dist/compiler/internal/Recipes.js.map +1 -1
- package/dist/compiler/internal/Selectors.js +1 -1
- package/dist/compiler/internal/Selectors.js.map +1 -1
- package/dist/compiler/internal/Themes.d.ts +12 -3
- package/dist/compiler/internal/Themes.d.ts.map +1 -1
- package/dist/compiler/internal/Themes.js +192 -52
- package/dist/compiler/internal/Themes.js.map +1 -1
- package/dist/compiler/internal/{Variables.d.ts → Vars.d.ts} +1 -1
- package/dist/compiler/internal/Vars.d.ts.map +1 -0
- package/dist/compiler/internal/{Variables.js → Vars.js} +3 -3
- package/dist/compiler/internal/Vars.js.map +1 -0
- package/dist/default.d.ts +147 -2562
- package/dist/default.d.ts.map +1 -1
- package/dist/default.js +85 -80
- package/dist/default.js.map +2 -2
- package/dist/default.js.zyzz.json +1 -1
- package/dist/esbuild/index.d.ts +3 -0
- package/dist/esbuild/index.d.ts.map +1 -0
- package/dist/esbuild/index.js +5 -0
- package/dist/esbuild/index.js.map +1 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/internal/Authoring.d.ts +1 -1
- package/dist/internal/Authoring.d.ts.map +1 -1
- package/dist/internal/Authoring.js +4 -4
- package/dist/internal/Authoring.js.map +1 -1
- package/dist/internal/Binding.d.ts +1 -1
- package/dist/internal/Binding.d.ts.map +1 -1
- package/dist/internal/Completion.d.ts +19 -0
- package/dist/internal/Completion.d.ts.map +1 -0
- package/dist/internal/Completion.js +2 -0
- package/dist/internal/Completion.js.map +1 -0
- package/dist/internal/Condition.d.ts +3 -1
- package/dist/internal/Condition.d.ts.map +1 -1
- package/dist/internal/Condition.js.map +1 -1
- package/dist/internal/Configuration.d.ts +248 -0
- package/dist/internal/Configuration.d.ts.map +1 -0
- package/dist/internal/Configuration.js +343 -0
- package/dist/internal/Configuration.js.map +1 -0
- package/dist/{Theme.d.ts → internal/Theme.d.ts} +15 -13
- package/dist/internal/Theme.d.ts.map +1 -0
- package/dist/{Theme.js → internal/Theme.js} +39 -12
- package/dist/internal/Theme.js.map +1 -0
- package/dist/internal/Token.d.ts +46 -16
- package/dist/internal/Token.d.ts.map +1 -1
- package/dist/internal/Token.js +89 -5
- package/dist/internal/Token.js.map +1 -1
- package/dist/internal/Typography.d.ts +13 -5
- package/dist/internal/Typography.d.ts.map +1 -1
- package/dist/internal/Typography.js +42 -6
- package/dist/internal/Typography.js.map +1 -1
- package/dist/internal/Value.d.ts +6 -1
- package/dist/internal/Value.d.ts.map +1 -1
- package/dist/internal/Value.js.map +1 -1
- package/dist/internal/VariableSets.d.ts +20 -0
- package/dist/internal/VariableSets.d.ts.map +1 -0
- package/dist/internal/VariableSets.js +317 -0
- package/dist/internal/VariableSets.js.map +1 -0
- package/dist/next/loader.js +15 -5
- package/dist/next/loader.js.map +1 -1
- package/dist/node/Host.d.ts.map +1 -1
- package/dist/node/Host.js +1 -1
- package/dist/node/Host.js.map +1 -1
- package/dist/react-native/Host.d.ts +2 -2
- package/dist/react-native/Host.d.ts.map +1 -1
- package/dist/react-native/Host.js +4 -4
- package/dist/react-native/Host.js.map +1 -1
- package/dist/react-native/StyleSheet.d.ts +9 -8
- package/dist/react-native/StyleSheet.d.ts.map +1 -1
- package/dist/react-native/StyleSheet.js +29 -23
- package/dist/react-native/StyleSheet.js.map +1 -1
- package/dist/react-native/Variants.d.ts +3 -3
- package/dist/react-native/Variants.d.ts.map +1 -1
- package/dist/react-native/Variants.js +2 -2
- package/dist/react-native/react.d.ts +1 -1
- package/dist/react-native/react.d.ts.map +1 -1
- package/dist/react-native/react.js +5 -5
- package/dist/react-native/react.js.map +1 -1
- package/dist/rollup/index.d.ts +3 -0
- package/dist/rollup/index.d.ts.map +1 -0
- package/dist/rollup/index.js +5 -0
- package/dist/rollup/index.js.map +1 -0
- package/dist/runtime/Appearance.d.ts +7 -7
- package/dist/runtime/Appearance.d.ts.map +1 -1
- package/dist/runtime/Appearance.js +15 -15
- package/dist/runtime/Appearance.js.map +1 -1
- package/dist/runtime/Dynamic.d.ts.map +1 -1
- package/dist/runtime/Dynamic.js +4 -1
- package/dist/runtime/Dynamic.js.map +1 -1
- package/dist/runtime/NativeContext.d.ts +4 -4
- package/dist/runtime/NativeContext.d.ts.map +1 -1
- package/dist/runtime/NativeContext.js +5 -5
- package/dist/runtime/NativeContext.js.map +1 -1
- package/dist/runtime/NativeDynamic.d.ts +1 -1
- package/dist/runtime/NativeDynamic.d.ts.map +1 -1
- package/dist/runtime/NativeDynamic.js.map +1 -1
- package/dist/runtime/Props.d.ts +1 -1
- package/dist/runtime/Props.js +3 -3
- package/dist/runtime/Props.js.map +1 -1
- package/dist/runtime/Selection.d.ts +14 -10
- package/dist/runtime/Selection.d.ts.map +1 -1
- package/dist/runtime/Selection.js +19 -18
- package/dist/runtime/Selection.js.map +1 -1
- package/dist/styleFunction.d.ts +14 -14
- package/dist/styleFunction.d.ts.map +1 -1
- package/dist/styleFunction.js.map +1 -1
- package/dist/unplugin/index.d.ts +20 -0
- package/dist/unplugin/index.d.ts.map +1 -0
- package/dist/unplugin/index.js +498 -0
- package/dist/unplugin/index.js.map +1 -0
- package/dist/variants.d.ts +3 -3
- package/dist/variants.d.ts.map +1 -1
- package/dist/variants.js.map +1 -1
- package/dist/vite/index.d.ts.map +1 -1
- package/dist/vite/index.js +6 -3
- package/dist/vite/index.js.map +1 -1
- package/dist/web/Css.d.ts +4 -3
- package/dist/web/Css.d.ts.map +1 -1
- package/dist/web/Css.js +4 -4
- package/dist/web/Css.js.map +1 -1
- package/dist/web/internal/Themes.d.ts +3 -2
- package/dist/web/internal/Themes.d.ts.map +1 -1
- package/dist/web/internal/Themes.js +42 -6
- package/dist/web/internal/Themes.js.map +1 -1
- package/dist/webpack/index.d.ts +3 -0
- package/dist/webpack/index.d.ts.map +1 -0
- package/dist/webpack/index.js +5 -0
- package/dist/webpack/index.js.map +1 -0
- package/package.json +23 -2
- package/src/Config.ts +43 -685
- package/src/Style.ts +97 -34
- package/src/Vars.ts +299 -0
- package/src/compiler/Graph.ts +14 -9
- package/src/compiler/Native.ts +29 -32
- package/src/compiler/Source.ts +59 -21
- package/src/compiler/Transform.ts +73 -23
- package/src/compiler/internal/Compositions.ts +36 -3
- package/src/compiler/internal/Configurations.ts +83 -11
- package/src/compiler/internal/Contract.ts +207 -15
- package/src/compiler/internal/Contributions.ts +1 -1
- package/src/compiler/internal/Dynamic.ts +1 -1
- package/src/compiler/internal/Expression.ts +26 -0
- package/src/compiler/internal/Identifiers.ts +2 -1
- package/src/compiler/internal/NativeBindings.ts +3 -3
- package/src/compiler/internal/PackedStyles.ts +22 -26
- package/src/compiler/internal/Recipes.ts +1 -1
- package/src/compiler/internal/Selectors.ts +1 -1
- package/src/compiler/internal/Themes.ts +266 -57
- package/src/compiler/internal/{Variables.ts → Vars.ts} +2 -2
- package/src/default.ts +173 -154
- package/src/esbuild/index.ts +5 -0
- package/src/index.ts +4 -4
- package/src/internal/Authoring.ts +5 -7
- package/src/internal/Binding.ts +1 -1
- package/src/internal/Completion.ts +42 -0
- package/src/internal/Condition.ts +31 -1
- package/src/internal/Configuration.ts +970 -0
- package/src/{Theme.ts → internal/Theme.ts} +75 -20
- package/src/internal/Token.ts +258 -85
- package/src/internal/Typography.ts +71 -16
- package/src/internal/Value.ts +45 -26
- package/src/internal/VariableSets.ts +458 -0
- package/src/next/loader.ts +19 -5
- package/src/node/Host.ts +1 -2
- package/src/react-native/Host.ts +6 -6
- package/src/react-native/StyleSheet.ts +49 -42
- package/src/react-native/Variants.ts +3 -3
- package/src/react-native/react.ts +6 -6
- package/src/rollup/index.ts +5 -0
- package/src/runtime/Appearance.ts +20 -20
- package/src/runtime/Dynamic.ts +4 -1
- package/src/runtime/NativeContext.ts +8 -8
- package/src/runtime/NativeDynamic.ts +2 -4
- package/src/runtime/Props.ts +3 -3
- package/src/runtime/Selection.ts +44 -33
- package/src/styleFunction.ts +22 -19
- package/src/unplugin/index.ts +600 -0
- package/src/variants.ts +7 -5
- package/src/vite/index.ts +5 -4
- package/src/web/Css.ts +10 -7
- package/src/web/internal/Themes.ts +52 -9
- package/src/webpack/index.ts +5 -0
- package/dist/Theme.d.ts.map +0 -1
- package/dist/Theme.js.map +0 -1
- package/dist/compiler/internal/Variables.d.ts.map +0 -1
- package/dist/compiler/internal/Variables.js.map +0 -1
|
@@ -0,0 +1,600 @@
|
|
|
1
|
+
/** Connects the static compiler to portable bundler hooks and the Vite adapter. @module */
|
|
2
|
+
import * as Mapping from '@jridgewell/gen-mapping'
|
|
3
|
+
import * as Crypto from 'node:crypto'
|
|
4
|
+
import * as Fs from 'node:fs/promises'
|
|
5
|
+
import * as Path from 'node:path'
|
|
6
|
+
import * as Parser from 'oxc-parser'
|
|
7
|
+
import { createUnplugin } from 'unplugin'
|
|
8
|
+
import type { UnpluginBuildContext } from 'unplugin'
|
|
9
|
+
import * as Graph from '../compiler/Graph.js'
|
|
10
|
+
import * as AtRules from '../compiler/internal/AtRules.js'
|
|
11
|
+
import * as Catalogs from '../compiler/internal/Catalogs.js'
|
|
12
|
+
import * as Contract from '../compiler/internal/Contract.js'
|
|
13
|
+
import * as Vite from '../vite/index.js'
|
|
14
|
+
|
|
15
|
+
/** Portable build configuration. Vite uses the options from `zyzz/vite` instead. */
|
|
16
|
+
export type Options = {
|
|
17
|
+
/** Rewrite authoring calls. Defaults to true. */
|
|
18
|
+
readonly compiler?: boolean | undefined
|
|
19
|
+
/** Source directory scanned for modules and global contributions. Defaults to the working directory. */
|
|
20
|
+
readonly root?: string | undefined
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const excludedPattern = /\.(?:d|test|test-d|bench|bench-d)\.[cm]?[jt]sx?$/
|
|
24
|
+
const sourcePattern = /\.[cm]?[jt]sx?$/
|
|
25
|
+
|
|
26
|
+
const portable = createUnplugin<Options | undefined, false>(
|
|
27
|
+
(options = {}, meta) => {
|
|
28
|
+
const root = Path.resolve(options.root ?? process.cwd())
|
|
29
|
+
const compiler = Graph.create()
|
|
30
|
+
let graph: Graph.compile.ReturnType | undefined
|
|
31
|
+
let pending: Promise<void> | undefined
|
|
32
|
+
let files = new Set<string>()
|
|
33
|
+
let directories = new Set<string>()
|
|
34
|
+
let sources = new Map<string, string>()
|
|
35
|
+
let assets = new Map<string, Uint8Array>()
|
|
36
|
+
let css = ''
|
|
37
|
+
let cssMap = ''
|
|
38
|
+
let script = ''
|
|
39
|
+
|
|
40
|
+
function identity(file: string) {
|
|
41
|
+
return `app/${Path.relative(root, file).split(Path.sep).join('/')}`
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function emit(context: UnpluginBuildContext) {
|
|
45
|
+
if (!graph) return
|
|
46
|
+
for (const [fileName, source] of assets)
|
|
47
|
+
context.emitFile({
|
|
48
|
+
type: 'asset',
|
|
49
|
+
fileName,
|
|
50
|
+
source: Uint8Array.from(source),
|
|
51
|
+
})
|
|
52
|
+
context.emitFile({
|
|
53
|
+
type: 'asset',
|
|
54
|
+
fileName: 'zyzz.css',
|
|
55
|
+
source: `${css}/*# sourceMappingURL=zyzz.css.map */\n`,
|
|
56
|
+
})
|
|
57
|
+
context.emitFile({
|
|
58
|
+
type: 'asset',
|
|
59
|
+
fileName: 'zyzz.css.map',
|
|
60
|
+
source: cssMap,
|
|
61
|
+
})
|
|
62
|
+
context.emitFile({
|
|
63
|
+
type: 'asset',
|
|
64
|
+
fileName: 'zyzz.js',
|
|
65
|
+
source: script || '/* No saved theme selections. */\n',
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function transform(code: string, id: string) {
|
|
70
|
+
const output = graph?.modules[identity(id)]
|
|
71
|
+
if (!output) return
|
|
72
|
+
if (code !== sources.get(id))
|
|
73
|
+
throw new Error(`Zyzz must run before source transforms: ${id}`)
|
|
74
|
+
return {
|
|
75
|
+
code: output.code,
|
|
76
|
+
map: JSON.stringify({
|
|
77
|
+
...output.map,
|
|
78
|
+
sources: output.map.sources.map((source) =>
|
|
79
|
+
source?.startsWith('app/')
|
|
80
|
+
? Path.join(root, source.slice(4))
|
|
81
|
+
: source,
|
|
82
|
+
),
|
|
83
|
+
}),
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
buildEnd:
|
|
89
|
+
meta.framework === 'webpack'
|
|
90
|
+
? undefined
|
|
91
|
+
: function () {
|
|
92
|
+
emit(this)
|
|
93
|
+
},
|
|
94
|
+
async buildStart() {
|
|
95
|
+
pending = (async () => {
|
|
96
|
+
graph = undefined
|
|
97
|
+
files = new Set()
|
|
98
|
+
directories = new Set()
|
|
99
|
+
sources = new Map()
|
|
100
|
+
assets = new Map()
|
|
101
|
+
const modules: Record<string, string> = Object.create(null)
|
|
102
|
+
const imports: Record<
|
|
103
|
+
string,
|
|
104
|
+
Record<string, string | null>
|
|
105
|
+
> = Object.create(null)
|
|
106
|
+
const contracts: Record<string, string> = Object.create(null)
|
|
107
|
+
|
|
108
|
+
async function scan(directory: string): Promise<void> {
|
|
109
|
+
directories.add(directory)
|
|
110
|
+
const entries = await Fs.readdir(directory, { withFileTypes: true })
|
|
111
|
+
|
|
112
|
+
for (const entry of entries.sort((a, b) =>
|
|
113
|
+
a.name < b.name ? -1 : a.name > b.name ? 1 : 0,
|
|
114
|
+
)) {
|
|
115
|
+
if (
|
|
116
|
+
entry.name.startsWith('.') ||
|
|
117
|
+
[
|
|
118
|
+
'node_modules',
|
|
119
|
+
'dist',
|
|
120
|
+
'build',
|
|
121
|
+
'coverage',
|
|
122
|
+
'test',
|
|
123
|
+
'tests',
|
|
124
|
+
'__tests__',
|
|
125
|
+
'fixtures',
|
|
126
|
+
'__fixtures__',
|
|
127
|
+
].includes(entry.name)
|
|
128
|
+
)
|
|
129
|
+
continue
|
|
130
|
+
const file = Path.join(directory, entry.name)
|
|
131
|
+
|
|
132
|
+
if (entry.isDirectory()) await scan(file)
|
|
133
|
+
else if (
|
|
134
|
+
entry.isFile() &&
|
|
135
|
+
sourcePattern.test(file) &&
|
|
136
|
+
!excludedPattern.test(file)
|
|
137
|
+
) {
|
|
138
|
+
const source = await Fs.readFile(file, 'utf8')
|
|
139
|
+
|
|
140
|
+
files.add(file)
|
|
141
|
+
sources.set(file, source)
|
|
142
|
+
modules[identity(file)] = source
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const resolve = async (specifier: string, importer: string) => {
|
|
148
|
+
if ('resolve' in this && typeof this.resolve === 'function') {
|
|
149
|
+
const result = await (
|
|
150
|
+
this as UnpluginBuildContext & {
|
|
151
|
+
resolve: (
|
|
152
|
+
id: string,
|
|
153
|
+
importer: string,
|
|
154
|
+
) => Promise<{
|
|
155
|
+
id: string
|
|
156
|
+
external?: boolean | 'absolute' | 'relative'
|
|
157
|
+
} | null>
|
|
158
|
+
}
|
|
159
|
+
).resolve(specifier, importer)
|
|
160
|
+
return result && !result.external ? result.id : undefined
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const native = this.getNativeBuildContext?.()
|
|
164
|
+
if (native?.framework === 'esbuild') {
|
|
165
|
+
const result = await native.build.resolve(specifier, {
|
|
166
|
+
importer,
|
|
167
|
+
kind: 'import-statement',
|
|
168
|
+
resolveDir: Path.dirname(importer),
|
|
169
|
+
})
|
|
170
|
+
if (result.errors.length)
|
|
171
|
+
throw new Error(
|
|
172
|
+
result.errors.map((error) => error.text).join('\n'),
|
|
173
|
+
)
|
|
174
|
+
return result.external ? undefined : result.path
|
|
175
|
+
}
|
|
176
|
+
if (native?.framework === 'webpack') {
|
|
177
|
+
const resolver = native.compiler.resolverFactory.get('normal', {
|
|
178
|
+
dependencyType: 'esm',
|
|
179
|
+
})
|
|
180
|
+
return new Promise<string | undefined>((accept, reject) => {
|
|
181
|
+
resolver.resolve(
|
|
182
|
+
{},
|
|
183
|
+
Path.dirname(importer),
|
|
184
|
+
specifier,
|
|
185
|
+
{},
|
|
186
|
+
(error, result) => {
|
|
187
|
+
if (error) reject(error)
|
|
188
|
+
else accept(result || undefined)
|
|
189
|
+
},
|
|
190
|
+
)
|
|
191
|
+
})
|
|
192
|
+
}
|
|
193
|
+
throw new Error('The bundler does not expose module resolution.')
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
async function contract(
|
|
197
|
+
file: string,
|
|
198
|
+
required = false,
|
|
199
|
+
): Promise<boolean> {
|
|
200
|
+
if (Object.hasOwn(contracts, file)) return true
|
|
201
|
+
const sidecar = `${file}.zyzz.json`
|
|
202
|
+
|
|
203
|
+
files.add(sidecar)
|
|
204
|
+
try {
|
|
205
|
+
contracts[file] = await Fs.readFile(sidecar, 'utf8')
|
|
206
|
+
} catch (error) {
|
|
207
|
+
if (
|
|
208
|
+
!required &&
|
|
209
|
+
(error as NodeJS.ErrnoException).code === 'ENOENT'
|
|
210
|
+
)
|
|
211
|
+
return false
|
|
212
|
+
|
|
213
|
+
throw error
|
|
214
|
+
}
|
|
215
|
+
const metadata = Contract.read(contracts[file]!, new Map(), file)
|
|
216
|
+
for (const section of metadata.stylesheets) {
|
|
217
|
+
let owner = file
|
|
218
|
+
for (const specifier of section.dependency ?? []) {
|
|
219
|
+
const target = await resolve(specifier, owner)
|
|
220
|
+
if (!target)
|
|
221
|
+
throw new Error(
|
|
222
|
+
`Unable to resolve packed stylesheet dependency: ${specifier}`,
|
|
223
|
+
)
|
|
224
|
+
;(imports[owner] ??= Object.create(null))[specifier] = target
|
|
225
|
+
await contract(target, true)
|
|
226
|
+
owner = target
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return true
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
await scan(root)
|
|
233
|
+
for (const [file, source] of sources) {
|
|
234
|
+
const links = (imports[identity(file)] = Object.create(null))
|
|
235
|
+
for (const node of Parser.parseSync(file, source, {
|
|
236
|
+
sourceType: 'module',
|
|
237
|
+
}).program.body) {
|
|
238
|
+
if (
|
|
239
|
+
(node.type !== 'ImportDeclaration' &&
|
|
240
|
+
node.type !== 'ExportNamedDeclaration' &&
|
|
241
|
+
node.type !== 'ExportAllDeclaration') ||
|
|
242
|
+
!node.source
|
|
243
|
+
)
|
|
244
|
+
continue
|
|
245
|
+
if (
|
|
246
|
+
node.type === 'ImportDeclaration'
|
|
247
|
+
? node.importKind === 'type'
|
|
248
|
+
: node.exportKind === 'type'
|
|
249
|
+
)
|
|
250
|
+
continue
|
|
251
|
+
if (
|
|
252
|
+
'specifiers' in node &&
|
|
253
|
+
node.specifiers.length &&
|
|
254
|
+
node.specifiers.every((specifier) =>
|
|
255
|
+
specifier.type === 'ImportSpecifier'
|
|
256
|
+
? specifier.importKind === 'type'
|
|
257
|
+
: specifier.type === 'ExportSpecifier' &&
|
|
258
|
+
specifier.exportKind === 'type',
|
|
259
|
+
)
|
|
260
|
+
)
|
|
261
|
+
continue
|
|
262
|
+
|
|
263
|
+
const specifier = node.source.value
|
|
264
|
+
links[specifier] = null
|
|
265
|
+
if (
|
|
266
|
+
specifier === 'zyzz' ||
|
|
267
|
+
(specifier.startsWith('zyzz/') &&
|
|
268
|
+
specifier !== 'zyzz/default') ||
|
|
269
|
+
/^(?:[a-z][a-z\d+.-]*:|\/\/)/i.test(specifier) ||
|
|
270
|
+
specifier.includes('?')
|
|
271
|
+
)
|
|
272
|
+
continue
|
|
273
|
+
const target = await resolve(specifier, file)
|
|
274
|
+
if (!target || !sourcePattern.test(target)) continue
|
|
275
|
+
files.add(target)
|
|
276
|
+
if (sources.has(target)) links[specifier] = identity(target)
|
|
277
|
+
else if (await contract(target)) links[specifier] = target
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const result = compiler.compile({
|
|
282
|
+
compiler: options.compiler,
|
|
283
|
+
contracts,
|
|
284
|
+
imports,
|
|
285
|
+
modules,
|
|
286
|
+
})
|
|
287
|
+
const copied = new Map<string, string>()
|
|
288
|
+
const owners = new Map<string, string>()
|
|
289
|
+
|
|
290
|
+
async function owner(id: string): Promise<string> {
|
|
291
|
+
if (id.startsWith('app/')) return Fs.realpath(root)
|
|
292
|
+
const cached = owners.get(id)
|
|
293
|
+
if (cached) return cached
|
|
294
|
+
|
|
295
|
+
let directory = Path.dirname(id)
|
|
296
|
+
for (;;) {
|
|
297
|
+
try {
|
|
298
|
+
await Fs.access(Path.join(directory, 'package.json'))
|
|
299
|
+
const real = await Fs.realpath(directory)
|
|
300
|
+
owners.set(id, real)
|
|
301
|
+
return real
|
|
302
|
+
} catch (error) {
|
|
303
|
+
if ((error as NodeJS.ErrnoException).code !== 'ENOENT')
|
|
304
|
+
throw error
|
|
305
|
+
const parent = Path.dirname(directory)
|
|
306
|
+
if (parent === directory)
|
|
307
|
+
throw new Error(
|
|
308
|
+
'Packed assets require an owning package.json.',
|
|
309
|
+
)
|
|
310
|
+
directory = parent
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
async function copy(file: string, boundary: string): Promise<string> {
|
|
316
|
+
const real = await Fs.realpath(file)
|
|
317
|
+
if (!inside(boundary, real))
|
|
318
|
+
throw new Error('Asset path escapes its owning package.')
|
|
319
|
+
files.add(real)
|
|
320
|
+
const cached = copied.get(real)
|
|
321
|
+
if (cached) return cached
|
|
322
|
+
|
|
323
|
+
const content = await Fs.readFile(real)
|
|
324
|
+
const name = `zyzz-assets/${Crypto.hash('sha256', real + '\0' + content.toString('base64')).slice(0, 16)}${Path.extname(real)}`
|
|
325
|
+
copied.set(real, name)
|
|
326
|
+
if (real.endsWith('.css')) {
|
|
327
|
+
const processed = await stylesheet(
|
|
328
|
+
content.toString(),
|
|
329
|
+
undefined,
|
|
330
|
+
real,
|
|
331
|
+
boundary,
|
|
332
|
+
Path.posix.dirname(name),
|
|
333
|
+
)
|
|
334
|
+
assets.set(name, processed.code)
|
|
335
|
+
} else assets.set(name, content)
|
|
336
|
+
return name
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
async function stylesheet(
|
|
340
|
+
source: string,
|
|
341
|
+
map: string | undefined,
|
|
342
|
+
file: string,
|
|
343
|
+
boundary: string,
|
|
344
|
+
outputDirectory = '.',
|
|
345
|
+
targets?: Readonly<Record<string, string>>,
|
|
346
|
+
) {
|
|
347
|
+
const urls = new Set<string>()
|
|
348
|
+
AtRules.transform({
|
|
349
|
+
code: Buffer.from(source),
|
|
350
|
+
filename: file,
|
|
351
|
+
visitor: {
|
|
352
|
+
Rule(rule) {
|
|
353
|
+
if (rule.type === 'import') urls.add(rule.value.url)
|
|
354
|
+
},
|
|
355
|
+
Url(url) {
|
|
356
|
+
urls.add(url.url)
|
|
357
|
+
},
|
|
358
|
+
},
|
|
359
|
+
})
|
|
360
|
+
const replacements = new Map<string, string>()
|
|
361
|
+
for (const url of urls) {
|
|
362
|
+
const target = targets?.[url]
|
|
363
|
+
if (
|
|
364
|
+
!target &&
|
|
365
|
+
(!url || /^(?:[a-z][a-z\d+.-]*:|[/?#])/i.test(url))
|
|
366
|
+
)
|
|
367
|
+
continue
|
|
368
|
+
const raw = (target ?? url).split(/[?#]/)[0]!
|
|
369
|
+
const path = (() => {
|
|
370
|
+
if (!target)
|
|
371
|
+
return Path.resolve(
|
|
372
|
+
Path.dirname(file),
|
|
373
|
+
decodeURIComponent(raw),
|
|
374
|
+
)
|
|
375
|
+
if (raw.startsWith('app/'))
|
|
376
|
+
return Path.join(root, decodeURIComponent(raw.slice(4)))
|
|
377
|
+
return decodeURIComponent(raw)
|
|
378
|
+
})()
|
|
379
|
+
const assetOwner = target
|
|
380
|
+
? await owner(result.sharedAssetOwners?.[url] ?? 'app/')
|
|
381
|
+
: boundary
|
|
382
|
+
const name = await copy(path, assetOwner)
|
|
383
|
+
replacements.set(
|
|
384
|
+
url,
|
|
385
|
+
Path.posix.relative(outputDirectory, name) +
|
|
386
|
+
(target ?? url).slice(raw.length),
|
|
387
|
+
)
|
|
388
|
+
}
|
|
389
|
+
return AtRules.transform({
|
|
390
|
+
code: Buffer.from(source),
|
|
391
|
+
filename: file,
|
|
392
|
+
...(map === undefined
|
|
393
|
+
? {}
|
|
394
|
+
: { inputSourceMap: map, sourceMap: true }),
|
|
395
|
+
visitor: {
|
|
396
|
+
Rule(rule) {
|
|
397
|
+
if (rule.type !== 'import') return
|
|
398
|
+
const url = replacements.get(rule.value.url)
|
|
399
|
+
if (url) return AtRules.relocateImport(rule.value, url)
|
|
400
|
+
},
|
|
401
|
+
Url(url) {
|
|
402
|
+
const target = replacements.get(url.url)
|
|
403
|
+
if (target) return { ...url, url: target }
|
|
404
|
+
},
|
|
405
|
+
},
|
|
406
|
+
})
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
const shared = await stylesheet(
|
|
410
|
+
result.sharedCss ?? '',
|
|
411
|
+
JSON.stringify(
|
|
412
|
+
result.sharedCssMap ??
|
|
413
|
+
Mapping.toEncodedMap(new Mapping.GenMapping()),
|
|
414
|
+
),
|
|
415
|
+
Path.join(root, 'zyzz.css'),
|
|
416
|
+
await Fs.realpath(root),
|
|
417
|
+
'.',
|
|
418
|
+
result.sharedAssets,
|
|
419
|
+
)
|
|
420
|
+
const chunks = [
|
|
421
|
+
{
|
|
422
|
+
code: Buffer.from(shared.code).toString(),
|
|
423
|
+
map: Buffer.from(shared.map!).toString(),
|
|
424
|
+
},
|
|
425
|
+
]
|
|
426
|
+
const seen = new Set<string>()
|
|
427
|
+
async function visit(id: string): Promise<void> {
|
|
428
|
+
if (seen.has(id)) return
|
|
429
|
+
seen.add(id)
|
|
430
|
+
for (const dependency of result.dependencies[id] ?? [])
|
|
431
|
+
await visit(dependency)
|
|
432
|
+
const output = result.modules[id]
|
|
433
|
+
if (output) {
|
|
434
|
+
const processed = await stylesheet(
|
|
435
|
+
output.css,
|
|
436
|
+
JSON.stringify(output.cssMap),
|
|
437
|
+
Path.join(root, id.slice(4)),
|
|
438
|
+
await Fs.realpath(root),
|
|
439
|
+
)
|
|
440
|
+
chunks.push({
|
|
441
|
+
code: Buffer.from(processed.code).toString(),
|
|
442
|
+
map: Buffer.from(processed.map!).toString(),
|
|
443
|
+
})
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
const ids = Object.keys(result.modules)
|
|
447
|
+
const imported = new Set(Object.values(result.dependencies).flat())
|
|
448
|
+
for (const id of ids) if (!imported.has(id)) await visit(id)
|
|
449
|
+
for (const id of ids) await visit(id)
|
|
450
|
+
|
|
451
|
+
const map = new Mapping.GenMapping({ file: 'zyzz.css' })
|
|
452
|
+
let line = 0
|
|
453
|
+
css = ''
|
|
454
|
+
for (const chunk of chunks) {
|
|
455
|
+
if (!chunk.code) continue
|
|
456
|
+
const traced = Mapping.fromMap(chunk.map)
|
|
457
|
+
for (const mapping of Mapping.allMappings(traced)) {
|
|
458
|
+
const generated = {
|
|
459
|
+
line: mapping.generated.line + line,
|
|
460
|
+
column: mapping.generated.column,
|
|
461
|
+
}
|
|
462
|
+
if (
|
|
463
|
+
mapping.source !== undefined &&
|
|
464
|
+
mapping.original !== undefined
|
|
465
|
+
) {
|
|
466
|
+
const location = {
|
|
467
|
+
generated,
|
|
468
|
+
original: mapping.original,
|
|
469
|
+
source: mapping.source.startsWith('app/')
|
|
470
|
+
? Path.join(root, mapping.source.slice(4))
|
|
471
|
+
: mapping.source,
|
|
472
|
+
}
|
|
473
|
+
if (mapping.name === undefined)
|
|
474
|
+
Mapping.addMapping(map, location)
|
|
475
|
+
else
|
|
476
|
+
Mapping.addMapping(map, { ...location, name: mapping.name })
|
|
477
|
+
} else Mapping.addMapping(map, { generated })
|
|
478
|
+
}
|
|
479
|
+
const encoded = Mapping.toEncodedMap(traced)
|
|
480
|
+
encoded.sources.forEach((source, index) => {
|
|
481
|
+
if (source !== null)
|
|
482
|
+
Mapping.setSourceContent(
|
|
483
|
+
map,
|
|
484
|
+
source.startsWith('app/')
|
|
485
|
+
? Path.join(root, source.slice(4))
|
|
486
|
+
: source,
|
|
487
|
+
encoded.sourcesContent?.[index] ?? null,
|
|
488
|
+
)
|
|
489
|
+
})
|
|
490
|
+
css += chunk.code + '\n'
|
|
491
|
+
line += chunk.code.split('\n').length
|
|
492
|
+
}
|
|
493
|
+
cssMap = JSON.stringify(Mapping.toEncodedMap(map))
|
|
494
|
+
script = Catalogs.scripts(
|
|
495
|
+
Object.values({ ...contracts, ...result.contracts }).flatMap(
|
|
496
|
+
Catalogs.read,
|
|
497
|
+
),
|
|
498
|
+
).join('\n')
|
|
499
|
+
graph = result
|
|
500
|
+
if (meta.framework === 'webpack') emit(this)
|
|
501
|
+
if (meta.framework === 'rollup')
|
|
502
|
+
for (const file of [...files, ...directories])
|
|
503
|
+
this.addWatchFile(file)
|
|
504
|
+
})()
|
|
505
|
+
await pending
|
|
506
|
+
},
|
|
507
|
+
enforce: 'pre',
|
|
508
|
+
esbuild: {
|
|
509
|
+
config(options) {
|
|
510
|
+
if (!options.outdir || options.write === false)
|
|
511
|
+
throw new Error(
|
|
512
|
+
'Zyzz requires esbuild outdir and write: true to emit CSS assets.',
|
|
513
|
+
)
|
|
514
|
+
options.outdir = Path.resolve(
|
|
515
|
+
options.absWorkingDir ?? process.cwd(),
|
|
516
|
+
options.outdir,
|
|
517
|
+
)
|
|
518
|
+
},
|
|
519
|
+
setup(build) {
|
|
520
|
+
// Unplugin forwards watchFiles but not watchDirs from its transform hook.
|
|
521
|
+
build.onLoad({ filter: sourcePattern }, async ({ path }) => {
|
|
522
|
+
await pending
|
|
523
|
+
if (!sources.has(path)) return
|
|
524
|
+
const output = transform(await Fs.readFile(path, 'utf8'), path)
|
|
525
|
+
if (!output) return
|
|
526
|
+
return {
|
|
527
|
+
contents: `${output.code}\n//# sourceMappingURL=data:application/json;base64,${Buffer.from(output.map).toString('base64')}`,
|
|
528
|
+
loader: (() => {
|
|
529
|
+
if (path.endsWith('.tsx')) return 'tsx'
|
|
530
|
+
if (path.endsWith('.jsx')) return 'jsx'
|
|
531
|
+
if (/\.[cm]?ts$/.test(path)) return 'ts'
|
|
532
|
+
return 'js'
|
|
533
|
+
})(),
|
|
534
|
+
resolveDir: Path.dirname(path),
|
|
535
|
+
watchDirs: [...directories],
|
|
536
|
+
watchFiles: [...files],
|
|
537
|
+
}
|
|
538
|
+
})
|
|
539
|
+
},
|
|
540
|
+
},
|
|
541
|
+
name: 'zyzz',
|
|
542
|
+
rollup: {
|
|
543
|
+
shouldTransformCachedModule() {
|
|
544
|
+
return true
|
|
545
|
+
},
|
|
546
|
+
},
|
|
547
|
+
transform: {
|
|
548
|
+
filter: {
|
|
549
|
+
id: {
|
|
550
|
+
include: sourcePattern,
|
|
551
|
+
exclude:
|
|
552
|
+
/(?:^|[/\\])node_modules[/\\]|\.(?:d|test|test-d|bench|bench-d)\.[cm]?[jt]sx?$/,
|
|
553
|
+
},
|
|
554
|
+
},
|
|
555
|
+
async handler(code, id) {
|
|
556
|
+
await pending
|
|
557
|
+
const output = transform(code, id)
|
|
558
|
+
if (!output) return
|
|
559
|
+
for (const file of files) this.addWatchFile(file)
|
|
560
|
+
const native = this.getNativeBuildContext?.()
|
|
561
|
+
for (const directory of directories) {
|
|
562
|
+
if (native?.framework === 'webpack')
|
|
563
|
+
native.loaderContext?.addContextDependency(directory)
|
|
564
|
+
else if (meta.framework === 'rollup') this.addWatchFile(directory)
|
|
565
|
+
}
|
|
566
|
+
return output
|
|
567
|
+
},
|
|
568
|
+
},
|
|
569
|
+
webpack(compiler) {
|
|
570
|
+
compiler.hooks.watchRun.tap('zyzz', () => {
|
|
571
|
+
// Directory invalidations must also discard cached source reads before the graph and loaders rebuild.
|
|
572
|
+
for (const file of compiler.modifiedFiles ?? [])
|
|
573
|
+
if (directories.has(file)) compiler.inputFileSystem?.purge?.(file)
|
|
574
|
+
})
|
|
575
|
+
},
|
|
576
|
+
}
|
|
577
|
+
},
|
|
578
|
+
)
|
|
579
|
+
|
|
580
|
+
/** Bundler factories. Vite retains its native CSS delivery and environment-specific HMR. */
|
|
581
|
+
export const zyzz = {
|
|
582
|
+
/** Creates an esbuild plugin that emits stylesheets and watches source directories. */
|
|
583
|
+
esbuild: portable.esbuild,
|
|
584
|
+
/** Creates a Rollup plugin with dependency-aware cached transforms. */
|
|
585
|
+
rollup: portable.rollup,
|
|
586
|
+
/** Creates the existing Vite plugin with automatic CSS delivery and HMR. */
|
|
587
|
+
vite: Vite.zyzz,
|
|
588
|
+
/** Creates a Webpack plugin that compiles before language loaders. */
|
|
589
|
+
webpack: portable.webpack,
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
function inside(parent: string, child: string) {
|
|
593
|
+
const relative = Path.relative(parent, child)
|
|
594
|
+
return (
|
|
595
|
+
relative === '' ||
|
|
596
|
+
(relative !== '..' &&
|
|
597
|
+
!relative.startsWith(`..${Path.sep}`) &&
|
|
598
|
+
!Path.isAbsolute(relative))
|
|
599
|
+
)
|
|
600
|
+
}
|
package/src/variants.ts
CHANGED
|
@@ -6,7 +6,7 @@ import type * as Binding from './internal/Binding.js'
|
|
|
6
6
|
import type * as Condition from './internal/Condition.js'
|
|
7
7
|
import type * as Shorthands from './internal/Shorthands.js'
|
|
8
8
|
import type * as Style from './Style.js'
|
|
9
|
-
import type * as Theme from './Theme.js'
|
|
9
|
+
import type * as Theme from './internal/Theme.js'
|
|
10
10
|
|
|
11
11
|
type Axes<definition> = definition extends { readonly variants: infer axes }
|
|
12
12
|
? axes
|
|
@@ -62,8 +62,10 @@ type Keys<value> = value extends unknown ? keyof value : never
|
|
|
62
62
|
type Selections<axes> = {
|
|
63
63
|
readonly [axis in keyof axes]?: Choice<axes[axis]> | null | undefined
|
|
64
64
|
}
|
|
65
|
-
type Input<definition> = Selections<
|
|
66
|
-
|
|
65
|
+
type Input<definition, output extends style.Output> = Selections<
|
|
66
|
+
Axes<definition>
|
|
67
|
+
> &
|
|
68
|
+
style.Options<output> &
|
|
67
69
|
(keyof Conditions<definition> extends never
|
|
68
70
|
? {}
|
|
69
71
|
: {
|
|
@@ -191,10 +193,10 @@ export declare namespace variants {
|
|
|
191
193
|
|
|
192
194
|
/** Callable selection; omitted values use defaults and null suppresses them. */
|
|
193
195
|
type ReturnType<definition, output extends style.Output = 'react'> = <
|
|
194
|
-
const input extends Input<definition> = Input<definition>,
|
|
196
|
+
const input extends Input<definition, output> = Input<definition, output>,
|
|
195
197
|
>(
|
|
196
198
|
input?: input &
|
|
197
|
-
Record<Exclude<Keys<input>, keyof Input<definition>>, never>,
|
|
199
|
+
Record<Exclude<Keys<input>, keyof Input<definition, output>>, never>,
|
|
198
200
|
) => style.Props<output> & {
|
|
199
201
|
readonly [axis in keyof Axes<definition> as `data-${axis & string}`]?:
|
|
200
202
|
| string
|
package/src/vite/index.ts
CHANGED
|
@@ -10,6 +10,7 @@ import * as Lightning from 'lightningcss'
|
|
|
10
10
|
import * as Crypto from 'node:crypto'
|
|
11
11
|
import * as Fs from 'node:fs/promises'
|
|
12
12
|
import * as Path from 'node:path'
|
|
13
|
+
import { isBuiltin } from 'node:module'
|
|
13
14
|
import * as Parser from 'oxc-parser'
|
|
14
15
|
import * as Walker from 'oxc-walker'
|
|
15
16
|
import * as Scope from '../compiler/internal/Scope.js'
|
|
@@ -28,8 +29,7 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
28
29
|
...options.native,
|
|
29
30
|
fonts:
|
|
30
31
|
options.native.fonts && Object.freeze({ ...options.native.fonts }),
|
|
31
|
-
|
|
32
|
-
options.native.themes && Object.freeze({ ...options.native.themes }),
|
|
32
|
+
vars: options.native.vars && Object.freeze({ ...options.native.vars }),
|
|
33
33
|
units:
|
|
34
34
|
options.native.units && Object.freeze({ ...options.native.units }),
|
|
35
35
|
})
|
|
@@ -296,6 +296,7 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
296
296
|
everything = false,
|
|
297
297
|
) {
|
|
298
298
|
async function resolve(source: string, importer: string) {
|
|
299
|
+
if (isBuiltin(source)) return { id: source, external: true }
|
|
299
300
|
const resolved = await host.resolve(source, importer)
|
|
300
301
|
if (!resolved) return resolved
|
|
301
302
|
|
|
@@ -523,8 +524,7 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
523
524
|
const specifier = node.source.value
|
|
524
525
|
if (
|
|
525
526
|
specifier === 'zyzz' ||
|
|
526
|
-
(specifier.startsWith('zyzz/') &&
|
|
527
|
-
specifier !== 'zyzz/default')
|
|
527
|
+
(specifier.startsWith('zyzz/') && specifier !== 'zyzz/default')
|
|
528
528
|
)
|
|
529
529
|
continue
|
|
530
530
|
|
|
@@ -1241,6 +1241,7 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
|
|
|
1241
1241
|
},
|
|
1242
1242
|
async load(id) {
|
|
1243
1243
|
if (!id.startsWith(prefix)) return
|
|
1244
|
+
id = id.split('?', 1)[0]!
|
|
1244
1245
|
|
|
1245
1246
|
const file =
|
|
1246
1247
|
id === sharedId
|