@tamagui/compiler-core 0.0.0-bootstrap.0 → 3.0.0-beta.1093.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.
- package/LICENSE +21 -0
- package/README.md +57 -1
- package/dist/cjs/ast.cjs +108 -0
- package/dist/cjs/contracts.cjs +61 -0
- package/dist/cjs/diagnostics.cjs +68 -0
- package/dist/cjs/evaluate.cjs +602 -0
- package/dist/cjs/graph.cjs +335 -0
- package/dist/cjs/hash.cjs +48 -0
- package/dist/cjs/index.cjs +43 -0
- package/dist/cjs/ir.cjs +32 -0
- package/dist/cjs/lower.cjs +232 -0
- package/dist/cjs/materialize.cjs +222 -0
- package/dist/cjs/normalize.cjs +628 -0
- package/dist/cjs/output.cjs +148 -0
- package/dist/cjs/planCache.cjs +262 -0
- package/dist/cjs/session.cjs +127 -0
- package/dist/cjs/yuku.cjs +166 -0
- package/dist/cjs/zero.cjs +389 -0
- package/dist/esm/ast.mjs +79 -0
- package/dist/esm/ast.mjs.map +1 -0
- package/dist/esm/contracts.mjs +34 -0
- package/dist/esm/contracts.mjs.map +1 -0
- package/dist/esm/diagnostics.mjs +44 -0
- package/dist/esm/diagnostics.mjs.map +1 -0
- package/dist/esm/evaluate.mjs +576 -0
- package/dist/esm/evaluate.mjs.map +1 -0
- package/dist/esm/graph.mjs +313 -0
- package/dist/esm/graph.mjs.map +1 -0
- package/dist/esm/hash.mjs +26 -0
- package/dist/esm/hash.mjs.map +1 -0
- package/dist/esm/index.mjs +30 -0
- package/dist/esm/ir.mjs +12 -0
- package/dist/esm/ir.mjs.map +1 -0
- package/dist/esm/lower.mjs +210 -0
- package/dist/esm/lower.mjs.map +1 -0
- package/dist/esm/materialize.mjs +203 -0
- package/dist/esm/materialize.mjs.map +1 -0
- package/dist/esm/normalize.mjs +604 -0
- package/dist/esm/normalize.mjs.map +1 -0
- package/dist/esm/output.mjs +119 -0
- package/dist/esm/output.mjs.map +1 -0
- package/dist/esm/planCache.mjs +232 -0
- package/dist/esm/planCache.mjs.map +1 -0
- package/dist/esm/session.mjs +108 -0
- package/dist/esm/session.mjs.map +1 -0
- package/dist/esm/yuku.mjs +144 -0
- package/dist/esm/yuku.mjs.map +1 -0
- package/dist/esm/zero.mjs +354 -0
- package/dist/esm/zero.mjs.map +1 -0
- package/package.json +42 -4
- package/src/ast.ts +106 -0
- package/src/contracts.ts +150 -0
- package/src/diagnostics.ts +96 -0
- package/src/evaluate.ts +875 -0
- package/src/graph.ts +425 -0
- package/src/hash.ts +36 -0
- package/src/index.ts +15 -0
- package/src/ir.ts +156 -0
- package/src/lower.ts +435 -0
- package/src/materialize.ts +383 -0
- package/src/normalize.ts +834 -0
- package/src/output.ts +175 -0
- package/src/planCache.ts +362 -0
- package/src/session.ts +192 -0
- package/src/yuku.ts +197 -0
- package/src/zero.ts +609 -0
- package/types/ast.d.ts +11 -0
- package/types/ast.d.ts.map +1 -0
- package/types/contracts.d.ts +99 -0
- package/types/contracts.d.ts.map +1 -0
- package/types/diagnostics.d.ts +31 -0
- package/types/diagnostics.d.ts.map +1 -0
- package/types/evaluate.d.ts +48 -0
- package/types/evaluate.d.ts.map +1 -0
- package/types/graph.d.ts +51 -0
- package/types/graph.d.ts.map +1 -0
- package/types/hash.d.ts +8 -0
- package/types/hash.d.ts.map +1 -0
- package/types/index.d.ts +16 -0
- package/types/index.d.ts.map +1 -0
- package/types/ir.d.ts +120 -0
- package/types/ir.d.ts.map +1 -0
- package/types/lower.d.ts +99 -0
- package/types/lower.d.ts.map +1 -0
- package/types/materialize.d.ts +121 -0
- package/types/materialize.d.ts.map +1 -0
- package/types/normalize.d.ts +7 -0
- package/types/normalize.d.ts.map +1 -0
- package/types/output.d.ts +32 -0
- package/types/output.d.ts.map +1 -0
- package/types/planCache.d.ts +123 -0
- package/types/planCache.d.ts.map +1 -0
- package/types/session.d.ts +52 -0
- package/types/session.d.ts.map +1 -0
- package/types/yuku.d.ts +4 -0
- package/types/yuku.d.ts.map +1 -0
- package/types/zero.d.ts +99 -0
- package/types/zero.d.ts.map +1 -0
package/src/ast.ts
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type { AstNode } from './contracts'
|
|
2
|
+
|
|
3
|
+
const ignoredKeys = new Set(['loc', 'range', 'parent', 'comments', 'tokens'])
|
|
4
|
+
|
|
5
|
+
export function isAstNode(value: unknown): value is AstNode {
|
|
6
|
+
return (
|
|
7
|
+
typeof value === 'object' &&
|
|
8
|
+
value !== null &&
|
|
9
|
+
typeof (value as AstNode).type === 'string' &&
|
|
10
|
+
typeof (value as AstNode).start === 'number' &&
|
|
11
|
+
typeof (value as AstNode).end === 'number'
|
|
12
|
+
)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function walkAst(
|
|
16
|
+
node: AstNode,
|
|
17
|
+
visitor: (node: AstNode, parent: AstNode | null, key: string | null) => void,
|
|
18
|
+
parent: AstNode | null = null,
|
|
19
|
+
key: string | null = null
|
|
20
|
+
): void {
|
|
21
|
+
visitor(node, parent, key)
|
|
22
|
+
|
|
23
|
+
for (const childKey of Object.keys(node)) {
|
|
24
|
+
if (ignoredKeys.has(childKey)) continue
|
|
25
|
+
const value = node[childKey]
|
|
26
|
+
if (isAstNode(value)) {
|
|
27
|
+
walkAst(value, visitor, node, childKey)
|
|
28
|
+
} else if (Array.isArray(value)) {
|
|
29
|
+
for (const child of value) {
|
|
30
|
+
if (isAstNode(child)) {
|
|
31
|
+
walkAst(child, visitor, node, childKey)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** With a source range, only descend into nodes that contain that range. */
|
|
39
|
+
export function findAstNode(
|
|
40
|
+
root: AstNode,
|
|
41
|
+
predicate: (node: AstNode, parent: AstNode | null, key: string | null) => boolean,
|
|
42
|
+
span?: Pick<AstNode, 'start' | 'end'>
|
|
43
|
+
): AstNode | null {
|
|
44
|
+
function visit(
|
|
45
|
+
node: AstNode,
|
|
46
|
+
parent: AstNode | null,
|
|
47
|
+
key: string | null
|
|
48
|
+
): AstNode | null {
|
|
49
|
+
if (span && (node.start > span.start || node.end < span.end)) return null
|
|
50
|
+
if (predicate(node, parent, key)) return node
|
|
51
|
+
for (const childKey of Object.keys(node)) {
|
|
52
|
+
if (ignoredKeys.has(childKey)) continue
|
|
53
|
+
const value = node[childKey]
|
|
54
|
+
if (isAstNode(value)) {
|
|
55
|
+
const found = visit(value, node, childKey)
|
|
56
|
+
if (found) return found
|
|
57
|
+
} else if (Array.isArray(value)) {
|
|
58
|
+
for (const child of value) {
|
|
59
|
+
if (!isAstNode(child)) continue
|
|
60
|
+
const found = visit(child, node, childKey)
|
|
61
|
+
if (found) return found
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return null
|
|
66
|
+
}
|
|
67
|
+
return visit(root, null, null)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function childNode(node: AstNode, key: string): AstNode | null {
|
|
71
|
+
const value = node[key]
|
|
72
|
+
return isAstNode(value) ? value : null
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function childNodes(node: AstNode, key: string): AstNode[] {
|
|
76
|
+
const value = node[key]
|
|
77
|
+
return Array.isArray(value) ? value.filter(isAstNode) : []
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function identifierName(node: AstNode | null): string | null {
|
|
81
|
+
if (!node || (node.type !== 'Identifier' && node.type !== 'JSXIdentifier')) return null
|
|
82
|
+
return typeof node.name === 'string' ? node.name : null
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function literalValue(node: AstNode | null): unknown {
|
|
86
|
+
if (!node) return undefined
|
|
87
|
+
if (node.type === 'Literal' || node.type.endsWith('Literal')) {
|
|
88
|
+
return node.value
|
|
89
|
+
}
|
|
90
|
+
return undefined
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function unwrapExpression(node: AstNode): AstNode {
|
|
94
|
+
let current = node
|
|
95
|
+
while (
|
|
96
|
+
current.type === 'TSAsExpression' ||
|
|
97
|
+
current.type === 'TSSatisfiesExpression' ||
|
|
98
|
+
current.type === 'TSNonNullExpression' ||
|
|
99
|
+
current.type === 'ParenthesizedExpression'
|
|
100
|
+
) {
|
|
101
|
+
const expression = childNode(current, 'expression')
|
|
102
|
+
if (!expression) break
|
|
103
|
+
current = expression
|
|
104
|
+
}
|
|
105
|
+
return current
|
|
106
|
+
}
|
package/src/contracts.ts
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
export interface AstNode {
|
|
2
|
+
type: string
|
|
3
|
+
start: number
|
|
4
|
+
end: number
|
|
5
|
+
[key: string]: unknown
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export type ResolvedModuleId = string & { readonly __resolvedModuleId: unique symbol }
|
|
9
|
+
|
|
10
|
+
export interface SourceSpan {
|
|
11
|
+
id: ResolvedModuleId
|
|
12
|
+
/** UTF-16 source-string index, inclusive. */
|
|
13
|
+
start: number
|
|
14
|
+
/** UTF-16 source-string index, exclusive. */
|
|
15
|
+
end: number
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface HostResolvedImport {
|
|
19
|
+
specifier: string
|
|
20
|
+
resolvedId: ResolvedModuleId
|
|
21
|
+
external?: boolean
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface HostModuleInput {
|
|
25
|
+
id: ResolvedModuleId
|
|
26
|
+
source: string
|
|
27
|
+
/** Every import identity is canonical and resolved before the compiler sees it. */
|
|
28
|
+
imports: readonly HostResolvedImport[]
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface HostResolvedProject {
|
|
32
|
+
modules: readonly HostModuleInput[]
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface ProjectInput {
|
|
36
|
+
files: ReadonlyMap<string, string>
|
|
37
|
+
resolutions: ReadonlyMap<string, string>
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface DefinitionSite {
|
|
41
|
+
id: ResolvedModuleId
|
|
42
|
+
name: string
|
|
43
|
+
start: number
|
|
44
|
+
end: number
|
|
45
|
+
initializer: AstNode | null
|
|
46
|
+
constant: boolean
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface ReferenceSite {
|
|
50
|
+
id: ResolvedModuleId
|
|
51
|
+
name: string
|
|
52
|
+
start: number
|
|
53
|
+
end: number
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface ParseDiagnostic {
|
|
57
|
+
kind: 'parse' | 'link'
|
|
58
|
+
id: ResolvedModuleId
|
|
59
|
+
message: string
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface AnalyzerCandidate {
|
|
63
|
+
readonly name: string
|
|
64
|
+
addFile(id: string, source: string): void
|
|
65
|
+
removeFile(id: string): boolean
|
|
66
|
+
link(): void
|
|
67
|
+
definitionOf(id: string, localName: string): DefinitionSite | null
|
|
68
|
+
definitionAt(id: string, start: number, end: number): DefinitionSite | null
|
|
69
|
+
referencesOf(definition: DefinitionSite): ReferenceSite[]
|
|
70
|
+
dependenciesOf(id: string): string[]
|
|
71
|
+
dependentsOf(id: string): string[]
|
|
72
|
+
affectedBy(id: string): string[]
|
|
73
|
+
programOf(id: string): AstNode
|
|
74
|
+
sourceOf(id: string): string
|
|
75
|
+
parseCount(id: string): number
|
|
76
|
+
diagnostics(): ParseDiagnostic[]
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface ExpressionReference extends SourceSpan {
|
|
80
|
+
readonly kind: 'expression'
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface SymbolDefinition {
|
|
84
|
+
id: ResolvedModuleId
|
|
85
|
+
name: string
|
|
86
|
+
span: SourceSpan
|
|
87
|
+
initializer: ExpressionReference | null
|
|
88
|
+
constant: boolean
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Parser-independent symbol access used by partial evaluation and element IR. */
|
|
92
|
+
export interface SymbolResolver {
|
|
93
|
+
resolveBinding(id: ResolvedModuleId, localName: string): SymbolDefinition | null
|
|
94
|
+
resolveReference(reference: ExpressionReference): SymbolDefinition | null
|
|
95
|
+
expressionNode(reference: ExpressionReference): AstNode | null
|
|
96
|
+
sourceOf(id: ResolvedModuleId): string
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export interface CandidateFactory {
|
|
100
|
+
name: AnalyzerCandidate['name']
|
|
101
|
+
create(project: ProjectInput): AnalyzerCandidate
|
|
102
|
+
/** Parser-owned static module scan; no parser-specific node types escape this boundary. */
|
|
103
|
+
scanImports(id: ResolvedModuleId, source: string): string[]
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function resolutionKey(importer: string, specifier: string): string {
|
|
107
|
+
return `${importer}\0${specifier}`
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function resolveFromHost(
|
|
111
|
+
resolutions: ReadonlyMap<string, string>,
|
|
112
|
+
specifier: string,
|
|
113
|
+
importer: string
|
|
114
|
+
): string | null {
|
|
115
|
+
return resolutions.get(resolutionKey(importer, specifier)) ?? null
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function resolvedModuleId(id: string): ResolvedModuleId {
|
|
119
|
+
const isAbsolute =
|
|
120
|
+
id.startsWith('/') ||
|
|
121
|
+
id.startsWith('\\') ||
|
|
122
|
+
id.startsWith('\0') ||
|
|
123
|
+
/^[A-Za-z]:[\\/]/.test(id) ||
|
|
124
|
+
/^[A-Za-z][A-Za-z\d+.-]*:\/\//.test(id)
|
|
125
|
+
if (!isAbsolute) {
|
|
126
|
+
throw new Error(`Host module id must be canonical and already resolved: ${id}`)
|
|
127
|
+
}
|
|
128
|
+
return id as ResolvedModuleId
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function expressionReference(
|
|
132
|
+
id: ResolvedModuleId,
|
|
133
|
+
node: Pick<AstNode, 'start' | 'end'>
|
|
134
|
+
): ExpressionReference {
|
|
135
|
+
return { kind: 'expression', id, start: node.start, end: node.end }
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export function spanOf(
|
|
139
|
+
id: ResolvedModuleId,
|
|
140
|
+
node: Pick<AstNode, 'start' | 'end'>
|
|
141
|
+
): SourceSpan {
|
|
142
|
+
return { id, start: node.start, end: node.end }
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export function textOfSpan(
|
|
146
|
+
source: string,
|
|
147
|
+
span: Pick<SourceSpan, 'start' | 'end'>
|
|
148
|
+
): string {
|
|
149
|
+
return source.slice(span.start, span.end)
|
|
150
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { ResolvedModuleId, SourceSpan } from './contracts'
|
|
2
|
+
|
|
3
|
+
export type BailoutCode =
|
|
4
|
+
| 'local/invalid-element-call'
|
|
5
|
+
| 'local/unsupported-element-name'
|
|
6
|
+
| 'local/unsupported-prop-key'
|
|
7
|
+
| 'local/unsupported-child'
|
|
8
|
+
| 'local/unsupported-expression'
|
|
9
|
+
| 'local/unsupported-styled-definition'
|
|
10
|
+
| 'local/dynamic-style-value'
|
|
11
|
+
| 'local/unsafe-style-spread'
|
|
12
|
+
| 'local/unsupported-target'
|
|
13
|
+
| 'local/style-resolution-failed'
|
|
14
|
+
| 'local/overlapping-edit'
|
|
15
|
+
| 'local/non-object-spread'
|
|
16
|
+
| 'local/static-evaluation-cycle'
|
|
17
|
+
| 'local/parse-error'
|
|
18
|
+
| 'linked/unresolved-component-binding'
|
|
19
|
+
| 'linked/unresolved-binding'
|
|
20
|
+
| 'linked/missing-initializer'
|
|
21
|
+
| 'linked/unresolved-import'
|
|
22
|
+
| 'linked/unresolved-component-config'
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The zero-runtime rule a diagnostic belongs to. Set by whichever site knows the
|
|
26
|
+
* reason; `zeroRuleForBailout` supplies the default for the rest.
|
|
27
|
+
*/
|
|
28
|
+
export type ZeroRule = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8
|
|
29
|
+
|
|
30
|
+
export interface BailoutReason {
|
|
31
|
+
code: BailoutCode
|
|
32
|
+
kind: 'local' | 'linked'
|
|
33
|
+
message: string
|
|
34
|
+
span: SourceSpan
|
|
35
|
+
dependencyId?: ResolvedModuleId
|
|
36
|
+
component?: string
|
|
37
|
+
specifier?: string
|
|
38
|
+
prop?: string
|
|
39
|
+
/**
|
|
40
|
+
* True when this diagnostic stopped its candidate from lowering. Zero mode
|
|
41
|
+
* reports exactly these: a diagnostic recorded alongside a successful
|
|
42
|
+
* lowering describes a dropped prop, not a retained runtime.
|
|
43
|
+
*/
|
|
44
|
+
blocking?: boolean
|
|
45
|
+
/** Set where the reporting site knows better than the code-level default. */
|
|
46
|
+
zeroRule?: ZeroRule
|
|
47
|
+
/** The design's fixed text for sites that have one, used verbatim. */
|
|
48
|
+
zeroMessage?: string
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* The rule a bailout code belongs to when its site did not name one. Ordinary
|
|
53
|
+
* compiler mode ignores this entirely.
|
|
54
|
+
*/
|
|
55
|
+
const ZERO_RULE_BY_CODE: Record<BailoutCode, ZeroRule> = {
|
|
56
|
+
'local/invalid-element-call': 2,
|
|
57
|
+
'local/unsupported-element-name': 2,
|
|
58
|
+
'local/unsupported-prop-key': 3,
|
|
59
|
+
'local/unsupported-child': 3,
|
|
60
|
+
'local/unsupported-expression': 3,
|
|
61
|
+
'local/unsupported-styled-definition': 3,
|
|
62
|
+
'local/dynamic-style-value': 3,
|
|
63
|
+
'local/unsafe-style-spread': 1,
|
|
64
|
+
'local/unsupported-target': 6,
|
|
65
|
+
'local/style-resolution-failed': 3,
|
|
66
|
+
'local/overlapping-edit': 6,
|
|
67
|
+
'local/non-object-spread': 1,
|
|
68
|
+
'local/static-evaluation-cycle': 3,
|
|
69
|
+
'local/parse-error': 3,
|
|
70
|
+
'linked/unresolved-component-binding': 2,
|
|
71
|
+
'linked/unresolved-binding': 2,
|
|
72
|
+
'linked/missing-initializer': 3,
|
|
73
|
+
'linked/unresolved-import': 2,
|
|
74
|
+
'linked/unresolved-component-config': 2,
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function zeroRuleForBailout(reason: BailoutReason): ZeroRule {
|
|
78
|
+
return reason.zeroRule ?? ZERO_RULE_BY_CODE[reason.code]
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function localBailout(
|
|
82
|
+
code: Extract<BailoutCode, `local/${string}`>,
|
|
83
|
+
span: SourceSpan,
|
|
84
|
+
message: string
|
|
85
|
+
): BailoutReason {
|
|
86
|
+
return { code, kind: 'local', message, span }
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function linkedBailout(
|
|
90
|
+
code: Extract<BailoutCode, `linked/${string}`>,
|
|
91
|
+
span: SourceSpan,
|
|
92
|
+
message: string,
|
|
93
|
+
dependencyId?: ResolvedModuleId
|
|
94
|
+
): BailoutReason {
|
|
95
|
+
return { code, kind: 'linked', message, span, dependencyId }
|
|
96
|
+
}
|