@tamagui/static 1.0.1-beta.193 → 1.0.1-beta.194

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 (44) hide show
  1. package/dist/extractor/babelParse.js.map +2 -2
  2. package/dist/extractor/bundle.js +117 -0
  3. package/dist/extractor/bundle.js.map +7 -0
  4. package/dist/extractor/createExtractor.js +147 -79
  5. package/dist/extractor/createExtractor.js.map +3 -3
  6. package/dist/extractor/extractHelpers.js +41 -6
  7. package/dist/extractor/extractHelpers.js.map +2 -2
  8. package/dist/extractor/extractToClassNames.js +2 -1
  9. package/dist/extractor/extractToClassNames.js.map +2 -2
  10. package/dist/extractor/getPropValueFromAttributes.js.map +2 -2
  11. package/dist/extractor/loadTamagui.js +219 -117
  12. package/dist/extractor/loadTamagui.js.map +3 -3
  13. package/dist/extractor/normalizeTernaries.js.map +2 -2
  14. package/dist/getPragmaOptions.js +1 -1
  15. package/dist/getPragmaOptions.js.map +2 -2
  16. package/dist/index.js +0 -1
  17. package/dist/index.js.map +2 -2
  18. package/dist/require.js +13 -7
  19. package/dist/require.js.map +2 -2
  20. package/dist/tamagui-node/tamagui.config.js +6781 -0
  21. package/dist/tamagui-node/tamaguicore-components.config.js +0 -0
  22. package/dist/tamagui-node/tamaguitestdesignsystem-components.config.js +31 -0
  23. package/dist/types.js.map +1 -1
  24. package/package.json +20 -17
  25. package/src/extractor/babelParse.ts +3 -2
  26. package/src/extractor/bundle.ts +110 -0
  27. package/src/extractor/createExtractor.ts +167 -69
  28. package/src/extractor/extractHelpers.ts +57 -10
  29. package/src/extractor/extractToClassNames.ts +12 -9
  30. package/src/extractor/getPropValueFromAttributes.ts +1 -1
  31. package/src/extractor/loadTamagui.ts +256 -145
  32. package/src/extractor/normalizeTernaries.ts +1 -1
  33. package/src/getPragmaOptions.ts +2 -1
  34. package/src/index.ts +0 -1
  35. package/src/require.ts +16 -8
  36. package/src/types.ts +5 -1
  37. package/types/extractor/babelParse.d.ts +2 -1
  38. package/types/extractor/bundle.d.ts +13 -0
  39. package/types/extractor/extractHelpers.d.ts +13 -3
  40. package/types/extractor/extractToClassNames.d.ts +3 -2
  41. package/types/extractor/findTopmostFunction.d.ts +1 -1
  42. package/types/extractor/loadTamagui.d.ts +9 -2
  43. package/types/index.d.ts +0 -1
  44. package/types/types.d.ts +4 -1
@@ -1,12 +1,11 @@
1
1
  /* eslint-disable no-console */
2
- import path, { basename, relative } from 'path'
2
+ import { basename, join, relative } from 'path'
3
3
 
4
- import traverse, { NodePath, Visitor } from '@babel/traverse'
4
+ import traverse, { NodePath, TraverseOptions } from '@babel/traverse'
5
5
  import * as t from '@babel/types'
