@tamagui/compiler-core 0.0.0-bootstrap.0 → 3.0.0-beta.637.1

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.
Files changed (98) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +57 -1
  3. package/dist/cjs/ast.cjs +95 -0
  4. package/dist/cjs/contracts.cjs +62 -0
  5. package/dist/cjs/diagnostics.cjs +69 -0
  6. package/dist/cjs/evaluate.cjs +351 -0
  7. package/dist/cjs/graph.cjs +279 -0
  8. package/dist/cjs/hash.cjs +49 -0
  9. package/dist/cjs/index.cjs +44 -0
  10. package/dist/cjs/ir.cjs +33 -0
  11. package/dist/cjs/lower.cjs +225 -0
  12. package/dist/cjs/materialize.cjs +200 -0
  13. package/dist/cjs/normalize.cjs +622 -0
  14. package/dist/cjs/output.cjs +149 -0
  15. package/dist/cjs/planCache.cjs +224 -0
  16. package/dist/cjs/session.cjs +119 -0
  17. package/dist/cjs/yuku.cjs +159 -0
  18. package/dist/cjs/zero.cjs +387 -0
  19. package/dist/esm/ast.mjs +65 -0
  20. package/dist/esm/ast.mjs.map +1 -0
  21. package/dist/esm/contracts.mjs +34 -0
  22. package/dist/esm/contracts.mjs.map +1 -0
  23. package/dist/esm/diagnostics.mjs +44 -0
  24. package/dist/esm/diagnostics.mjs.map +1 -0
  25. package/dist/esm/evaluate.mjs +327 -0
  26. package/dist/esm/evaluate.mjs.map +1 -0
  27. package/dist/esm/graph.mjs +256 -0
  28. package/dist/esm/graph.mjs.map +1 -0
  29. package/dist/esm/hash.mjs +26 -0
  30. package/dist/esm/hash.mjs.map +1 -0
  31. package/dist/esm/index.mjs +30 -0
  32. package/dist/esm/ir.mjs +12 -0
  33. package/dist/esm/ir.mjs.map +1 -0
  34. package/dist/esm/lower.mjs +202 -0
  35. package/dist/esm/lower.mjs.map +1 -0
  36. package/dist/esm/materialize.mjs +179 -0
  37. package/dist/esm/materialize.mjs.map +1 -0
  38. package/dist/esm/normalize.mjs +596 -0
  39. package/dist/esm/normalize.mjs.map +1 -0
  40. package/dist/esm/output.mjs +119 -0
  41. package/dist/esm/output.mjs.map +1 -0
  42. package/dist/esm/planCache.mjs +194 -0
  43. package/dist/esm/planCache.mjs.map +1 -0
  44. package/dist/esm/session.mjs +99 -0
  45. package/dist/esm/session.mjs.map +1 -0
  46. package/dist/esm/yuku.mjs +136 -0
  47. package/dist/esm/yuku.mjs.map +1 -0
  48. package/dist/esm/zero.mjs +352 -0
  49. package/dist/esm/zero.mjs.map +1 -0
  50. package/package.json +42 -4
  51. package/src/ast.ts +86 -0
  52. package/src/contracts.ts +148 -0
  53. package/src/diagnostics.ts +96 -0
  54. package/src/evaluate.ts +497 -0
  55. package/src/graph.ts +347 -0
  56. package/src/hash.ts +36 -0
  57. package/src/index.ts +15 -0
  58. package/src/ir.ts +154 -0
  59. package/src/lower.ts +418 -0
  60. package/src/materialize.ts +330 -0
  61. package/src/normalize.ts +846 -0
  62. package/src/output.ts +175 -0
  63. package/src/planCache.ts +327 -0
  64. package/src/session.ts +172 -0
  65. package/src/yuku.ts +189 -0
  66. package/src/zero.ts +598 -0
  67. package/types/ast.d.ts +10 -0
  68. package/types/ast.d.ts.map +1 -0
  69. package/types/contracts.d.ts +97 -0
  70. package/types/contracts.d.ts.map +1 -0
  71. package/types/diagnostics.d.ts +31 -0
  72. package/types/diagnostics.d.ts.map +1 -0
  73. package/types/evaluate.d.ts +36 -0
  74. package/types/evaluate.d.ts.map +1 -0
  75. package/types/graph.d.ts +37 -0
  76. package/types/graph.d.ts.map +1 -0
  77. package/types/hash.d.ts +8 -0
  78. package/types/hash.d.ts.map +1 -0
  79. package/types/index.d.ts +16 -0
  80. package/types/index.d.ts.map +1 -0
  81. package/types/ir.d.ts +118 -0
  82. package/types/ir.d.ts.map +1 -0
  83. package/types/lower.d.ts +99 -0
  84. package/types/lower.d.ts.map +1 -0
  85. package/types/materialize.d.ts +104 -0
  86. package/types/materialize.d.ts.map +1 -0
  87. package/types/normalize.d.ts +8 -0
  88. package/types/normalize.d.ts.map +1 -0
  89. package/types/output.d.ts +32 -0
  90. package/types/output.d.ts.map +1 -0
  91. package/types/planCache.d.ts +113 -0
  92. package/types/planCache.d.ts.map +1 -0
  93. package/types/session.d.ts +44 -0
  94. package/types/session.d.ts.map +1 -0
  95. package/types/yuku.d.ts +4 -0
  96. package/types/yuku.d.ts.map +1 -0
  97. package/types/zero.d.ts +98 -0
  98. package/types/zero.d.ts.map +1 -0
