@tamagui/compiler-core 0.0.0-bootstrap.0 → 3.0.0-beta.643.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
package/src/graph.ts ADDED
@@ -0,0 +1,347 @@
1
+ import { createHash } from 'node:crypto'
2
+
3
+ import type {
4
+ AnalyzerCandidate,
5
+ CandidateFactory,
6
+ ExpressionReference,
7
+ HostModuleInput,
8
+ HostResolvedImport,
9
+ HostResolvedProject,
10
+ ProjectInput,
11
+ ResolvedModuleId,
12
+ SymbolDefinition,
13
+ SymbolResolver,
14
+ } from './contracts'
15
+ import { expressionReference, resolutionKey, resolvedModuleId } from './contracts'
16
+ import { linkedBailout, localBailout, type BailoutReason } from './diagnostics'
17
+ import {
18
+ evaluateBinding,
19
+ evaluateConditionalExpression,
20
+ evaluateExpression,
21
+ type ConditionalEvaluation,
22
+ type EvaluationResult,
23
+ } from './evaluate'
24
+ import type { ElementIRResult } from './ir'
25
+ import { nodeAtSpan, normalizeElements } from './normalize'
26
+
27
+ interface ModuleRecord {
28
+ input: HostModuleInput
29
+ hash: string
30
+ }
31
+
32
+ interface CachedElements {
33
+ hash: string
34
+ result: ElementIRResult
35
+ }
36
+
37
+ export interface GraphInvalidation {
38
+ changed: boolean
39
+ id: ResolvedModuleId
40
+ previousHash: string | null
41
+ contentHash: string | null
42
+ invalidatedIds: ResolvedModuleId[]
43
+ }
44
+
45
+ function compareIds(left: ResolvedModuleId, right: ResolvedModuleId): number {
46
+ return compareCodeUnits(left, right)
47
+ }
48
+
49
+ function compareCodeUnits(left: string, right: string): number {
50
+ return left < right ? -1 : left > right ? 1 : 0
51
+ }
52
+
53
+ function stableImports(imports: readonly HostResolvedImport[]): HostResolvedImport[] {
54
+ return [...imports].sort((left, right) => {
55
+ const bySpecifier = compareCodeUnits(left.specifier, right.specifier)
56
+ return bySpecifier || compareCodeUnits(left.resolvedId, right.resolvedId)
57
+ })
58
+ }
59
+
60
+ export function moduleContentHash(input: HostModuleInput): string {
61
+ const hash = createHash('sha256')
62
+ hash.update(input.source)
63
+ hash.update('\0')
64
+ for (const dependency of stableImports(input.imports)) {
65
+ hash.update(dependency.specifier)
66
+ hash.update('\0')
67
+ hash.update(dependency.resolvedId)
68
+ hash.update('\0')
69
+ hash.update(dependency.external ? 'external' : 'internal')
70
+ hash.update('\0')
71
+ }
72
+ return hash.digest('hex')
73
+ }
74
+
75
+ /**
76
+ * Long-lived semantic graph. The host owns resolution and supplies every canonical id;
77
+ * this service owns parsing, linking, hashes, reverse edges, IR, and evaluation caches.
78
+ */
79
+ export class ProjectGraph implements SymbolResolver {
80
+ readonly #files = new Map<string, string>()
81
+ readonly #resolutions = new Map<string, string>()
82
+ readonly #modules = new Map<ResolvedModuleId, ModuleRecord>()
83
+ readonly #dependencies = new Map<ResolvedModuleId, Set<ResolvedModuleId>>()
84
+ readonly #dependents = new Map<ResolvedModuleId, Set<ResolvedModuleId>>()
85
+ readonly #elementCache = new Map<ResolvedModuleId, CachedElements>()
86
+ readonly #candidate: AnalyzerCandidate
87
+
88
+ constructor(factory: CandidateFactory, project: HostResolvedProject) {
89
+ for (const input of project.modules) this.#installHostRecord(input)
90
+ const candidateProject: ProjectInput = {
91
+ files: this.#files,
92
+ resolutions: this.#resolutions,
93
+ }
94
+ this.#candidate = factory.create(candidateProject)
95
+ this.#candidate.link()
96
+ }
97
+
98
+ moduleIds(): ResolvedModuleId[] {
99
+ return [...this.#modules.keys()].sort(compareIds)
100
+ }
101
+
102
+ contentHash(id: ResolvedModuleId): string | null {
103
+ return this.#modules.get(id)?.hash ?? null
104
+ }
105
+
106
+ sourceOf(id: ResolvedModuleId): string {
107
+ const source = this.#modules.get(id)?.input.source
108
+ if (source === undefined) throw new Error(`Unknown host module ${id}`)
109
+ return source
110
+ }
111
+
112
+ dependenciesOf(id: ResolvedModuleId): ResolvedModuleId[] {
113
+ return [...(this.#dependencies.get(id) ?? [])].sort(compareIds)
114
+ }
115
+
116
+ dependentsOf(id: ResolvedModuleId): ResolvedModuleId[] {
117
+ return [...(this.#dependents.get(id) ?? [])].sort(compareIds)
118
+ }
119
+
120
+ affectedBy(id: ResolvedModuleId): ResolvedModuleId[] {
121
+ const affected = new Set<ResolvedModuleId>([id])
122
+ const queue = [id]
123
+ while (queue.length) {
124
+ const current = queue.shift()!
125
+ for (const dependent of this.#dependents.get(current) ?? []) {
126
+ if (affected.has(dependent)) continue
127
+ affected.add(dependent)
128
+ queue.push(dependent)
129
+ }
130
+ }
131
+ return [...affected].sort(compareIds)
132
+ }
133
+
134
+ parseCount(id: ResolvedModuleId): number {
135
+ return this.#candidate.parseCount(id)
136
+ }
137
+
138
+ resolveBinding(id: ResolvedModuleId, localName: string): SymbolDefinition | null {
139
+ const definition = this.#candidate.definitionOf(id, localName)
140
+ if (!definition) return null
141
+ return {
142
+ id: definition.id,
143
+ name: definition.name,
144
+ span: {
145
+ id: definition.id,
146
+ start: definition.start,
147
+ end: definition.end,
148
+ },
149
+ initializer: definition.initializer
150
+ ? expressionReference(definition.id, definition.initializer)
151
+ : null,
152
+ constant: definition.constant,
153
+ }
154
+ }
155
+
156
+ expressionNode(reference: ExpressionReference) {
157
+ if (!this.#modules.has(reference.id)) return null
158
+ return nodeAtSpan(
159
+ this.#candidate.programOf(reference.id),
160
+ reference.start,
161
+ reference.end
162
+ )
163
+ }
164
+
165
+ evaluate(reference: ExpressionReference): EvaluationResult {
166
+ return evaluateExpression(this, reference)
167
+ }
168
+
169
+ evaluateConditional(reference: ExpressionReference): ConditionalEvaluation | null {
170
+ return evaluateConditionalExpression(this, reference)
171
+ }
172
+
173
+ evaluateBinding(id: ResolvedModuleId, localName: string): EvaluationResult {
174
+ return evaluateBinding(this, id, localName)
175
+ }
176
+
177
+ elementsOf(id: ResolvedModuleId): ElementIRResult {
178
+ const record = this.#modules.get(id)
179
+ if (!record) throw new Error(`Unknown host module ${id}`)
180
+ const cached = this.#elementCache.get(id)
181
+ if (cached?.hash === record.hash) return cached.result
182
+ const result = normalizeElements(this.#candidate, id, record.input.imports)
183
+ this.#elementCache.set(id, { hash: record.hash, result })
184
+ return result
185
+ }
186
+
187
+ diagnostics(): BailoutReason[] {
188
+ const diagnostics = this.#candidate
189
+ .diagnostics()
190
+ .map((diagnostic) =>
191
+ diagnostic.kind === 'parse'
192
+ ? localBailout(
193
+ 'local/parse-error',
194
+ { id: diagnostic.id, start: 0, end: 0 },
195
+ diagnostic.message
196
+ )
197
+ : linkedBailout(
198
+ 'linked/unresolved-binding',
199
+ { id: diagnostic.id, start: 0, end: 0 },
200
+ diagnostic.message
201
+ )
202
+ )
203
+ for (const [id, record] of this.#modules) {
204
+ for (const dependency of record.input.imports) {
205
+ if (dependency.external) continue
206
+ if (this.#modules.has(dependency.resolvedId)) continue
207
+ diagnostics.push(
208
+ linkedBailout(
209
+ 'linked/unresolved-import',
210
+ { id, start: 0, end: 0 },
211
+ `Host-resolved import ${dependency.specifier} points outside the project graph`,
212
+ dependency.resolvedId
213
+ )
214
+ )
215
+ }
216
+ }
217
+ return diagnostics.sort((left, right) => {
218
+ const byId = compareCodeUnits(left.span.id, right.span.id)
219
+ return (
220
+ byId ||
221
+ left.span.start - right.span.start ||
222
+ compareCodeUnits(left.code, right.code)
223
+ )
224
+ })
225
+ }
226
+
227
+ updateModule(input: HostModuleInput): GraphInvalidation {
228
+ const previous = this.#modules.get(input.id)
229
+ const nextHash = moduleContentHash(input)
230
+ if (previous?.hash === nextHash) {
231
+ return {
232
+ changed: false,
233
+ id: input.id,
234
+ previousHash: previous.hash,
235
+ contentHash: previous.hash,
236
+ invalidatedIds: [],
237
+ }
238
+ }
239
+
240
+ const invalidatedIds = this.affectedBy(input.id)
241
+ const previousHash = previous?.hash ?? null
242
+ if (previous) this.#candidate.removeFile(input.id)
243
+ this.#installHostRecord(input)
244
+ this.#candidate.addFile(input.id, input.source)
245
+ this.#candidate.link()
246
+ for (const id of invalidatedIds) this.#elementCache.delete(id)
247
+
248
+ return {
249
+ changed: true,
250
+ id: input.id,
251
+ previousHash,
252
+ contentHash: nextHash,
253
+ invalidatedIds,
254
+ }
255
+ }
256
+
257
+ removeModule(id: ResolvedModuleId): GraphInvalidation {
258
+ const previous = this.#modules.get(id)
259
+ if (!previous) {
260
+ return {
261
+ changed: false,
262
+ id,
263
+ previousHash: null,
264
+ contentHash: null,
265
+ invalidatedIds: [],
266
+ }
267
+ }
268
+ const invalidatedIds = this.affectedBy(id)
269
+ this.#candidate.removeFile(id)
270
+ this.#removeOutgoingEdges(id)
271
+ this.#removeResolutions(id)
272
+ this.#modules.delete(id)
273
+ this.#files.delete(id)
274
+ this.#candidate.link()
275
+ for (const invalidated of invalidatedIds) this.#elementCache.delete(invalidated)
276
+ return {
277
+ changed: true,
278
+ id,
279
+ previousHash: previous.hash,
280
+ contentHash: null,
281
+ invalidatedIds,
282
+ }
283
+ }
284
+
285
+ #installHostRecord(input: HostModuleInput): void {
286
+ resolvedModuleId(input.id)
287
+ const seenSpecifiers = new Set<string>()
288
+ for (const dependency of input.imports) {
289
+ resolvedModuleId(dependency.resolvedId)
290
+ if (seenSpecifiers.has(dependency.specifier)) {
291
+ throw new Error(
292
+ `Duplicate host resolution for ${input.id}:${dependency.specifier}`
293
+ )
294
+ }
295
+ seenSpecifiers.add(dependency.specifier)
296
+ }
297
+
298
+ this.#removeOutgoingEdges(input.id)
299
+ this.#removeResolutions(input.id)
300
+ const dependencies = new Set(
301
+ input.imports
302
+ .filter(({ external }) => !external)
303
+ .map(({ resolvedId }) => resolvedId)
304
+ )
305
+ this.#dependencies.set(input.id, dependencies)
306
+ for (const dependency of dependencies) {
307
+ let reverse = this.#dependents.get(dependency)
308
+ if (!reverse) {
309
+ reverse = new Set()
310
+ this.#dependents.set(dependency, reverse)
311
+ }
312
+ reverse.add(input.id)
313
+ }
314
+ for (const dependency of input.imports) {
315
+ if (dependency.external) continue
316
+ this.#resolutions.set(
317
+ resolutionKey(input.id, dependency.specifier),
318
+ dependency.resolvedId
319
+ )
320
+ }
321
+ const installedInput: HostModuleInput = {
322
+ ...input,
323
+ imports: input.imports.map((dependency) => ({ ...dependency })),
324
+ }
325
+ this.#files.set(installedInput.id, installedInput.source)
326
+ this.#modules.set(installedInput.id, {
327
+ input: installedInput,
328
+ hash: moduleContentHash(installedInput),
329
+ })
330
+ }
331
+
332
+ #removeOutgoingEdges(id: ResolvedModuleId): void {
333
+ for (const dependency of this.#dependencies.get(id) ?? []) {
334
+ const reverse = this.#dependents.get(dependency)
335
+ reverse?.delete(id)
336
+ if (reverse?.size === 0) this.#dependents.delete(dependency)
337
+ }
338
+ this.#dependencies.delete(id)
339
+ }
340
+
341
+ #removeResolutions(id: ResolvedModuleId): void {
342
+ const prefix = `${id}\0`
343
+ for (const key of this.#resolutions.keys()) {
344
+ if (key.startsWith(prefix)) this.#resolutions.delete(key)
345
+ }
346
+ }
347
+ }
package/src/hash.ts ADDED
@@ -0,0 +1,36 @@
1
+ import { createHash } from 'node:crypto'
2
+
3
+ /** The one content hash every compiler cache identity is built from. */
4
+ export function contentHash(value: string | Uint8Array): string {
5
+ return createHash('sha256').update(value).digest('hex')
6
+ }
7
+
8
+ function compareCodeUnits(left: string, right: string): number {
9
+ return left < right ? -1 : left > right ? 1 : 0
10
+ }
11
+
12
+ function stringify(value: unknown): string | undefined {
13
+ if (Array.isArray(value)) {
14
+ return `[${value.map((child) => stringify(child) ?? 'null').join(',')}]`
15
+ }
16
+ if (value && typeof value === 'object') {
17
+ const entries = Object.entries(value as Record<string, unknown>)
18
+ .sort(([left], [right]) => compareCodeUnits(left, right))
19
+ .map(([key, child]) => [key, stringify(child)] as const)
20
+ .filter((entry): entry is readonly [string, string] => entry[1] !== undefined)
21
+ return `{${entries
22
+ .map(([key, child]) => `${JSON.stringify(key)}:${child}`)
23
+ .join(',')}}`
24
+ }
25
+ return JSON.stringify(value)
26
+ }
27
+
28
+ /**
29
+ * Key-order-independent JSON. Cache identities are hashed from this, so two
30
+ * objects that differ only in property order must serialize identically.
31
+ */
32
+ export function stableStringify(value: unknown): string {
33
+ const serialized = stringify(value)
34
+ if (serialized === undefined) throw new Error('Cannot serialize undefined cache root')
35
+ return serialized
36
+ }
package/src/index.ts ADDED
@@ -0,0 +1,15 @@
1
+ export * from './ast'
2
+ export * from './contracts'
3
+ export * from './diagnostics'
4
+ export * from './evaluate'
5
+ export * from './graph'
6
+ export * from './hash'
7
+ export * from './ir'
8
+ export * from './lower'
9
+ export * from './materialize'
10
+ export * from './output'
11
+ export * from './planCache'
12
+ export * from './session'
13
+ export { normalizeElements } from './normalize'
14
+ export * from './zero'
15
+ export { parseModuleAst, yukuFactory } from './yuku'
package/src/ir.ts ADDED
@@ -0,0 +1,154 @@
1
+ import type {
2
+ ExpressionReference,
3
+ HostResolvedImport,
4
+ ResolvedModuleId,
5
+ SourceSpan,
6
+ SymbolDefinition,
7
+ } from './contracts'
8
+ import type { BailoutReason } from './diagnostics'
9
+
10
+ export type ElementForm = 'jsx' | 'jsx-runtime' | 'create-element'
11
+
12
+ export type StaticValue = string | number | boolean | null
13
+
14
+ export type ElementValue =
15
+ | { kind: 'static'; value: StaticValue; span: SourceSpan }
16
+ | ExpressionReference
17
+ | DOMStyleProgramIR
18
+
19
+ export interface DOMStyleProgramIR {
20
+ kind: 'dom-style'
21
+ span: SourceSpan
22
+ items: {
23
+ condition: ExpressionReference | null
24
+ value: ExpressionReference
25
+ }[]
26
+ }
27
+
28
+ export interface ComponentImportProvenance {
29
+ specifier: string
30
+ importedName: string
31
+ resolvedId: ResolvedModuleId
32
+ external: boolean
33
+ }
34
+
35
+ export interface ElementComponentIR {
36
+ kind: 'binding' | 'intrinsic'
37
+ name: string
38
+ span: SourceSpan
39
+ closingSpan: SourceSpan | null
40
+ definition: SymbolDefinition | null
41
+ provenance: ComponentImportProvenance | null
42
+ }
43
+
44
+ export interface ElementPropIR {
45
+ kind: 'prop'
46
+ name: string
47
+ span: SourceSpan
48
+ value: ElementValue
49
+ }
50
+
51
+ export interface ElementSpreadIR {
52
+ kind: 'spread'
53
+ span: SourceSpan
54
+ value: ExpressionReference
55
+ }
56
+
57
+ export interface ElementChildIR {
58
+ kind: 'child'
59
+ span: SourceSpan
60
+ value:
61
+ | ElementValue
62
+ | { kind: 'element'; span: SourceSpan }
63
+ | { kind: 'empty'; span: SourceSpan }
64
+ }
65
+
66
+ /**
67
+ * Entries remain in source order. Consumers must apply duplicate props in this order;
68
+ * the last statically evaluated value wins exactly as it does at runtime.
69
+ */
70
+ export type ElementEntryIR = ElementPropIR | ElementSpreadIR | ElementChildIR
71
+
72
+ export interface ElementIRBase {
73
+ kind: 'element'
74
+ form: ElementForm
75
+ id: ResolvedModuleId
76
+ span: SourceSpan
77
+ /** JSX opening element or compiled props argument, used for punctuation-safe edits. */
78
+ propsSpan: SourceSpan | null
79
+ component: ElementComponentIR
80
+ }
81
+
82
+ export interface CompleteElementIR extends ElementIRBase {
83
+ complete: true
84
+ entries: ElementEntryIR[]
85
+ bailouts: readonly []
86
+ }
87
+
88
+ export interface IncompleteElementIR extends ElementIRBase {
89
+ complete: false
90
+ /** Preserved only for diagnostics; incomplete entries must never be optimized. */
91
+ bailedEntries: ElementEntryIR[]
92
+ bailouts: readonly [BailoutReason, ...BailoutReason[]]
93
+ }
94
+
95
+ export type ElementIR = CompleteElementIR | IncompleteElementIR
96
+
97
+ export interface StyledDefinitionIRBase {
98
+ kind: 'styled-definition'
99
+ id: ResolvedModuleId
100
+ name: string
101
+ span: SourceSpan
102
+ definitionSpan: SourceSpan
103
+ factory: ComponentImportProvenance
104
+ base: ElementComponentIR
105
+ baseClassName: ElementValue | null
106
+ options: ExpressionReference
107
+ }
108
+
109
+ export interface CompleteStyledDefinitionIR extends StyledDefinitionIRBase {
110
+ complete: true
111
+ bailouts: readonly []
112
+ }
113
+
114
+ export interface IncompleteStyledDefinitionIR extends StyledDefinitionIRBase {
115
+ complete: false
116
+ bailouts: readonly [BailoutReason, ...BailoutReason[]]
117
+ }
118
+
119
+ export type StyledDefinitionIR = CompleteStyledDefinitionIR | IncompleteStyledDefinitionIR
120
+
121
+ /** A compile-time style handle declared by the standalone DOM frontend. */
122
+ export interface DOMStyleDefinitionIR {
123
+ kind: 'dom-style-definition'
124
+ id: ResolvedModuleId
125
+ name: string
126
+ /** Span of the complete style(...) call. */
127
+ span: SourceSpan
128
+ definitionSpan: SourceSpan
129
+ factory: ComponentImportProvenance
130
+ value: ExpressionReference
131
+ }
132
+
133
+ export interface ElementIRResult {
134
+ elements: ElementIR[]
135
+ styledDefinitions: StyledDefinitionIR[]
136
+ domStyleDefinitions: DOMStyleDefinitionIR[]
137
+ bailouts: BailoutReason[]
138
+ }
139
+
140
+ export function hostImportProvenance(
141
+ imports: readonly HostResolvedImport[],
142
+ specifier: string,
143
+ importedName: string
144
+ ): ComponentImportProvenance | null {
145
+ const resolution = imports.find((candidate) => candidate.specifier === specifier)
146
+ return resolution
147
+ ? {
148
+ specifier,
149
+ importedName,
150
+ resolvedId: resolution.resolvedId,
151
+ external: resolution.external === true,
152
+ }
153
+ : null
154
+ }