6
6
  import {
7
7
  PseudoStyles,
8
8
  StaticConfigParsed,
9
- createDOMProps,
10
9
  expandStyles,
11
10
  getSplitStyles,
12
11
  getStylesAtomic,
@@ -14,6 +13,7 @@ import {
14
13
  proxyThemeVariables,
15
14
  pseudoDescriptors,
16
15
  } from '@tamagui/core-node'
16
+ import { createDOMProps } from '@tamagui/rnw'
17
17
  import type { ViewStyle } from 'react-native'
18
18
 
19
19
  import { FAILED_EVAL } from '../constants.js'
@@ -29,12 +29,25 @@ import type {
29
29
  } from '../types.js'
30
30
  import { createEvaluator, createSafeEvaluator } from './createEvaluator.js'
31
31
  import { evaluateAstNode } from './evaluateAstNode.js'
32
- import { attrStr, findComponentName, isPresent, isValidImport, objToStr } from './extractHelpers.js'
32
+ import {
33
+ attrStr,
34
+ findComponentName,
35
+ getValidComponent,
36
+ getValidImport,
37
+ isPresent,
38
+ isValidImport,
39
+ objToStr,
40
+ } from './extractHelpers.js'
33
41
  import { findTopmostFunction } from './findTopmostFunction.js'
34
42
  import { getPrefixLogs } from './getPrefixLogs.js'
35
43
  import { cleanupBeforeExit, getStaticBindingsForScope } from './getStaticBindingsForScope.js'
36
44
  import { literalToAst } from './literalToAst.js'
37
- import { TamaguiProjectInfo, loadTamagui, loadTamaguiSync } from './loadTamagui.js'
45
+ import {
46
+ LoadedComponents,
47
+ TamaguiProjectInfo,
48
+ loadTamagui,
49
+ loadTamaguiSync,
50
+ } from './loadTamagui.js'
38
51
  import { logLines } from './logLines.js'
39
52
  import { normalizeTernaries } from './normalizeTernaries.js'
40
53
  import { removeUnusedHooks } from './removeUnusedHooks.js'
@@ -71,6 +84,8 @@ export type Extractor = ReturnType<typeof createExtractor>
71
84
 
72
85
  type FileOrPath = NodePath<t.Program> | t.File
73
86
 
87
+ let hasLoggedBaseInfo = false
88
+
74
89
  export function createExtractor({ logger = console }: ExtractorOptions = { logger: console }) {
75
90
  if (!process.env.TAMAGUI_TARGET) {
76
91
  console.log('⚠️ Please set process.env.TAMAGUI_TARGET to either "web" or "native"')
@@ -156,6 +171,7 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
156
171
  disableExtractVariables,
157
172
  disableDebugAttr,
158
173
  disableExtractFoundComponents,
174
+ includeExtensions = ['.tsx', '.jsx'],
159
175
  extractStyledDefinitions = false,
160
176
  prefixLogs,
161
177
  excludeProps,
@@ -165,7 +181,7 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
165
181
 
166
182
  let shouldPrintDebug = options.shouldPrintDebug || false
167
183
 
168
- if (disable) {
184
+ if (disable === true || (Array.isArray(disable) && disable.includes(sourcePath))) {
169
185
  return null
170
186
  }
171
187
  if (sourcePath === '') {
@@ -174,6 +190,20 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
174
190
  if (!components) {
175
191
  throw new Error(`Must provide components`)
176
192
  }
193
+ if (includeExtensions && !includeExtensions.some((ext) => sourcePath.endsWith(ext))) {
194
+ if (shouldPrintDebug) {
195
+ logger.info(
196
+ `Ignoring file due to includeExtensions: ${sourcePath}, includeExtensions: ${includeExtensions.join(
197
+ ', '
198
+ )}`
199
+ )
200
+ }
201
+ return null
202
+ }
203
+
204
+ /**
205
+ * Step 1: Determine if importing any statically extractable components
206
+ */
177
207
 
178
208
  const isTargetingHTML = target === 'html'
179
209
  const ogDebug = shouldPrintDebug
@@ -181,10 +211,31 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
181
211
  const propsWithFileInfo: TamaguiOptionsWithFileInfo = {
182
212
  ...options,
183
213
  sourcePath,
214
+ allLoadedComponents: [...components],
184
215
  }
185
216
 
186
- if (shouldPrintDebug === 'verbose') {
187
- console.log('tamagui.config.ts:', { components, config })
217
+ if (!hasLoggedBaseInfo) {
218
+ hasLoggedBaseInfo = true
219
+ if (shouldPrintDebug) {
220
+ logger.info(
221
+ [
222
+ 'loaded components:',
223
+ propsWithFileInfo.allLoadedComponents
224
+ .map((comp) => Object.keys(comp.nameToInfo).join(', '))
225
+ .join(', '),
226
+ ].join(' ')
227
+ )
228
+ }
229
+ if (process.env.DEBUG?.startsWith('tamagui')) {
230
+ const next = [...propsWithFileInfo.allLoadedComponents].map((info) => {
231
+ const nameToInfo = { ...info.nameToInfo }
232
+ for (const key in nameToInfo) {
233
+ delete nameToInfo[key].staticConfig.validStyles
234
+ }
235
+ return { ...info, nameToInfo }
236
+ })
237
+ logger.info(['loaded:', JSON.stringify(next, null, 2)].join('\n'))
238
+ }
188
239
  }
189
240
 
190
241
  tm.mark('load-tamagui', !!shouldPrintDebug)
@@ -194,7 +245,7 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
194
245
 
195
246
  if (!firstTheme || typeof firstTheme !== 'object') {
196
247
  console.error(`Missing theme, an error occurred when importing your config`)
197
- console.log(`Got themes:`, tamaguiConfig.themes)
248
+ console.log(`Got config:`, tamaguiConfig)
198
249
  console.log(`Looking for theme:`, firstThemeName)
199
250
  process.exit(0)
200
251
  }
@@ -214,19 +265,7 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
214
265
  // @ts-ignore
215
266
  const body = fileOrPath.type === 'Program' ? fileOrPath.get('body') : fileOrPath.program.body
216
267
 
217
- /**
218
- * Step 1: Determine if importing any statically extractable components
219
- */
220
-
221
- const validComponents: { [key: string]: any } = Object.keys(components)
222
- // check if uppercase to avoid hitting media query proxy before init
223
- .filter((key) => key[0].toUpperCase() === key[0] && !!components[key]?.staticConfig)
224
- .reduce((obj, name) => {
225
- obj[name] = components[name]
226
- return obj
227
- }, {})
228
-
229
- if (Object.keys(validComponents).length === 0) {
268
+ if (Object.keys(components).length === 0) {
230
269
  console.warn(`Warning: Tamagui didn't find any valid components (DEBUG=tamagui for more)`)
231
270
  if (process.env.DEBUG === 'tamagui') {
232
271
  console.log(`components`, Object.keys(components), components)
@@ -234,27 +273,33 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
234
273
  }
235
274
 
236
275
  if (shouldPrintDebug === 'verbose') {
237
- logger.info(`validComponents ${Object.keys(validComponents).join(', ')}`)
276
+ logger.info(
277
+ `allLoadedComponent modules ${propsWithFileInfo.allLoadedComponents
278
+ .map((k) => k.moduleName)
279
+ .join(', ')}`
280
+ )
238
281
  }
239
282
 
240
283
  let doesUseValidImport = false
241
284
  let hasImportedTheme = false
242
285
 
286
+ const importDeclarations: t.ImportDeclaration[] = []
287
+
243
288
  for (const bodyPath of body) {
244
289
  if (bodyPath.type !== 'ImportDeclaration') continue
245
290
  const node = ('node' in bodyPath ? bodyPath.node : bodyPath) as t.ImportDeclaration
246
- const from = node.source.value
291
+ const moduleName = node.source.value
247
292
 
248
- // if importing styled()
249
- const valid = isValidImport(propsWithFileInfo, from)
293
+ // if importing valid module
294
+ const valid = isValidImport(propsWithFileInfo, moduleName)
295
+
296
+ if (valid) {
297
+ importDeclarations.push(node)
298
+ }
250
299
 
251
300
  if (extractStyledDefinitions) {
252
301
  if (valid) {
253
- if (
254
- node.specifiers.some((specifier) => {
255
- return specifier.local.name === 'styled'
256
- })
257
- ) {
302
+ if (node.specifiers.some((specifier) => specifier.local.name === 'styled')) {
258
303
  doesUseValidImport = true
259
304
  break
260
305
  }
@@ -263,10 +308,12 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
263
308
 
264
309
  if (valid) {
265
310
  const names = node.specifiers.map((specifier) => specifier.local.name)
266
- const isValidComponent = names.some((name) => !!(validComponents[name] || validHooks[name]))
311
+ const isValidComponent = names.some((name) =>
312
+ Boolean(isValidImport(propsWithFileInfo, moduleName, name) || validHooks[name])
313
+ )
267
314
  if (shouldPrintDebug === 'verbose') {
268
315
  logger.info(
269
- `import ${names.join(', ')} from ${from} isValidComponent ${isValidComponent}`
316
+ `import ${names.join(', ')} from ${moduleName} isValidComponent ${isValidComponent}`
270
317
  )
271
318
  }
272
319
  if (isValidComponent) {
@@ -277,13 +324,23 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
277
324
  }
278
325
 
279
326
  if (shouldPrintDebug) {
280
- logger.info(`source: ${sourcePath} doesUseValidImport ${doesUseValidImport}`)
327
+ logger.info(`file: ${sourcePath} ${JSON.stringify({ doesUseValidImport, hasImportedTheme })}`)
281
328
  }
282
329
 
283
330
  if (!doesUseValidImport) {
284
331
  return null
285
332
  }
286
333
 
334
+ function getValidImportedComponent(componentName: string) {
335
+ const importDeclaration = importDeclarations.find((dec) =>
336
+ dec.specifiers.some((spec) => spec.local.name === componentName)
337
+ )
338
+ if (!importDeclaration) {
339
+ return null
340
+ }
341
+ return getValidImport(propsWithFileInfo, importDeclaration.source.value, componentName)
342
+ }
343
+
287
344
  tm.mark('import-check', !!shouldPrintDebug)
288
345
 
289
346
  let couldntParse = false
@@ -292,10 +349,14 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
292
349
  // only keeping a cache around per-file, reset it if it changes
293
350
  const bindingCache: Record<string, string | null> = {}
294
351
 
295
- const callTraverse = (a: Visitor<{}>) => {
352
+ const callTraverse = (a: TraverseOptions<any>) => {
296
353
  return fileOrPath.type === 'File' ? traverse(fileOrPath, a) : fileOrPath.traverse(a)
297
354
  }
298
355
 
356
+ const shouldDisableExtraction =
357
+ disableExtraction === true ||
358
+ (Array.isArray(disableExtraction) && disableExtraction.includes(sourcePath))
359
+
299
360
  /**
300
361
  * Step 2: Statically extract from JSX < /> nodes
301
362
  */
@@ -310,6 +371,7 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
310
371
  }
311
372
 
312
373
  callTraverse({
374
+ // @ts-ignore
313
375
  Program: {
314
376
  enter(path) {
315
377
  programPath = path
@@ -318,7 +380,7 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
318
380
 
319
381
  // styled() calls
320
382
  CallExpression(path) {
321
- if (disable || disableExtraction || extractStyledDefinitions === false) {
383
+ if (disable || shouldDisableExtraction || extractStyledDefinitions === false) {
322
384
  return
323
385
  }
324
386
 
@@ -330,20 +392,31 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
330
392
  t.isVariableDeclarator(path.parent) && t.isIdentifier(path.parent.id)
331
393
  ? path.parent.id.name
332
394
  : 'unknown'
395
+
333
396
  const definition = path.node.arguments[1]
334
397
 
335
398
  if (!name || !definition || !t.isObjectExpression(definition)) {
336
399
  return
337
400
  }
338
401
 
339
- let Component = validComponents[name] as { staticConfig: StaticConfigParsed } | undefined
402
+ let Component = getValidImportedComponent(name)
340
403
 
341
404
  if (!Component) {
342
- if (disableExtractFoundComponents) {
405
+ if (disableExtractFoundComponents === true) {
406
+ return
407
+ }
408
+ if (
409
+ Array.isArray(disableExtractFoundComponents) &&
410
+ disableExtractFoundComponents.includes(name)
411
+ ) {
343
412
  return
344
413
  }
345
414
 
346
415
  try {
416
+ if (shouldPrintDebug) {
417
+ logger.info(`Unknown component ${name}, attempting dynamic load: ${sourcePath}`)
418
+ }
419
+
347
420
  const out = loadTamaguiSync({
348
421
  // TODO would extract more, is NO-OP for now..
349
422
  forceExports: true,
@@ -351,16 +424,22 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
351
424
  components: [sourcePath],
352
425
  })
353
426
 
354
- if (out.components?.[name]) {
355
- // add new components
356
- // TODO dont Clobber, do by file
357
- Object.assign(validComponents, out.components)
427
+ if (!out?.components) {
428
+ if (shouldPrintDebug) {
429
+ logger.info(`Couldn't load, got ${out}`)
430
+ }
431
+ return
358
432
  }
359
433
 
360
- Component = validComponents[name]
434
+ propsWithFileInfo.allLoadedComponents = [
435
+ ...propsWithFileInfo.allLoadedComponents,
436
+ ...out.components,
437
+ ]
438
+
439
+ Component = out.components.flatMap((x) => x.nameToInfo[name] ?? [])[0]
361
440
 
362
441
  if (shouldPrintDebug) {
363
- logger.info([`Loaded`, Object.keys(out.components).join(', '), !!Component].join(' '))
442
+ logger.info([`Tamagui Loaded`, JSON.stringify(out.components), !!Component].join(' '))
364
443
  }
365
444
  } catch (err: any) {
366
445
  if (shouldPrintDebug) {
@@ -410,7 +489,7 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
410
489
  const attemptEval = !evaluateVars
411
490
  ? evaluateAstNode
412
491
  : createEvaluator({
413
- props: options,
492
+ props: propsWithFileInfo,
414
493
  staticNamespace,
415
494
  sourcePath,
416
495
  shouldPrintDebug,
@@ -491,6 +570,10 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
491
570
  },
492
571
 
493
572
  JSXElement(traversePath) {
573
+ if (shouldDisableExtraction) {
574
+ return
575
+ }
576
+
494
577
  tm.mark('jsx-element', !!shouldPrintDebug)
495
578
 
496
579
  const node = traversePath.node.openingElement
@@ -505,6 +588,7 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
505
588
 
506
589
  // validate its a proper import from tamagui (or internally inside tamagui)
507
590
  const binding = traversePath.scope.getBinding(node.name.name)
591
+ let modulePath = ''
508
592
 
509
593
  if (binding) {
510
594
  if (!t.isImportDeclaration(binding.path.parent)) {
@@ -513,24 +597,16 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
513
597
  }
514
598
  return
515
599
  }
516
- const source = binding.path.parent.source
517
- if (!isValidImport(propsWithFileInfo, source.value)) {
600
+ modulePath = binding.path.parent.source.value
601
+ if (!isValidImport(propsWithFileInfo, modulePath, binding.identifier.name)) {
518
602
  if (shouldPrintDebug) {
519
- logger.info(` - Binding not internal import or from components ${source.value}`)
520
- }
521
- return
522
- }
523
- if (!validComponents[binding.identifier.name]) {
524
- if (shouldPrintDebug) {
525
- logger.info(
526
- ` - Binding not valid component (binding.identifier.name) ${binding.identifier.name}`
527
- )
603
+ logger.info(` - Binding not internal import or from components ${modulePath}`)
528
604
  }
529
605
  return
530
606
  }
531
607
  }
532
608
 
533
- const component = validComponents[node.name.name] as { staticConfig?: StaticConfigParsed }
609
+ const component = getValidComponent(propsWithFileInfo, modulePath, node.name.name)
534
610
  if (!component || !component.staticConfig) {
535
611
  if (shouldPrintDebug) {
536
612
  logger.info(` - No Tamagui conf on this: ${node.name.name}`)
@@ -556,7 +632,8 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
556
632
  .filter(
557
633
  (n) => t.isJSXAttribute(n) && t.isJSXIdentifier(n.name) && n.name.name === 'debug'
558
634
  )
559
- .map((n) => {
635
+ // @ts-ignore
636
+ .map((n: t.JSXAttribute) => {
560
637
  if (n.value === null) return true
561
638
  if (t.isStringLiteral(n.value)) return n.value.value as 'verbose'
562
639
  return false
@@ -657,7 +734,7 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
657
734
  const attemptEval = !evaluateVars
658
735
  ? evaluateAstNode
659
736
  : createEvaluator({
660
- props: options,
737
+ props: propsWithFileInfo,
661
738
  staticNamespace,
662
739
  sourcePath,
663
740
  traversePath,
@@ -1404,7 +1481,11 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
1404
1481
  traversePath.node.children.every((x) => x.type === 'JSXText')))
1405
1482
 
1406
1483
  const themeVal = inlined.get('theme')
1407
- inlined.delete('theme')
1484
+
1485
+ // on native we can't flatten when theme prop is set
1486
+ if (target !== 'native') {
1487
+ inlined.delete('theme')
1488
+ }
1408
1489
 
1409
1490
  for (const [key] of [...inlined]) {
1410
1491
  const isStaticObjectVariant = staticConfig.variants?.[key] && variantValues.has(key)
@@ -1415,13 +1496,14 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
1415
1496
 
1416
1497
  const canFlattenProps = inlined.size === 0
1417
1498
 
1418
- let shouldFlatten =
1499
+ let shouldFlatten = Boolean(
1419
1500
  flatNode &&
1420
- !shouldDeopt &&
1421
- canFlattenProps &&
1422
- !hasSpread &&
1423
- staticConfig.neverFlatten !== true &&
1424
- (staticConfig.neverFlatten === 'jsx' ? hasOnlyStringChildren : true)
1501
+ !shouldDeopt &&
1502
+ canFlattenProps &&
1503
+ !hasSpread &&
1504
+ staticConfig.neverFlatten !== true &&
1505
+ (staticConfig.neverFlatten === 'jsx' ? hasOnlyStringChildren : true)
1506
+ )
1425
1507
 
1426
1508
  const shouldWrapTheme = shouldFlatten && themeVal
1427
1509
  const usedThemeKeys = new Set<string>()
@@ -1431,7 +1513,7 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
1431
1513
  themeAccessListeners.add((key) => {
1432
1514
  shouldFlatten = false
1433
1515
  usedThemeKeys.add(key)
1434
- if (shouldPrintDebug) {
1516
+ if (shouldPrintDebug === 'verbose') {
1435
1517
  logger.info([' ! accessing theme key, avoid flatten', key].join(' '))
1436
1518
  }
1437
1519
  })
@@ -1516,6 +1598,9 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
1516
1598
  }
1517
1599
 
1518
1600
  if (shouldDeopt) {
1601
+ if (shouldPrintDebug) {
1602
+ logger.info(`Deopting`)
1603
+ }
1519
1604
  node.attributes = ogAttributes
1520
1605
  return
1521
1606
  }
@@ -1851,6 +1936,7 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
1851
1936
  },
1852
1937
  undefined,
1853
1938
  undefined,
1939
+ undefined,
1854
1940
  debugPropValue
1855
1941
  )
1856
1942
 
@@ -1881,6 +1967,15 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
1881
1967
  throw new Error(`Impossible, no styles`)
1882
1968
  }
1883
1969
 
1970
+ const isNativeNotFlat = !shouldFlatten && target === 'native'
1971
+ if (isNativeNotFlat) {
1972
+ if (shouldPrintDebug) {
1973
+ logger.info(`Disabled flattening except for simple cases on native for now`)
1974
+ node.attributes = ogAttributes
1975
+ return null
1976
+ }
1977
+ }
1978
+
1884
1979
  let getStyleError: any = null
1885
1980
 
1886
1981
  // fix up ternaries, combine final style values
@@ -1924,7 +2019,7 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
1924
2019
  if (getStyleError) {
1925
2020
  logger.info([' ⚠️ postprocessing error, deopt', getStyleError].join(' '))
1926
2021
  node.attributes = ogAttributes
1927
- return node
2022
+ return null
1928
2023
  }
1929
2024
 
1930
2025
  // final lazy extra loop:
@@ -1995,9 +2090,11 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
1995
2090
  if (shouldPrintDebug) {
1996
2091
  logger.info([' [✅] flattening', originalNodeName, flatNode].join(' '))
1997
2092
  }
2093
+ // @ts-ignore
1998
2094
  node.name.name = flatNode
1999
2095
  res.flattened++
2000
2096
  if (closingElement) {
2097
+ // @ts-ignore
2001
2098
  closingElement.name.name = flatNode
2002
2099
  }
2003
2100
  }
@@ -2009,6 +2106,7 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
2009
2106
  }
2010
2107
 
2011
2108
  onExtractTag({
2109
+ parserProps: propsWithFileInfo,
2012
2110
  attrs,
2013
2111
  node,
2014
2112
  lineNumbers,
@@ -2017,7 +2115,7 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
2017
2115
  jsxPath: traversePath,
2018
2116
  originalNodeName,
2019
2117
  isFlattened: shouldFlatten,
2020
- programPath,
2118
+ programPath: programPath!,
2021
2119
  completeProps,
2022
2120
  staticConfig,
2023
2121
  })
@@ -58,7 +58,7 @@ export const ternaryStr = (x: Ternary) => {
58
58
  ? x.test.name
59
59
  : t.isMemberExpression(x.test)
60
60
  ? [x.test.object['name'], x.test.property['name']]
61
- : generate(x.test).code
61
+ : generate(x.test as any).code
62
62
  return [
63
63
  'ternary(',
64
64
  conditional,
@@ -118,9 +118,9 @@ export function isValidThemeHook(
118
118
  return true
119
119
  }
120
120
 
121
- export const isInsideComponentPackage = (props: TamaguiOptionsWithFileInfo, srcName: string) => {
121
+ export const isInsideComponentPackage = (props: TamaguiOptionsWithFileInfo, moduleName: string) => {
122
122
  return getValidComponentsPaths(props).some((path) => {
123
- return srcName.startsWith(path)
123
+ return moduleName.startsWith(path)
124
124
  })
125
125
  }
126
126
 
@@ -130,15 +130,62 @@ export const isComponentPackage = (props: TamaguiOptionsWithFileInfo, srcName: s
130
130
  })
131
131
  }
132
132
 
133
- export const isValidImport = (props: TamaguiOptionsWithFileInfo, srcName: string) => {
134
- if (typeof srcName !== 'string') {
135
- // eslint-disable-next-line no-console
136
- console.trace(`Invalid file name: ${srcName}`)
133
+ export function getValidComponent(
134
+ props: TamaguiOptionsWithFileInfo,
135
+ moduleName: string,
136
+ componentName: string
137
+ ) {
138
+ // must be uppercase of course
139
+ if (componentName[0].toUpperCase() !== componentName[0]) {
137
140
  return false
138
141
  }
139
- return srcName.startsWith('.')
140
- ? isInsideComponentPackage(props, srcName)
141
- : isComponentPackage(props, srcName)
142
+
143
+ for (const loaded of props.allLoadedComponents) {
144
+ const isInModule = moduleName === '*' || moduleName.startsWith(loaded.moduleName)
145
+ const foundComponent = loaded.nameToInfo[componentName]
146
+ // eslint-disable-next-line no-console
147
+ if (isInModule && foundComponent) {
148
+ return foundComponent
149
+ }
150
+ }
151
+
152
+ return null
153
+ }
154
+
155
+ export const isValidModule = (props: TamaguiOptionsWithFileInfo, moduleName: string) => {
156
+ if (typeof moduleName !== 'string') {
157
+ throw new Error(`No module name`)
158
+ }
159
+ const isLocal = moduleName.startsWith('.')
160
+ return {
161
+ isLocal,
162
+ isValid: isLocal
163
+ ? isInsideComponentPackage(props, moduleName)
164
+ : isComponentPackage(props, moduleName),
165
+ }
166
+ }
167
+
168
+ export const getValidImport = (
169
+ props: TamaguiOptionsWithFileInfo,
170
+ moduleName: string,
171
+ componentName?: string
172
+ ) => {
173
+ const { isValid, isLocal } = isValidModule(props, moduleName)
174
+ if (!isValid || !componentName) {
175
+ return null
176
+ }
177
+ return getValidComponent(props, isLocal ? '*' : moduleName, componentName) || null
178
+ }
179
+
180
+ export const isValidImport = (
181
+ props: TamaguiOptionsWithFileInfo,
182
+ moduleName: string,
183
+ componentName?: string
184
+ ) => {
185
+ if (!componentName) {
186
+ return isValidModule(props, moduleName).isValid
187
+ }
188
+ return Boolean(getValidImport(props, moduleName, componentName))
142
189
  }
143
190
 
144
191
  const getValidComponentPackages = memoize((props: TamaguiOptionsWithFileInfo) => {
@@ -36,19 +36,21 @@ export type ExtractedResponse = {
36
36
  map: any // RawSourceMap from 'source-map'
37
37
  }
38
38
 
39
+ export type ExtractToClassNamesProps = {
40
+ extractor: Extractor
41
+ source: string | Buffer
42
+ sourcePath: string
43
+ options: TamaguiOptions
44
+ shouldPrintDebug: boolean | 'verbose'
45
+ }
46
+
39
47
  export async function extractToClassNames({
40
48
  extractor,
41
49
  source,
42
50
  sourcePath,
43
51
  options,
44
52
  shouldPrintDebug,
45
- }: {
46
- extractor: Extractor
47
- source: string | Buffer
48
- sourcePath: string
49
- options: TamaguiOptions
50
- shouldPrintDebug: boolean | 'verbose'
51
- }): Promise<ExtractedResponse | null> {
53
+ }: ExtractToClassNamesProps): Promise<ExtractedResponse | null> {
52
54
  const tm = timer()
53
55
 
54
56
  if (typeof source !== 'string') {
@@ -98,6 +100,7 @@ export async function extractToClassNames({
98
100
  return tag
99
101
  },
100
102
  onExtractTag: ({
103
+ parserProps,
101
104
  attrs,
102
105
  node,
103
106
  attemptEval,
@@ -223,7 +226,7 @@ export async function extractToClassNames({
223
226
  }
224
227
  case 'ternary': {
225
228
  const mediaExtraction = extractMediaStyle(
226
- { ...options, sourcePath },
229
+ parserProps,
227
230
  attr.value,
228
231
  jsxPath,
229
232
  extractor.getTamagui()!,
@@ -383,7 +386,7 @@ export async function extractToClassNames({
383
386
  .trim()
384
387
 
385
388
  const result = generate(
386
- ast,
389
+ ast as any,
387
390
  {
388
391
  concise: false,
389
392
  filename: sourcePath,
@@ -70,7 +70,7 @@ export function getPropValueFromAttributes(
70
70
  return false
71
71
  }
72
72
  throw new Error(
73
- `unsupported spread of type "${attr.argument.type}": ${generate(attr).code}`
73
+ `unsupported spread of type "${attr.argument.type}": ${generate(attr as any).code}`
74
74
  )
75
75
  }
76
76
  return false