1 | const ASTCreator = require('./utils/ASTCreator')
|
2 |
|
3 | class ASTTransformer {
|
4 | constructor (ctx) {
|
5 | this.__transformers = {}
|
6 | this.ctx = ctx
|
7 | }
|
8 |
|
9 | add (type, fn) {
|
10 | if (!this.__transformers[type]) {
|
11 | this.__transformers[type] = []
|
12 | }
|
13 |
|
14 | this.__transformers[type].push(fn)
|
15 | }
|
16 |
|
17 | get (type) {
|
18 | return this.__transformers[type] || null
|
19 | }
|
20 |
|
21 | load (dirName) {
|
22 | const transformations = [
|
23 | 'classDeclaration',
|
24 | 'exportAllDeclaration',
|
25 | 'exportDeclaration',
|
26 | 'functionDeclaration',
|
27 | 'functionExpression',
|
28 | 'functionParamTyping',
|
29 | 'importDeclaration',
|
30 | 'logStatement',
|
31 | 'programm',
|
32 | 'regexp',
|
33 | 'templateLiteral',
|
34 | 'variableTyping'
|
35 | ]
|
36 |
|
37 | transformations.forEach((t) => {
|
38 | const fn = require(`./${dirName}/${t}.js`)
|
39 | fn(this)
|
40 | })
|
41 | }
|
42 |
|
43 | test (fn) {
|
44 | return fn(this.ctx)
|
45 | }
|
46 |
|
47 | transform (ast) {
|
48 | const transformatedAst = this.transformItem(ast)
|
49 | if (this.importRuntime && this.ctx.dissableRuntime !== true) {
|
50 | this.importModule([[ 'FirescriptRuntime' ]], this.ctx.fireRTModuleName || 'firescript-runtime', transformatedAst)
|
51 | }
|
52 |
|
53 | return transformatedAst
|
54 | }
|
55 |
|
56 | transformItem (ast, index, parent) {
|
57 | const transformatedAst = {}
|
58 | if (ast.FS_skipTransform) {
|
59 | return ast.FS_skipTransform
|
60 | }
|
61 |
|
62 | const transformationFn = (funcs, ast) => {
|
63 | let trans = ast
|
64 | funcs.forEach((fn) => {
|
65 | trans = Array.isArray(trans)
|
66 | ? trans.map(fn)
|
67 | : fn(trans)
|
68 | })
|
69 |
|
70 | return trans
|
71 | }
|
72 |
|
73 | const funcs = this.get(ast.type)
|
74 | if (funcs) {
|
75 | const transformed = transformationFn(funcs, ast)
|
76 | if (Array.isArray(transformed)) {
|
77 | return transformed
|
78 | } else if (transformed !== ast) {
|
79 | ast = transformed
|
80 | }
|
81 | }
|
82 |
|
83 | const keys = Object.keys(ast)
|
84 | for (const key of keys) {
|
85 | if (Array.isArray(ast[key])) {
|
86 | const childs = []
|
87 | ast[key].forEach((item, index, parent) => {
|
88 | if (item && typeof item === 'object') {
|
89 | const transformed = this.transformItem(item, index, parent)
|
90 | if (Array.isArray(transformed)) {
|
91 | transformed.forEach((child) => childs.push(this.transformItem(child)))
|
92 | } else {
|
93 | childs.push(transformed)
|
94 | }
|
95 | } else {
|
96 | childs.push(item)
|
97 | }
|
98 | })
|
99 | transformatedAst[key] = childs
|
100 | } else if (typeof ast[key] === 'object' && ast[key] !== null) {
|
101 | transformatedAst[key] = this.transformItem(ast[key])
|
102 | } else {
|
103 | transformatedAst[key] = ast[key]
|
104 | }
|
105 | }
|
106 |
|
107 | return transformatedAst
|
108 | }
|
109 |
|
110 | importModule (specifiers, moduleName, ast) {
|
111 | const importDeclaration = ASTCreator.importDeclaration(specifiers, moduleName)
|
112 |
|
113 | const runtimeImport = this.transformItem(importDeclaration)
|
114 | ast.body.unshift(Array.isArray(runtimeImport) ? runtimeImport[0] : runtimeImport)
|
115 | }
|
116 | }
|
117 |
|
118 | module.exports = ASTTransformer
|