Skip to content

Commit 8529a04

Browse files
committed
feat(app): add import processor
1 parent 553d547 commit 8529a04

File tree

4 files changed

+146
-1
lines changed

4 files changed

+146
-1
lines changed

packages/app/modules/evaluation/parser/parser.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,20 @@ import { Lexer, TokenType } from '@language-kit/lexer'
22
import { Node } from '../types/node'
33
import { Processor } from '../types/processor'
44
import { ParserToken } from '../types/token'
5+
6+
import importProcessor from './processor.import'
57
import variableProcessor from './processor.variable'
68
import functionProcessor from './processor.function'
79
import eofProcessor from './processor.eof'
810

911
export function createParser() {
1012
const lexer = new Lexer()
11-
const processors: Processor[] = [variableProcessor, functionProcessor, eofProcessor]
13+
const processors: Processor[] = [
14+
importProcessor,
15+
variableProcessor,
16+
functionProcessor,
17+
eofProcessor,
18+
]
1219

1320
function toTokens(value: string) {
1421
const tokens = lexer.tokenize(value)
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { describe, it, expect } from 'vitest'
2+
3+
import { createParser } from './parser'
4+
import { NodeImport, NodeType } from '../types/node'
5+
6+
describe('Parser', () => {
7+
const parser = createParser()
8+
9+
it.each([
10+
["import lodash from 'lodash'", 'lodash', 'lodash'],
11+
[`import lodash from "lodash"`, 'lodash', 'lodash'],
12+
['import lodash from `lodash`', 'lodash', 'lodash'],
13+
['import { ref } from "vue"', 'vue', '{ ref }'],
14+
['import { ref, computed } from "vue"', 'vue', '{ ref, computed }'],
15+
])('should convert %o to import node', (code, moduleId, statements) => {
16+
const result = parser.toNodes(code)
17+
18+
const node = result[0] as NodeImport
19+
20+
expect(result.length).toBe(1)
21+
22+
expect(node.moduleId).toEqual(moduleId)
23+
expect(node.statements).toBe(statements)
24+
expect(node.start).toEqual(0)
25+
expect(node.end).toEqual(code.length)
26+
expect(node.type).toEqual(NodeType.Import)
27+
expect(node.tokens).toEqual(parser.toTokens(code))
28+
})
29+
})
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import { TokenType } from '@language-kit/lexer'
2+
import { defineProcessor } from '../helpers/define-processor'
3+
import { NodeImport, NodeType, NodeVariable } from '../types/node'
4+
import { ParserToken } from '../types/token'
5+
6+
const quotes = [`'`, `"`, '`']
7+
8+
function findStatements(tokens: ParserToken[]) {
9+
const start = tokens[2]
10+
11+
if (!start) {
12+
return []
13+
}
14+
15+
if (start.type == TokenType.Word) {
16+
return [start]
17+
}
18+
19+
if (start.value === '{') {
20+
const end = tokens.findIndex((t) => t.value === '}')
21+
22+
return tokens.slice(2, end + 1)
23+
}
24+
25+
return []
26+
}
27+
28+
function findModuleId(tokens: ParserToken[]) {
29+
const start = tokens.findIndex((t) => quotes.includes(t.value))
30+
const end = tokens.findIndex((t, i) => {
31+
if (i <= start) return false
32+
33+
return quotes.includes(t.value)
34+
})
35+
36+
if (start === -1 || end === -1) {
37+
return ''
38+
}
39+
40+
return tokens
41+
.slice(start + 1, end)
42+
.map((t) => t.value)
43+
.join('')
44+
}
45+
46+
export default defineProcessor({
47+
process(options) {
48+
const { tokens, nodes } = options
49+
50+
const result = {
51+
processed: false,
52+
tokens,
53+
nodes,
54+
}
55+
56+
const current = tokens[0]
57+
const moduleId = findModuleId(tokens)
58+
59+
if (current.value !== 'import') {
60+
return result
61+
}
62+
63+
const endIndex = tokens.findIndex((t, i) => {
64+
const prev = tokens[i - 1]
65+
66+
if (!prev) return false
67+
68+
if (prev.type !== TokenType.Word) return false
69+
70+
if (prev.value !== moduleId) return false
71+
72+
return quotes.includes(t.value)
73+
})
74+
75+
if (endIndex === -1) {
76+
return result
77+
}
78+
79+
const nodeTokens = tokens.slice(0, endIndex + 1)
80+
const statementsTokens = findStatements(tokens)
81+
const statements = statementsTokens.map((t) => t.value).join('')
82+
83+
if (!nodeTokens.length) {
84+
return result
85+
}
86+
87+
const node: NodeImport = {
88+
type: NodeType.Import,
89+
tokens: nodeTokens,
90+
start: nodeTokens[0].start,
91+
end: nodeTokens[nodeTokens.length - 1].end,
92+
moduleId,
93+
statements,
94+
}
95+
96+
result.processed = true
97+
result.nodes = [...nodes, node]
98+
result.tokens = tokens.slice(endIndex + 1)
99+
100+
return result
101+
},
102+
})

packages/app/modules/evaluation/types/node.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export enum NodeType {
44
Unknown = 'Unknown',
55
Variable = 'Variable',
66
Function = 'Function',
7+
Import = 'Import',
78
}
89

910
export interface Node {
@@ -18,3 +19,9 @@ export interface NodeVariable extends Node {
1819
name: string
1920
value: string
2021
}
22+
23+
export interface NodeImport extends Node {
24+
type: NodeType.Import
25+
moduleId: string
26+
statements: string
27+
}

0 commit comments

Comments
 (0)