gaffer-generator 1.2.5 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +7 -5
  2. package/cli.js +43 -37
  3. package/lib/argv.js +9 -0
  4. package/lib/create.js +40 -0
  5. package/{src → lib}/generate/directory.js +13 -14
  6. package/{src → lib}/generate/file.js +13 -13
  7. package/{src → lib}/generate/node.js +6 -9
  8. package/lib/generate/root.js +95 -0
  9. package/{src → lib}/templateArgs.js +1 -1
  10. package/lib/utils/contentsDiffer.js +20 -0
  11. package/lib/utils/log.js +26 -0
  12. package/lib/utils/logChange.js +16 -0
  13. package/lib/utils/logError.js +10 -0
  14. package/lib/utils/logRemoval.js +10 -0
  15. package/lib/utils/lowerCaseFirst.js +11 -0
  16. package/lib/utils/normalizeLineEndings.js +8 -0
  17. package/lib/utils/normalizePath.js +10 -0
  18. package/lib/utils/parameterizeString.js +19 -0
  19. package/lib/utils/safeRead.js +17 -0
  20. package/lib/utils/safeWrite.js +23 -0
  21. package/lib/utils.js +16 -0
  22. package/package.json +42 -14
  23. package/.github/dependabot.yml +0 -8
  24. package/.github/workflows/codeql-analysis.yml +0 -67
  25. package/SECURITY.md +0 -15
  26. package/example/sample.json +0 -431
  27. package/example/sample.templateroot/date-parser.ts +0 -10
  28. package/example/sample.templateroot/is-set.ts +0 -3
  29. package/example/sample.templateroot/models/_eachEnum.fileName_.ts +0 -13
  30. package/example/sample.templateroot/models/_eachModel.fileName_.ts +0 -73
  31. package/example/sample.templateroot/models/index.ts +0 -14
  32. package/example/sample.templateroot/services/_eachController.fileName_.ts +0 -82
  33. package/example/sample.templateroot/services/index.ts +0 -11
  34. package/example/sample.templateroot/template.js +0 -413
  35. package/jest.config.js +0 -185
  36. package/src/__mocks__/fs.js +0 -59
  37. package/src/create.js +0 -38
  38. package/src/create.test.js +0 -5
  39. package/src/generate/directory.test.js +0 -5
  40. package/src/generate/file.test.js +0 -5
  41. package/src/generate/node.test.js +0 -5
  42. package/src/generate/root.js +0 -82
  43. package/src/generate/root.test.js +0 -5
  44. package/src/lodash.js +0 -17205
  45. package/src/utils.js +0 -179
  46. package/src/utils.test.js +0 -146
