zyzz 0.0.21 → 0.0.22
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/Zyzz.podspec +16 -0
- package/dist/Style.d.ts +3 -1
- package/dist/Style.d.ts.map +1 -1
- package/dist/Style.js.map +1 -1
- package/dist/babel/NativeJsx.d.ts.map +1 -1
- package/dist/babel/NativeJsx.js +204 -12
- package/dist/babel/NativeJsx.js.map +1 -1
- package/dist/babel/index.d.ts +6 -2
- package/dist/babel/index.d.ts.map +1 -1
- package/dist/babel/index.js +10 -1
- package/dist/babel/index.js.map +1 -1
- package/dist/compiler/Graph.d.ts.map +1 -1
- package/dist/compiler/Graph.js +64 -0
- package/dist/compiler/Graph.js.map +1 -1
- package/dist/compiler/Native.d.ts +6 -3
- package/dist/compiler/Native.d.ts.map +1 -1
- package/dist/compiler/Native.js +142 -24
- package/dist/compiler/Native.js.map +1 -1
- package/dist/compiler/Source.d.ts +2 -0
- package/dist/compiler/Source.d.ts.map +1 -1
- package/dist/compiler/Source.js +17 -5
- package/dist/compiler/Source.js.map +1 -1
- package/dist/compiler/internal/Configurations.d.ts +2 -0
- package/dist/compiler/internal/Configurations.d.ts.map +1 -1
- package/dist/compiler/internal/Configurations.js +21 -3
- 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 +75 -38
- 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 +7 -1
- package/dist/compiler/internal/Contributions.js.map +1 -1
- package/dist/compiler/internal/Descriptors.d.ts.map +1 -1
- package/dist/compiler/internal/Descriptors.js +11 -2
- package/dist/compiler/internal/Descriptors.js.map +1 -1
- package/dist/compiler/internal/NativeBindings.d.ts +24 -26
- package/dist/compiler/internal/NativeBindings.d.ts.map +1 -1
- package/dist/compiler/internal/NativeBindings.js +61 -8
- package/dist/compiler/internal/NativeBindings.js.map +1 -1
- package/dist/compiler/internal/NativeMedia.d.ts +14 -0
- package/dist/compiler/internal/NativeMedia.d.ts.map +1 -0
- package/dist/compiler/internal/NativeMedia.js +287 -0
- package/dist/compiler/internal/NativeMedia.js.map +1 -0
- package/dist/compiler/internal/NativeVars.d.ts +28 -0
- package/dist/compiler/internal/NativeVars.d.ts.map +1 -0
- package/dist/compiler/internal/NativeVars.js +157 -0
- package/dist/compiler/internal/NativeVars.js.map +1 -0
- package/dist/compiler/internal/PackedStyles.d.ts +2 -0
- package/dist/compiler/internal/PackedStyles.d.ts.map +1 -1
- package/dist/compiler/internal/PackedStyles.js +2 -0
- package/dist/compiler/internal/PackedStyles.js.map +1 -1
- package/dist/compiler/internal/Themes.d.ts +22 -1
- package/dist/compiler/internal/Themes.d.ts.map +1 -1
- package/dist/compiler/internal/Themes.js +118 -3
- package/dist/compiler/internal/Themes.js.map +1 -1
- package/dist/compiler/internal/Vars.d.ts +1 -1
- package/dist/compiler/internal/Vars.d.ts.map +1 -1
- package/dist/compiler/internal/Vars.js +7 -2
- package/dist/compiler/internal/Vars.js.map +1 -1
- package/dist/default.js.zyzz.json +1 -1
- package/dist/internal/Completion.d.ts +1 -1
- package/dist/internal/Completion.d.ts.map +1 -1
- package/dist/internal/Targets.d.ts.map +1 -1
- package/dist/internal/Targets.js +2 -0
- package/dist/internal/Targets.js.map +1 -1
- package/dist/internal/Token.d.ts +0 -2
- package/dist/internal/Token.d.ts.map +1 -1
- package/dist/internal/Token.js.map +1 -1
- package/dist/internal/Value.d.ts +7 -0
- package/dist/internal/Value.d.ts.map +1 -1
- package/dist/internal/Value.js.map +1 -1
- package/dist/metro/Graph.d.ts +22 -7
- package/dist/metro/Graph.d.ts.map +1 -1
- package/dist/metro/Graph.js +179 -42
- package/dist/metro/Graph.js.map +1 -1
- package/dist/metro/Watch.d.ts +28 -4
- package/dist/metro/Watch.d.ts.map +1 -1
- package/dist/metro/Watch.js +39 -7
- package/dist/metro/Watch.js.map +1 -1
- package/dist/metro/index.d.ts +15 -4
- package/dist/metro/index.d.ts.map +1 -1
- package/dist/metro/index.js +27 -0
- package/dist/metro/index.js.map +1 -1
- package/dist/metro/transformer.d.ts +5 -1
- package/dist/metro/transformer.d.ts.map +1 -1
- package/dist/metro/transformer.js +5 -3
- package/dist/metro/transformer.js.map +1 -1
- package/dist/react-native/StyleSheet.d.ts +3 -2
- package/dist/react-native/StyleSheet.d.ts.map +1 -1
- package/dist/react-native/StyleSheet.js +17 -34
- package/dist/react-native/StyleSheet.js.map +1 -1
- package/dist/react-native/index.d.ts +1 -1
- package/dist/react-native/index.d.ts.map +1 -1
- package/dist/react-native/index.js +1 -1
- package/dist/react-native/index.js.map +1 -1
- package/dist/react-native/index.native.d.ts +5 -0
- package/dist/react-native/index.native.js +20 -0
- package/dist/react-native/index.native.js.map +7 -0
- package/dist/react-native/internal/Calculation.d.ts +7 -0
- package/dist/react-native/internal/Calculation.d.ts.map +1 -0
- package/dist/react-native/internal/Calculation.js +134 -0
- package/dist/react-native/internal/Calculation.js.map +1 -0
- package/dist/react-native/internal/Device.js +191 -0
- package/dist/react-native/internal/Device.js.map +7 -0
- package/dist/react-native/internal/NativeZyzz.js +7 -0
- package/dist/react-native/internal/NativeZyzz.js.map +7 -0
- package/dist/react-native/internal/Scalar.d.ts.map +1 -1
- package/dist/react-native/internal/Scalar.js +9 -2
- package/dist/react-native/internal/Scalar.js.map +1 -1
- package/dist/react-native/internal/Store.d.ts +32 -0
- package/dist/react-native/internal/Store.d.ts.map +1 -0
- package/dist/react-native/internal/Store.js +57 -0
- package/dist/react-native/internal/Store.js.map +1 -0
- package/dist/react-native/internal/Tokens.d.ts +21 -0
- package/dist/react-native/internal/Tokens.d.ts.map +1 -0
- package/dist/react-native/internal/Tokens.js +58 -0
- package/dist/react-native/internal/Tokens.js.map +1 -0
- package/dist/react-native/internal/Viewport.d.ts +6 -0
- package/dist/react-native/internal/Viewport.d.ts.map +1 -0
- package/dist/react-native/internal/Viewport.js +4 -0
- package/dist/react-native/internal/Viewport.js.map +1 -0
- package/dist/react-native/react.d.ts +74 -11
- package/dist/react-native/react.d.ts.map +1 -1
- package/dist/react-native/react.js +111 -12
- package/dist/react-native/react.js.map +1 -1
- package/dist/react-native/reanimated.d.ts +39 -0
- package/dist/react-native/reanimated.d.ts.map +1 -0
- package/dist/react-native/reanimated.js +76 -0
- package/dist/react-native/reanimated.js.map +1 -0
- package/dist/runtime/NativeContext.d.ts +10 -1
- package/dist/runtime/NativeContext.d.ts.map +1 -1
- package/dist/runtime/NativeContext.js +67 -14
- package/dist/runtime/NativeContext.js.map +1 -1
- package/dist/runtime/NativeDynamic.d.ts +3 -2
- package/dist/runtime/NativeDynamic.d.ts.map +1 -1
- package/dist/runtime/NativeDynamic.js +32 -7
- package/dist/runtime/NativeDynamic.js.map +1 -1
- package/dist/runtime/NativeStatic.d.ts +23 -0
- package/dist/runtime/NativeStatic.d.ts.map +1 -0
- package/dist/runtime/NativeStatic.js +106 -0
- package/dist/runtime/NativeStatic.js.map +1 -0
- package/dist/runtime/NativeVars.d.ts +53 -0
- package/dist/runtime/NativeVars.d.ts.map +1 -0
- package/dist/runtime/NativeVars.js +77 -0
- package/dist/runtime/NativeVars.js.map +1 -0
- package/dist/runtime/index.d.ts +4 -0
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +4 -0
- package/dist/runtime/index.js.map +1 -1
- package/dist/runtime/internal/NativeMedia.d.ts +25 -0
- package/dist/runtime/internal/NativeMedia.d.ts.map +1 -0
- package/dist/runtime/internal/NativeMedia.js +36 -0
- package/dist/runtime/internal/NativeMedia.js.map +1 -0
- package/dist/vite/index.d.ts.map +1 -1
- package/dist/vite/index.js +7 -35
- package/dist/vite/index.js.map +1 -1
- package/dist/web/Css.d.ts.map +1 -1
- package/dist/web/Css.js +31 -19
- package/dist/web/Css.js.map +1 -1
- package/dist/web/internal/Themes.d.ts +0 -2
- package/dist/web/internal/Themes.d.ts.map +1 -1
- package/dist/web/internal/Themes.js +30 -28
- package/dist/web/internal/Themes.js.map +1 -1
- package/dist/web/page.d.ts +2 -0
- package/dist/web/page.d.ts.map +1 -1
- package/native/NativeZyzz.cpp +215 -0
- package/native/NativeZyzz.h +52 -0
- package/native/ZyzzSpecJSI.h +65 -0
- package/native/android/CMakeLists.txt +8 -0
- package/native/android/ZyzzSpec-generated.cpp +50 -0
- package/native/android/ZyzzSpec.h +31 -0
- package/native/ios/ZyzzModuleProvider.mm +13 -0
- package/package.json +39 -1
- package/react-native.config.ts +14 -0
- package/src/Style.ts +11 -8
- package/src/babel/NativeJsx.ts +305 -28
- package/src/babel/index.ts +21 -3
- package/src/compiler/Graph.ts +75 -0
- package/src/compiler/Native.ts +158 -26
- package/src/compiler/Source.ts +32 -5
- package/src/compiler/internal/Configurations.ts +25 -3
- package/src/compiler/internal/Contract.ts +98 -50
- package/src/compiler/internal/Contributions.ts +7 -1
- package/src/compiler/internal/Descriptors.ts +12 -8
- package/src/compiler/internal/NativeBindings.ts +98 -15
- package/src/compiler/internal/NativeMedia.ts +342 -0
- package/src/compiler/internal/NativeVars.ts +228 -0
- package/src/compiler/internal/PackedStyles.ts +4 -0
- package/src/compiler/internal/Themes.ts +187 -2
- package/src/compiler/internal/Vars.ts +12 -1
- package/src/internal/Completion.ts +6 -3
- package/src/internal/Targets.ts +2 -0
- package/src/internal/Token.ts +0 -2
- package/src/internal/Value.ts +20 -0
- package/src/metro/Graph.ts +235 -50
- package/src/metro/Watch.ts +95 -10
- package/src/metro/index.ts +62 -4
- package/src/metro/transformer.ts +21 -11
- package/src/react-native/StyleSheet.ts +28 -44
- package/src/react-native/index.native.ts +10 -0
- package/src/react-native/index.ts +1 -1
- package/src/react-native/internal/Calculation.ts +159 -0
- package/src/react-native/internal/Device.ts +231 -0
- package/src/react-native/internal/NativeZyzz.ts +20 -0
- package/src/react-native/internal/Scalar.ts +13 -2
- package/src/react-native/internal/Store.ts +78 -0
- package/src/react-native/internal/Tokens.ts +85 -0
- package/src/react-native/internal/Viewport.ts +8 -0
- package/src/react-native/react.ts +211 -19
- package/src/react-native/reanimated.ts +162 -0
- package/src/runtime/NativeContext.ts +88 -17
- package/src/runtime/NativeDynamic.ts +35 -10
- package/src/runtime/NativeStatic.ts +145 -0
- package/src/runtime/NativeVars.ts +189 -0
- package/src/runtime/index.ts +6 -0
- package/src/runtime/internal/NativeMedia.ts +63 -0
- package/src/vite/index.ts +9 -42
- package/src/web/Css.ts +42 -27
- package/src/web/internal/Themes.ts +34 -57
- package/src/web/page.ts +2 -0
package/src/babel/NativeJsx.ts
CHANGED
|
@@ -112,9 +112,13 @@ export function visitor(
|
|
|
112
112
|
callables: WeakSet<Babel.types.Node>,
|
|
113
113
|
): Babel.Visitor<Babel.PluginPass> {
|
|
114
114
|
const t = api.types
|
|
115
|
-
type
|
|
115
|
+
type Method = 'nativeStyle' | 'props' | 'style' | 'view'
|
|
116
|
+
type Bindings = Map<Method, Babel.types.Identifier>
|
|
116
117
|
type Owners = Map<Babel.NodePath<Babel.types.Function>, Bindings>
|
|
117
118
|
const files = new WeakMap<Babel.BabelFile, Owners>()
|
|
119
|
+
const native = new WeakSet<Babel.types.JSXOpeningElement>()
|
|
120
|
+
const animated = new WeakSet<Babel.types.JSXOpeningElement>()
|
|
121
|
+
const wrapped = new WeakSet<Babel.types.JSXOpeningElement>()
|
|
118
122
|
return {
|
|
119
123
|
Program: {
|
|
120
124
|
enter(_, state) {
|
|
@@ -123,42 +127,233 @@ export function visitor(
|
|
|
123
127
|
exit(path, state) {
|
|
124
128
|
const owners = files.get(state.file)!
|
|
125
129
|
if (!owners.size) return
|
|
126
|
-
const
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
130
|
+
const hooks = new Map<boolean, Babel.types.Identifier>()
|
|
131
|
+
for (const native of [false, true]) {
|
|
132
|
+
if (
|
|
133
|
+
![...owners.values()].some((bindings) =>
|
|
134
|
+
[...bindings.keys()].some(
|
|
135
|
+
(method) =>
|
|
136
|
+
(method === 'nativeStyle' || method === 'view') === native,
|
|
137
|
+
),
|
|
138
|
+
)
|
|
139
|
+
)
|
|
140
|
+
continue
|
|
141
|
+
const hook = path.scope.generateUidIdentifier(
|
|
142
|
+
native ? 'useZyzzNativeStyles' : 'useZyzzStyles',
|
|
143
|
+
)
|
|
144
|
+
hooks.set(native, hook)
|
|
145
|
+
path.unshiftContainer(
|
|
146
|
+
'body',
|
|
147
|
+
t.importDeclaration(
|
|
148
|
+
[
|
|
149
|
+
t.importSpecifier(
|
|
150
|
+
t.cloneNode(hook),
|
|
151
|
+
t.identifier(native ? 'useNativeStyles' : 'useStyles'),
|
|
152
|
+
),
|
|
153
|
+
],
|
|
154
|
+
t.stringLiteral('zyzz/react-native/react'),
|
|
155
|
+
),
|
|
156
|
+
)
|
|
157
|
+
}
|
|
134
158
|
for (const [owner, bindings] of owners) {
|
|
135
159
|
if (!t.isBlockStatement(owner.node.body))
|
|
136
160
|
owner.node.body = t.blockStatement([
|
|
137
161
|
t.returnStatement(owner.node.body),
|
|
138
162
|
])
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
? [t.variableDeclarator(context, t.callExpression(hook, []))]
|
|
145
|
-
: []
|
|
146
|
-
for (const [method, binding] of bindings)
|
|
147
|
-
declarations.push(
|
|
148
|
-
t.variableDeclarator(
|
|
149
|
-
binding,
|
|
150
|
-
t.memberExpression(
|
|
151
|
-
context ?? t.callExpression(hook, []),
|
|
152
|
-
t.identifier(method),
|
|
153
|
-
),
|
|
154
|
-
),
|
|
163
|
+
const declarations: Babel.types.VariableDeclarator[] = []
|
|
164
|
+
for (const [native, hook] of hooks) {
|
|
165
|
+
const entries = [...bindings].filter(
|
|
166
|
+
([method]) =>
|
|
167
|
+
(method === 'nativeStyle' || method === 'view') === native,
|
|
155
168
|
)
|
|
169
|
+
const context =
|
|
170
|
+
entries.length > 1
|
|
171
|
+
? owner.scope.generateUidIdentifier('zyzzStyles')
|
|
172
|
+
: undefined
|
|
173
|
+
if (context)
|
|
174
|
+
declarations.push(
|
|
175
|
+
t.variableDeclarator(
|
|
176
|
+
t.cloneNode(context),
|
|
177
|
+
t.callExpression(t.cloneNode(hook), []),
|
|
178
|
+
),
|
|
179
|
+
)
|
|
180
|
+
for (const [method, binding] of entries)
|
|
181
|
+
declarations.push(
|
|
182
|
+
t.variableDeclarator(
|
|
183
|
+
t.cloneNode(binding),
|
|
184
|
+
t.memberExpression(
|
|
185
|
+
context
|
|
186
|
+
? t.cloneNode(context)
|
|
187
|
+
: t.callExpression(t.cloneNode(hook), []),
|
|
188
|
+
t.identifier(method === 'nativeStyle' ? 'style' : method),
|
|
189
|
+
),
|
|
190
|
+
),
|
|
191
|
+
)
|
|
192
|
+
}
|
|
156
193
|
owner.node.body.body.unshift(
|
|
157
194
|
t.variableDeclaration('var', declarations),
|
|
158
195
|
)
|
|
159
196
|
}
|
|
160
197
|
},
|
|
161
198
|
},
|
|
199
|
+
JSXOpeningElement: {
|
|
200
|
+
enter(path, state) {
|
|
201
|
+
const name = path.node.name
|
|
202
|
+
const root = (() => {
|
|
203
|
+
if (t.isJSXIdentifier(name)) return name
|
|
204
|
+
if (t.isJSXMemberExpression(name) && t.isJSXIdentifier(name.object))
|
|
205
|
+
return name.object
|
|
206
|
+
return undefined
|
|
207
|
+
})()
|
|
208
|
+
if (!root) return
|
|
209
|
+
const binding = path.scope.getBinding(root.name)
|
|
210
|
+
if (
|
|
211
|
+
binding?.path.parentPath?.isImportDeclaration() &&
|
|
212
|
+
binding.path.parentPath.node.source.value ===
|
|
213
|
+
'react-native-reanimated'
|
|
214
|
+
) {
|
|
215
|
+
animated.add(path.node)
|
|
216
|
+
return
|
|
217
|
+
}
|
|
218
|
+
if (binding?.constant && binding.path.isVariableDeclarator()) {
|
|
219
|
+
const call = binding.path.node.init
|
|
220
|
+
if (t.isCallExpression(call)) {
|
|
221
|
+
const callee = call.callee
|
|
222
|
+
const name = t.isIdentifier(callee)
|
|
223
|
+
? callee
|
|
224
|
+
: t.isMemberExpression(callee) &&
|
|
225
|
+
!callee.computed &&
|
|
226
|
+
t.isIdentifier(callee.object) &&
|
|
227
|
+
t.isIdentifier(callee.property, { name: 'withStyles' })
|
|
228
|
+
? callee.object
|
|
229
|
+
: undefined
|
|
230
|
+
const factory = name && binding.path.scope.getBinding(name.name)
|
|
231
|
+
if (
|
|
232
|
+
factory?.path.parentPath?.isImportDeclaration() &&
|
|
233
|
+
['zyzz/react-native', 'zyzz/react-native/react'].includes(
|
|
234
|
+
factory.path.parentPath.node.source.value,
|
|
235
|
+
) &&
|
|
236
|
+
(t.isIdentifier(callee)
|
|
237
|
+
? factory.path.isImportSpecifier() &&
|
|
238
|
+
t.isIdentifier(factory.path.node.imported, {
|
|
239
|
+
name: 'withStyles',
|
|
240
|
+
})
|
|
241
|
+
: factory.path.isImportNamespaceSpecifier())
|
|
242
|
+
) {
|
|
243
|
+
wrapped.add(path.node)
|
|
244
|
+
return
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
if (
|
|
249
|
+
!binding?.path.parentPath?.isImportDeclaration() ||
|
|
250
|
+
binding.path.parentPath.node.source.value !== 'react-native'
|
|
251
|
+
)
|
|
252
|
+
return
|
|
253
|
+
const imported = (() => {
|
|
254
|
+
if (
|
|
255
|
+
binding.path.isImportSpecifier() &&
|
|
256
|
+
t.isIdentifier(binding.path.node.imported)
|
|
257
|
+
)
|
|
258
|
+
return binding.path.node.imported.name
|
|
259
|
+
if (
|
|
260
|
+
t.isJSXMemberExpression(name) &&
|
|
261
|
+
binding.path.isImportNamespaceSpecifier()
|
|
262
|
+
)
|
|
263
|
+
return name.property.name
|
|
264
|
+
return undefined
|
|
265
|
+
})()
|
|
266
|
+
if (
|
|
267
|
+
!imported ||
|
|
268
|
+
!['Image', 'Pressable', 'Text', 'TextInput', 'View'].includes(
|
|
269
|
+
imported,
|
|
270
|
+
)
|
|
271
|
+
)
|
|
272
|
+
return
|
|
273
|
+
if (
|
|
274
|
+
!path.node.attributes.some(
|
|
275
|
+
(attribute) =>
|
|
276
|
+
t.isJSXSpreadAttribute(attribute) ||
|
|
277
|
+
(t.isJSXAttribute(attribute) &&
|
|
278
|
+
t.isJSXIdentifier(attribute.name, { name: 'style' })),
|
|
279
|
+
)
|
|
280
|
+
)
|
|
281
|
+
return
|
|
282
|
+
native.add(path.node)
|
|
283
|
+
owner(path, files.get(state.file)!, 'view')
|
|
284
|
+
},
|
|
285
|
+
exit(path, state) {
|
|
286
|
+
if (!native.has(path.node)) return
|
|
287
|
+
const properties: (
|
|
288
|
+
| Babel.types.ObjectProperty
|
|
289
|
+
| Babel.types.SpreadElement
|
|
290
|
+
)[] = []
|
|
291
|
+
for (const attribute of path.node.attributes) {
|
|
292
|
+
if (t.isJSXSpreadAttribute(attribute))
|
|
293
|
+
properties.push(t.spreadElement(attribute.argument))
|
|
294
|
+
else if (t.isJSXIdentifier(attribute.name)) {
|
|
295
|
+
const value = attribute.value
|
|
296
|
+
const expression = (() => {
|
|
297
|
+
if (value === null) return t.booleanLiteral(true)
|
|
298
|
+
if (
|
|
299
|
+
t.isJSXExpressionContainer(value) &&
|
|
300
|
+
!t.isJSXEmptyExpression(value.expression)
|
|
301
|
+
)
|
|
302
|
+
return value.expression
|
|
303
|
+
if (t.isStringLiteral(value))
|
|
304
|
+
return t.stringLiteral(value.value.replace(/\n\s+/g, ' '))
|
|
305
|
+
if (t.isJSXElement(value) || t.isJSXFragment(value)) return value
|
|
306
|
+
return undefined
|
|
307
|
+
})()
|
|
308
|
+
if (!expression)
|
|
309
|
+
throw path.buildCodeFrameError(
|
|
310
|
+
'Unsupported native JSX attribute.',
|
|
311
|
+
)
|
|
312
|
+
properties.push(
|
|
313
|
+
t.objectProperty(
|
|
314
|
+
t.stringLiteral(attribute.name.name),
|
|
315
|
+
expression,
|
|
316
|
+
),
|
|
317
|
+
)
|
|
318
|
+
} else
|
|
319
|
+
throw path.buildCodeFrameError('Unsupported native JSX attribute.')
|
|
320
|
+
}
|
|
321
|
+
const binding = owner(path, files.get(state.file)!, 'view')
|
|
322
|
+
const props = t.objectExpression(properties)
|
|
323
|
+
const key = path.node.attributes.some(
|
|
324
|
+
(attribute) =>
|
|
325
|
+
t.isJSXAttribute(attribute) &&
|
|
326
|
+
t.isJSXIdentifier(attribute.name, { name: 'key' }),
|
|
327
|
+
)
|
|
328
|
+
const temporary = key
|
|
329
|
+
? path.scope.generateUidIdentifier('zyzzProps')
|
|
330
|
+
: undefined
|
|
331
|
+
if (temporary)
|
|
332
|
+
path.scope.push({ id: t.cloneNode(temporary), kind: 'var' })
|
|
333
|
+
path.node.attributes = [
|
|
334
|
+
t.jsxSpreadAttribute(
|
|
335
|
+
t.callExpression(binding, [
|
|
336
|
+
temporary
|
|
337
|
+
? t.assignmentExpression('=', t.cloneNode(temporary), props)
|
|
338
|
+
: props,
|
|
339
|
+
]),
|
|
340
|
+
),
|
|
341
|
+
...(temporary
|
|
342
|
+
? [
|
|
343
|
+
t.jsxAttribute(
|
|
344
|
+
t.jsxIdentifier('key'),
|
|
345
|
+
t.jsxExpressionContainer(
|
|
346
|
+
t.memberExpression(
|
|
347
|
+
t.cloneNode(temporary),
|
|
348
|
+
t.identifier('key'),
|
|
349
|
+
),
|
|
350
|
+
),
|
|
351
|
+
),
|
|
352
|
+
]
|
|
353
|
+
: []),
|
|
354
|
+
]
|
|
355
|
+
},
|
|
356
|
+
},
|
|
162
357
|
JSXAttribute(path, state) {
|
|
163
358
|
if (
|
|
164
359
|
!t.isJSXIdentifier(path.node.name, { name: 'style' }) ||
|
|
@@ -166,7 +361,36 @@ export function visitor(
|
|
|
166
361
|
t.isJSXEmptyExpression(path.node.value.expression)
|
|
167
362
|
)
|
|
168
363
|
return
|
|
169
|
-
|
|
364
|
+
if (
|
|
365
|
+
animated.has(path.parentPath.node as Babel.types.JSXOpeningElement) &&
|
|
366
|
+
!requiresResolution(path, path.node.value.expression)
|
|
367
|
+
)
|
|
368
|
+
return
|
|
369
|
+
if (wrapped.has(path.parentPath.node as Babel.types.JSXOpeningElement)) {
|
|
370
|
+
const value = path.node.value.expression
|
|
371
|
+
if (t.isIdentifier(value) && callables.has(value))
|
|
372
|
+
path.node.value.expression = t.memberExpression(
|
|
373
|
+
t.callExpression(value, []),
|
|
374
|
+
t.identifier('style'),
|
|
375
|
+
)
|
|
376
|
+
else if (
|
|
377
|
+
t.isCallExpression(value) &&
|
|
378
|
+
t.isIdentifier(value.callee) &&
|
|
379
|
+
callables.has(value.callee)
|
|
380
|
+
)
|
|
381
|
+
path.node.value.expression = t.memberExpression(
|
|
382
|
+
value,
|
|
383
|
+
t.identifier('style'),
|
|
384
|
+
)
|
|
385
|
+
return
|
|
386
|
+
}
|
|
387
|
+
const binding = owner(
|
|
388
|
+
path,
|
|
389
|
+
files.get(state.file)!,
|
|
390
|
+
native.has(path.parentPath.node as Babel.types.JSXOpeningElement)
|
|
391
|
+
? 'nativeStyle'
|
|
392
|
+
: 'style',
|
|
393
|
+
)
|
|
170
394
|
let inputs = [path.node.value.expression]
|
|
171
395
|
let value = path.node.value.expression
|
|
172
396
|
while (
|
|
@@ -216,14 +440,67 @@ export function visitor(
|
|
|
216
440
|
path.node.value.expression = t.callExpression(binding, inputs)
|
|
217
441
|
},
|
|
218
442
|
JSXSpreadAttribute(path, state) {
|
|
443
|
+
if (
|
|
444
|
+
(animated.has(path.parentPath.node as Babel.types.JSXOpeningElement) &&
|
|
445
|
+
!requiresResolution(path, path.node.argument)) ||
|
|
446
|
+
native.has(path.parentPath.node as Babel.types.JSXOpeningElement) ||
|
|
447
|
+
wrapped.has(path.parentPath.node as Babel.types.JSXOpeningElement)
|
|
448
|
+
)
|
|
449
|
+
return
|
|
219
450
|
const binding = owner(path, files.get(state.file)!, 'props')
|
|
220
451
|
path.node.argument = t.callExpression(binding, [path.node.argument])
|
|
221
452
|
},
|
|
222
453
|
}
|
|
454
|
+
function requiresResolution(
|
|
455
|
+
path: Babel.NodePath,
|
|
456
|
+
expression: Babel.types.Node,
|
|
457
|
+
): boolean {
|
|
458
|
+
const pending = [{ expression, scope: path.scope }]
|
|
459
|
+
const seen = new Set<Babel.types.VariableDeclarator>()
|
|
460
|
+
for (const entry of pending) {
|
|
461
|
+
let required = false
|
|
462
|
+
t.traverseFast(entry.expression, (node) => {
|
|
463
|
+
if (
|
|
464
|
+
callables.has(node) ||
|
|
465
|
+
(entry.expression === expression && t.isCallExpression(node)) ||
|
|
466
|
+
(t.isMemberExpression(node) &&
|
|
467
|
+
!node.computed &&
|
|
468
|
+
t.isIdentifier(node.property, { name: 'style' }))
|
|
469
|
+
) {
|
|
470
|
+
required = true
|
|
471
|
+
return t.traverseFast.stop
|
|
472
|
+
}
|
|
473
|
+
// Alias factories stay opaque so worklet inputs do not become React subscriptions.
|
|
474
|
+
if (
|
|
475
|
+
t.isCallExpression(node) ||
|
|
476
|
+
t.isFunction(node) ||
|
|
477
|
+
t.isNewExpression(node)
|
|
478
|
+
)
|
|
479
|
+
return t.traverseFast.skip
|
|
480
|
+
if (!t.isIdentifier(node)) return
|
|
481
|
+
const binding = entry.scope.getBinding(node.name)
|
|
482
|
+
if (
|
|
483
|
+
binding?.constant &&
|
|
484
|
+
binding.path.isVariableDeclarator() &&
|
|
485
|
+
binding.path.node.init &&
|
|
486
|
+
!seen.has(binding.path.node)
|
|
487
|
+
) {
|
|
488
|
+
seen.add(binding.path.node)
|
|
489
|
+
pending.push({
|
|
490
|
+
expression: binding.path.node.init,
|
|
491
|
+
scope: binding.path.scope,
|
|
492
|
+
})
|
|
493
|
+
}
|
|
494
|
+
})
|
|
495
|
+
if (required) return true
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
return false
|
|
499
|
+
}
|
|
223
500
|
function owner(
|
|
224
501
|
path: Babel.NodePath,
|
|
225
502
|
owners: Owners,
|
|
226
|
-
method:
|
|
503
|
+
method: Method,
|
|
227
504
|
): Babel.types.Identifier {
|
|
228
505
|
const parent = path.findParent((candidate) => {
|
|
229
506
|
if (!candidate.isFunction()) return false
|
|
@@ -255,6 +532,6 @@ export function visitor(
|
|
|
255
532
|
binding = parent.scope.generateUidIdentifier(`zyzz${method}`)
|
|
256
533
|
bindings.set(method, binding)
|
|
257
534
|
}
|
|
258
|
-
return binding
|
|
535
|
+
return t.cloneNode(binding)
|
|
259
536
|
}
|
|
260
537
|
}
|
package/src/babel/index.ts
CHANGED
|
@@ -17,12 +17,16 @@ import * as Transform from '../compiler/Transform.js'
|
|
|
17
17
|
export type NativeOptions = {
|
|
18
18
|
/** Fixed build-time scheme. Omit for runtime selection through React. */
|
|
19
19
|
readonly colorScheme?: 'dark' | 'light' | undefined
|
|
20
|
-
/**
|
|
21
|
-
readonly
|
|
20
|
+
/** Packed authoring contracts supplied by the bundler. */
|
|
21
|
+
readonly contracts?: Graph.compile.Options['contracts']
|
|
22
|
+
/** Authored font-family text mapped to registered native families. */
|
|
23
|
+
readonly fonts?: Native.compile.Options['fonts']
|
|
22
24
|
/** Host-resolved graph imports. */
|
|
23
25
|
readonly imports?: Graph.compile.Options['imports']
|
|
24
26
|
/** Portable source identity. Defaults to a native module-local identity. */
|
|
25
27
|
readonly moduleId?: string | undefined
|
|
28
|
+
/** Closed source graph supplied by the bundler for imported authoring. */
|
|
29
|
+
readonly modules?: Readonly<Record<string, string>> | undefined
|
|
26
30
|
/** Native destination selected by the bundler. */
|
|
27
31
|
readonly platform: 'android' | 'ios'
|
|
28
32
|
/** Native compiler selection. Omission preserves existing native configurations. */
|
|
@@ -188,9 +192,11 @@ export function zyzz(
|
|
|
188
192
|
options[Compilation.key]?.programs ??
|
|
189
193
|
(parsed ? new Map([[moduleId, parsed]]) : undefined),
|
|
190
194
|
modules: { ...options.modules, [moduleId]: file.code },
|
|
195
|
+
contracts: options.contracts,
|
|
191
196
|
imports: options.imports,
|
|
192
197
|
native: {
|
|
193
198
|
[Edits.runtime]: true,
|
|
199
|
+
fonts: options.fonts,
|
|
194
200
|
platform: options.platform,
|
|
195
201
|
units: options.units,
|
|
196
202
|
colorScheme: options.colorScheme ?? 'light',
|
|
@@ -201,6 +207,7 @@ export function zyzz(
|
|
|
201
207
|
return Native.compile({
|
|
202
208
|
[Themes.context]: parsed ? { parsed, links: {} } : undefined,
|
|
203
209
|
[Edits.runtime]: true,
|
|
210
|
+
fonts: options.fonts,
|
|
204
211
|
platform: options.platform,
|
|
205
212
|
units: options.units,
|
|
206
213
|
colorScheme: options.colorScheme ?? 'light',
|
|
@@ -333,7 +340,18 @@ export function zyzz(
|
|
|
333
340
|
},
|
|
334
341
|
visitor:
|
|
335
342
|
options.target !== 'web' && options.colorScheme === undefined
|
|
336
|
-
?
|
|
343
|
+
? {
|
|
344
|
+
Program(path, state) {
|
|
345
|
+
// Bind before framework transforms clone components or rewrite imports.
|
|
346
|
+
api.traverse(
|
|
347
|
+
state.file.ast,
|
|
348
|
+
NativeJsx.visitor(api, callables),
|
|
349
|
+
path.scope,
|
|
350
|
+
state,
|
|
351
|
+
)
|
|
352
|
+
path.scope.crawl()
|
|
353
|
+
},
|
|
354
|
+
}
|
|
337
355
|
: {
|
|
338
356
|
Program(path) {
|
|
339
357
|
if (options.target !== 'web' || !options.reset) return
|
package/src/compiler/Graph.ts
CHANGED
|
@@ -8,6 +8,8 @@ import type * as Mapping from '@jridgewell/gen-mapping'
|
|
|
8
8
|
import * as Css from '../web/Css.js'
|
|
9
9
|
import * as ClassName from '../web/internal/ClassName.js'
|
|
10
10
|
import * as Native from './Native.js'
|
|
11
|
+
import * as NativeVars from './internal/NativeVars.js'
|
|
12
|
+
import * as NativeStyleSheet from '../react-native/StyleSheet.js'
|
|
11
13
|
import * as Edits from './internal/Edits.js'
|
|
12
14
|
import * as Identity from '../internal/Identity.js'
|
|
13
15
|
import type * as Ast from '@oxc-project/types'
|
|
@@ -1086,10 +1088,82 @@ function build(options: compile.Options, cache?: Cache): Cache {
|
|
|
1086
1088
|
: {}),
|
|
1087
1089
|
}
|
|
1088
1090
|
}
|
|
1091
|
+
const profiles = new Map<
|
|
1092
|
+
string,
|
|
1093
|
+
{
|
|
1094
|
+
definitions: Map<string, string>
|
|
1095
|
+
reads: Map<number, { name: string; source?: string }>
|
|
1096
|
+
}
|
|
1097
|
+
>()
|
|
1098
|
+
const reserved = new Set(
|
|
1099
|
+
[...identifiers.values()].flatMap((names) => [...names]),
|
|
1100
|
+
)
|
|
1101
|
+
function profile(moduleId: string) {
|
|
1102
|
+
let value = profiles.get(moduleId)
|
|
1103
|
+
if (!value) {
|
|
1104
|
+
value = { definitions: new Map(), reads: new Map() }
|
|
1105
|
+
profiles.set(moduleId, value)
|
|
1106
|
+
}
|
|
1107
|
+
return value
|
|
1108
|
+
}
|
|
1109
|
+
if (ids.some((id) => extracted.get(id)!.nativeVars?.length))
|
|
1110
|
+
NativeStyleSheet.compile({
|
|
1111
|
+
fonts: native.fonts,
|
|
1112
|
+
platform: native.platform,
|
|
1113
|
+
units: native.units,
|
|
1114
|
+
styles: { styles: [] },
|
|
1115
|
+
})
|
|
1116
|
+
for (const moduleId of ids) {
|
|
1117
|
+
for (const read of extracted.get(moduleId)!.nativeVars ?? []) {
|
|
1118
|
+
const owner = owners[read.owner]?.moduleId
|
|
1119
|
+
// Single-file adapters cannot publish changes to dependency modules.
|
|
1120
|
+
// Packed catalogs without source also retain their local fallback.
|
|
1121
|
+
if (
|
|
1122
|
+
native[Edits.runtime] ||
|
|
1123
|
+
!owner ||
|
|
1124
|
+
!Object.hasOwn(options.modules, owner)
|
|
1125
|
+
)
|
|
1126
|
+
continue
|
|
1127
|
+
let value: string
|
|
1128
|
+
try {
|
|
1129
|
+
value = JSON.stringify(
|
|
1130
|
+
NativeVars.compile({
|
|
1131
|
+
...read,
|
|
1132
|
+
fonts: native.fonts,
|
|
1133
|
+
units: native.units,
|
|
1134
|
+
}),
|
|
1135
|
+
)
|
|
1136
|
+
} catch (error) {
|
|
1137
|
+
throw new Native.CompileError((error as Error).message)
|
|
1138
|
+
}
|
|
1139
|
+
const definitions = profile(owner).definitions
|
|
1140
|
+
let name = definitions.get(value)
|
|
1141
|
+
if (!name) {
|
|
1142
|
+
name = `__zyzzProfile${Identity.hash(value)}`
|
|
1143
|
+
while (reserved.has(name)) name += '_'
|
|
1144
|
+
reserved.add(name)
|
|
1145
|
+
definitions.set(value, name)
|
|
1146
|
+
}
|
|
1147
|
+
const from = moduleId.split('/').slice(0, -1)
|
|
1148
|
+
const to = owner.split('/')
|
|
1149
|
+
while (from.length && from[0] === to[0]) {
|
|
1150
|
+
from.shift()
|
|
1151
|
+
to.shift()
|
|
1152
|
+
}
|
|
1153
|
+
const source =
|
|
1154
|
+
(from.length ? '../'.repeat(from.length) : './') +
|
|
1155
|
+
to.join('/').replace(/\.([cm]?)tsx?$/, '.$1js')
|
|
1156
|
+
profile(moduleId).reads.set(read.start, {
|
|
1157
|
+
name,
|
|
1158
|
+
...(owner !== moduleId ? { source } : {}),
|
|
1159
|
+
})
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1089
1162
|
const modules = Object.fromEntries(
|
|
1090
1163
|
ids.map((moduleId) => {
|
|
1091
1164
|
if (
|
|
1092
1165
|
previous &&
|
|
1166
|
+
!profiles.size &&
|
|
1093
1167
|
extracted.get(moduleId) === previous.extracted.get(moduleId)
|
|
1094
1168
|
)
|
|
1095
1169
|
return [moduleId, previous.result.modules[moduleId]!]
|
|
@@ -1133,6 +1207,7 @@ function build(options: compile.Options, cache?: Cache): Cache {
|
|
|
1133
1207
|
}
|
|
1134
1208
|
const output = Native.compile({
|
|
1135
1209
|
...native,
|
|
1210
|
+
[NativeVars.shared]: profiles.get(moduleId),
|
|
1136
1211
|
moduleId,
|
|
1137
1212
|
source: options.modules[moduleId]!,
|
|
1138
1213
|
[Themes.context]: {
|