@tamagui/metro-plugin 2.7.7 → 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.
- package/README.md +12 -0
- package/dist/cjs/babel.cjs +77 -0
- package/dist/cjs/compilerCache.cjs +237 -0
- package/dist/cjs/diagnostics.cjs +41 -0
- package/dist/cjs/frontend.cjs +870 -0
- package/dist/cjs/index.cjs +102 -0
- package/dist/cjs/lowering.cjs +109 -0
- package/dist/cjs/metroResolver.cjs +197 -0
- package/dist/cjs/transformOptions.cjs +35 -0
- package/dist/cjs/transformer.cjs +142 -0
- package/dist/cjs/zeroRuntime.cjs +140 -0
- package/dist/cjs/zeroSerializer.cjs +150 -0
- package/dist/esm/babel.mjs +52 -0
- package/dist/esm/babel.mjs.map +1 -0
- package/dist/esm/compilerCache.mjs +212 -0
- package/dist/esm/compilerCache.mjs.map +1 -0
- package/dist/esm/diagnostics.mjs +18 -0
- package/dist/esm/diagnostics.mjs.map +1 -0
- package/dist/esm/frontend.mjs +839 -0
- package/dist/esm/frontend.mjs.map +1 -0
- package/dist/esm/index.mjs +64 -22
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/lowering.mjs +89 -0
- package/dist/esm/lowering.mjs.map +1 -0
- package/dist/esm/metroResolver.mjs +173 -0
- package/dist/esm/metroResolver.mjs.map +1 -0
- package/dist/esm/transformOptions.mjs +14 -0
- package/dist/esm/transformOptions.mjs.map +1 -0
- package/dist/esm/transformer.mjs +119 -0
- package/dist/esm/transformer.mjs.map +1 -0
- package/dist/esm/zeroRuntime.mjs +105 -0
- package/dist/esm/zeroRuntime.mjs.map +1 -0
- package/dist/esm/zeroSerializer.mjs +123 -0
- package/dist/esm/zeroSerializer.mjs.map +1 -0
- package/package.json +33 -5
- package/src/babel.ts +87 -0
- package/src/compilerCache.ts +346 -0
- package/src/diagnostics.ts +47 -0
- package/src/frontend.ts +1178 -0
- package/src/index.ts +117 -14
- package/src/lowering.ts +136 -0
- package/src/metroResolver.ts +209 -0
- package/src/transformOptions.ts +36 -0
- package/src/transformer.ts +210 -0
- package/src/zeroRuntime.ts +212 -0
- package/src/zeroSerializer.ts +175 -0
- package/types/babel.d.ts +28 -0
- package/types/babel.d.ts.map +11 -0
- package/types/compilerCache.d.ts +63 -0
- package/types/compilerCache.d.ts.map +11 -0
- package/types/diagnostics.d.ts +16 -0
- package/types/diagnostics.d.ts.map +11 -0
- package/types/frontend.d.ts +73 -0
- package/types/frontend.d.ts.map +11 -0
- package/types/index.d.ts +49 -32
- package/types/index.d.ts.map +11 -1
- package/types/lowering.d.ts +20 -0
- package/types/lowering.d.ts.map +11 -0
- package/types/metroResolver.d.ts +21 -0
- package/types/metroResolver.d.ts.map +11 -0
- package/types/transformOptions.d.ts +13 -0
- package/types/transformOptions.d.ts.map +11 -0
- package/types/transformer.d.ts +26 -0
- package/types/transformer.d.ts.map +11 -0
- package/types/zeroRuntime.d.ts +75 -0
- package/types/zeroRuntime.d.ts.map +11 -0
- package/types/zeroSerializer.d.ts +6 -0
- package/types/zeroSerializer.d.ts.map +11 -0
- package/dist/cjs/index.js +0 -45
- package/dist/cjs/index.js.map +0 -6
- package/dist/esm/index.js +0 -25
- package/dist/esm/index.js.map +0 -1
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
import { randomBytes } from 'node:crypto'
|
|
2
|
+
import { mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises'
|
|
3
|
+
import { join } from 'node:path'
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
LOWERED_MODULE_PLAN_VERSION,
|
|
7
|
+
contentHash,
|
|
8
|
+
stableStringify,
|
|
9
|
+
tamaguiCacheRoot,
|
|
10
|
+
} from '@tamagui/compiler-core'
|
|
11
|
+
import type { LoweredModulePlan } from '@tamagui/compiler-core'
|
|
12
|
+
|
|
13
|
+
import { metroDiagnostic, type MetroCompilerDiagnostic } from './diagnostics'
|
|
14
|
+
|
|
15
|
+
export const METRO_COMPILER_CACHE_VERSION = 6
|
|
16
|
+
|
|
17
|
+
export interface MetroCompilerCacheEntry {
|
|
18
|
+
schemaVersion: typeof METRO_COMPILER_CACHE_VERSION
|
|
19
|
+
moduleId: string
|
|
20
|
+
/** Hash of the raw on-disk module source the plan was generated from. */
|
|
21
|
+
sourceHash: string
|
|
22
|
+
plan: LoweredModulePlan
|
|
23
|
+
diagnostics: MetroCompilerDiagnostic[]
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
interface MetroCompilerCacheDescriptor {
|
|
27
|
+
blobHash: string
|
|
28
|
+
sourceHash: string
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
interface MetroCompilerCacheManifest {
|
|
32
|
+
schemaVersion: typeof METRO_COMPILER_CACHE_VERSION
|
|
33
|
+
generation: string
|
|
34
|
+
optionsHash: string
|
|
35
|
+
platform: string | null
|
|
36
|
+
entries: Record<string, MetroCompilerCacheDescriptor>
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface MetroCompilerCacheValidation {
|
|
40
|
+
valid: boolean
|
|
41
|
+
diagnostics: MetroCompilerDiagnostic[]
|
|
42
|
+
generation: string | null
|
|
43
|
+
moduleIds: string[]
|
|
44
|
+
/** Raw module source hash by module id, for host freshness checks. */
|
|
45
|
+
sourceHashes: Record<string, string>
|
|
46
|
+
optionsHash: string | null
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* The zero build's CSS side effects, persisted beside the plan cache.
|
|
51
|
+
*
|
|
52
|
+
* A published plan generation and its artifact contents are the same fact
|
|
53
|
+
* observed twice: the scan produces both. Persisting only the plans means a
|
|
54
|
+
* warm build reuses them while emitting an artifact missing every rule it never
|
|
55
|
+
* collected, and still derives TAMAGUI_DID_OUTPUT_CSS from it. This is what lets
|
|
56
|
+
* the warm path skip the scan without that divergence.
|
|
57
|
+
*/
|
|
58
|
+
export interface MetroZeroCSSSidecar {
|
|
59
|
+
schemaVersion: typeof METRO_COMPILER_CACHE_VERSION
|
|
60
|
+
generation: string
|
|
61
|
+
configCSS: string
|
|
62
|
+
/** Per-module compiler atomic CSS, by resolved module id. */
|
|
63
|
+
zeroModuleCSS: Record<string, string>
|
|
64
|
+
/** Theme-bridge class rules, by bridge id. */
|
|
65
|
+
bridgeCSS: Record<string, string>
|
|
66
|
+
/** The bridge manifest, by island id. */
|
|
67
|
+
bridges: Record<string, unknown[]>
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export class MetroCompilerCacheError extends Error {
|
|
71
|
+
constructor(readonly diagnostic: MetroCompilerDiagnostic) {
|
|
72
|
+
super(diagnostic.message)
|
|
73
|
+
this.name = 'MetroCompilerCacheError'
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function compareCodeUnits(left: string, right: string): number {
|
|
78
|
+
return left < right ? -1 : left > right ? 1 : 0
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function stableEntries<T>(record: Record<string, T>): [string, T][] {
|
|
82
|
+
return Object.entries(record).sort(([left], [right]) => compareCodeUnits(left, right))
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function cacheCorrupt(message: string, moduleId?: string): MetroCompilerCacheError {
|
|
86
|
+
return new MetroCompilerCacheError(
|
|
87
|
+
metroDiagnostic('metro/cache-corrupt', message, { moduleId })
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function parseJson<T>(source: string, description: string, moduleId?: string): T {
|
|
92
|
+
try {
|
|
93
|
+
return JSON.parse(source) as T
|
|
94
|
+
} catch (error) {
|
|
95
|
+
throw cacheCorrupt(
|
|
96
|
+
`${description} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,
|
|
97
|
+
moduleId
|
|
98
|
+
)
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function defaultMetroCompilerCacheRoot(projectRoot: string): string {
|
|
103
|
+
return join(tamaguiCacheRoot(projectRoot), 'metro-compiler')
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Filesystem handoff shared by the Metro main process and isolated transform workers.
|
|
108
|
+
* Immutable blobs are content addressed; a single manifest rename publishes a generation.
|
|
109
|
+
*/
|
|
110
|
+
export class MetroCompilerCache {
|
|
111
|
+
readonly #blobsDirectory: string
|
|
112
|
+
readonly #manifestPath: string
|
|
113
|
+
|
|
114
|
+
constructor(readonly root: string) {
|
|
115
|
+
this.#blobsDirectory = join(root, `v${METRO_COMPILER_CACHE_VERSION}`, 'blobs')
|
|
116
|
+
this.#manifestPath = join(root, `v${METRO_COMPILER_CACHE_VERSION}`, 'manifest.json')
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async publish(
|
|
120
|
+
platform: string | null,
|
|
121
|
+
entries: readonly MetroCompilerCacheEntry[],
|
|
122
|
+
optionsHash: string
|
|
123
|
+
): Promise<string> {
|
|
124
|
+
await mkdir(this.#blobsDirectory, { recursive: true })
|
|
125
|
+
const descriptors: Record<string, MetroCompilerCacheDescriptor> = {}
|
|
126
|
+
|
|
127
|
+
for (const entry of [...entries].sort((left, right) =>
|
|
128
|
+
compareCodeUnits(left.moduleId, right.moduleId)
|
|
129
|
+
)) {
|
|
130
|
+
if (entry.schemaVersion !== METRO_COMPILER_CACHE_VERSION) {
|
|
131
|
+
throw new Error(`Cannot publish cache schema ${entry.schemaVersion}`)
|
|
132
|
+
}
|
|
133
|
+
const serialized = `${stableStringify(entry)}\n`
|
|
134
|
+
const blobHash = contentHash(serialized)
|
|
135
|
+
const blobPath = join(this.#blobsDirectory, `${blobHash}.json`)
|
|
136
|
+
try {
|
|
137
|
+
await writeFile(blobPath, serialized, { encoding: 'utf8', flag: 'wx' })
|
|
138
|
+
} catch (error) {
|
|
139
|
+
if ((error as NodeJS.ErrnoException).code !== 'EEXIST') throw error
|
|
140
|
+
const existing = await readFile(blobPath, 'utf8')
|
|
141
|
+
if (contentHash(existing) !== blobHash) {
|
|
142
|
+
const temporaryBlobPath = `${blobPath}.${process.pid}-${randomBytes(6).toString('hex')}.tmp`
|
|
143
|
+
await writeFile(temporaryBlobPath, serialized, 'utf8')
|
|
144
|
+
await rename(temporaryBlobPath, blobPath)
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
descriptors[entry.moduleId] = {
|
|
148
|
+
blobHash,
|
|
149
|
+
sourceHash: entry.sourceHash,
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const generation = contentHash(stableStringify(descriptors))
|
|
154
|
+
const manifest: MetroCompilerCacheManifest = {
|
|
155
|
+
schemaVersion: METRO_COMPILER_CACHE_VERSION,
|
|
156
|
+
generation,
|
|
157
|
+
optionsHash,
|
|
158
|
+
platform,
|
|
159
|
+
entries: descriptors,
|
|
160
|
+
}
|
|
161
|
+
const manifestDirectory = join(this.root, `v${METRO_COMPILER_CACHE_VERSION}`)
|
|
162
|
+
const temporaryPath = join(
|
|
163
|
+
manifestDirectory,
|
|
164
|
+
`.manifest-${process.pid}-${randomBytes(6).toString('hex')}.json`
|
|
165
|
+
)
|
|
166
|
+
await writeFile(temporaryPath, `${stableStringify(manifest)}\n`, 'utf8')
|
|
167
|
+
await rename(temporaryPath, this.#manifestPath)
|
|
168
|
+
return generation
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
async read(
|
|
172
|
+
moduleId: string,
|
|
173
|
+
rawSource: string,
|
|
174
|
+
onMiss?: (reason: 'no-entry' | 'source-hash-mismatch', detail?: string) => void
|
|
175
|
+
): Promise<MetroCompilerCacheEntry | null> {
|
|
176
|
+
const manifest = await this.#readManifest()
|
|
177
|
+
if (!manifest) return null
|
|
178
|
+
const descriptor = manifest.entries[moduleId]
|
|
179
|
+
if (!descriptor) {
|
|
180
|
+
onMiss?.('no-entry')
|
|
181
|
+
return null
|
|
182
|
+
}
|
|
183
|
+
const sourceHash = contentHash(rawSource)
|
|
184
|
+
if (sourceHash !== descriptor.sourceHash) {
|
|
185
|
+
onMiss?.(
|
|
186
|
+
'source-hash-mismatch',
|
|
187
|
+
`worker ${sourceHash.slice(0, 12)} vs plan ${descriptor.sourceHash.slice(0, 12)}`
|
|
188
|
+
)
|
|
189
|
+
return null
|
|
190
|
+
}
|
|
191
|
+
return await this.#readBlob(moduleId, descriptor)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
async validate(): Promise<MetroCompilerCacheValidation> {
|
|
195
|
+
const diagnostics: MetroCompilerDiagnostic[] = []
|
|
196
|
+
try {
|
|
197
|
+
const manifest = await this.#readManifest()
|
|
198
|
+
if (!manifest) {
|
|
199
|
+
return {
|
|
200
|
+
valid: false,
|
|
201
|
+
diagnostics,
|
|
202
|
+
generation: null,
|
|
203
|
+
moduleIds: [],
|
|
204
|
+
sourceHashes: {},
|
|
205
|
+
optionsHash: null,
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
const sourceHashes: Record<string, string> = {}
|
|
209
|
+
for (const [moduleId, descriptor] of stableEntries(manifest.entries)) {
|
|
210
|
+
await this.#readBlob(moduleId, descriptor)
|
|
211
|
+
sourceHashes[moduleId] = descriptor.sourceHash
|
|
212
|
+
}
|
|
213
|
+
return {
|
|
214
|
+
valid: true,
|
|
215
|
+
diagnostics,
|
|
216
|
+
generation: manifest.generation,
|
|
217
|
+
moduleIds: Object.keys(manifest.entries).sort(compareCodeUnits),
|
|
218
|
+
sourceHashes,
|
|
219
|
+
optionsHash: manifest.optionsHash,
|
|
220
|
+
}
|
|
221
|
+
} catch (error) {
|
|
222
|
+
if (error instanceof MetroCompilerCacheError) {
|
|
223
|
+
diagnostics.push(error.diagnostic)
|
|
224
|
+
return {
|
|
225
|
+
valid: false,
|
|
226
|
+
diagnostics,
|
|
227
|
+
generation: null,
|
|
228
|
+
moduleIds: [],
|
|
229
|
+
sourceHashes: {},
|
|
230
|
+
optionsHash: null,
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
throw error
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
async discardManifest(): Promise<void> {
|
|
238
|
+
await rm(this.#manifestPath, { force: true })
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
#zeroSidecarPath(generation: string): string {
|
|
242
|
+
return join(
|
|
243
|
+
this.root,
|
|
244
|
+
`v${METRO_COMPILER_CACHE_VERSION}`,
|
|
245
|
+
`zero-${generation.slice(0, 32)}.json`
|
|
246
|
+
)
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
async publishZeroCSS(sidecar: MetroZeroCSSSidecar): Promise<void> {
|
|
250
|
+
await mkdir(join(this.root, `v${METRO_COMPILER_CACHE_VERSION}`), { recursive: true })
|
|
251
|
+
const file = this.#zeroSidecarPath(sidecar.generation)
|
|
252
|
+
const temporaryPath = `${file}.${process.pid}-${randomBytes(6).toString('hex')}.tmp`
|
|
253
|
+
await writeFile(temporaryPath, `${stableStringify(sidecar)}\n`, 'utf8')
|
|
254
|
+
await rename(temporaryPath, file)
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/** Null whenever the sidecar is absent or does not describe this generation. */
|
|
258
|
+
async readZeroCSS(generation: string): Promise<MetroZeroCSSSidecar | null> {
|
|
259
|
+
let source: string
|
|
260
|
+
try {
|
|
261
|
+
source = await readFile(this.#zeroSidecarPath(generation), 'utf8')
|
|
262
|
+
} catch (error) {
|
|
263
|
+
if ((error as NodeJS.ErrnoException).code === 'ENOENT') return null
|
|
264
|
+
throw error
|
|
265
|
+
}
|
|
266
|
+
const sidecar = parseJson<MetroZeroCSSSidecar>(source, 'Zero CSS sidecar')
|
|
267
|
+
if (
|
|
268
|
+
sidecar.schemaVersion !== METRO_COMPILER_CACHE_VERSION ||
|
|
269
|
+
sidecar.generation !== generation ||
|
|
270
|
+
typeof sidecar.configCSS !== 'string' ||
|
|
271
|
+
!sidecar.zeroModuleCSS ||
|
|
272
|
+
typeof sidecar.zeroModuleCSS !== 'object' ||
|
|
273
|
+
!sidecar.bridgeCSS ||
|
|
274
|
+
typeof sidecar.bridgeCSS !== 'object' ||
|
|
275
|
+
!sidecar.bridges ||
|
|
276
|
+
typeof sidecar.bridges !== 'object'
|
|
277
|
+
) {
|
|
278
|
+
return null
|
|
279
|
+
}
|
|
280
|
+
return sidecar
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
async #readManifest(): Promise<MetroCompilerCacheManifest | null> {
|
|
284
|
+
let source: string
|
|
285
|
+
try {
|
|
286
|
+
source = await readFile(this.#manifestPath, 'utf8')
|
|
287
|
+
} catch (error) {
|
|
288
|
+
if ((error as NodeJS.ErrnoException).code === 'ENOENT') return null
|
|
289
|
+
throw error
|
|
290
|
+
}
|
|
291
|
+
const manifest = parseJson<MetroCompilerCacheManifest>(source, 'Cache manifest')
|
|
292
|
+
if (
|
|
293
|
+
manifest.schemaVersion !== METRO_COMPILER_CACHE_VERSION ||
|
|
294
|
+
typeof manifest.generation !== 'string' ||
|
|
295
|
+
typeof manifest.optionsHash !== 'string' ||
|
|
296
|
+
!manifest.entries ||
|
|
297
|
+
typeof manifest.entries !== 'object'
|
|
298
|
+
) {
|
|
299
|
+
throw cacheCorrupt('Cache manifest has an unsupported schema')
|
|
300
|
+
}
|
|
301
|
+
return manifest
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
async #readBlob(
|
|
305
|
+
moduleId: string,
|
|
306
|
+
descriptor: MetroCompilerCacheDescriptor
|
|
307
|
+
): Promise<MetroCompilerCacheEntry> {
|
|
308
|
+
const blobPath = join(this.#blobsDirectory, `${descriptor.blobHash}.json`)
|
|
309
|
+
let source: string
|
|
310
|
+
try {
|
|
311
|
+
source = await readFile(blobPath, 'utf8')
|
|
312
|
+
} catch (error) {
|
|
313
|
+
if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
|
|
314
|
+
throw cacheCorrupt(`Cache blob ${descriptor.blobHash} is missing`, moduleId)
|
|
315
|
+
}
|
|
316
|
+
throw error
|
|
317
|
+
}
|
|
318
|
+
if (contentHash(source) !== descriptor.blobHash) {
|
|
319
|
+
throw cacheCorrupt(`Cache blob ${descriptor.blobHash} failed its hash`, moduleId)
|
|
320
|
+
}
|
|
321
|
+
const entry = parseJson<MetroCompilerCacheEntry>(
|
|
322
|
+
source,
|
|
323
|
+
`Cache blob ${descriptor.blobHash}`,
|
|
324
|
+
moduleId
|
|
325
|
+
)
|
|
326
|
+
if (
|
|
327
|
+
entry.schemaVersion !== METRO_COMPILER_CACHE_VERSION ||
|
|
328
|
+
entry.moduleId !== moduleId ||
|
|
329
|
+
typeof entry.sourceHash !== 'string' ||
|
|
330
|
+
entry.sourceHash !== descriptor.sourceHash ||
|
|
331
|
+
!entry.plan ||
|
|
332
|
+
entry.plan.version !== LOWERED_MODULE_PLAN_VERSION ||
|
|
333
|
+
entry.plan.id !== moduleId ||
|
|
334
|
+
entry.plan.sourceHash !== entry.sourceHash ||
|
|
335
|
+
!Array.isArray(entry.plan.edits) ||
|
|
336
|
+
!Array.isArray(entry.plan.diagnostics) ||
|
|
337
|
+
!Array.isArray(entry.diagnostics)
|
|
338
|
+
) {
|
|
339
|
+
throw cacheCorrupt(
|
|
340
|
+
`Cache blob ${descriptor.blobHash} has invalid contents`,
|
|
341
|
+
moduleId
|
|
342
|
+
)
|
|
343
|
+
}
|
|
344
|
+
return entry
|
|
345
|
+
}
|
|
346
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { isAbsolute, relative } from 'node:path'
|
|
2
|
+
|
|
3
|
+
import type { SourceSpan } from '@tamagui/compiler-core'
|
|
4
|
+
|
|
5
|
+
export type MetroCompilerDiagnosticCode =
|
|
6
|
+
| 'metro/cache-corrupt'
|
|
7
|
+
| 'metro/cache-stale'
|
|
8
|
+
| 'metro/no-linked-components'
|
|
9
|
+
| 'metro/plan-miss'
|
|
10
|
+
| 'metro/resolve-failed'
|
|
11
|
+
| 'metro/transform-failed'
|
|
12
|
+
|
|
13
|
+
export interface MetroCompilerDiagnostic {
|
|
14
|
+
code: MetroCompilerDiagnosticCode
|
|
15
|
+
message: string
|
|
16
|
+
moduleId?: string
|
|
17
|
+
dependency?: string
|
|
18
|
+
span?: SourceSpan
|
|
19
|
+
line?: number
|
|
20
|
+
column?: number
|
|
21
|
+
component?: string
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function metroDiagnostic(
|
|
25
|
+
code: MetroCompilerDiagnosticCode,
|
|
26
|
+
message: string,
|
|
27
|
+
details: Omit<MetroCompilerDiagnostic, 'code' | 'message'> = {}
|
|
28
|
+
): MetroCompilerDiagnostic {
|
|
29
|
+
return { code, message, ...details }
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function formatMetroCompilerDiagnostic(
|
|
33
|
+
diagnostic: MetroCompilerDiagnostic,
|
|
34
|
+
projectRoot: string
|
|
35
|
+
): string {
|
|
36
|
+
const sourceId = diagnostic.span?.id ?? diagnostic.moduleId
|
|
37
|
+
const file = sourceId
|
|
38
|
+
? isAbsolute(sourceId)
|
|
39
|
+
? relative(projectRoot, sourceId) || '.'
|
|
40
|
+
: sourceId
|
|
41
|
+
: null
|
|
42
|
+
const location =
|
|
43
|
+
file && diagnostic.line != null && diagnostic.column != null
|
|
44
|
+
? `${file}:${diagnostic.line}:${diagnostic.column}: `
|
|
45
|
+
: ''
|
|
46
|
+
return `[@tamagui/metro-plugin] ${location}${diagnostic.code}: ${diagnostic.message}`
|
|
47
|
+
}
|