UNPKG

9.9 kBJavaScriptView Raw
1"use strict";
2var __importDefault = (this && this.__importDefault) || function (mod) {
3 return (mod && mod.__esModule) ? mod : { "default": mod };
4};
5Object.defineProperty(exports, "__esModule", { value: true });
6/* tslint:disable:variable-name */
7const fs_1 = __importDefault(require("fs"));
8const path_1 = __importDefault(require("path"));
9const utils_1 = require("@terascope/utils");
10const shims_1 = require("./operations/shims");
11class OperationLoader {
12 constructor(options = {}) {
13 this.options = utils_1.cloneDeep(options);
14 this.availableExtensions = availableExtensions();
15 }
16 find(name, assetIds) {
17 let filePath = null;
18 const findCodeFn = this.findCode(name);
19 const findCodeByConvention = (basePath, subfolders) => {
20 if (!basePath)
21 return;
22 if (!fs_1.default.existsSync(basePath))
23 return;
24 if (!subfolders || !subfolders.length)
25 return;
26 subfolders.forEach((folder) => {
27 const folderPath = path_1.default.join(basePath, folder);
28 if (!filePath && fs_1.default.existsSync(folderPath)) {
29 filePath = findCodeFn(folderPath);
30 }
31 });
32 };
33 findCodeByConvention(this.options.assetPath, assetIds);
34 if (!filePath) {
35 findCodeByConvention(this.getBuiltinDir(), ['.']);
36 }
37 if (!filePath) {
38 findCodeByConvention(this.options.terasliceOpPath, ['readers', 'processors']);
39 }
40 if (!filePath) {
41 filePath = this.resolvePath(name);
42 }
43 return filePath;
44 }
45 /**
46 * Load any LegacyOperation
47 * DEPRECATED to accommadate for new Job APIs,
48 * use loadReader, or loadProcessor
49 */
50 load(name, assetIds) {
51 const codePath = this.findOrThrow(name, assetIds);
52 try {
53 return this.require(codePath);
54 }
55 catch (err) {
56 throw new Error(`Failure loading module: ${name}, error: ${utils_1.parseError(err, true)}`);
57 }
58 }
59 loadProcessor(name, assetIds) {
60 const codePath = this.findOrThrow(name, assetIds);
61 if (this.isLegacyProcessor(codePath)) {
62 return this.shimLegacyProcessor(name, codePath);
63 }
64 let Processor;
65 let Schema;
66 let API;
67 try {
68 Processor = this.require(codePath, 'processor');
69 }
70 catch (err) {
71 throw new Error(`Failure loading processor from module: ${name}, error: ${utils_1.parseError(err, true)}`);
72 }
73 try {
74 Schema = this.require(codePath, 'schema');
75 }
76 catch (err) {
77 throw new Error(`Failure loading schema from module: ${name}, error: ${utils_1.parseError(err, true)}`);
78 }
79 try {
80 API = this.require(codePath, 'api');
81 }
82 catch (err) {
83 }
84 return {
85 // @ts-ignore
86 Processor,
87 // @ts-ignore
88 Schema,
89 API,
90 };
91 }
92 loadReader(name, assetIds) {
93 const codePath = this.findOrThrow(name, assetIds);
94 if (this.isLegacyReader(codePath)) {
95 return this.shimLegacyReader(name, codePath);
96 }
97 let Fetcher;
98 let Slicer;
99 let Schema;
100 let API;
101 try {
102 Slicer = this.require(codePath, 'slicer');
103 }
104 catch (err) {
105 throw new Error(`Failure loading slicer from module: ${name}, error: ${utils_1.parseError(err, true)}`);
106 }
107 try {
108 Fetcher = this.require(codePath, 'fetcher');
109 }
110 catch (err) {
111 throw new Error(`Failure loading fetcher from module: ${name}, error: ${utils_1.parseError(err, true)}`);
112 }
113 try {
114 Schema = this.require(codePath, 'schema');
115 }
116 catch (err) {
117 throw new Error(`Failure loading schema from module: ${name}, error: ${utils_1.parseError(err, true)}`);
118 }
119 try {
120 API = this.require(codePath, 'api');
121 }
122 catch (err) {
123 }
124 return {
125 // @ts-ignore
126 Slicer,
127 // @ts-ignore
128 Fetcher,
129 // @ts-ignore
130 Schema,
131 API,
132 };
133 }
134 loadAPI(name, assetIds) {
135 const [apiName] = name.split(':');
136 const codePath = this.findOrThrow(apiName, assetIds);
137 let API;
138 try {
139 API = this.require(codePath, 'api');
140 }
141 catch (err) {
142 }
143 let Observer;
144 try {
145 Observer = this.require(codePath, 'observer');
146 }
147 catch (err) {
148 }
149 let Schema;
150 try {
151 Schema = this.require(codePath, 'schema');
152 }
153 catch (err) {
154 throw new Error(`Failure loading schema from module: ${apiName}, error: ${utils_1.parseError(err, true)}`);
155 }
156 if (Observer == null && API == null) {
157 throw new Error(`Failure to load api module: ${apiName}, requires at least an api.js or observer.js`);
158 }
159 else if (Observer != null && API != null) {
160 throw new Error(`Failure to load api module: ${apiName}, required only one api.js or observer.js`);
161 }
162 const type = API != null ? 'api' : 'observer';
163 return {
164 // @ts-ignore
165 API: API || Observer,
166 // @ts-ignore
167 Schema,
168 type,
169 };
170 }
171 findOrThrow(name, assetIds) {
172 this.verifyOpName(name);
173 const codePath = this.find(name, assetIds);
174 if (!codePath) {
175 throw new Error(`Unable to find module for operation: ${name}`);
176 }
177 return codePath;
178 }
179 isLegacyReader(codePath) {
180 return !this.fileExists(codePath, 'fetcher') && !this.fileExists(codePath, 'slicer');
181 }
182 shimLegacyReader(name, codePath) {
183 try {
184 return shims_1.readerShim(this.require(codePath));
185 }
186 catch (err) {
187 throw new Error(`Failure loading reader: ${name}, error: ${utils_1.parseError(err, true)}`);
188 }
189 }
190 isLegacyProcessor(codePath) {
191 return !this.fileExists(codePath, 'processor');
192 }
193 shimLegacyProcessor(name, codePath) {
194 try {
195 return shims_1.processorShim(this.require(codePath));
196 }
197 catch (err) {
198 throw new Error(`Failure loading processor: ${name}, error: ${utils_1.parseError(err, true)}`);
199 }
200 }
201 fileExists(dir, name) {
202 const filePaths = this.availableExtensions.map((ext) => {
203 return path_1.default.format({
204 dir,
205 name,
206 ext,
207 });
208 });
209 return filePaths.some((filePath) => fs_1.default.existsSync(filePath));
210 }
211 require(dir, name) {
212 const filePaths = name ? this.availableExtensions.map((ext) => {
213 return path_1.default.format({
214 dir,
215 name,
216 ext,
217 });
218 }) : [dir];
219 let err;
220 for (const filePath of filePaths) {
221 try {
222 const mod = require(filePath);
223 return mod.default || mod;
224 }
225 catch (_err) {
226 err = _err;
227 }
228 }
229 if (err) {
230 throw err;
231 }
232 else {
233 throw new Error(`Unable to find module at paths: ${filePaths.join(', ')}`);
234 }
235 }
236 resolvePath(filePath) {
237 if (fs_1.default.existsSync(filePath))
238 return filePath;
239 try {
240 return require.resolve(filePath);
241 }
242 catch (err) {
243 return null;
244 }
245 }
246 verifyOpName(name) {
247 if (!utils_1.isString(name)) {
248 throw new TypeError('Please verify that the "_op" name exists for each operation');
249 }
250 }
251 findCode(name) {
252 let filePath = null;
253 const codeNames = this.availableExtensions.map((ext) => {
254 return path_1.default.format({
255 name,
256 ext,
257 });
258 });
259 const allowedNames = utils_1.uniq([name, ...codeNames]);
260 const invalid = [
261 'node_modules',
262 ...ignoreDirectories(),
263 ];
264 const findCode = (rootDir) => {
265 const fileNames = fs_1.default.readdirSync(rootDir)
266 .filter((fileName) => !invalid.includes(fileName));
267 for (const fileName of fileNames) {
268 if (filePath)
269 break;
270 const nextPath = path_1.default.join(rootDir, fileName);
271 // if name is same as fileName/dir then we found it
272 if (allowedNames.includes(fileName)) {
273 filePath = this.resolvePath(nextPath);
274 }
275 if (!filePath && this.isDir(nextPath)) {
276 filePath = findCode(nextPath);
277 }
278 }
279 return filePath;
280 };
281 return findCode;
282 }
283 isDir(filePath) {
284 return fs_1.default.statSync(filePath).isDirectory();
285 }
286 getBuiltinDir() {
287 if (this.availableExtensions.includes('.ts')) {
288 return path_1.default.join(__dirname, 'builtin');
289 }
290 return path_1.default.join(__dirname, '..', '..', 'dist', 'src', 'builtin');
291 }
292}
293exports.OperationLoader = OperationLoader;
294function availableExtensions() {
295 // populated by teraslice Jest configuration
296 // @ts-ignore
297 return global.availableExtensions ? global.availableExtensions : ['.js'];
298}
299function ignoreDirectories() {
300 // populated by teraslice Jest configuration
301 // @ts-ignore
302 return global.ignoreDirectories || [];
303}
304//# sourceMappingURL=operation-loader.js.map
\No newline at end of file