@@ -1,14 +0,0 @@
1
- // ------------------------------------------------------------------------------
2
- // <auto-generated>
3
- // This code was generated by a tool using the template near this directory.
4
- // Please see this solution for more details: Codegen\Codegen.sln
5
- // Changes to this file may cause incorrect behavior and will be lost if
6
- // the code is regenerated.
7
- // </auto-generated>
8
- // ------------------------------------------------------------------------------<%
9
- enums.forEach(item => { %>
10
- export { <%= item.name %> } from './<%= item.fileName %>';<%
11
- });
12
- models.forEach(model => { %>
13
- export { <%= model.name %> } from '<%= utils.customExists(model) ? '../custom/' : './' %><%= model.fileName %>';<%
14
- }); %>
@@ -1,82 +0,0 @@
1
- // ------------------------------------------------------------------------------
2
- // <auto-generated>
3
- // This code was generated by a tool using the template near this directory.
4
- // Please see this solution for more details: Codegen\Codegen.sln
5
- // Changes to this file may cause incorrect behavior and will be lost if
6
- // the code is regenerated.
7
- // </auto-generated>
8
- // ------------------------------------------------------------------------------
9
- import { HttpClient } from '@angular/common/http';
10
- import { Injectable } from '@angular/core';
11
- import { Observable, of } from 'rxjs';
12
- import { catchError, map, mergeMap } from 'rxjs/operators';
13
- import {<%
14
- dependencies.forEach((dependency, index) => { %>
15
- <%= dependency %><%= index + 1 !== dependencies.length ? ',' : '' %><%
16
- }); %> } from '../models';
17
-
18
- @Injectable({
19
- providedIn: 'root'
20
- })
21
- export class <%= name %>Service {
22
- public name = '<%= name %>';
23
-
24
- // TODO: Specify the proper dependencies for making HTTP calls.
25
- constructor(protected headerInfo:HeaderInfoService,
26
- protected http:HttpClient,
27
- protected serviceCache:ServiceCacheService,
28
- protected settings:SettingsService) {
29
- }
30
- <% methods.forEach(method => { %>
31
- public <%= utils.translateReserved(utils.lowerCaseFirst(method.name)) %>(<%=
32
- utils.hasParams(method) ? 'args' + (utils.hasRequiredParams(method) ? '' : '?') + ':I' + utils.translateReserved(method.name) + 'Args' : ''
33
- %>)
34
- :Observable<%= method.returnType ? '<' + utils.parseType(method.returnType) + '>' : '<any>' %> {<%
35
- if (utils.hasParams(method) && !utils.hasRequiredParams(method)) { %>
36
- if (!args) {
37
- args = {};
38
- }<%
39
- } %><%=
40
- utils.protectPath(method) %>
41
- let url = this.settings.apiServer + `<%= utils.parsePath(method) %>`;<%=
42
- utils.outputQuery(method.parameters) %>
43
- let httpRequest = this.http
44
- .request<%= method.returnType && !utils.isString(method.returnType) ? '<' + utils.parseType(method.returnType) + '>' : '' %>('<%= utils.httpMethodToString(method) %>', url, {<%=
45
- utils.outputBody(method) %>
46
- headers: this.headerInfo.getApiHeaders('<%= utils.httpMethodToString(method) %>', this.settings.bearerToken),
47
- responseType: '<%= method.returnType === null || utils.isString(method.returnType) ? 'text' : 'json' %>'
48
- })
49
- .pipe(<% if (method.returnType) {%>
50
- map((json:any) => {<% if (utils.enableCaching(name, method.name)) { %>
51
- if (json) {
52
- this.serviceCache.store(url, json);
53
- }<% } %>
54
- if (json === null || json === undefined) {
55
- return null;
56
- }
57
- return <%= utils.fromJSON(method.returnType) %>;
58
- }),<% } %>
59
- catchError(err => this.handleError(err))
60
- );<%
61
- if (utils.enableCaching(name, method.name)) { %>
62
- return this.serviceCache
63
- .retrieve<%= method.returnType ? '<' + utils.parseType(method.returnType) + '>' : '<any>' %>(url)
64
- .pipe(
65
- mergeMap(json => json ? of(<%= utils.fromJSON(method.returnType) %>) : httpRequest)
66
- );<% } else { %>
67
- return httpRequest;<% } %>
68
- }
69
- <% }); %>
70
- }
71
- <%
72
- methods.filter(utils.hasParams).forEach(method => { %>
73
-
74
- export interface I<%= utils.translateReserved(method.name) %>Args {<%= utils.parseParams(method.parameters) %>}<%
75
- });
76
- %>
77
-
78
- export const enum <%= name %>Method {<%
79
- methods.forEach(method => { %>
80
- <%= utils.translateReserved(utils.lowerCaseFirst(method.name)) %> = '<%= utils.translateReserved(utils.lowerCaseFirst(method.name)) %>',<%
81
- }); %>
82
- }
@@ -1,11 +0,0 @@
1
- // ------------------------------------------------------------------------------
2
- // <auto-generated>
3
- // This code was generated by a tool using the template near this directory.
4
- // Please see this solution for more details: Codegen\Codegen.sln
5
- // Changes to this file may cause incorrect behavior and will be lost if
6
- // the code is regenerated.
7
- // </auto-generated>
8
- // ------------------------------------------------------------------------------<%
9
- controllers.forEach(item => { %>
10
- export { <%= item.name %>Service } from './<%= item.fileName %>';<%
11
- }); %>
@@ -1,413 +0,0 @@
1
- const path = require('path'),
2
- fs = require('fs');
3
-
4
- // Download (or fake-download) the necessary metadata:
5
- exports.download = () => new Promise(resolve => resolve(require('../sample.json')))
6
- .then(json => createFileNames(json));
7
- // or: require('node-fetch').fetch('https://some-api.com/swagger')
8
- // .then(res => res.json()),
9
-
10
- // Set the target directory:
11
- exports.into = '../sample.output/';
12
-
13
- // Customize the templates (if desired):
14
- // exports.templateArgs = {
15
- // evaluate: /(?:\/\*_|<#)([\s\S]+?)(?:_\*\/|#>)/g,
16
- // escape: /(?:\/\*_|<#)-([\s\S]+?)(?:_\*\/|#>)/g,
17
- // interpolate: /(?:\/\*_|<#)=([\s\S]+?)(?:_\*\/|#>)/g,
18
- // };
19
-
20
- // Map the generated code one last time for clean-up:
21
- exports.mapContents = mapContents;
22
-
23
- // That's it, you're all configured!
24
- // Everything below will be used by the templates to maintain your fancy new code.
25
-
26
- /*
27
- Metadata types (not relevant for Swagger).
28
- */
29
- let MetaTypes = {
30
- Model: 0,
31
- Enum: 1,
32
- Object: 2,
33
- Array: 3,
34
- Dictionary: 4,
35
- Boolean: 5,
36
- Number: 6,
37
- String: 7,
38
- },
39
- MetaParameterSource = {
40
- Body: 0,
41
- Uri: 1,
42
- Query: 2,
43
- },
44
- MetaNumberFormat = {
45
- Byte: 0,
46
- SByte: 1,
47
- Int16: 2,
48
- UInt16: 3,
49
- Int32: 4,
50
- UInt32: 5,
51
- Int64: 6,
52
- UInt64: 7,
53
- Float: 8,
54
- Double: 9,
55
- Decimal: 10,
56
- },
57
- MetaStringFormat = {
58
- String: 0,
59
- Byte: 1,
60
- DateTime: 2,
61
- UUID: 3,
62
- },
63
- MetaHttpMethod = {
64
- Post: 0,
65
- Get: 1,
66
- Put: 2,
67
- Delete: 3,
68
- Head: 4,
69
- Options: 5,
70
- };
71
-
72
- /*
73
- Utilities for template.
74
- */
75
- exports.parseType = parseType;
76
- exports.copyProperties = copyProperties;
77
- exports.fromJSON = fromJSON;
78
- exports.httpMethodToString = httpMethodToString;
79
- exports.parseParams = parseParams;
80
- exports.parsePath = parsePath;
81
- exports.protectPath = protectPath;
82
- exports.outputQuery = outputQuery;
83
- exports.outputBody = outputBody;
84
- exports.lowerCaseFirst = lowerCaseFirst;
85
- exports.translateReserved = translateReserved;
86
- exports.hasParams = hasParams;
87
- exports.hasRequiredParams = hasRequiredParams;
88
- exports.enableCaching = enableCaching;
89
- exports.isString = isString;
90
- exports.toFileName = toFileName;
91
- exports.customExists = customExists;
92
- exports.handleBase = handleBase;
93
- exports.MetaTypes = MetaTypes;
94
- exports.MetaStringFormat = MetaStringFormat;
95
-
96
- /*
97
- Implementation.
98
- */
99
- function parseType(def) {
100
- return typeToString(def.type || def);
101
- }
102
-
103
- function typeToString(type) {
104
- // type = something like {
105
- // "typeId": 0,
106
- // "nullable": false,
107
- // "name": "AddressType"
108
- // }
109
- return `${typeToStringInner(type)}`;
110
- }
111
-
112
- function typeToStringInner(type) {
113
- switch (type.typeId) {
114
- case MetaTypes.Model:
115
- case MetaTypes.Enum:
116
- return type.name;
117
- case MetaTypes.Object:
118
- return 'any';
119
- case MetaTypes.Array:
120
- return `${typeToString(type.of)}[]`;
121
- case MetaTypes.Dictionary:
122
- return `{ [p:${typeToString(type.keyType)}]: ${typeToString(type.valueType)} }`;
123
- case MetaTypes.Boolean:
124
- return 'boolean';
125
- case MetaTypes.Number:
126
- switch (type.formatId) {
127
- case MetaNumberFormat.Byte:
128
- return 'byte';
129
- case MetaNumberFormat.SByte:
130
- return 'sbyte';
131
- case MetaNumberFormat.Int16:
132
- case MetaNumberFormat.UInt16:
133
- case MetaNumberFormat.Int32:
134
- case MetaNumberFormat.UInt32:
135
- case MetaNumberFormat.Int64:
136
- case MetaNumberFormat.UInt64:
137
- case MetaNumberFormat.Float:
138
- case MetaNumberFormat.Double:
139
- case MetaNumberFormat.Decimal:
140
- return 'number';
141
- default:
142
- console.error(type);
143
- throw new Error('Encountered unhandled property type number format id in typeToStringInner: ' + type.formatId);
144
- }
145
- case MetaTypes.String:
146
- switch (type.formatId) {
147
- case MetaStringFormat.String:
148
- return 'string';
149
- case MetaStringFormat.Byte:
150
- return 'byte';
151
- case MetaStringFormat.DateTime:
152
- return 'string';
153
- case MetaStringFormat.UUID:
154
- return 'string';
155
- default:
156
- console.error(type);
157
- throw new Error('Encountered unhandled property type string format id in typeToStringInner: ' + type.formatId);
158
- }
159
- default:
160
- console.error(type);
161
- throw new Error('Encountered unhandled property type id in typeToStringInner: ' + type.typeId);
162
- }
163
- }
164
-
165
- function copyProperties(propertyName, type, depth) {
166
- let key = lowerCaseFirst(propertyName),
167
- directAssignment = 'to.' + key + ' = from.' + key;
168
- switch (type.typeId) {
169
- case MetaTypes.Model:
170
- return 'to.' + key + ' = new ' + type.name + '(from.' + key + ');';
171
- case MetaTypes.Enum:
172
- return directAssignment + ' as ' + type.name + ';';
173
- case MetaTypes.Array:
174
- if (type.of.typeId === MetaTypes.Model) {
175
- return directAssignment + '.map(\n' + depthToTabs(depth) + '\tinstance => new ' + type.of.name + '(instance));';
176
- }
177
- return directAssignment + '.slice() as ' + typeToString(type.of) + '[];';
178
- case MetaTypes.Dictionary:
179
- return copyDictionaryProperties(key, type.valueType, depth || 1);
180
- default:
181
- return directAssignment + ' as ' + typeToString(type) + ';';
182
- }
183
- }
184
-
185
- function copyDictionaryProperties(key, valueType, depth) {
186
- return tabify([
187
- 'to.' + key + ' = Object.assign({}, from.' + key + ');',
188
- 'for (let key' + depth + ' in from.' + key + ') {',
189
- '\tif (from.' + key + '.hasOwnProperty(key' + depth + ')) {',
190
- '\t\t' + copyProperties(key + '[key' + depth + ']', valueType, depth + 1),
191
- '\t}',
192
- '}',
193
- ], depthToTabs(depth));
194
- }
195
-
196
- function depthToTabs(depth) {
197
- let tabs = '\t\t\t';
198
- for (let i = 1; i < depth; i++) {
199
- tabs += '\t\t';
200
- }
201
- return tabs;
202
- }
203
-
204
- function fromJSON(type, key) {
205
- if (!key) {
206
- key = 'json';
207
- }
208
-
209
- switch (type.typeId) {
210
- case MetaTypes.Model:
211
- return type.name + '.fromJSON(' + key + ')';
212
- case MetaTypes.Enum:
213
- return key + ' as ' + type.name;
214
- case MetaTypes.Array:
215
- if (type.of.typeId === MetaTypes.Model) {
216
- return key + '.map(' + type.of.name + '.fromJSON)';
217
- }
218
- return key + ' as ' + typeToString(type.of) + '[]';
219
- case MetaTypes.Dictionary:
220
- return copyDictionaryProperties(key, type.valueType, 1);
221
- default:
222
- return key + ' as ' + typeToString(type);
223
- }
224
-
225
- }
226
-
227
- function toJSON(type, key) {
228
- if (!key) {
229
- key = 'this';
230
- }
231
-
232
- switch (type.typeId) {
233
- case MetaTypes.Model:
234
- return key + '.toJSON()';
235
- case MetaTypes.Enum:
236
- return key;
237
- case MetaTypes.Array:
238
- if (type.of.typeId === MetaTypes.Model) {
239
- return key + '.map(item => item.toJSON())';
240
- }
241
- return key;
242
- case MetaTypes.Dictionary:
243
- return key;
244
- default:
245
- return key;
246
- }
247
- }
248
-
249
- function httpMethodToString(method) {
250
- return Object.keys(MetaHttpMethod)[method.httpMethodId].toUpperCase();
251
- }
252
-
253
- function parseParams(params) {
254
- if (!params) {
255
- return '';
256
- }
257
- return '\n\t' + params
258
- .map(function(param) {
259
- if (!param.type) {
260
- console.log('WARNING: Parameter without a type found:');
261
- console.log(param);
262
- console.trace();
263
- }
264
- return param.name.replace(/\./g, '_') + (param.optional ? '?' : '') + ':' + typeToString(param.type);
265
- })
266
- .join(';\n\t') + ';\n';
267
- }
268
-
269
- function parsePath(method) {
270
- let path = method.path;
271
- return path.replace(/\{([^}]+)}/g, (match, name) => '${args.' + name + '}');
272
- }
273
-
274
- function protectPath(method) {
275
- let path = method.path,
276
- retVal = [],
277
- matches = path.match(/\{([^}]+)}/g) || [];
278
- for (let i = 0; i < matches.length; i++) {
279
- let match = matches[i].slice(1, -1),
280
- param = method.parameters.find(param => param.name === match);
281
- if (param) {
282
- retVal.push('\n\t\tif (args.' + param.name + ' === undefined || args.' + param.name + ' === null) {\n\t\t\targs.' + param.name + ' = <any>\'\';\n\t\t}');
283
- }
284
- }
285
- return retVal.join('');
286
- }
287
-
288
- function outputQuery(params) {
289
- let queryParams = params.find(param => param.sourceId === MetaParameterSource.Query);
290
- if (!queryParams || !queryParams.length) {
291
- return '';
292
- }
293
- let retVal = '\n\t\tlet qp = [];';
294
- for (let i = 0; i < queryParams.length; i++) {
295
- let param = queryParams[i];
296
- retVal += '\n\t\tif (IsSpecified(args.' + param.name.replace(/\./g, '_') + ')) {' +
297
- '\n\t\t\tqp.push(\'' + param.name + '=\'\n\t\t\t\t+ encodeURIComponent(String(args.' + param.name.replace(/\./g, '_') + ')));' +
298
- '\n\t\t}';
299
- }
300
- retVal += '\n\t\tif (qp.length) {';
301
- retVal += '\n\t\t\turl += \'?\' + qp.join(\'&\');';
302
- retVal += '\n\t\t}';
303
- return retVal;
304
- }
305
-
306
- function outputBody(method) {
307
- let bodyParam = method.parameters.find(parameter => parameter.sourceId === MetaParameterSource.Body),
308
- requiresBody = [MetaHttpMethod.Post, MetaHttpMethod.Put].indexOf(method.httpMethodId) >= 0,
309
- prefix = '\n\t\t\t\tbody: ';
310
-
311
- if (!bodyParam) {
312
- return requiresBody ? prefix + '\'{}\',' : null;
313
- }
314
- return prefix + 'JSON.stringify(args.' + toJSON(bodyParam.type, bodyParam.name) + '),';
315
- }
316
-
317
- function lowerCaseFirst(val) {
318
- if (!val || !val.toLowerCase) {
319
- return val;
320
- }
321
- return val[0].toLowerCase() + val.substr(1);
322
- }
323
-
324
- function translateReserved(name) {
325
- switch (name) {
326
- case 'delete':
327
- return 'remove';
328
- case 'new':
329
- return 'blank';
330
- case 'switch':
331
- return 'change';
332
- default:
333
- return name;
334
- }
335
- }
336
-
337
- function hasParams(m) {
338
- return m.parameters && m.parameters.length;
339
- }
340
-
341
- function hasRequiredParams(m) {
342
- if (!m || !m.parameters || !m.parameters.length) {
343
- return false;
344
- }
345
- return m.parameters
346
- .filter(function(param) {
347
- return !param.optional;
348
- })
349
- .length > 0;
350
- }
351
-
352
- function tabify(lines, tabs) {
353
- return lines.join('\n' + tabs);
354
- }
355
-
356
- function enableCaching(serviceName, methodName) {
357
- // TODO: caching is usually a good candidate for configuration, then generation.
358
- return false;
359
- }
360
-
361
- function isString(param) {
362
- return param && param.typeId === MetaTypes.String;
363
- }
364
-
365
- function createFileNames(sdk) {
366
- ['controllers', 'models', 'enums'].forEach(type => {
367
- sdk[type].forEach(instance => {
368
- instance.fileName = toFileName(instance.name);
369
- if (type === 'controllers') {
370
- instance.fileName += '.service';
371
- }
372
- });
373
- });
374
- return sdk;
375
- }
376
-
377
- function toFileName(name) {
378
- return lowerCaseFirst(name)
379
- .replace(/[a-z][A-Z]/g, letters => letters[0] + '-' + letters[1].toLowerCase())
380
- .toLowerCase();
381
- }
382
-
383
- function mapContents(newContents, instanceData, item) {
384
- return cleanUpImports(newContents);
385
- }
386
-
387
- function cleanUpImports(str) {
388
- return str
389
- .replace(/import {\s*([^,\s}]+)\s*}[^;]+;\r?\n/g, (val, ns) =>
390
- str.match(new RegExp('[^a-zA-Z]' + ns + '[^a-zA-Z]', 'g')).length <= 1 ? '' : val)
391
- .replace(/\r\n/g, '\n')
392
- .replace(/\n{3,}/g, '\n\n');
393
- }
394
-
395
- let customExistsHash = {};
396
-
397
- function customExists(Model) {
398
- const ref = path.resolve(
399
- path.join(
400
- __dirname,
401
- exports.into,
402
- 'custom',
403
- Model.fileName + '.ts',
404
- ),
405
- );
406
- return customExistsHash[ref] !== undefined
407
- ? customExistsHash[ref]
408
- : customExistsHash[ref] = fs.existsSync(ref);
409
- }
410
-
411
- function handleBase(Model) {
412
- return Model.name + (customExists(Model) ? 'Base' : '');
413
- }