@@ -0,0 +1,497 @@
1
+ import { childNode, childNodes, identifierName, isAstNode, unwrapExpression } from './ast'
2
+ import type {
3
+ AstNode,
4
+ ExpressionReference,
5
+ ResolvedModuleId,
6
+ SourceSpan,
7
+ SymbolDefinition,
8
+ SymbolResolver,
9
+ } from './contracts'
10
+ import { expressionReference, spanOf } from './contracts'
11
+ import { linkedBailout, localBailout, type BailoutReason } from './diagnostics'
12
+
13
+ export type StaticEvaluationValue =
14
+ | string
15
+ | number
16
+ | boolean
17
+ | null
18
+ | StaticEvaluationValue[]
19
+ | { [key: string]: StaticEvaluationValue }
20
+
21
+ export type EvaluationResult =
22
+ | {
23
+ ok: true
24
+ value: StaticEvaluationValue
25
+ dependencies: ResolvedModuleId[]
26
+ }
27
+ | {
28
+ ok: false
29
+ bailout: BailoutReason
30
+ }
31
+
32
+ type InternalResult =
33
+ | { ok: true; value: StaticEvaluationValue }
34
+ | { ok: false; bailout: BailoutReason }
35
+
36
+ interface EvaluationState {
37
+ activeDefinitions: Set<string>
38
+ dependencies: Set<ResolvedModuleId>
39
+ }
40
+
41
+ function success(value: StaticEvaluationValue): InternalResult {
42
+ return { ok: true, value }
43
+ }
44
+
45
+ function literal(node: AstNode): StaticEvaluationValue | undefined {
46
+ if (node.type === 'NullLiteral') return null
47
+ if (node.type === 'Literal' || node.type.endsWith('Literal')) {
48
+ const value = node.value
49
+ if (
50
+ typeof value === 'string' ||
51
+ typeof value === 'number' ||
52
+ typeof value === 'boolean' ||
53
+ value === null
54
+ ) {
55
+ return value
56
+ }
57
+ }
58
+ return undefined
59
+ }
60
+
61
+ function unsupported(
62
+ id: ResolvedModuleId,
63
+ node: AstNode,
64
+ detail = `Expression ${node.type} is not statically supported`
65
+ ): InternalResult {
66
+ return {
67
+ ok: false,
68
+ bailout: localBailout('local/unsupported-expression', spanOf(id, node), detail),
69
+ }
70
+ }
71
+
72
+ function evaluateDefinition(
73
+ resolver: SymbolResolver,
74
+ definition: SymbolDefinition,
75
+ useSpan: SourceSpan,
76
+ state: EvaluationState
77
+ ): InternalResult {
78
+ const key = `${definition.id}:${definition.span.start}`
79
+ if (state.activeDefinitions.has(key)) {
80
+ return {
81
+ ok: false,
82
+ bailout: localBailout(
83
+ 'local/static-evaluation-cycle',
84
+ useSpan,
85
+ `Static evaluation cycle reached ${definition.name}`
86
+ ),
87
+ }
88
+ }
89
+ if (!definition.initializer) {
90
+ return {
91
+ ok: false,
92
+ bailout: linkedBailout(
93
+ 'linked/missing-initializer',
94
+ useSpan,
95
+ `Binding ${definition.name} has no static initializer`,
96
+ definition.id
97
+ ),
98
+ }
99
+ }
100
+ if (!definition.constant) {
101
+ return {
102
+ ok: false,
103
+ bailout: linkedBailout(
104
+ 'linked/unresolved-binding',
105
+ useSpan,
106
+ `Binding ${definition.name} is mutable and cannot be statically evaluated`,
107
+ definition.id
108
+ ),
109
+ }
110
+ }
111
+ const initializer = resolver.expressionNode(definition.initializer)
112
+ if (!initializer) {
113
+ return {
114
+ ok: false,
115
+ bailout: linkedBailout(
116
+ 'linked/missing-initializer',
117
+ useSpan,
118
+ `Binding ${definition.name} initializer is outside the linked graph`,
119
+ definition.id
120
+ ),
121
+ }
122
+ }
123
+
124
+ state.dependencies.add(definition.id)
125
+ state.activeDefinitions.add(key)
126
+ try {
127
+ return evaluateNode(resolver, definition.id, initializer, state)
128
+ } finally {
129
+ state.activeDefinitions.delete(key)
130
+ }
131
+ }
132
+
133
+ function evaluateObject(
134
+ resolver: SymbolResolver,
135
+ id: ResolvedModuleId,
136
+ node: AstNode,
137
+ state: EvaluationState
138
+ ): InternalResult {
139
+ const output: Record<string, StaticEvaluationValue> = {}
140
+ for (const property of childNodes(node, 'properties')) {
141
+ if (property.type === 'SpreadElement') {
142
+ const argument = childNode(property, 'argument')
143
+ if (!argument) return unsupported(id, property)
144
+ const spread = evaluateNode(resolver, id, argument, state)
145
+ if (!spread.ok) return spread
146
+ if (
147
+ !spread.value ||
148
+ typeof spread.value !== 'object' ||
149
+ Array.isArray(spread.value)
150
+ ) {
151
+ return {
152
+ ok: false,
153
+ bailout: localBailout(
154
+ 'local/non-object-spread',
155
+ spanOf(id, property),
156
+ 'Static object spread did not evaluate to an object'
157
+ ),
158
+ }
159
+ }
160
+ Object.assign(output, spread.value)
161
+ continue
162
+ }
163
+ if (property.type !== 'Property' && property.type !== 'ObjectProperty') {
164
+ return unsupported(id, property)
165
+ }
166
+ const keyNode = childNode(property, 'key')
167
+ const valueNode = childNode(property, 'value')
168
+ if (!keyNode || !valueNode) return unsupported(id, property)
169
+ let key: StaticEvaluationValue | undefined = identifierName(keyNode) ?? undefined
170
+ if (property.computed === true || key === undefined) {
171
+ const evaluatedKey = evaluateNode(resolver, id, keyNode, state)
172
+ if (!evaluatedKey.ok) return evaluatedKey
173
+ key = evaluatedKey.value
174
+ }
175
+ if (typeof key !== 'string' && typeof key !== 'number') {
176
+ return unsupported(id, keyNode, 'Static object key is not a string or number')
177
+ }
178
+ const value = evaluateNode(resolver, id, valueNode, state)
179
+ if (!value.ok) return value
180
+ output[String(key)] = value.value
181
+ }
182
+ return success(output)
183
+ }
184
+
185
+ function evaluateArray(
186
+ resolver: SymbolResolver,
187
+ id: ResolvedModuleId,
188
+ node: AstNode,
189
+ state: EvaluationState
190
+ ): InternalResult {
191
+ const output: StaticEvaluationValue[] = []
192
+ const rawElements = node.elements
193
+ if (
194
+ !Array.isArray(rawElements) ||
195
+ rawElements.some((element) => element === null || !isAstNode(element))
196
+ ) {
197
+ return unsupported(id, node, 'Sparse arrays are not statically supported')
198
+ }
199
+ for (const element of rawElements.filter(isAstNode)) {
200
+ if (element.type === 'SpreadElement') {
201
+ const argument = childNode(element, 'argument')
202
+ if (!argument) return unsupported(id, element)
203
+ const spread = evaluateNode(resolver, id, argument, state)
204
+ if (!spread.ok) return spread
205
+ if (!Array.isArray(spread.value)) {
206
+ return unsupported(
207
+ id,
208
+ element,
209
+ 'Static array spread did not evaluate to an array'
210
+ )
211
+ }
212
+ output.push(...spread.value)
213
+ continue
214
+ }
215
+ const value = evaluateNode(resolver, id, element, state)
216
+ if (!value.ok) return value
217
+ output.push(value.value)
218
+ }
219
+ return success(output)
220
+ }
221
+
222
+ function evaluateNode(
223
+ resolver: SymbolResolver,
224
+ id: ResolvedModuleId,
225
+ input: AstNode,
226
+ state: EvaluationState
227
+ ): InternalResult {
228
+ const node = unwrapExpression(input)
229
+ const literalValue = literal(node)
230
+ if (literalValue !== undefined) return success(literalValue)
231
+
232
+ switch (node.type) {
233
+ case 'Identifier': {
234
+ const name = identifierName(node)
235
+ if (!name) return unsupported(id, node)
236
+ const definition = resolver.resolveBinding(id, name)
237
+ if (!definition) {
238
+ return {
239
+ ok: false,
240
+ bailout: linkedBailout(
241
+ 'linked/unresolved-binding',
242
+ spanOf(id, node),
243
+ `Binding ${name} has no host-linked definition`
244
+ ),
245
+ }
246
+ }
247
+ return evaluateDefinition(resolver, definition, spanOf(id, node), state)
248
+ }
249
+ case 'ObjectExpression':
250
+ return evaluateObject(resolver, id, node, state)
251
+ case 'ArrayExpression':
252
+ return evaluateArray(resolver, id, node, state)
253
+ case 'MemberExpression': {
254
+ const objectNode = childNode(node, 'object')
255
+ const propertyNode = childNode(node, 'property')
256
+ if (!objectNode || !propertyNode) return unsupported(id, node)
257
+ const object = evaluateNode(resolver, id, objectNode, state)
258
+ if (!object.ok) return object
259
+ let property: StaticEvaluationValue | null = identifierName(propertyNode)
260
+ if (node.computed === true || property === null) {
261
+ const evaluatedProperty = evaluateNode(resolver, id, propertyNode, state)
262
+ if (!evaluatedProperty.ok) return evaluatedProperty
263
+ property = evaluatedProperty.value
264
+ }
265
+ if (
266
+ (typeof object.value !== 'object' || object.value === null) &&
267
+ typeof object.value !== 'string'
268
+ ) {
269
+ return unsupported(id, node, 'Static member target is not indexable')
270
+ }
271
+ if (typeof property !== 'string' && typeof property !== 'number') {
272
+ return unsupported(
273
+ id,
274
+ propertyNode,
275
+ 'Static member key is not a string or number'
276
+ )
277
+ }
278
+ const value = (object.value as Record<string, StaticEvaluationValue>)[
279
+ String(property)
280
+ ]
281
+ return value === undefined
282
+ ? unsupported(id, node, `Static member ${String(property)} does not exist`)
283
+ : success(value)
284
+ }
285
+ case 'UnaryExpression': {
286
+ const argument = childNode(node, 'argument')
287
+ if (!argument) return unsupported(id, node)
288
+ const value = evaluateNode(resolver, id, argument, state)
289
+ if (!value.ok) return value
290
+ if (node.operator === '-' && typeof value.value === 'number') {
291
+ return success(-value.value)
292
+ }
293
+ if (node.operator === '+' && typeof value.value === 'number') {
294
+ return success(value.value)
295
+ }
296
+ if (node.operator === '!') return success(!value.value)
297
+ return unsupported(
298
+ id,
299
+ node,
300
+ `Unary operator ${String(node.operator)} is unsupported`
301
+ )
302
+ }
303
+ case 'BinaryExpression':
304
+ case 'LogicalExpression': {
305
+ const leftNode = childNode(node, 'left')
306
+ const rightNode = childNode(node, 'right')
307
+ if (!leftNode || !rightNode) return unsupported(id, node)
308
+ const left = evaluateNode(resolver, id, leftNode, state)
309
+ if (!left.ok) return left
310
+ if (node.type === 'LogicalExpression') {
311
+ if (node.operator === '&&' && !left.value) return left
312
+ if (node.operator === '||' && left.value) return left
313
+ if (node.operator === '??' && left.value !== null) return left
314
+ }
315
+ const right = evaluateNode(resolver, id, rightNode, state)
316
+ if (!right.ok) return right
317
+ switch (node.operator) {
318
+ case '+':
319
+ if (typeof left.value === 'number' && typeof right.value === 'number') {
320
+ return success(left.value + right.value)
321
+ }
322
+ if (typeof left.value === 'string' || typeof right.value === 'string') {
323
+ return success(String(left.value) + String(right.value))
324
+ }
325
+ break
326
+ case '-':
327
+ if (typeof left.value === 'number' && typeof right.value === 'number') {
328
+ return success(left.value - right.value)
329
+ }
330
+ break
331
+ case '*':
332
+ if (typeof left.value === 'number' && typeof right.value === 'number') {
333
+ return success(left.value * right.value)
334
+ }
335
+ break
336
+ case '/':
337
+ if (typeof left.value === 'number' && typeof right.value === 'number') {
338
+ return success(left.value / right.value)
339
+ }
340
+ break
341
+ case '&&':
342
+ case '||':
343
+ case '??':
344
+ return right
345
+ }
346
+ return unsupported(
347
+ id,
348
+ node,
349
+ `Binary operator ${String(node.operator)} is unsupported`
350
+ )
351
+ }
352
+ case 'ConditionalExpression': {
353
+ const testNode = childNode(node, 'test')
354
+ const consequent = childNode(node, 'consequent')
355
+ const alternate = childNode(node, 'alternate')
356
+ if (!testNode || !consequent || !alternate) return unsupported(id, node)
357
+ const test = evaluateNode(resolver, id, testNode, state)
358
+ if (!test.ok) return test
359
+ return evaluateNode(resolver, id, test.value ? consequent : alternate, state)
360
+ }
361
+ case 'TemplateLiteral': {
362
+ const quasis = childNodes(node, 'quasis')
363
+ const expressions = childNodes(node, 'expressions')
364
+ let output = ''
365
+ for (let index = 0; index < quasis.length; index++) {
366
+ const quasi = quasis[index]
367
+ const cooked = (quasi?.value as { cooked?: unknown } | undefined)?.cooked
368
+ const raw = (quasi?.value as { raw?: unknown } | undefined)?.raw
369
+ output += typeof cooked === 'string' ? cooked : typeof raw === 'string' ? raw : ''
370
+ const expression = expressions[index]
371
+ if (expression) {
372
+ const value = evaluateNode(resolver, id, expression, state)
373
+ if (!value.ok) return value
374
+ output += String(value.value)
375
+ }
376
+ }
377
+ return success(output)
378
+ }
379
+ default:
380
+ return unsupported(id, node)
381
+ }
382
+ }
383
+
384
+ export interface ConditionalEvaluation {
385
+ /** Span of the test expression, sliced verbatim into compiled output. */
386
+ test: SourceSpan
387
+ whenTrue: { value: StaticEvaluationValue; dependencies: ResolvedModuleId[] }
388
+ whenFalse: { value: StaticEvaluationValue; dependencies: ResolvedModuleId[] }
389
+ }
390
+
391
+ /**
392
+ * A conditional whose test resists static evaluation while both branches
393
+ * evaluate: `cond ? 'body' : 'heading'`. Plain evaluation bails on the test;
394
+ * this recovers the branch values so a lowering can resolve each branch at
395
+ * compile time and leave only the test in the output. Returns null for any
396
+ * other expression shape — the caller keeps its ordinary bailout.
397
+ */
398
+ export function evaluateConditionalExpression(
399
+ resolver: SymbolResolver,
400
+ reference: ExpressionReference
401
+ ): ConditionalEvaluation | null {
402
+ const node = resolver.expressionNode(reference)
403
+ if (!node) return null
404
+ const expression = unwrapExpression(node)
405
+ if (!isAstNode(expression) || expression.type !== 'ConditionalExpression') return null
406
+ const testNode = childNode(expression, 'test')
407
+ const consequent = childNode(expression, 'consequent')
408
+ const alternate = childNode(expression, 'alternate')
409
+ if (!testNode || !consequent || !alternate) return null
410
+ const trueState: EvaluationState = {
411
+ activeDefinitions: new Set(),
412
+ dependencies: new Set(),
413
+ }
414
+ const whenTrue = evaluateNode(resolver, reference.id, consequent, trueState)
415
+ if (!whenTrue.ok) return null
416
+ const falseState: EvaluationState = {
417
+ activeDefinitions: new Set(),
418
+ dependencies: new Set(),
419
+ }
420
+ const whenFalse = evaluateNode(resolver, reference.id, alternate, falseState)
421
+ if (!whenFalse.ok) return null
422
+ return {
423
+ test: spanOf(reference.id, testNode),
424
+ whenTrue: {
425
+ value: whenTrue.value,
426
+ dependencies: [...trueState.dependencies].sort(),
427
+ },
428
+ whenFalse: {
429
+ value: whenFalse.value,
430
+ dependencies: [...falseState.dependencies].sort(),
431
+ },
432
+ }
433
+ }
434
+
435
+ export function evaluateExpression(
436
+ resolver: SymbolResolver,
437
+ reference: ExpressionReference
438
+ ): EvaluationResult {
439
+ const node = resolver.expressionNode(reference)
440
+ if (!node) {
441
+ return {
442
+ ok: false,
443
+ bailout: linkedBailout(
444
+ 'linked/missing-initializer',
445
+ reference,
446
+ 'Expression is outside the linked project graph',
447
+ reference.id
448
+ ),
449
+ }
450
+ }
451
+ const state: EvaluationState = {
452
+ activeDefinitions: new Set(),
453
+ dependencies: new Set(),
454
+ }
455
+ const result = evaluateNode(resolver, reference.id, node, state)
456
+ return result.ok
457
+ ? {
458
+ ok: true,
459
+ value: result.value,
460
+ dependencies: [...state.dependencies].sort(),
461
+ }
462
+ : result
463
+ }
464
+
465
+ export function evaluateBinding(
466
+ resolver: SymbolResolver,
467
+ id: ResolvedModuleId,
468
+ localName: string
469
+ ): EvaluationResult {
470
+ const definition = resolver.resolveBinding(id, localName)
471
+ if (!definition) {
472
+ const emptySpan: SourceSpan = { id, start: 0, end: 0 }
473
+ return {
474
+ ok: false,
475
+ bailout: linkedBailout(
476
+ 'linked/unresolved-binding',
477
+ emptySpan,
478
+ `Binding ${localName} has no host-linked definition`
479
+ ),
480
+ }
481
+ }
482
+ if (!definition.initializer) {
483
+ return {
484
+ ok: false,
485
+ bailout: linkedBailout(
486
+ 'linked/missing-initializer',
487
+ definition.span,
488
+ `Binding ${localName} has no static initializer`,
489
+ definition.id
490
+ ),
491
+ }
492
+ }
493
+ return evaluateExpression(
494
+ resolver,
495
+ expressionReference(definition.id, definition.initializer)
496
+ )
497
+ }