@hanzogui/static 2.0.0
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 +1 -0
- package/dist/check-dep-versions.cjs +267 -0
- package/dist/checkDeps.cjs +200 -0
- package/dist/constants.cjs +49 -0
- package/dist/exports.cjs +44 -0
- package/dist/extractor/accessSafe.cjs +46 -0
- package/dist/extractor/babelParse.cjs +54 -0
- package/dist/extractor/buildClassName.cjs +62 -0
- package/dist/extractor/bundle.cjs +185 -0
- package/dist/extractor/bundleConfig.cjs +513 -0
- package/dist/extractor/concatClassName.cjs +80 -0
- package/dist/extractor/createEvaluator.cjs +75 -0
- package/dist/extractor/createExtractor.cjs +1150 -0
- package/dist/extractor/createLogger.cjs +45 -0
- package/dist/extractor/detectModuleFormat.cjs +49 -0
- package/dist/extractor/ensureImportingConcat.cjs +48 -0
- package/dist/extractor/errors.cjs +26 -0
- package/dist/extractor/esbuildAliasPlugin.cjs +44 -0
- package/dist/extractor/esbuildTsconfigPaths.cjs +86 -0
- package/dist/extractor/evaluateAstNode.cjs +83 -0
- package/dist/extractor/extractHelpers.cjs +119 -0
- package/dist/extractor/extractMediaStyle.cjs +128 -0
- package/dist/extractor/extractToClassNames.cjs +321 -0
- package/dist/extractor/extractToNative.cjs +266 -0
- package/dist/extractor/findTopmostFunction.cjs +34 -0
- package/dist/extractor/generatedUid.cjs +47 -0
- package/dist/extractor/getGuiConfigPathFromOptionsConfig.cjs +35 -0
- package/dist/extractor/getPrefixLogs.cjs +29 -0
- package/dist/extractor/getPropValueFromAttributes.cjs +67 -0
- package/dist/extractor/getSourceModule.cjs +64 -0
- package/dist/extractor/getStaticBindingsForScope.cjs +150 -0
- package/dist/extractor/hoistClassNames.cjs +62 -0
- package/dist/extractor/literalToAst.cjs +84 -0
- package/dist/extractor/loadFile.cjs +11 -0
- package/dist/extractor/loadGui.cjs +322 -0
- package/dist/extractor/logLines.cjs +35 -0
- package/dist/extractor/normalizeTernaries.cjs +73 -0
- package/dist/extractor/propsToFontFamilyCache.cjs +38 -0
- package/dist/extractor/regenerateConfig.cjs +150 -0
- package/dist/extractor/removeUnusedHooks.cjs +76 -0
- package/dist/extractor/timer.cjs +43 -0
- package/dist/extractor/validHTMLAttributes.cjs +77 -0
- package/dist/extractor/watchGuiConfig.cjs +58 -0
- package/dist/getPragmaOptions.cjs +58 -0
- package/dist/helpers/memoize.cjs +37 -0
- package/dist/helpers/requireGuiCore.cjs +33 -0
- package/dist/index.cjs +40 -0
- package/dist/registerRequire.cjs +115 -0
- package/dist/server.cjs +75 -0
- package/dist/setup.cjs +0 -0
- package/dist/types.cjs +16 -0
- package/dist/worker.cjs +89 -0
- package/package.json +101 -0
- package/src/check-dep-versions.ts +738 -0
- package/src/checkDeps.ts +371 -0
- package/src/constants.ts +14 -0
- package/src/exports.ts +15 -0
- package/src/extractor/accessSafe.ts +22 -0
- package/src/extractor/babelParse.ts +37 -0
- package/src/extractor/buildClassName.ts +76 -0
- package/src/extractor/bundle.ts +277 -0
- package/src/extractor/bundleConfig.ts +958 -0
- package/src/extractor/concatClassName.ts +105 -0
- package/src/extractor/createEvaluator.ts +82 -0
- package/src/extractor/createExtractor.ts +2665 -0
- package/src/extractor/createLogger.ts +41 -0
- package/src/extractor/detectModuleFormat.ts +42 -0
- package/src/extractor/ensureImportingConcat.ts +36 -0
- package/src/extractor/errors.ts +1 -0
- package/src/extractor/esbuildAliasPlugin.ts +40 -0
- package/src/extractor/esbuildTsconfigPaths.ts +103 -0
- package/src/extractor/evaluateAstNode.ts +136 -0
- package/src/extractor/extractHelpers.ts +211 -0
- package/src/extractor/extractMediaStyle.ts +194 -0
- package/src/extractor/extractToClassNames.ts +631 -0
- package/src/extractor/extractToNative.ts +463 -0
- package/src/extractor/findTopmostFunction.ts +24 -0
- package/src/extractor/generatedUid.ts +41 -0
- package/src/extractor/getGuiConfigPathFromOptionsConfig.ts +24 -0
- package/src/extractor/getPrefixLogs.ts +9 -0
- package/src/extractor/getPropValueFromAttributes.ts +95 -0
- package/src/extractor/getSourceModule.ts +96 -0
- package/src/extractor/getStaticBindingsForScope.ts +237 -0
- package/src/extractor/hoistClassNames.ts +52 -0
- package/src/extractor/literalToAst.ts +85 -0
- package/src/extractor/loadFile.ts +17 -0
- package/src/extractor/loadGui.ts +487 -0
- package/src/extractor/logLines.ts +16 -0
- package/src/extractor/normalizeTernaries.ts +75 -0
- package/src/extractor/propsToFontFamilyCache.ts +18 -0
- package/src/extractor/regenerateConfig.ts +186 -0
- package/src/extractor/removeUnusedHooks.ts +83 -0
- package/src/extractor/timer.ts +25 -0
- package/src/extractor/validHTMLAttributes.ts +52 -0
- package/src/extractor/watchGuiConfig.ts +57 -0
- package/src/getPragmaOptions.ts +57 -0
- package/src/helpers/memoize.ts +24 -0
- package/src/helpers/requireGuiCore.ts +28 -0
- package/src/index.ts +4 -0
- package/src/registerRequire.ts +236 -0
- package/src/server.ts +43 -0
- package/src/setup.ts +0 -0
- package/src/types.ts +109 -0
- package/src/worker.ts +142 -0
- package/types/check-dep-versions.d.ts +37 -0
- package/types/check-dep-versions.d.ts.map +1 -0
- package/types/checkDeps.d.ts +19 -0
- package/types/checkDeps.d.ts.map +1 -0
- package/types/constants.d.ts +6 -0
- package/types/constants.d.ts.map +1 -0
- package/types/exports.d.ts +16 -0
- package/types/exports.d.ts.map +1 -0
- package/types/extractor/accessSafe.d.ts +3 -0
- package/types/extractor/accessSafe.d.ts.map +1 -0
- package/types/extractor/babelParse.d.ts +5 -0
- package/types/extractor/babelParse.d.ts.map +1 -0
- package/types/extractor/buildClassName.d.ts +7 -0
- package/types/extractor/buildClassName.d.ts.map +1 -0
- package/types/extractor/bundle.d.ts +121 -0
- package/types/extractor/bundle.d.ts.map +1 -0
- package/types/extractor/bundleConfig.d.ts +49 -0
- package/types/extractor/bundleConfig.d.ts.map +1 -0
- package/types/extractor/concatClassName.d.ts +8 -0
- package/types/extractor/concatClassName.d.ts.map +1 -0
- package/types/extractor/createEvaluator.d.ts +12 -0
- package/types/extractor/createEvaluator.d.ts.map +1 -0
- package/types/extractor/createExtractor.d.ts +32 -0
- package/types/extractor/createExtractor.d.ts.map +1 -0
- package/types/extractor/createLogger.d.ts +3 -0
- package/types/extractor/createLogger.d.ts.map +1 -0
- package/types/extractor/detectModuleFormat.d.ts +5 -0
- package/types/extractor/detectModuleFormat.d.ts.map +1 -0
- package/types/extractor/ensureImportingConcat.d.ts +4 -0
- package/types/extractor/ensureImportingConcat.d.ts.map +1 -0
- package/types/extractor/errors.d.ts +3 -0
- package/types/extractor/errors.d.ts.map +1 -0
- package/types/extractor/esbuildAliasPlugin.d.ts +18 -0
- package/types/extractor/esbuildAliasPlugin.d.ts.map +1 -0
- package/types/extractor/esbuildTsconfigPaths.d.ts +11 -0
- package/types/extractor/esbuildTsconfigPaths.d.ts.map +1 -0
- package/types/extractor/evaluateAstNode.d.ts +3 -0
- package/types/extractor/evaluateAstNode.d.ts.map +1 -0
- package/types/extractor/extractHelpers.d.ts +28 -0
- package/types/extractor/extractHelpers.d.ts.map +1 -0
- package/types/extractor/extractMediaStyle.d.ts +11 -0
- package/types/extractor/extractMediaStyle.d.ts.map +1 -0
- package/types/extractor/extractToClassNames.d.ts +25 -0
- package/types/extractor/extractToClassNames.d.ts.map +1 -0
- package/types/extractor/extractToNative.d.ts +13 -0
- package/types/extractor/extractToNative.d.ts.map +1 -0
- package/types/extractor/findTopmostFunction.d.ts +4 -0
- package/types/extractor/findTopmostFunction.d.ts.map +1 -0
- package/types/extractor/generatedUid.d.ts +5 -0
- package/types/extractor/generatedUid.d.ts.map +1 -0
- package/types/extractor/getGuiConfigPathFromOptionsConfig.d.ts +3 -0
- package/types/extractor/getGuiConfigPathFromOptionsConfig.d.ts.map +1 -0
- package/types/extractor/getPrefixLogs.d.ts +3 -0
- package/types/extractor/getPrefixLogs.d.ts.map +1 -0
- package/types/extractor/getPropValueFromAttributes.d.ts +19 -0
- package/types/extractor/getPropValueFromAttributes.d.ts.map +1 -0
- package/types/extractor/getSourceModule.d.ts +16 -0
- package/types/extractor/getSourceModule.d.ts.map +1 -0
- package/types/extractor/getStaticBindingsForScope.d.ts +5 -0
- package/types/extractor/getStaticBindingsForScope.d.ts.map +1 -0
- package/types/extractor/hoistClassNames.d.ts +6 -0
- package/types/extractor/hoistClassNames.d.ts.map +1 -0
- package/types/extractor/literalToAst.d.ts +4 -0
- package/types/extractor/literalToAst.d.ts.map +1 -0
- package/types/extractor/loadFile.d.ts +1 -0
- package/types/extractor/loadFile.d.ts.map +1 -0
- package/types/extractor/loadGui.d.ts +22 -0
- package/types/extractor/loadGui.d.ts.map +1 -0
- package/types/extractor/logLines.d.ts +2 -0
- package/types/extractor/logLines.d.ts.map +1 -0
- package/types/extractor/normalizeTernaries.d.ts +3 -0
- package/types/extractor/normalizeTernaries.d.ts.map +1 -0
- package/types/extractor/propsToFontFamilyCache.d.ts +4 -0
- package/types/extractor/propsToFontFamilyCache.d.ts.map +1 -0
- package/types/extractor/regenerateConfig.d.ts +9 -0
- package/types/extractor/regenerateConfig.d.ts.map +1 -0
- package/types/extractor/removeUnusedHooks.d.ts +3 -0
- package/types/extractor/removeUnusedHooks.d.ts.map +1 -0
- package/types/extractor/timer.d.ts +5 -0
- package/types/extractor/timer.d.ts.map +1 -0
- package/types/extractor/validHTMLAttributes.d.ts +52 -0
- package/types/extractor/validHTMLAttributes.d.ts.map +1 -0
- package/types/extractor/watchGuiConfig.d.ts +5 -0
- package/types/extractor/watchGuiConfig.d.ts.map +1 -0
- package/types/getPragmaOptions.d.ts +8 -0
- package/types/getPragmaOptions.d.ts.map +1 -0
- package/types/helpers/memoize.d.ts +8 -0
- package/types/helpers/memoize.d.ts.map +1 -0
- package/types/helpers/requireGuiCore.d.ts +3 -0
- package/types/helpers/requireGuiCore.d.ts.map +1 -0
- package/types/index.d.ts +4 -0
- package/types/index.d.ts.map +1 -0
- package/types/registerRequire.d.ts +10 -0
- package/types/registerRequire.d.ts.map +1 -0
- package/types/server.d.ts +3 -0
- package/types/server.d.ts.map +1 -0
- package/types/setup.d.ts +1 -0
- package/types/setup.d.ts.map +1 -0
- package/types/types.d.ts +92 -0
- package/types/types.d.ts.map +1 -0
- package/types/worker.d.ts +46 -0
- package/types/worker.d.ts.map +1 -0
|
@@ -0,0 +1,631 @@
|
|
|
1
|
+
import generate from '@babel/generator'
|
|
2
|
+
import type { NodePath } from '@babel/traverse'
|
|
3
|
+
import * as t from '@babel/types'
|
|
4
|
+
import { mergeProps, StyleObjectIdentifier, StyleObjectRules } from '@hanzogui/web'
|
|
5
|
+
import * as path from 'node:path'
|
|
6
|
+
import * as util from 'node:util'
|
|
7
|
+
import { requireGuiCore } from '../helpers/requireGuiCore'
|
|
8
|
+
import type { StyleObject, GuiOptions, Ternary } from '../types'
|
|
9
|
+
import { babelParse } from './babelParse'
|
|
10
|
+
import type { Extractor } from './createExtractor'
|
|
11
|
+
import { createLogger } from './createLogger'
|
|
12
|
+
import { extractMediaStyle } from './extractMediaStyle'
|
|
13
|
+
import { normalizeTernaries } from './normalizeTernaries'
|
|
14
|
+
import {
|
|
15
|
+
forwardFontFamilyName,
|
|
16
|
+
getFontFamilyNameFromProps,
|
|
17
|
+
} from './propsToFontFamilyCache'
|
|
18
|
+
import { timer } from './timer'
|
|
19
|
+
import { BailOptimizationError } from './errors'
|
|
20
|
+
import { concatClassName } from './concatClassName'
|
|
21
|
+
|
|
22
|
+
export type ExtractedResponse = {
|
|
23
|
+
js: string | Buffer
|
|
24
|
+
styles: string
|
|
25
|
+
stylesPath?: string
|
|
26
|
+
ast: t.File
|
|
27
|
+
map: any
|
|
28
|
+
stats: {
|
|
29
|
+
styled: number
|
|
30
|
+
flattened: number
|
|
31
|
+
optimized: number
|
|
32
|
+
found: number
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export type ExtractToClassNamesProps = {
|
|
37
|
+
extractor: Extractor
|
|
38
|
+
source: string | Buffer
|
|
39
|
+
sourcePath?: string
|
|
40
|
+
options: GuiOptions
|
|
41
|
+
shouldPrintDebug: boolean | 'verbose'
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// we only expand into ternaries or plain attr, all style is turned into a always-true ternary
|
|
45
|
+
// this lets us more easily combine everything easily
|
|
46
|
+
// all ternaries in this array ONLY have consequent, they are normalized
|
|
47
|
+
const remove = () => {} // we dont remove after this step
|
|
48
|
+
const spaceString = t.stringLiteral(' ')
|
|
49
|
+
|
|
50
|
+
export async function extractToClassNames({
|
|
51
|
+
extractor,
|
|
52
|
+
source,
|
|
53
|
+
sourcePath = '',
|
|
54
|
+
options,
|
|
55
|
+
shouldPrintDebug,
|
|
56
|
+
}: ExtractToClassNamesProps): Promise<ExtractedResponse | null> {
|
|
57
|
+
const tm = timer()
|
|
58
|
+
const { getCSSStylesAtomic, createMediaStyle } = requireGuiCore('web')
|
|
59
|
+
|
|
60
|
+
if (sourcePath.includes('node_modules')) {
|
|
61
|
+
return null
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (shouldPrintDebug) {
|
|
65
|
+
console.warn(`--- ${sourcePath} --- \n\n`)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (typeof source !== 'string') {
|
|
69
|
+
throw new Error('`source` must be a string of javascript')
|
|
70
|
+
}
|
|
71
|
+
if (!path.isAbsolute(sourcePath)) {
|
|
72
|
+
throw new Error(
|
|
73
|
+
'`sourcePath` must be an absolute path to a .js file, got: ' + sourcePath
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (!/.[tj]sx?$/i.test(sourcePath || '')) {
|
|
78
|
+
console.warn(`${sourcePath.slice(0, 100)} - bad filename.`)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (!options.disableExtraction && !options['_disableLoadGui']) {
|
|
82
|
+
// dont include loading in timing of parsing (one time cost)
|
|
83
|
+
await extractor.loadGui(options)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const printLog = createLogger(sourcePath, options)
|
|
87
|
+
|
|
88
|
+
// Using a map for (officially supported) guaranteed insertion order
|
|
89
|
+
let ast: t.File
|
|
90
|
+
|
|
91
|
+
try {
|
|
92
|
+
ast = babelParse(source, sourcePath)
|
|
93
|
+
} catch (err) {
|
|
94
|
+
console.error('babel parse error:', sourcePath.slice(0, 100))
|
|
95
|
+
throw err
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
tm.mark(`babel-parse`, shouldPrintDebug === 'verbose')
|
|
99
|
+
|
|
100
|
+
const cssMap = new Map<string, { css: string; commentTexts: string[] }>()
|
|
101
|
+
const guiConfig = extractor.getGui()!
|
|
102
|
+
|
|
103
|
+
const res = await extractor.parse(ast, {
|
|
104
|
+
shouldPrintDebug,
|
|
105
|
+
...options,
|
|
106
|
+
platform: 'web',
|
|
107
|
+
sourcePath,
|
|
108
|
+
extractStyledDefinitions: true,
|
|
109
|
+
onStyledDefinitionRule(identifier, rules) {
|
|
110
|
+
const css = rules.join('\n')
|
|
111
|
+
if (shouldPrintDebug) {
|
|
112
|
+
console.info(`adding styled() rule: .${identifier} ${css}`)
|
|
113
|
+
}
|
|
114
|
+
cssMap.set(`.${identifier}`, { css, commentTexts: [] })
|
|
115
|
+
},
|
|
116
|
+
getFlattenedNode: ({ tag }) => {
|
|
117
|
+
return tag
|
|
118
|
+
},
|
|
119
|
+
onExtractTag: ({
|
|
120
|
+
parserProps,
|
|
121
|
+
attrs,
|
|
122
|
+
node,
|
|
123
|
+
attemptEval,
|
|
124
|
+
jsxPath,
|
|
125
|
+
originalNodeName,
|
|
126
|
+
filePath,
|
|
127
|
+
lineNumbers,
|
|
128
|
+
staticConfig,
|
|
129
|
+
}) => {
|
|
130
|
+
// bail out of views that don't accept className (falls back to runtime + style={})
|
|
131
|
+
if (staticConfig.acceptsClassName === false) {
|
|
132
|
+
throw new BailOptimizationError()
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// re-worked how we do this
|
|
136
|
+
// merging ternaries on top of base styles is not simple, because we need to ensure the final
|
|
137
|
+
// className has no duplicate style props and selector order is preserved
|
|
138
|
+
// before we tried to be smart and build a big binary expression
|
|
139
|
+
// instead, what we'll do now is pre-calculate the entire className for every possible path
|
|
140
|
+
// for super complex components that means we *will* output a lot of bigger classNames
|
|
141
|
+
// but its so much simpler than trying to implement a multi-stage solver here
|
|
142
|
+
// and in the end its just strings that gzip very well
|
|
143
|
+
// its also much easier to intuit/debug for end users and ourselves
|
|
144
|
+
|
|
145
|
+
// example:
|
|
146
|
+
// a ? 'a' : 'b'
|
|
147
|
+
// b ? 'c' : 'd'
|
|
148
|
+
// we want:
|
|
149
|
+
// a && b ? 'a c' : ''
|
|
150
|
+
// !a && b ? 'b c' : ''
|
|
151
|
+
// a && !b ? 'a d' : ''
|
|
152
|
+
// !a && !b ? 'b d' : ''
|
|
153
|
+
|
|
154
|
+
// we also simplified the compiler to only handle views that can be fully flattened
|
|
155
|
+
// this means we don't need to account for strange in-between spreads, so we can merge things
|
|
156
|
+
// fairly simply. first, we just merge forward all the non-ternary styles into ternaries.
|
|
157
|
+
|
|
158
|
+
// save for the end
|
|
159
|
+
const finalAttrs: t.JSXAttribute[] = []
|
|
160
|
+
|
|
161
|
+
let mergeForwardBaseStyle: object | null = null
|
|
162
|
+
let attrClassName: t.Expression | null = null
|
|
163
|
+
let baseFontFamily = ''
|
|
164
|
+
let mediaStylesSeen = 1
|
|
165
|
+
|
|
166
|
+
const comment = util.format(
|
|
167
|
+
'/* %s:%s (%s) */',
|
|
168
|
+
filePath,
|
|
169
|
+
lineNumbers,
|
|
170
|
+
originalNodeName
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
function addStyle(style: StyleObject) {
|
|
174
|
+
const identifier = style[StyleObjectIdentifier]
|
|
175
|
+
const rules = style[StyleObjectRules]
|
|
176
|
+
const selector = `.${identifier}`
|
|
177
|
+
if (cssMap.has(selector)) {
|
|
178
|
+
const val = cssMap.get(selector)!
|
|
179
|
+
val.commentTexts.push(comment)
|
|
180
|
+
} else if (rules.length) {
|
|
181
|
+
cssMap.set(selector, {
|
|
182
|
+
css: rules.join('\n'),
|
|
183
|
+
commentTexts: [comment],
|
|
184
|
+
})
|
|
185
|
+
}
|
|
186
|
+
return identifier
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function addStyles(style: object) {
|
|
190
|
+
const cssStyles = getCSSStylesAtomic(style as any)
|
|
191
|
+
const classNames: string[] = []
|
|
192
|
+
|
|
193
|
+
for (const style of cssStyles) {
|
|
194
|
+
const property = style[0]
|
|
195
|
+
const mediaName = property.slice(1)
|
|
196
|
+
|
|
197
|
+
// $group- styles must bail out entirely - they need runtime handling because
|
|
198
|
+
// group changes can affect children that may be animated and need hard values.
|
|
199
|
+
// In the future, CSS animation drivers could potentially optimize this.
|
|
200
|
+
if (mediaName.startsWith('group-')) {
|
|
201
|
+
throw new BailOptimizationError()
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Check for theme/platform media queries (e.g., $theme-dark, $platform-web)
|
|
205
|
+
const mediaTypeMatch = mediaName.match(/^(theme|platform)-/)
|
|
206
|
+
if (mediaTypeMatch) {
|
|
207
|
+
const mediaType = mediaTypeMatch[1] as 'theme' | 'platform'
|
|
208
|
+
const mediaStyle = createMediaStyle(
|
|
209
|
+
style,
|
|
210
|
+
mediaName,
|
|
211
|
+
extractor.getGui()!.media,
|
|
212
|
+
mediaType,
|
|
213
|
+
false,
|
|
214
|
+
mediaStylesSeen
|
|
215
|
+
)
|
|
216
|
+
const identifier = addStyle(mediaStyle)
|
|
217
|
+
classNames.push(identifier)
|
|
218
|
+
continue
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (mediaName in guiConfig.media) {
|
|
222
|
+
const mediaStyle = createMediaStyle(
|
|
223
|
+
style,
|
|
224
|
+
mediaName,
|
|
225
|
+
extractor.getGui()!.media,
|
|
226
|
+
true,
|
|
227
|
+
false,
|
|
228
|
+
mediaStylesSeen
|
|
229
|
+
)
|
|
230
|
+
const identifier = addStyle(mediaStyle)
|
|
231
|
+
classNames.push(identifier)
|
|
232
|
+
continue
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const identifier = addStyle(style)
|
|
236
|
+
classNames.push(identifier)
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return classNames
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const onlyTernaries: Ternary[] = attrs.flatMap((attr) => {
|
|
243
|
+
if (attr.type === 'attr') {
|
|
244
|
+
const value = attr.value
|
|
245
|
+
|
|
246
|
+
if (t.isJSXSpreadAttribute(value)) {
|
|
247
|
+
// we only handle flattened stuff now so skip this
|
|
248
|
+
console.error(`Should never happen`)
|
|
249
|
+
return []
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (value.name.name === 'className') {
|
|
253
|
+
let inner: any = value.value
|
|
254
|
+
if (t.isJSXExpressionContainer(inner)) {
|
|
255
|
+
inner = inner.expression
|
|
256
|
+
}
|
|
257
|
+
try {
|
|
258
|
+
const evaluatedValue = inner ? attemptEval(inner) : null
|
|
259
|
+
if (typeof evaluatedValue === 'string') {
|
|
260
|
+
attrClassName = t.stringLiteral(evaluatedValue)
|
|
261
|
+
}
|
|
262
|
+
} catch (e) {
|
|
263
|
+
if (inner) {
|
|
264
|
+
attrClassName ||= inner
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
return []
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
finalAttrs.push(value)
|
|
271
|
+
return []
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (attr.type === 'style') {
|
|
275
|
+
mergeForwardBaseStyle = mergeProps(mergeForwardBaseStyle || {}, attr.value)
|
|
276
|
+
baseFontFamily = getFontFamilyNameFromProps(attr.value) || ''
|
|
277
|
+
return []
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
let ternary = attr.value
|
|
281
|
+
|
|
282
|
+
if (ternary.inlineMediaQuery) {
|
|
283
|
+
const mediaExtraction = extractMediaStyle(
|
|
284
|
+
parserProps,
|
|
285
|
+
attr.value,
|
|
286
|
+
jsxPath,
|
|
287
|
+
extractor.getGui()!,
|
|
288
|
+
sourcePath || '',
|
|
289
|
+
mediaStylesSeen++,
|
|
290
|
+
shouldPrintDebug
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
if (mediaExtraction) {
|
|
294
|
+
if (mediaExtraction.mediaStyles) {
|
|
295
|
+
mergeForwardBaseStyle = mergeProps(mergeForwardBaseStyle || {}, {
|
|
296
|
+
[`$${ternary.inlineMediaQuery}`]: attr.value.consequent!,
|
|
297
|
+
})
|
|
298
|
+
}
|
|
299
|
+
if (mediaExtraction.ternaryWithoutMedia) {
|
|
300
|
+
ternary = mediaExtraction.ternaryWithoutMedia
|
|
301
|
+
} else {
|
|
302
|
+
return []
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
let mergedAlternate
|
|
308
|
+
let mergedConsequent
|
|
309
|
+
|
|
310
|
+
if (ternary.alternate && Object.keys(ternary.alternate).length) {
|
|
311
|
+
mergedAlternate = mergeProps(
|
|
312
|
+
mergeForwardBaseStyle || {},
|
|
313
|
+
ternary.alternate || {}
|
|
314
|
+
)
|
|
315
|
+
forwardFontFamilyName(ternary.alternate, mergedAlternate, baseFontFamily)
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
if (ternary.consequent && Object.keys(ternary.consequent).length) {
|
|
319
|
+
mergedConsequent = mergeProps(
|
|
320
|
+
mergeForwardBaseStyle || {},
|
|
321
|
+
ternary.consequent || {}
|
|
322
|
+
)
|
|
323
|
+
forwardFontFamilyName(ternary.consequent, mergedConsequent, baseFontFamily)
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// merge the base style forward into both sides
|
|
327
|
+
return {
|
|
328
|
+
...ternary,
|
|
329
|
+
alternate: mergedAlternate,
|
|
330
|
+
consequent: mergedConsequent,
|
|
331
|
+
}
|
|
332
|
+
})
|
|
333
|
+
|
|
334
|
+
const hasTernaries = Boolean(onlyTernaries.length)
|
|
335
|
+
|
|
336
|
+
const baseClassNames = mergeForwardBaseStyle
|
|
337
|
+
? addStyles(mergeForwardBaseStyle)
|
|
338
|
+
: null
|
|
339
|
+
|
|
340
|
+
let baseClassNameStr = !baseClassNames ? '' : baseClassNames.join(' ')
|
|
341
|
+
|
|
342
|
+
if (baseFontFamily) {
|
|
343
|
+
baseClassNameStr = `font_${baseFontFamily}${baseClassNameStr ? ` ${baseClassNameStr}` : ''}`
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// add is_View or is_Text base class matching runtime behavior
|
|
347
|
+
const baseTypeClass = staticConfig.isText ? 'is_Text' : 'is_View'
|
|
348
|
+
baseClassNameStr = `${baseTypeClass}${baseClassNameStr ? ` ${baseClassNameStr}` : ''}`
|
|
349
|
+
|
|
350
|
+
// add component name class (skip 'Text' since is_Text already covers it)
|
|
351
|
+
const componentNameFinal = staticConfig.componentName
|
|
352
|
+
let base =
|
|
353
|
+
componentNameFinal && componentNameFinal !== 'Text'
|
|
354
|
+
? t.stringLiteral(
|
|
355
|
+
`is_${componentNameFinal}${baseClassNameStr ? ` ${baseClassNameStr}` : ''}`
|
|
356
|
+
)
|
|
357
|
+
: t.stringLiteral(baseClassNameStr || '')
|
|
358
|
+
|
|
359
|
+
attrClassName = attrClassName as t.Expression | null // actual typescript bug, flatMap doesn't update from never
|
|
360
|
+
|
|
361
|
+
const baseClassNameExpression: t.Expression = (() => {
|
|
362
|
+
if (attrClassName) {
|
|
363
|
+
if (t.isStringLiteral(attrClassName)) {
|
|
364
|
+
return t.stringLiteral(
|
|
365
|
+
base.value ? `${base.value} ${attrClassName.value}` : attrClassName.value
|
|
366
|
+
)
|
|
367
|
+
} else {
|
|
368
|
+
// space after to ensure its a string and its spaced
|
|
369
|
+
return t.binaryExpression(
|
|
370
|
+
'+',
|
|
371
|
+
t.binaryExpression('+', attrClassName, spaceString),
|
|
372
|
+
base
|
|
373
|
+
)
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
return base
|
|
378
|
+
})()
|
|
379
|
+
|
|
380
|
+
const expandedTernaries: Ternary[] = []
|
|
381
|
+
|
|
382
|
+
if (onlyTernaries.length) {
|
|
383
|
+
// normalize tests to reduce duplicates
|
|
384
|
+
const normalizedTernaries = normalizeTernaries(onlyTernaries)
|
|
385
|
+
|
|
386
|
+
for (const ternary of normalizedTernaries) {
|
|
387
|
+
if (!expandedTernaries.length) {
|
|
388
|
+
expandTernary(ternary)
|
|
389
|
+
continue
|
|
390
|
+
}
|
|
391
|
+
// snapshot current array before iterating - expandTernary mutates expandedTernaries
|
|
392
|
+
const prevTernaries = [...expandedTernaries]
|
|
393
|
+
for (const prev of prevTernaries) {
|
|
394
|
+
expandTernary(ternary, prev)
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
function expandTernary(ternary: Ternary, prev?: Ternary) {
|
|
400
|
+
// need to diverge into two (or four if alternate)
|
|
401
|
+
if (ternary.consequent && Object.keys(ternary.consequent).length) {
|
|
402
|
+
const fontFamily = getFontFamilyNameFromProps(ternary.consequent)
|
|
403
|
+
|
|
404
|
+
expandedTernaries.push({
|
|
405
|
+
fontFamily,
|
|
406
|
+
// prevTest && test: merge consequent
|
|
407
|
+
test: prev
|
|
408
|
+
? t.logicalExpression('&&', prev.test, ternary.test)
|
|
409
|
+
: ternary.test,
|
|
410
|
+
consequent: prev
|
|
411
|
+
? mergeProps(prev.consequent!, ternary.consequent)
|
|
412
|
+
: ternary.consequent,
|
|
413
|
+
remove,
|
|
414
|
+
alternate: null,
|
|
415
|
+
})
|
|
416
|
+
|
|
417
|
+
if (prev) {
|
|
418
|
+
expandedTernaries.push({
|
|
419
|
+
fontFamily,
|
|
420
|
+
// !prevTest && test: just consequent
|
|
421
|
+
test: t.logicalExpression(
|
|
422
|
+
'&&',
|
|
423
|
+
t.unaryExpression('!', prev.test),
|
|
424
|
+
ternary.test
|
|
425
|
+
),
|
|
426
|
+
consequent: ternary.consequent,
|
|
427
|
+
alternate: null,
|
|
428
|
+
remove,
|
|
429
|
+
})
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
if (ternary.alternate && Object.keys(ternary.alternate).length) {
|
|
434
|
+
const fontFamily = getFontFamilyNameFromProps(ternary.alternate)
|
|
435
|
+
const negated = t.unaryExpression('!', ternary.test)
|
|
436
|
+
expandedTernaries.push({
|
|
437
|
+
fontFamily,
|
|
438
|
+
// prevTest && !test: merge alternate
|
|
439
|
+
test: prev ? t.logicalExpression('&&', prev.test, negated) : negated,
|
|
440
|
+
consequent: prev
|
|
441
|
+
? mergeProps(prev.alternate!, ternary.alternate)
|
|
442
|
+
: ternary.alternate,
|
|
443
|
+
remove,
|
|
444
|
+
alternate: null,
|
|
445
|
+
})
|
|
446
|
+
|
|
447
|
+
if (prev) {
|
|
448
|
+
expandedTernaries.push({
|
|
449
|
+
fontFamily,
|
|
450
|
+
test: t.logicalExpression(
|
|
451
|
+
'&&',
|
|
452
|
+
t.unaryExpression('!', prev.test),
|
|
453
|
+
ternary.test
|
|
454
|
+
),
|
|
455
|
+
consequent: ternary.alternate,
|
|
456
|
+
remove,
|
|
457
|
+
alternate: null,
|
|
458
|
+
})
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
let ternaryClassNameExpr: t.Expression | null = null
|
|
464
|
+
|
|
465
|
+
// next: create all CSS, build className strings and hoist, and create final node with props
|
|
466
|
+
if (hasTernaries) {
|
|
467
|
+
for (const ternary of expandedTernaries) {
|
|
468
|
+
if (!ternary.consequent) continue
|
|
469
|
+
const classNames = addStyles(ternary.consequent)
|
|
470
|
+
if (ternary.fontFamily) {
|
|
471
|
+
classNames.unshift(`font_${ternary.fontFamily}`)
|
|
472
|
+
}
|
|
473
|
+
const baseString = t.isStringLiteral(baseClassNameExpression)
|
|
474
|
+
? baseClassNameExpression.value
|
|
475
|
+
: ''
|
|
476
|
+
|
|
477
|
+
const fullClassNameWithDups =
|
|
478
|
+
(baseString ? `${baseString} ` : '') + classNames.join(' ')
|
|
479
|
+
|
|
480
|
+
// we concat here as the base could be conditionally overriden by our classNames
|
|
481
|
+
const fullClassName = concatClassName(fullClassNameWithDups)
|
|
482
|
+
|
|
483
|
+
const classNameLiteral = t.stringLiteral(fullClassName)
|
|
484
|
+
|
|
485
|
+
if (!ternaryClassNameExpr) {
|
|
486
|
+
ternaryClassNameExpr = t.conditionalExpression(
|
|
487
|
+
ternary.test,
|
|
488
|
+
classNameLiteral,
|
|
489
|
+
baseClassNameExpression
|
|
490
|
+
)
|
|
491
|
+
} else {
|
|
492
|
+
ternaryClassNameExpr = t.conditionalExpression(
|
|
493
|
+
ternary.test,
|
|
494
|
+
classNameLiteral,
|
|
495
|
+
ternaryClassNameExpr
|
|
496
|
+
)
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
let finalExpression: t.Expression | null =
|
|
502
|
+
ternaryClassNameExpr || baseClassNameExpression || null
|
|
503
|
+
|
|
504
|
+
if (shouldPrintDebug) {
|
|
505
|
+
console.info('attrs', JSON.stringify(attrs, null, 2))
|
|
506
|
+
console.info('expandedTernaries', JSON.stringify(expandedTernaries, null, 2))
|
|
507
|
+
console.info('finalExpression', JSON.stringify(finalExpression, null, 2))
|
|
508
|
+
console.info({ hasTernaries, baseClassNameExpression })
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
if (finalExpression) {
|
|
512
|
+
// hoist to global variables
|
|
513
|
+
finalExpression = hoistClassNames(jsxPath, finalExpression)
|
|
514
|
+
|
|
515
|
+
// console.log('finalExpression', finalExpression)
|
|
516
|
+
|
|
517
|
+
const classNameProp = t.jsxAttribute(
|
|
518
|
+
t.jsxIdentifier('className'),
|
|
519
|
+
t.jsxExpressionContainer(finalExpression!)
|
|
520
|
+
)
|
|
521
|
+
finalAttrs.unshift(classNameProp)
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
node.attributes = finalAttrs
|
|
525
|
+
},
|
|
526
|
+
})
|
|
527
|
+
|
|
528
|
+
if (!res || (!res.modified && !res.optimized && !res.flattened && !res.styled)) {
|
|
529
|
+
if (shouldPrintDebug) {
|
|
530
|
+
console.info('no res or none modified', res)
|
|
531
|
+
}
|
|
532
|
+
return null
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
const styles = Array.from(cssMap.values())
|
|
536
|
+
.map((x) => x.css)
|
|
537
|
+
.join('\n')
|
|
538
|
+
.trim()
|
|
539
|
+
|
|
540
|
+
// @ts-ignore
|
|
541
|
+
const result = generate(
|
|
542
|
+
ast as any,
|
|
543
|
+
{
|
|
544
|
+
concise: false,
|
|
545
|
+
filename: sourcePath,
|
|
546
|
+
// this makes the debug output terrible, and i think sourcemap works already
|
|
547
|
+
retainLines: false,
|
|
548
|
+
sourceFileName: sourcePath,
|
|
549
|
+
sourceMaps: true,
|
|
550
|
+
},
|
|
551
|
+
source
|
|
552
|
+
)
|
|
553
|
+
|
|
554
|
+
if (shouldPrintDebug) {
|
|
555
|
+
console.info(
|
|
556
|
+
'\n -------- output code ------- \n\n',
|
|
557
|
+
result.code
|
|
558
|
+
.split('\n')
|
|
559
|
+
.filter((x) => !x.startsWith('//'))
|
|
560
|
+
.join('\n')
|
|
561
|
+
)
|
|
562
|
+
console.info('\n -------- output style -------- \n\n', styles)
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
printLog(res)
|
|
566
|
+
|
|
567
|
+
return {
|
|
568
|
+
ast,
|
|
569
|
+
styles,
|
|
570
|
+
js: result.code,
|
|
571
|
+
map: result.map,
|
|
572
|
+
stats: {
|
|
573
|
+
styled: res.styled,
|
|
574
|
+
flattened: res.flattened,
|
|
575
|
+
optimized: res.optimized,
|
|
576
|
+
found: res.found,
|
|
577
|
+
},
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
function hoistClassNames(path: NodePath<t.JSXElement>, expr: t.Expression) {
|
|
582
|
+
if (t.isStringLiteral(expr)) {
|
|
583
|
+
return hoistClassName(path, expr.value)
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
if (t.isLogicalExpression(expr)) {
|
|
587
|
+
const left = t.isStringLiteral(expr.left)
|
|
588
|
+
? hoistClassName(path, expr.left.value)
|
|
589
|
+
: expr.left
|
|
590
|
+
const right = t.isStringLiteral(expr.right)
|
|
591
|
+
? hoistClassName(path, expr.right.value)
|
|
592
|
+
: hoistClassNames(path, expr.right)
|
|
593
|
+
return t.logicalExpression(expr.operator, left, right)
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
if (t.isConditionalExpression(expr)) {
|
|
597
|
+
const cons = t.isStringLiteral(expr.consequent)
|
|
598
|
+
? hoistClassName(path, expr.consequent.value)
|
|
599
|
+
: hoistClassNames(path, expr.consequent)
|
|
600
|
+
|
|
601
|
+
const alt = t.isStringLiteral(expr.alternate)
|
|
602
|
+
? hoistClassName(path, expr.alternate.value)
|
|
603
|
+
: hoistClassNames(path, expr.alternate)
|
|
604
|
+
|
|
605
|
+
return t.conditionalExpression(expr.test, cons, alt)
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
return expr
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
function hoistClassName(path: NodePath<t.JSXElement>, str: string) {
|
|
612
|
+
const uid = path.scope.generateUidIdentifier('cn')
|
|
613
|
+
const parent = path.findParent((path) => path.isProgram())
|
|
614
|
+
if (!parent) throw new Error(`no program?`)
|
|
615
|
+
const variable = t.variableDeclaration('const', [
|
|
616
|
+
t.variableDeclarator(uid, t.stringLiteral(cleanupClassName(str))),
|
|
617
|
+
])
|
|
618
|
+
// @ts-ignore
|
|
619
|
+
parent.unshiftContainer('body', variable)
|
|
620
|
+
return uid
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
function cleanupClassName(inStr: string) {
|
|
624
|
+
const out = new Set<string>()
|
|
625
|
+
for (const part of inStr.split(' ')) {
|
|
626
|
+
if (!part || part === ' ') continue
|
|
627
|
+
if (part === 'font_') continue
|
|
628
|
+
out.add(part)
|
|
629
|
+
}
|
|
630
|
+
return [...out].join(' ')
|
|
631
|
+
}
|