-
Notifications
You must be signed in to change notification settings - Fork 3.8k
Expand file tree
/
Copy pathenvironment.ts
More file actions
69 lines (67 loc) · 2.54 KB
/
Copy pathenvironment.ts
File metadata and controls
69 lines (67 loc) · 2.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import * as t from '@babel/types'
import { fingerprint, parseSource, propertyName } from '#design-diff/ast'
interface EnvironmentFields {
fields: Map<string, string>
options: string
}
/** Extract the literal createEnv schema convention without running validators or configuration. */
export function environmentFields(source: string, file: string): Map<string, EnvironmentFields> {
const ast = parseSource(source, file)
const factories = new Set<string>()
for (const node of ast.program.body)
if (t.isImportDeclaration(node) && /^@t3-oss\/env-/.test(node.source.value))
for (const specifier of node.specifiers)
if (t.isImportSpecifier(specifier) && propertyName(specifier.imported) === 'createEnv')
factories.add(specifier.local.name)
const result = new Map<string, EnvironmentFields>()
for (const statement of ast.program.body) {
const node = t.isExportNamedDeclaration(statement) ? statement.declaration : statement
if (!t.isVariableDeclaration(node)) continue
for (const declaration of node.declarations) {
const call = declaration.init
if (
!t.isIdentifier(declaration.id) ||
!t.isCallExpression(call) ||
!t.isIdentifier(call.callee) ||
!factories.has(call.callee.name) ||
call.arguments.length !== 1 ||
!t.isObjectExpression(call.arguments[0])
)
continue
const fields = new Map<string, string[]>()
const options: t.Node[] = []
let supported = true
for (const section of call.arguments[0].properties) {
if (!t.isObjectProperty(section) || section.computed) {
supported = false
break
}
const name = propertyName(section.key)
if (
!['server', 'client', 'shared', 'runtimeEnv', 'experimental__runtimeEnv'].includes(name)
) {
options.push(section)
continue
}
if (!t.isObjectExpression(section.value)) {
supported = false
break
}
for (const property of section.value.properties) {
if (!t.isObjectProperty(property) || property.computed) {
supported = false
break
}
const key = propertyName(property.key)
fields.set(key, [...(fields.get(key) ?? []), fingerprint([name, property.value])])
}
}
if (supported)
result.set(declaration.id.name, {
fields: new Map([...fields].map(([key, values]) => [key, fingerprint(values)])),
options: fingerprint(options),
})
}
}
return result
}