-
Notifications
You must be signed in to change notification settings - Fork 5
/
extendedTokens.ts
62 lines (61 loc) · 2.42 KB
/
extendedTokens.ts
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
import { ErrorType, type ExtendedFormulaEntry, type Token, TokenType } from './types'
import { getTokens } from './lexer'
import { getTokenNodes } from './nodeGenerator'
import { getValidationErrors, getCircularValidationErrors, getTokenDependenciesDeep } from './validator'
export function getExtendedTokens (formulasByReferences: Record<string, string>, supportedRefs?: string[]) {
const out: Record<string, ExtendedFormulaEntry> = {}
const tokensByRefs: Record<string, Token[]> = {}
Object.entries(formulasByReferences).forEach(([referenceNameOrig, formula]) => {
const referenceName = referenceNameOrig.toLowerCase()
const tokens = getTokens(formula)
const tokenNodes = getTokenNodes(formula)
tokensByRefs[referenceName] = tokens
out[referenceName] = {
referenceName,
referenceNameOrig,
formula,
tokens,
tokenNodes,
validationErrors: [],
dependencies: [],
order: 0
}
})
const allSupportedRefs = [...(supportedRefs || []), ...Object.keys(tokensByRefs)]
const dependenciesByRefs = getTokenDependenciesDeep(tokensByRefs)
Object.values(out).forEach((entry) => {
const validationErrors = getValidationErrors(entry.tokens, allSupportedRefs)
const circularErrors = getCircularValidationErrors(entry.referenceName, tokensByRefs)
entry.validationErrors = [...validationErrors, ...circularErrors]
entry.dependencies = dependenciesByRefs[entry.referenceName] || []
})
const resolved: Record<string, boolean> = {}
let order = 1
let updated = true
while (updated) {
updated = false
Object.values(out).forEach((entry) => {
if (!resolved[entry.referenceName] && !entry.dependencies.some(ref => !resolved[ref])) {
entry.order = order
resolved[entry.referenceName] = true
updated = true
}
})
if (updated) {
order++
}
}
const orderedOut = Object.keys(out).sort((key1, key2) => out[key1].order - out[key2].order)
orderedOut.forEach((referenceName) => {
const entry = out[referenceName]
entry.tokens.forEach((token, tokenIndex) => {
if (token.type === TokenType.ReferenceName) {
const tokenValue = token.value.toLowerCase()
if (tokenValue !== referenceName && !entry.validationErrors.length && out[tokenValue]?.validationErrors.length) {
entry.validationErrors.push({ token, tokenIndex, errorType: ErrorType.DependsOnInvalid })
}
}
})
})
return out
}