1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | const fs = require("fs-extra");
|
4 | const path = require("path");
|
5 | const ts = require("typescript");
|
6 | const bearer_state_injector_1 = require("./transformers/bearer-state-injector");
|
7 | const component_tag_name_scoping_1 = require("./transformers/component-tag-name-scoping");
|
8 | const gather_metadata_1 = require("./transformers/gather-metadata");
|
9 | const imports_transformer_1 = require("./transformers/imports-transformer");
|
10 | const navigator_screen_transformer_1 = require("./transformers/navigator-screen-transformer");
|
11 | const prop_bearer_context_injector_1 = require("./transformers/prop-bearer-context-injector");
|
12 | const prop_importer_1 = require("./transformers/prop-importer");
|
13 | const prop_injector_1 = require("./transformers/prop-injector");
|
14 | const reference_id_injector_1 = require("./transformers/reference-id-injector");
|
15 | const replace_intent_decorator_1 = require("./transformers/replace-intent-decorator");
|
16 | const root_component_transformer_1 = require("./transformers/root-component-transformer");
|
17 | const scenario_id_accessor_injector_1 = require("./transformers/scenario-id-accessor-injector");
|
18 | const utils_1 = require("./utils");
|
19 | class Transpiler {
|
20 | constructor(options) {
|
21 | this.rootFileNames = [];
|
22 | this.subscribers = {};
|
23 | this.watchFiles = true;
|
24 | this.buildFolder = '.bearer/views';
|
25 | this.srcFolder = 'views';
|
26 | this.verbose = true;
|
27 | this.files = {};
|
28 | this.metadata = {
|
29 | components: []
|
30 | };
|
31 | this.compilerOptions = {
|
32 | module: ts.ModuleKind.CommonJS
|
33 | };
|
34 | this.emitFiles = () => {
|
35 |
|
36 | this.rootFileNames.forEach(fileName => {
|
37 | this.files[fileName] = { version: 0 };
|
38 |
|
39 | this.emitFile(fileName);
|
40 | if (this.watchFiles) {
|
41 |
|
42 | fs.watchFile(fileName, { persistent: true, interval: 250 }, (curr, prev) => {
|
43 |
|
44 | if (+curr.mtime <= +prev.mtime) {
|
45 | return;
|
46 | }
|
47 |
|
48 | this.files[fileName].version++;
|
49 |
|
50 | this.emitFile(fileName);
|
51 | });
|
52 | }
|
53 | });
|
54 | };
|
55 | this.emitFile = (fileName) => {
|
56 | const output = this.service.getEmitOutput(fileName);
|
57 | if (!output.emitSkipped) {
|
58 | if (this.verbose) {
|
59 | console.log(`Emitting ${fileName}`);
|
60 | }
|
61 | }
|
62 | else {
|
63 | console.log(`Emitting ${fileName} failed`);
|
64 | this.logErrors(fileName);
|
65 | }
|
66 | };
|
67 | this.trigger = (eventName) => {
|
68 | const subscribers = this.subscribers[eventName] || [];
|
69 | subscribers.forEach(callback => {
|
70 | callback();
|
71 | });
|
72 | };
|
73 | Object.assign(this, options);
|
74 | this.ROOT_DIRECTORY = this.ROOT_DIRECTORY || process.cwd();
|
75 | if (options.tagNamePrefix) {
|
76 | this.metadata.prefix = options.tagNamePrefix;
|
77 | }
|
78 | if (options.tagNameSuffix) {
|
79 | this.metadata.suffix = options.tagNameSuffix;
|
80 | }
|
81 | }
|
82 | get transformers() {
|
83 | const verbose = true;
|
84 | return {
|
85 | before: [
|
86 | gather_metadata_1.default({
|
87 | verbose,
|
88 | metadata: this.metadata,
|
89 | outDir: this.BUILD_SRC_DIRECTORY,
|
90 | srcDir: this.ROOT_DIRECTORY
|
91 | }),
|
92 | root_component_transformer_1.default({ verbose, metadata: this.metadata }),
|
93 | reference_id_injector_1.default({ verbose, metadata: this.metadata }),
|
94 | replace_intent_decorator_1.default({ verbose, metadata: this.metadata }),
|
95 | scenario_id_accessor_injector_1.default({ verbose, metadata: this.metadata }),
|
96 | prop_importer_1.default({ verbose, metadata: this.metadata }),
|
97 | prop_injector_1.default({ verbose, metadata: this.metadata }),
|
98 | prop_bearer_context_injector_1.default({ verbose, metadata: this.metadata }),
|
99 | bearer_state_injector_1.default({ verbose, metadata: this.metadata }),
|
100 | navigator_screen_transformer_1.default({ verbose, metadata: this.metadata }),
|
101 | imports_transformer_1.default({ verbose, metadata: this.metadata }),
|
102 | component_tag_name_scoping_1.default({ verbose, metadata: this.metadata }),
|
103 | dumpSourceCode({
|
104 | verbose,
|
105 | srcDirectory: this.VIEWS_DIRECTORY,
|
106 | buildDirectory: this.BUILD_SRC_DIRECTORY
|
107 | })
|
108 | ],
|
109 | after: []
|
110 | };
|
111 | }
|
112 | get BUILD_DIRECTORY() {
|
113 | return path.join(this.ROOT_DIRECTORY, this.buildFolder);
|
114 | }
|
115 | get BUILD_SRC_DIRECTORY() {
|
116 | return path.join(this.BUILD_DIRECTORY, 'src');
|
117 | }
|
118 | get VIEWS_DIRECTORY() {
|
119 | return path.join(this.ROOT_DIRECTORY, this.srcFolder);
|
120 | }
|
121 | run() {
|
122 | this.refresh();
|
123 | if (!this.watchFiles) {
|
124 | this.stop();
|
125 | }
|
126 | }
|
127 | refresh() {
|
128 | this.clearWatchers();
|
129 | const config = ts.readConfigFile(path.join(this.BUILD_DIRECTORY, 'tsconfig.json'), ts.sys.readFile);
|
130 | if (config.error) {
|
131 | throw new Error(config.error.messageText);
|
132 | }
|
133 | const parsed = ts.parseJsonConfigFileContent(config, ts.sys, this.VIEWS_DIRECTORY);
|
134 | this.rootFileNames = parsed.fileNames;
|
135 | if (!this.rootFileNames.length) {
|
136 | console.warn('[BEARER]', 'No file to transpile');
|
137 | }
|
138 | const servicesHost = {
|
139 | getScriptFileNames: () => this.rootFileNames,
|
140 | getScriptVersion: fileName => this.files[fileName] && this.files[fileName].version.toString(),
|
141 | getScriptSnapshot: fileName => {
|
142 | if (!fs.existsSync(fileName)) {
|
143 | return null;
|
144 | }
|
145 | return ts.ScriptSnapshot.fromString(fs.readFileSync(fileName).toString());
|
146 | },
|
147 | getCurrentDirectory: () => process.cwd(),
|
148 | getCompilationSettings: () => this.compilerOptions,
|
149 | getDefaultLibFileName: options => ts.getDefaultLibFilePath(options),
|
150 | getCustomTransformers: () => this.transformers,
|
151 | fileExists: ts.sys.fileExists,
|
152 | readFile: ts.sys.readFile,
|
153 | readDirectory: ts.sys.readDirectory
|
154 | };
|
155 |
|
156 | this.service = ts.createLanguageService(servicesHost, ts.createDocumentRegistry());
|
157 | this.emitFiles();
|
158 | }
|
159 | stop() {
|
160 | this.clearWatchers();
|
161 | this.trigger('STOP');
|
162 | }
|
163 | clearWatchers() {
|
164 | this.rootFileNames.forEach(fileName => {
|
165 | fs.unwatchFile(fileName);
|
166 | });
|
167 | }
|
168 | on(event, callback) {
|
169 | this.subscribers[event] = this.subscribers[event] || [];
|
170 | this.subscribers[event].push(callback);
|
171 | }
|
172 | logErrors(fileName) {
|
173 | let allDiagnostics = this.service
|
174 | .getCompilerOptionsDiagnostics()
|
175 | .concat(this.service.getSyntacticDiagnostics(fileName))
|
176 | .concat(this.service.getSemanticDiagnostics(fileName));
|
177 | allDiagnostics.forEach(diagnostic => {
|
178 | let message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
|
179 | if (diagnostic.file) {
|
180 | let { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
|
181 | console.log(` Error ${diagnostic.file.fileName} (${line + 1},${character +
|
182 | 1}): ${message}`);
|
183 | }
|
184 | else {
|
185 | console.log(` Error: ${message}`);
|
186 | }
|
187 | });
|
188 | }
|
189 | }
|
190 | exports.default = Transpiler;
|
191 | function dumpSourceCode({ srcDirectory, buildDirectory } = {
|
192 | srcDirectory,
|
193 | buildDirectory
|
194 | }) {
|
195 | return _transformContext => {
|
196 | return tsSourceFile => {
|
197 | let outPath = tsSourceFile.fileName
|
198 | .replace(srcDirectory, buildDirectory)
|
199 | .replace(/js$/, 'ts')
|
200 | .replace(/jsx$/, 'tsx');
|
201 | fs.ensureFileSync(outPath);
|
202 | fs.writeFileSync(outPath, utils_1.getSourceCode(tsSourceFile));
|
203 | return tsSourceFile;
|
204 | };
|
205 | };
|
206 | }
|