@tamagui/codemod-flat-values 0.0.0-bootstrap.0 → 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 +211 -1
- package/dist/builtInNames.mjs +13 -0
- package/dist/builtInNames.mjs.map +1 -0
- package/dist/containers.mjs +141 -0
- package/dist/containers.mjs.map +1 -0
- package/dist/convert.mjs +1139 -0
- package/dist/convert.mjs.map +1 -0
- package/dist/expressions.mjs +188 -0
- package/dist/expressions.mjs.map +1 -0
- package/dist/grammar.mjs +68 -0
- package/dist/grammar.mjs.map +1 -0
- package/dist/index.mjs +342 -0
- package/dist/index.mjs.map +1 -0
- package/dist/legacyConditions.mjs +293 -0
- package/dist/legacyConditions.mjs.map +1 -0
- package/dist/legacyNames.mjs +130 -0
- package/dist/legacyNames.mjs.map +1 -0
- package/dist/provenance.mjs +137 -0
- package/dist/provenance.mjs.map +1 -0
- package/dist/report.mjs +129 -0
- package/dist/report.mjs.map +1 -0
- package/dist/structuredNative.mjs +275 -0
- package/dist/structuredNative.mjs.map +1 -0
- package/package.json +35 -7
- package/src/builtInNames.ts +21 -0
- package/src/containers.ts +227 -0
- package/src/convert.ts +1784 -0
- package/src/expressions.ts +220 -0
- package/src/grammar.ts +180 -0
- package/src/index.ts +517 -0
- package/src/legacyConditions.ts +346 -0
- package/src/legacyNames.ts +160 -0
- package/src/provenance.ts +210 -0
- package/src/report.ts +235 -0
- package/src/structuredNative.ts +459 -0
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
import {
|
|
2
|
+
transformFamilyProps,
|
|
3
|
+
unitlessNumberProperties,
|
|
4
|
+
} from '@tamagui/style-grammar/tooling'
|
|
5
|
+
import type { ModifierRegistryView, ParsedClause } from '@tamagui/style-grammar/tooling'
|
|
6
|
+
|
|
7
|
+
export const pseudoToModifier: Readonly<Record<string, string>> = Object.freeze({
|
|
8
|
+
hoverStyle: 'hover',
|
|
9
|
+
pressStyle: 'press',
|
|
10
|
+
focusStyle: 'focus',
|
|
11
|
+
focusVisibleStyle: 'focus-visible',
|
|
12
|
+
focusWithinStyle: 'focus-within',
|
|
13
|
+
disabledStyle: 'disabled',
|
|
14
|
+
enterStyle: 'enter',
|
|
15
|
+
exitStyle: 'exit',
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
const transformPartProperties: ReadonlySet<string> = new Set([
|
|
19
|
+
'scale',
|
|
20
|
+
'scaleX',
|
|
21
|
+
'scaleY',
|
|
22
|
+
'rotate',
|
|
23
|
+
'rotateX',
|
|
24
|
+
'rotateY',
|
|
25
|
+
'rotateZ',
|
|
26
|
+
'x',
|
|
27
|
+
'y',
|
|
28
|
+
'skewX',
|
|
29
|
+
'skewY',
|
|
30
|
+
'perspective',
|
|
31
|
+
])
|
|
32
|
+
|
|
33
|
+
export interface ConvertLegacyConditionOptions {
|
|
34
|
+
registry: ModifierRegistryView
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface LegacyConditionContribution {
|
|
38
|
+
prop: string
|
|
39
|
+
clause: ParsedClause
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface LegacyConditionError {
|
|
43
|
+
code: string
|
|
44
|
+
path: string
|
|
45
|
+
message: string
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface LegacyConditionResult {
|
|
49
|
+
contributions: LegacyConditionContribution[]
|
|
50
|
+
errors: LegacyConditionError[]
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
type ConditionResolution =
|
|
54
|
+
| { recognized: false }
|
|
55
|
+
| { recognized: true; modifiers: readonly string[] }
|
|
56
|
+
| { recognized: true; error: Omit<LegacyConditionError, 'path'> }
|
|
57
|
+
|
|
58
|
+
function resolveLegacyCondition(
|
|
59
|
+
propName: string,
|
|
60
|
+
registry: ModifierRegistryView
|
|
61
|
+
): ConditionResolution {
|
|
62
|
+
const pseudoModifier = pseudoToModifier[propName]
|
|
63
|
+
if (pseudoModifier !== undefined) {
|
|
64
|
+
return registry.get(pseudoModifier) === 'state'
|
|
65
|
+
? { recognized: true, modifiers: [pseudoModifier] }
|
|
66
|
+
: {
|
|
67
|
+
recognized: true,
|
|
68
|
+
error: {
|
|
69
|
+
code: 'unregistered-legacy-condition',
|
|
70
|
+
message: `legacy condition "${propName}" maps to unregistered state modifier "${pseudoModifier}"`,
|
|
71
|
+
},
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (propName.startsWith('$theme-')) {
|
|
76
|
+
const modifier = propName.slice('$theme-'.length)
|
|
77
|
+
return modifier && registry.get(modifier) === 'theme'
|
|
78
|
+
? { recognized: true, modifiers: [modifier] }
|
|
79
|
+
: {
|
|
80
|
+
recognized: true,
|
|
81
|
+
error: {
|
|
82
|
+
code: 'unregistered-legacy-condition',
|
|
83
|
+
message: `legacy theme condition "${propName}" does not name a registered theme`,
|
|
84
|
+
},
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (propName.startsWith('$platform-')) {
|
|
89
|
+
const modifier = propName.slice('$platform-'.length)
|
|
90
|
+
return modifier && registry.get(modifier) === 'platform'
|
|
91
|
+
? { recognized: true, modifiers: [modifier] }
|
|
92
|
+
: {
|
|
93
|
+
recognized: true,
|
|
94
|
+
error: {
|
|
95
|
+
code: 'unregistered-legacy-condition',
|
|
96
|
+
message: `legacy platform condition "${propName}" does not name a registered platform`,
|
|
97
|
+
},
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (propName.startsWith('$group-')) {
|
|
102
|
+
const remainder = propName.slice('$group-'.length)
|
|
103
|
+
const candidates: string[] = []
|
|
104
|
+
let start = 0
|
|
105
|
+
while (start < remainder.length) {
|
|
106
|
+
const state = remainder.slice(start)
|
|
107
|
+
if (registry.get(state) === 'state') candidates.push(state)
|
|
108
|
+
const dash = remainder.indexOf('-', start)
|
|
109
|
+
if (dash === -1) break
|
|
110
|
+
start = dash + 1
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const longestLength = candidates.reduce(
|
|
114
|
+
(length, state) => Math.max(length, state.length),
|
|
115
|
+
0
|
|
116
|
+
)
|
|
117
|
+
const longest = candidates.filter((state) => state.length === longestLength)
|
|
118
|
+
if (longest.length > 1) {
|
|
119
|
+
return {
|
|
120
|
+
recognized: true,
|
|
121
|
+
error: {
|
|
122
|
+
code: 'ambiguous-legacy-group',
|
|
123
|
+
message: `legacy group condition "${propName}" has more than one equally specific state suffix`,
|
|
124
|
+
},
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const state = longest.length === 1 ? longest[0] : null
|
|
129
|
+
let namePart =
|
|
130
|
+
state === null
|
|
131
|
+
? remainder
|
|
132
|
+
: state.length === remainder.length
|
|
133
|
+
? ''
|
|
134
|
+
: remainder.slice(0, -(state.length + 1))
|
|
135
|
+
let media: string | null = null
|
|
136
|
+
|
|
137
|
+
if (namePart) {
|
|
138
|
+
let scanStart = 0
|
|
139
|
+
while (scanStart < namePart.length) {
|
|
140
|
+
const suffix = namePart.slice(scanStart)
|
|
141
|
+
if (registry.get(`@${suffix}`) === 'container') {
|
|
142
|
+
media = suffix
|
|
143
|
+
break
|
|
144
|
+
}
|
|
145
|
+
const dash = namePart.indexOf('-', scanStart)
|
|
146
|
+
if (dash === -1) break
|
|
147
|
+
scanStart = dash + 1
|
|
148
|
+
}
|
|
149
|
+
if (media !== null) {
|
|
150
|
+
namePart =
|
|
151
|
+
media.length === namePart.length ? '' : namePart.slice(0, -(media.length + 1))
|
|
152
|
+
} else if (state === null) {
|
|
153
|
+
return {
|
|
154
|
+
recognized: true,
|
|
155
|
+
error: {
|
|
156
|
+
code: 'unregistered-legacy-condition',
|
|
157
|
+
message: `legacy group condition "${propName}" has no registered state or container-size suffix`,
|
|
158
|
+
},
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
} else if (state === null) {
|
|
162
|
+
return {
|
|
163
|
+
recognized: true,
|
|
164
|
+
error: {
|
|
165
|
+
code: 'unregistered-legacy-condition',
|
|
166
|
+
message: `legacy group condition "${propName}" has no registered state suffix`,
|
|
167
|
+
},
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const suffix = namePart ? `/${namePart}` : ''
|
|
172
|
+
const modifiers: string[] = []
|
|
173
|
+
if (media !== null) modifiers.push(`@${media}${suffix}`)
|
|
174
|
+
if (state !== null) modifiers.push(`group-${state}${suffix}`)
|
|
175
|
+
return { recognized: true, modifiers }
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (propName[0] === '$') {
|
|
179
|
+
const modifier = propName.slice(1)
|
|
180
|
+
const kind = registry.get(modifier)
|
|
181
|
+
if (kind === 'media' || kind === 'container') {
|
|
182
|
+
return { recognized: true, modifiers: [modifier] }
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return { recognized: false }
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function isConditionObject(value: unknown): value is Record<string, unknown> {
|
|
190
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)) return false
|
|
191
|
+
const prototype = Object.getPrototypeOf(value)
|
|
192
|
+
return prototype === Object.prototype || prototype === null
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function convertStyleValue(
|
|
196
|
+
prop: string,
|
|
197
|
+
value: unknown,
|
|
198
|
+
path: string,
|
|
199
|
+
errors: LegacyConditionError[]
|
|
200
|
+
): string | null {
|
|
201
|
+
if (transformPartProperties.has(prop) && !transformFamilyProps.has(prop)) {
|
|
202
|
+
errors.push({
|
|
203
|
+
code: 'legacy-transform-part',
|
|
204
|
+
path,
|
|
205
|
+
message: `legacy transform part "${prop}" has no flat spelling; author it inside a flat \`transform\` value (only x, y, scale, scaleX, scaleY, and rotate are first-class)`,
|
|
206
|
+
})
|
|
207
|
+
return null
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (
|
|
211
|
+
typeof value === 'number' &&
|
|
212
|
+
Number.isFinite(value) &&
|
|
213
|
+
transformFamilyProps.has(prop)
|
|
214
|
+
) {
|
|
215
|
+
if (prop === 'rotate') return value === 0 ? '0deg' : `${value}deg`
|
|
216
|
+
if (prop === 'x' || prop === 'y') return value === 0 ? '0' : `${value}px`
|
|
217
|
+
return String(value)
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (typeof value === 'string') {
|
|
221
|
+
if (!value.length) {
|
|
222
|
+
errors.push({
|
|
223
|
+
code: 'unsupported-legacy-value',
|
|
224
|
+
path,
|
|
225
|
+
message: 'an empty string cannot become a condition clause payload',
|
|
226
|
+
})
|
|
227
|
+
return null
|
|
228
|
+
}
|
|
229
|
+
if (value.indexOf('$') === -1) return value
|
|
230
|
+
if (value.includes('"') || value.includes("'") || value.includes('url(')) {
|
|
231
|
+
errors.push({
|
|
232
|
+
code: 'unsupported-legacy-value',
|
|
233
|
+
path,
|
|
234
|
+
message: `"${value}" mixes "$" with quoted or url() content; migrate the token spelling by hand`,
|
|
235
|
+
})
|
|
236
|
+
return null
|
|
237
|
+
}
|
|
238
|
+
if (/\$[\w-]*\./.test(value)) {
|
|
239
|
+
errors.push({
|
|
240
|
+
code: 'legacy-token-dot-path',
|
|
241
|
+
path,
|
|
242
|
+
message: `legacy token in "${value}" uses dot-path naming; rename it to one configured flat token name before conversion`,
|
|
243
|
+
})
|
|
244
|
+
return null
|
|
245
|
+
}
|
|
246
|
+
if (/\$-?\d/.test(value) && !/^\$-?[\w-]+$/.test(value)) {
|
|
247
|
+
errors.push({
|
|
248
|
+
code: 'legacy-numeric-composite-token',
|
|
249
|
+
path,
|
|
250
|
+
message: `numeric token in "${value}" is embedded in a composite value; replace it with its resolved CSS value before conversion`,
|
|
251
|
+
})
|
|
252
|
+
return null
|
|
253
|
+
}
|
|
254
|
+
if (/\$(?![\w-])/.test(value)) {
|
|
255
|
+
errors.push({
|
|
256
|
+
code: 'unsupported-legacy-value',
|
|
257
|
+
path,
|
|
258
|
+
message: `"$" in "${value}" is not followed by a token name`,
|
|
259
|
+
})
|
|
260
|
+
return null
|
|
261
|
+
}
|
|
262
|
+
return value.replace(/\$([\w-]+)/g, '$1')
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (typeof value === 'number') {
|
|
266
|
+
if (Number.isFinite(value)) {
|
|
267
|
+
return unitlessNumberProperties.has(prop) ? String(value) : `${value}px`
|
|
268
|
+
}
|
|
269
|
+
errors.push({
|
|
270
|
+
code: 'unsupported-legacy-value',
|
|
271
|
+
path,
|
|
272
|
+
message: `non-finite number ${String(value)} cannot become a CSS payload`,
|
|
273
|
+
})
|
|
274
|
+
return null
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
errors.push({
|
|
278
|
+
code: 'unsupported-legacy-value',
|
|
279
|
+
path,
|
|
280
|
+
message: `legacy condition value for "${prop}" must be a string or finite number`,
|
|
281
|
+
})
|
|
282
|
+
return null
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
export function convertLegacyConditionProp(
|
|
286
|
+
propName: string,
|
|
287
|
+
value: unknown,
|
|
288
|
+
options: ConvertLegacyConditionOptions
|
|
289
|
+
): LegacyConditionResult | null {
|
|
290
|
+
const root = resolveLegacyCondition(propName, options.registry)
|
|
291
|
+
if (!root.recognized) return null
|
|
292
|
+
|
|
293
|
+
const result: LegacyConditionResult = { contributions: [], errors: [] }
|
|
294
|
+
if ('error' in root) {
|
|
295
|
+
result.errors.push({ ...root.error, path: propName })
|
|
296
|
+
return result
|
|
297
|
+
}
|
|
298
|
+
if (!isConditionObject(value)) {
|
|
299
|
+
result.errors.push({
|
|
300
|
+
code: 'legacy-condition-object',
|
|
301
|
+
path: propName,
|
|
302
|
+
message: `legacy condition "${propName}" must contain a style object`,
|
|
303
|
+
})
|
|
304
|
+
return result
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
const modifiers = root.modifiers.slice()
|
|
308
|
+
const visit = (object: Record<string, unknown>, objectPath: string): void => {
|
|
309
|
+
for (const childProp in object) {
|
|
310
|
+
if (!Object.prototype.hasOwnProperty.call(object, childProp)) continue
|
|
311
|
+
const childValue = object[childProp]
|
|
312
|
+
const childPath = `${objectPath}.${childProp}`
|
|
313
|
+
const condition = resolveLegacyCondition(childProp, options.registry)
|
|
314
|
+
|
|
315
|
+
if (condition.recognized) {
|
|
316
|
+
if ('error' in condition) {
|
|
317
|
+
result.errors.push({ ...condition.error, path: childPath })
|
|
318
|
+
continue
|
|
319
|
+
}
|
|
320
|
+
if (!isConditionObject(childValue)) {
|
|
321
|
+
result.errors.push({
|
|
322
|
+
code: 'legacy-condition-object',
|
|
323
|
+
path: childPath,
|
|
324
|
+
message: `legacy condition "${childProp}" must contain a style object`,
|
|
325
|
+
})
|
|
326
|
+
continue
|
|
327
|
+
}
|
|
328
|
+
modifiers.push(...condition.modifiers)
|
|
329
|
+
visit(childValue, childPath)
|
|
330
|
+
modifiers.length -= condition.modifiers.length
|
|
331
|
+
continue
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
const payload = convertStyleValue(childProp, childValue, childPath, result.errors)
|
|
335
|
+
if (payload !== null) {
|
|
336
|
+
result.contributions.push({
|
|
337
|
+
prop: childProp,
|
|
338
|
+
clause: { modifiers: modifiers.slice(), payload },
|
|
339
|
+
})
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
visit(value, propName)
|
|
345
|
+
return result
|
|
346
|
+
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
// Legacy condition prop names, normalized to the one spelling the shared
|
|
2
|
+
// converter resolves.
|
|
3
|
+
//
|
|
4
|
+
// Three v1 spellings need normalizing before the shared converter sees them:
|
|
5
|
+
// the platform conditions are written `$web`/`$ios` rather than `$platform-web`;
|
|
6
|
+
// v1 media keys are camelCase where the V6 built-ins are kebab-case (decision
|
|
7
|
+
// 15); and a legacy group condition may carry a container size, which V3 splits
|
|
8
|
+
// into a container query plus a group state (`$group-card-sm-hover` becomes
|
|
9
|
+
// `@sm/card:group-hover/card:`).
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
grammarPlatformNames,
|
|
13
|
+
pseudoToModifier,
|
|
14
|
+
type ModifierRegistryView,
|
|
15
|
+
} from './grammar'
|
|
16
|
+
|
|
17
|
+
export interface ContainerRequest {
|
|
18
|
+
/** the media key the container measures */
|
|
19
|
+
size: string
|
|
20
|
+
/** the group name the query is scoped to, or null for the nearest container */
|
|
21
|
+
group: string | null
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface ResolvedLegacyName {
|
|
25
|
+
/** the spelling handed to the shared converter */
|
|
26
|
+
canonical: string
|
|
27
|
+
/** modifiers replacing the converter's root modifier, when the split applies */
|
|
28
|
+
replaceRoot: readonly string[] | null
|
|
29
|
+
/** the container the parent group element has to declare */
|
|
30
|
+
container: ContainerRequest | null
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type LegacyNameResolution =
|
|
34
|
+
| { ok: true; resolved: ResolvedLegacyName }
|
|
35
|
+
| { ok: false; code: string; message: string }
|
|
36
|
+
|
|
37
|
+
export function isLegacyConditionName(name: string): boolean {
|
|
38
|
+
return name.startsWith('$') || pseudoToModifier[name] !== undefined
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function kebab(name: string): string {
|
|
42
|
+
return name.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase()
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** the registered media name for a v1 media key, kebab-cased when v1 spelled it camelCase */
|
|
46
|
+
function mediaName(name: string, registry: ModifierRegistryView): string | null {
|
|
47
|
+
if (registry.get(name) === 'media') return name
|
|
48
|
+
const kebabbed = kebab(name)
|
|
49
|
+
return registry.get(kebabbed) === 'media' ? kebabbed : null
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** the longest suffix of `parts` that resolves through `resolve` */
|
|
53
|
+
function longestSuffix(
|
|
54
|
+
parts: readonly string[],
|
|
55
|
+
resolve: (candidate: string) => string | null
|
|
56
|
+
): { value: string; rest: readonly string[] } | null {
|
|
57
|
+
for (let start = 0; start < parts.length; start++) {
|
|
58
|
+
const resolved = resolve(parts.slice(start).join('-'))
|
|
59
|
+
if (resolved !== null) return { value: resolved, rest: parts.slice(0, start) }
|
|
60
|
+
}
|
|
61
|
+
return null
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function resolveGroupName(
|
|
65
|
+
name: string,
|
|
66
|
+
registry: ModifierRegistryView
|
|
67
|
+
): LegacyNameResolution {
|
|
68
|
+
const parts = name.slice('$group-'.length).split('-')
|
|
69
|
+
const state = longestSuffix(parts, (candidate) =>
|
|
70
|
+
registry.get(candidate) === 'state' ? candidate : null
|
|
71
|
+
)
|
|
72
|
+
const beforeState = state ? state.rest : parts
|
|
73
|
+
const size = longestSuffix(beforeState, (candidate) => mediaName(candidate, registry))
|
|
74
|
+
const group = (size ? size.rest : beforeState).join('-') || null
|
|
75
|
+
const suffix = group === null ? '' : `/${group}`
|
|
76
|
+
|
|
77
|
+
if (!state && !size) {
|
|
78
|
+
return {
|
|
79
|
+
ok: false,
|
|
80
|
+
code: 'legacy-group-presence',
|
|
81
|
+
message: `"${name}" styles every descendant of the group unconditionally; V3 has no group-presence condition, so move the value to the base program or add a state`,
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (!size) {
|
|
86
|
+
// the shared converter already splits `$group-[name-]state`
|
|
87
|
+
return { ok: true, resolved: { canonical: name, replaceRoot: null, container: null } }
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const modifiers = [`@${size.value}${suffix}`]
|
|
91
|
+
if (state) modifiers.push(`group-${state.value}${suffix}`)
|
|
92
|
+
for (const modifier of modifiers) {
|
|
93
|
+
if (registry.get(modifier) === undefined) {
|
|
94
|
+
return {
|
|
95
|
+
ok: false,
|
|
96
|
+
code: 'unregistered-legacy-condition',
|
|
97
|
+
message: `"${name}" needs modifier "${modifier}", which is not registered`,
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return {
|
|
103
|
+
ok: true,
|
|
104
|
+
resolved: {
|
|
105
|
+
// any registered root works: `replaceRoot` substitutes the whole chain
|
|
106
|
+
canonical: state
|
|
107
|
+
? `$group-${group === null ? '' : `${group}-`}${state.value}`
|
|
108
|
+
: `$${size.value}`,
|
|
109
|
+
replaceRoot: modifiers,
|
|
110
|
+
container: { size: size.value, group },
|
|
111
|
+
},
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function resolveLegacyName(
|
|
116
|
+
name: string,
|
|
117
|
+
registry: ModifierRegistryView
|
|
118
|
+
): LegacyNameResolution {
|
|
119
|
+
if (pseudoToModifier[name] !== undefined || name.startsWith('$theme-')) {
|
|
120
|
+
return { ok: true, resolved: { canonical: name, replaceRoot: null, container: null } }
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (name.startsWith('$platform-')) {
|
|
124
|
+
return { ok: true, resolved: { canonical: name, replaceRoot: null, container: null } }
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (name.startsWith('$group-')) return resolveGroupName(name, registry)
|
|
128
|
+
|
|
129
|
+
if (name.startsWith('$')) {
|
|
130
|
+
const bare = name.slice(1)
|
|
131
|
+
if (grammarPlatformNames.has(bare)) {
|
|
132
|
+
return {
|
|
133
|
+
ok: true,
|
|
134
|
+
resolved: {
|
|
135
|
+
canonical: `$platform-${bare}`,
|
|
136
|
+
replaceRoot: null,
|
|
137
|
+
container: null,
|
|
138
|
+
},
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
const media = mediaName(bare, registry)
|
|
142
|
+
if (media !== null) {
|
|
143
|
+
return {
|
|
144
|
+
ok: true,
|
|
145
|
+
resolved: { canonical: `$${media}`, replaceRoot: null, container: null },
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return {
|
|
149
|
+
ok: false,
|
|
150
|
+
code: 'unknown-legacy-condition',
|
|
151
|
+
message: `"${name}" is not a registered legacy condition spelling`,
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
ok: false,
|
|
157
|
+
code: 'unknown-legacy-condition',
|
|
158
|
+
message: `"${name}" is not a registered legacy condition spelling`,
|
|
159
|
+
}
|
|
160
|
+
}
|