@tamagui/static 1.0.1-beta.192 → 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 -70
  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,13 +245,12 @@ 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
  }
201
252
 
202
253
  const proxiedTheme = proxyThemeVariables(firstTheme)
203
-
204
254
  type AccessListener = (key: string) => void
205
255
  const themeAccessListeners = new Set<AccessListener>()
206
256
  const defaultTheme = new Proxy(proxiedTheme, {
@@ -215,19 +265,7 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
215
265
  // @ts-ignore
216
266
  const body = fileOrPath.type === 'Program' ? fileOrPath.get('body') : fileOrPath.program.body
217
267
 
218
- /**
219
- * Step 1: Determine if importing any statically extractable components
220
- */
221
-
222
- const validComponents: { [key: string]: any } = Object.keys(components)
223
- // check if uppercase to avoid hitting media query proxy before init
224
- .filter((key) => key[0].toUpperCase() === key[0] && !!components[key]?.staticConfig)
225
- .reduce((obj, name) => {
226
- obj[name] = components[name]
227
- return obj
228
- }, {})
229
-
230
- if (Object.keys(validComponents).length === 0) {
268
+ if (Object.keys(components).length === 0) {
231
269
  console.warn(`Warning: Tamagui didn't find any valid components (DEBUG=tamagui for more)`)
232
270
  if (process.env.DEBUG === 'tamagui') {
233
271
  console.log(`components`, Object.keys(components), components)
@@ -235,27 +273,33 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
235
273
  }
236
274
 
237
275
  if (shouldPrintDebug === 'verbose') {
238
- logger.info(`validComponents ${Object.keys(validComponents).join(', ')}`)
276
+ logger.info(
277
+ `allLoadedComponent modules ${propsWithFileInfo.allLoadedComponents
278
+ .map((k) => k.moduleName)
279
+ .join(', ')}`
280
+ )
239
281
  }
240
282
 
241
283
  let doesUseValidImport = false
242
284
  let hasImportedTheme = false
243
285
 
286
+ const importDeclarations: t.ImportDeclaration[] = []
287
+
244
288
  for (const bodyPath of body) {
245
289
  if (bodyPath.type !== 'ImportDeclaration') continue
246
290
  const node = ('node' in bodyPath ? bodyPath.node : bodyPath) as t.ImportDeclaration
247
- const from = node.source.value
291
+ const moduleName = node.source.value
292
+
293
+ // if importing valid module
294
+ const valid = isValidImport(propsWithFileInfo, moduleName)
248
295
 
249
- // if importing styled()
250
- const valid = isValidImport(propsWithFileInfo, from)
296
+ if (valid) {
297
+ importDeclarations.push(node)
298
+ }
251
299
 
252
300
  if (extractStyledDefinitions) {
253
301
  if (valid) {
254
- if (
255
- node.specifiers.some((specifier) => {
256
- return specifier.local.name === 'styled'
257
- })
258
- ) {
302
+ if (node.specifiers.some((specifier) => specifier.local.name === 'styled')) {
259
303
  doesUseValidImport = true
260
304
  break
261
305
  }
@@ -264,10 +308,12 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
264
308
 
265
309
  if (valid) {
266
310
  const names = node.specifiers.map((specifier) => specifier.local.name)
267
- const isValidComponent = names.some((name) => !!(validComponents[name] || validHooks[name]))
311
+ const isValidComponent = names.some((name) =>
312
+ Boolean(isValidImport(propsWithFileInfo, moduleName, name) || validHooks[name])
313
+ )
268
314
  if (shouldPrintDebug === 'verbose') {
269
315
  logger.info(
270
- `import ${names.join(', ')} from ${from} isValidComponent ${isValidComponent}`
316
+ `import ${names.join(', ')} from ${moduleName} isValidComponent ${isValidComponent}`
271
317
  )
272
318
  }
273
319
  if (isValidComponent) {
@@ -278,13 +324,23 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
278
324
  }
279
325
 
280
326
  if (shouldPrintDebug) {
281
- logger.info(`source: ${sourcePath} doesUseValidImport ${doesUseValidImport}`)
327
+ logger.info(`file: ${sourcePath} ${JSON.stringify({ doesUseValidImport, hasImportedTheme })}`)
282
328
  }
283
329
 
284
330
  if (!doesUseValidImport) {
285
331
  return null
286
332
  }
287
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
+
288
344
  tm.mark('import-check', !!shouldPrintDebug)
289
345
 
290
346
  let couldntParse = false
@@ -293,10 +349,14 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
293
349
  // only keeping a cache around per-file, reset it if it changes
294
350
  const bindingCache: Record<string, string | null> = {}
295
351
 
296
- const callTraverse = (a: Visitor<{}>) => {
352
+ const callTraverse = (a: TraverseOptions<any>) => {
297
353
  return fileOrPath.type === 'File' ? traverse(fileOrPath, a) : fileOrPath.traverse(a)
298
354
  }
299
355
 
356
+ const shouldDisableExtraction =
357
+ disableExtraction === true ||
358
+ (Array.isArray(disableExtraction) && disableExtraction.includes(sourcePath))
359
+
300
360
  /**
301
361
  * Step 2: Statically extract from JSX < /> nodes
302
362
  */
@@ -311,6 +371,7 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
311
371
  }
312
372
 
313
373
  callTraverse({
374
+ // @ts-ignore
314
375
  Program: {
315
376
  enter(path) {
316
377
  programPath = path
@@ -319,7 +380,7 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
319
380
 
320
381
  // styled() calls
321
382
  CallExpression(path) {
322
- if (disable || disableExtraction || extractStyledDefinitions === false) {
383
+ if (disable || shouldDisableExtraction || extractStyledDefinitions === false) {
323
384
  return
324
385
  }
325
386
 
@@ -331,20 +392,31 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
331
392
  t.isVariableDeclarator(path.parent) && t.isIdentifier(path.parent.id)
332
393
  ? path.parent.id.name
333
394
  : 'unknown'
395
+
334
396
  const definition = path.node.arguments[1]
335
397
 
336
398
  if (!name || !definition || !t.isObjectExpression(definition)) {
337
399
  return
338
400
  }
339
401
 
340
- let Component = validComponents[name] as { staticConfig: StaticConfigParsed } | undefined
402
+ let Component = getValidImportedComponent(name)
341
403
 
342
404
  if (!Component) {
343
- if (disableExtractFoundComponents) {
405
+ if (disableExtractFoundComponents === true) {
406
+ return
407
+ }
408
+ if (
409
+ Array.isArray(disableExtractFoundComponents) &&
410
+ disableExtractFoundComponents.includes(name)
411
+ ) {
344
412
  return
345
413
  }
346
414
 
347
415
  try {
416
+ if (shouldPrintDebug) {
417
+ logger.info(`Unknown component ${name}, attempting dynamic load: ${sourcePath}`)
418
+ }
419
+
348
420
  const out = loadTamaguiSync({
349
421
  // TODO would extract more, is NO-OP for now..
350
422
  forceExports: true,
@@ -352,16 +424,22 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
352
424
  components: [sourcePath],
353
425
  })
354
426
 
355
- if (out.components?.[name]) {
356
- // add new components
357
- // TODO dont Clobber, do by file
358
- Object.assign(validComponents, out.components)
427
+ if (!out?.components) {
428
+ if (shouldPrintDebug) {
429
+ logger.info(`Couldn't load, got ${out}`)
430
+ }
431
+ return
359
432
  }
360
433
 
361
- Component = validComponents[name]
434
+ propsWithFileInfo.allLoadedComponents = [
435
+ ...propsWithFileInfo.allLoadedComponents,
436
+ ...out.components,
437
+ ]
438
+
439
+ Component = out.components.flatMap((x) => x.nameToInfo[name] ?? [])[0]
362
440
 
363
441
  if (shouldPrintDebug) {
364
- logger.info([`Loaded`, Object.keys(out.components).join(', '), !!Component].join(' '))
442
+ logger.info([`Tamagui Loaded`, JSON.stringify(out.components), !!Component].join(' '))
365
443
  }
366
444
  } catch (err: any) {
367
445
  if (shouldPrintDebug) {
@@ -411,7 +489,7 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
411
489
  const attemptEval = !evaluateVars
412
490
  ? evaluateAstNode
413
491
  : createEvaluator({
414
- props: options,
492
+ props: propsWithFileInfo,
415
493
  staticNamespace,
416
494
  sourcePath,
417
495
  shouldPrintDebug,
@@ -492,6 +570,10 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
492
570
  },
493
571
 
494
572
  JSXElement(traversePath) {
573
+ if (shouldDisableExtraction) {
574
+ return
575
+ }
576
+
495
577
  tm.mark('jsx-element', !!shouldPrintDebug)
496
578
 
497
579
  const node = traversePath.node.openingElement
@@ -506,6 +588,7 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
506
588
 
507
589
  // validate its a proper import from tamagui (or internally inside tamagui)
508
590
  const binding = traversePath.scope.getBinding(node.name.name)
591
+ let modulePath = ''
509
592
 
510
593
  if (binding) {
511
594
  if (!t.isImportDeclaration(binding.path.parent)) {
@@ -514,24 +597,16 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
514
597
  }
515
598
  return
516
599
  }
517
- const source = binding.path.parent.source
518
- if (!isValidImport(propsWithFileInfo, source.value)) {
600
+ modulePath = binding.path.parent.source.value
601
+ if (!isValidImport(propsWithFileInfo, modulePath, binding.identifier.name)) {
519
602
  if (shouldPrintDebug) {
520
- logger.info(` - Binding not internal import or from components ${source.value}`)
521
- }
522
- return
523
- }
524
- if (!validComponents[binding.identifier.name]) {
525
- if (shouldPrintDebug) {
526
- logger.info(
527
- ` - Binding not valid component (binding.identifier.name) ${binding.identifier.name}`
528
- )
603
+ logger.info(` - Binding not internal import or from components ${modulePath}`)
529
604
  }
530
605
  return
531
606
  }
532
607
  }
533
608
 
534
- const component = validComponents[node.name.name] as { staticConfig?: StaticConfigParsed }
609
+ const component = getValidComponent(propsWithFileInfo, modulePath, node.name.name)
535
610
  if (!component || !component.staticConfig) {
536
611
  if (shouldPrintDebug) {
537
612
  logger.info(` - No Tamagui conf on this: ${node.name.name}`)
@@ -557,7 +632,8 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
557
632
  .filter(
558
633
  (n) => t.isJSXAttribute(n) && t.isJSXIdentifier(n.name) && n.name.name === 'debug'
559
634
  )
560
- .map((n) => {
635
+ // @ts-ignore
636
+ .map((n: t.JSXAttribute) => {
561
637
  if (n.value === null) return true
562
638
  if (t.isStringLiteral(n.value)) return n.value.value as 'verbose'
563
639
  return false
@@ -658,7 +734,7 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
658
734
  const attemptEval = !evaluateVars
659
735
  ? evaluateAstNode
660
736
  : createEvaluator({
661
- props: options,
737
+ props: propsWithFileInfo,
662
738
  staticNamespace,
663
739
  sourcePath,
664
740
  traversePath,
@@ -1405,7 +1481,11 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
1405
1481
  traversePath.node.children.every((x) => x.type === 'JSXText')))
1406
1482
 
1407
1483
  const themeVal = inlined.get('theme')
1408
- 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
+ }
1409
1489
 
1410
1490
  for (const [key] of [...inlined]) {
1411
1491
  const isStaticObjectVariant = staticConfig.variants?.[key] && variantValues.has(key)
@@ -1416,13 +1496,14 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
1416
1496
 
1417
1497
  const canFlattenProps = inlined.size === 0
1418
1498
 
1419
- let shouldFlatten =
1499
+ let shouldFlatten = Boolean(
1420
1500
  flatNode &&
1421
- !shouldDeopt &&
1422
- canFlattenProps &&
1423
- !hasSpread &&
1424
- staticConfig.neverFlatten !== true &&
1425
- (staticConfig.neverFlatten === 'jsx' ? hasOnlyStringChildren : true)
1501
+ !shouldDeopt &&
1502
+ canFlattenProps &&
1503
+ !hasSpread &&
1504
+ staticConfig.neverFlatten !== true &&
1505
+ (staticConfig.neverFlatten === 'jsx' ? hasOnlyStringChildren : true)
1506
+ )
1426
1507
 
1427
1508
  const shouldWrapTheme = shouldFlatten && themeVal
1428
1509
  const usedThemeKeys = new Set<string>()
@@ -1432,7 +1513,7 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
1432
1513
  themeAccessListeners.add((key) => {
1433
1514
  shouldFlatten = false
1434
1515
  usedThemeKeys.add(key)
1435
- if (shouldPrintDebug) {
1516
+ if (shouldPrintDebug === 'verbose') {
1436
1517
  logger.info([' ! accessing theme key, avoid flatten', key].join(' '))
1437
1518
  }
1438
1519
  })
@@ -1517,6 +1598,9 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
1517
1598
  }
1518
1599
 
1519
1600
  if (shouldDeopt) {
1601
+ if (shouldPrintDebug) {
1602
+ logger.info(`Deopting`)
1603
+ }
1520
1604
  node.attributes = ogAttributes
1521
1605
  return
1522
1606
  }
@@ -1852,6 +1936,7 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
1852
1936
  },
1853
1937
  undefined,
1854
1938
  undefined,
1939
+ undefined,
1855
1940
  debugPropValue
1856
1941
  )
1857
1942
 
@@ -1882,6 +1967,15 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
1882
1967
  throw new Error(`Impossible, no styles`)
1883
1968
  }
1884
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
+
1885
1979
  let getStyleError: any = null
1886
1980
 
1887
1981
  // fix up ternaries, combine final style values
@@ -1925,7 +2019,7 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
1925
2019
  if (getStyleError) {
1926
2020
  logger.info([' ⚠️ postprocessing error, deopt', getStyleError].join(' '))
1927
2021
  node.attributes = ogAttributes
1928
- return node
2022
+ return null
1929
2023
  }
1930
2024
 
1931
2025
  // final lazy extra loop:
@@ -1996,9 +2090,11 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
1996
2090
  if (shouldPrintDebug) {
1997
2091
  logger.info([' [✅] flattening', originalNodeName, flatNode].join(' '))
1998
2092
  }
2093
+ // @ts-ignore
1999
2094
  node.name.name = flatNode
2000
2095
  res.flattened++
2001
2096
  if (closingElement) {
2097
+ // @ts-ignore
2002
2098
  closingElement.name.name = flatNode
2003
2099
  }
2004
2100
  }
@@ -2010,6 +2106,7 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
2010
2106
  }
2011
2107
 
2012
2108
  onExtractTag({
2109
+ parserProps: propsWithFileInfo,
2013
2110
  attrs,
2014
2111
  node,
2015
2112
  lineNumbers,
@@ -2018,7 +2115,7 @@ export function createExtractor({ logger = console }: ExtractorOptions = { logge
2018
2115
  jsxPath: traversePath,
2019
2116
  originalNodeName,
2020
2117
  isFlattened: shouldFlatten,
2021
- programPath,
2118
+ programPath: programPath!,
2022
2119
  completeProps,
2023
2120
  staticConfig,
2024
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