-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.js
148 lines (122 loc) · 4.81 KB
/
index.js
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
const fs = require('fs');
const program = require('commander');
const kebabcase = require('lodash.kebabcase');
const os = require('os');
const ts = require('byots');
let fileValue;
const dependencyImports = {};
const definedFunctions = {};
const barrelExportDeclarations = [];
const barrelExportAssignments = [];
program
.version('0.1.0')
.arguments('<file>')
.action(function(file) {
fileValue = file;
})
.parse(process.argv)
// read file passed as parameter
const data = fs.readFileSync(fileValue)
// get filename without file ending
const fileName = fileValue.substring(0, fileValue.lastIndexOf('.'));
// create folder with same name as the file (without ending)
if (!fs.existsSync(fileName)) {
fs.mkdirSync(fileName);
}
let content = data.toString();
const sourceFile = ts.createSourceFile(fileValue, content,
ts.ScriptTarget.ES5,
true,
ts.LanguageVariant.Standard
);
parseAllChildren(sourceFile);
// generate import block from outsourced functions
const indexImportBlock = Object.keys(definedFunctions).map(functionName => `import { ${functionName} } from './${kebabcase(functionName)}';`).join(os.EOL);
// create index.ts
fs.writeFile(
fileName + '/index.ts',
indexImportBlock + os.EOL +
barrelExportDeclarations.join('') +
barrelExportAssignments.join('') +
os.EOL
);
// write file on fileName/function-name.ts with imports, comment and exported function
Object.keys(definedFunctions).forEach(functionName => {
const outsourcedContent =
Object.keys(dependencyImports)
// TODO: use a more sophisticated method (check AST for usage)
.filter(importedContent => dependencyImports[importedContent].some(func => definedFunctions[functionName].indexOf(func) > 1))
.join('')
// get relative imports one level higher
.replace(/'\.{2}\//g, `'../../`)
.replace(/'\.\//g, `'../`) +
os.EOL +
// cross-import own files to have all functions available
Object.keys(definedFunctions)
.filter(func => func !== functionName)
// only those that are used
// TODO: use a more sophisticated method (check AST for usage)
.filter(func => definedFunctions[functionName].indexOf(func) > -1)
.map(func => `import { ${func} } from './${kebabcase(func)}';`)
.join(os.EOL) +
os.EOL +
definedFunctions[functionName] + os.EOL + os.EOL +
`export { ${functionName} };` + os.EOL +
`export default { ${functionName} };` + os.EOL;
fs.writeFile(
fileName + '/' + kebabcase(functionName) + '.ts',
outsourcedContent,
err => {
if (err) {
console.error(err);
}
}
);
})
function parseAllChildren(node, depth = 0) {
if (depth === 2) {
const nodeContent = content.substring(node.pos, node.end);
switch (node.kind) {
case ts.SyntaxKind.FunctionDeclaration:
const functionName = node.name.text;
definedFunctions[functionName] = nodeContent;
break;
/*
TODO: implement logic for variable declarations
case ts.SyntaxKind.VariableDeclaration:
break
*/
case ts.SyntaxKind.ImportDeclaration:
let importedDeclarations = [];
if (node.importClause.name) {
// import * as foobar from 'foobar';
importedDeclarations = [node.importClause.name.text];
} else if (node.importClause.namedBindings) {
if (node.importClause.namedBindings.name) {
// import foobar from 'foobar';
importedDeclarations = [node.importClause.namedBindings.name.text];
} else if (node.importClause.namedBindings.elements) {
// import { Foo, Bar} from 'foobar';
importedDeclarations = node.importClause.namedBindings.elements.map(v => v.name.text);
}
}
dependencyImports[nodeContent] = importedDeclarations;
break;
case ts.SyntaxKind.ExportAssignment:
barrelExportAssignments.push(nodeContent);
break;
case ts.SyntaxKind.ExportDeclaration:
barrelExportDeclarations.push(nodeContent);
break;
default:
console.warn('Unexpected element: ', ts.formatSyntaxKind(node.kind), nodeContent, '. Please check the according code and copy it yourself.');
break;
}
} else if (depth > 2) {
// end early if past function layer
return;
}
// recursively handle next layer
depth++;
node.getChildren().forEach(c => parseAllChildren(c, depth));
}