diff --git a/.babelrc.js b/.babelrc.js index d3303619..eacd411c 100644 --- a/.babelrc.js +++ b/.babelrc.js @@ -1,3 +1,5 @@ +'use strict'; + module.exports = { presets: [ '@babel/preset-env', diff --git a/.gitignore b/.gitignore index 208ac7c2..57cdca36 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ junit.xml .vscode *.iml dist +src/**/*.js archive coverage test/result diff --git a/package.json b/package.json index d249f690..1d69823e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "openapi-typescript-codegen", - "version": "0.2.9", + "version": "0.3.0", "description": "NodeJS library that generates Typescript or Javascript clients based on the OpenAPI specification.", "author": "Ferdi Koomen", "homepage": "https://github.com/ferdikoomen/openapi-typescript-codegen", @@ -41,17 +41,17 @@ "bin/index.js", "dist/index.js", "dist/**/*.js", - "src/templates/**/*.hbs", + "src/templates/**/*.js", "src/templates/**/*.ts" ], "scripts": { - "clean": "rimraf ./dist ./test/result ./coverage", - "build": "tsc", - "run": "tsc && node ./test/index.js", - "test": "tsc && jest", - "test:update": "tsc && jest --updateSnapshot", - "test:watch": "tsc && jest --watch", - "test:coverage": "tsc && jest --coverage", + "clean": "rimraf ./dist ./src/**/*.js ./test/result ./coverage", + "build": "tsc && node ./precompile.js", + "run": "npm run build && node ./test/index.js", + "test": "npm run build && jest", + "test:update": "npm run build && jest --updateSnapshot", + "test:watch": "npm run build && jest --watch", + "test:coverage": "npm run builds && jest --coverage", "eslint": "eslint \"./src/**/*.ts\"", "eslint:fix": "eslint \"./src/**/*.ts\" --fix", "prettier": "prettier \"./src/**/*.ts\" --check", diff --git a/precompile.js b/precompile.js new file mode 100644 index 00000000..a447eda2 --- /dev/null +++ b/precompile.js @@ -0,0 +1,32 @@ +'use strict'; + +const Handlebars = require('handlebars'); +const glob = require('glob'); +const fs = require('fs'); +const os = require('os'); + +glob.sync('./src/templates/**/*.hbs').forEach(file => { + // Read handlebars template as string + const template = fs.readFileSync(file, 'utf8').toString().trim(); + + // Precompile template to spec file, according to Handlebars this spec + // should be readable by a client, however it does not contain an export. + const templateSpec = Handlebars.precompile(template, { + strict: true, + noEscape: true, + preventIndent: true, + knownHelpersOnly: true, + knownHelpers: { + equals: true, + notEquals: true, + }, + }); + + // Wrap the spec with an export statement, so we can import this using require. + const module = `'use strict'${os.EOL}module.exports = ${templateSpec};`; + + // Write javascript module, this is the file we will import in the generator. + // This is much faster because we dont need to compile templates on the fly, + // plus we can load the handlebars/runtime which is quite lightweight. + fs.writeFileSync(file.replace('.hbs', '.js'), module); +}); diff --git a/src/utils/readHandlebarsTemplate.spec.ts b/src/utils/readHandlebarsTemplate.spec.ts deleted file mode 100644 index 2f940548..00000000 --- a/src/utils/readHandlebarsTemplate.spec.ts +++ /dev/null @@ -1,20 +0,0 @@ -import * as fs from 'fs'; - -import { readHandlebarsTemplate } from './readHandlebarsTemplate'; - -jest.mock('fs'); - -const fsExistsSync = fs.existsSync as jest.MockedFunction; -const fsReadFileSync = fs.readFileSync as jest.MockedFunction; - -describe('readHandlebarsTemplate', () => { - it('should read the template', () => { - fsExistsSync.mockReturnValue(true); - fsReadFileSync.mockReturnValue('{{{message}}}'); - - const template = readHandlebarsTemplate('/'); - - expect(template).toBeDefined(); - expect(template({ message: 'Hello World!' })).toEqual('Hello World!'); - }); -}); diff --git a/src/utils/readHandlebarsTemplate.ts b/src/utils/readHandlebarsTemplate.ts index 898686bf..64b4d0b4 100644 --- a/src/utils/readHandlebarsTemplate.ts +++ b/src/utils/readHandlebarsTemplate.ts @@ -1,21 +1,11 @@ -import * as fs from 'fs'; -import * as Handlebars from 'handlebars'; +import * as Handlebars from 'handlebars/runtime'; /** * Read and compile the Handlebars template. * @param filePath */ export function readHandlebarsTemplate(filePath: string): Handlebars.TemplateDelegate { - const template = fs.readFileSync(filePath, 'utf8').toString().trim(); + const template = require(filePath); - return Handlebars.compile(template, { - strict: true, - noEscape: true, - preventIndent: true, - knownHelpersOnly: true, - knownHelpers: { - equals: true, - notEquals: true, - }, - }); + return Handlebars.template(template); } diff --git a/src/utils/readHandlebarsTemplates.spec.ts b/src/utils/readHandlebarsTemplates.spec.ts deleted file mode 100644 index d02a3ca1..00000000 --- a/src/utils/readHandlebarsTemplates.spec.ts +++ /dev/null @@ -1,27 +0,0 @@ -import * as fs from 'fs'; - -import { readHandlebarsTemplates } from './readHandlebarsTemplates'; - -jest.mock('fs'); - -const fsExistsSync = fs.existsSync as jest.MockedFunction; -const fsReadFileSync = fs.readFileSync as jest.MockedFunction; - -describe('readHandlebarsTemplates', () => { - it('should read the templates', () => { - fsExistsSync.mockReturnValue(true); - fsReadFileSync.mockReturnValue('{{{message}}}'); - - const template = readHandlebarsTemplates(); - - expect(template).toBeDefined(); - expect(template.index).toBeDefined(); - expect(template.model).toBeDefined(); - expect(template.service).toBeDefined(); - expect(template.settings).toBeDefined(); - expect(template.index({ message: 'Hello World!' })).toEqual('Hello World!'); - expect(template.model({ message: 'Hello World!' })).toEqual('Hello World!'); - expect(template.service({ message: 'Hello World!' })).toEqual('Hello World!'); - expect(template.settings({ message: 'Hello World!' })).toEqual('Hello World!'); - }); -}); diff --git a/src/utils/readHandlebarsTemplates.ts b/src/utils/readHandlebarsTemplates.ts index 775b6b09..61041ea6 100644 --- a/src/utils/readHandlebarsTemplates.ts +++ b/src/utils/readHandlebarsTemplates.ts @@ -1,4 +1,4 @@ -import * as Handlebars from 'handlebars'; +import * as Handlebars from 'handlebars/runtime'; import * as path from 'path'; import { readHandlebarsTemplate } from './readHandlebarsTemplate'; @@ -24,41 +24,41 @@ export function readHandlebarsTemplates(): Templates { registerHandlebarHelpers(); const templates: Templates = { - index: readHandlebarsTemplate(resolveTemplate('index.hbs')), - model: readHandlebarsTemplate(resolveTemplate('model.hbs')), - schema: readHandlebarsTemplate(resolveTemplate('schema.hbs')), - service: readHandlebarsTemplate(resolveTemplate('service.hbs')), - settings: readHandlebarsTemplate(resolveTemplate('core/OpenAPI.hbs')), + index: readHandlebarsTemplate(resolveTemplate('index.js')), + model: readHandlebarsTemplate(resolveTemplate('model.js')), + schema: readHandlebarsTemplate(resolveTemplate('schema.js')), + service: readHandlebarsTemplate(resolveTemplate('service.js')), + settings: readHandlebarsTemplate(resolveTemplate('core/OpenAPI.js')), }; const partials = [ - 'exportEnum.hbs', - 'exportInterface.hbs', - 'exportType.hbs', - 'extends.hbs', - 'isNullable.hbs', - 'isReadOnly.hbs', - 'isRequired.hbs', - 'parameters.hbs', - 'result.hbs', - 'schema.hbs', - 'schemaArray.hbs', - 'schemaDictionary.hbs', - 'schemaEnum.hbs', - 'schemaGeneric.hbs', - 'schemaInterface.hbs', - 'type.hbs', - 'typeArray.hbs', - 'typeDictionary.hbs', - 'typeEnum.hbs', - 'typeGeneric.hbs', - 'typeInterface.hbs', - 'typeReference.hbs', + 'exportEnum.js', + 'exportInterface.js', + 'exportType.js', + 'extends.js', + 'isNullable.js', + 'isReadOnly.js', + 'isRequired.js', + 'parameters.js', + 'result.js', + 'schema.js', + 'schemaArray.js', + 'schemaDictionary.js', + 'schemaEnum.js', + 'schemaGeneric.js', + 'schemaInterface.js', + 'type.js', + 'typeArray.js', + 'typeDictionary.js', + 'typeEnum.js', + 'typeGeneric.js', + 'typeInterface.js', + 'typeReference.js', ]; partials.forEach(partial => { const templatePath = resolveTemplate(`partials/${partial}`); - const templateName = path.basename(partial, '.hbs'); + const templateName = path.basename(partial, '.js'); const template = readHandlebarsTemplate(templatePath); Handlebars.registerPartial(templateName, template); }); diff --git a/src/utils/registerHandlebarHelpers.ts b/src/utils/registerHandlebarHelpers.ts index ea085618..ebd99b69 100644 --- a/src/utils/registerHandlebarHelpers.ts +++ b/src/utils/registerHandlebarHelpers.ts @@ -1,4 +1,4 @@ -import * as Handlebars from 'handlebars'; +import * as Handlebars from 'handlebars/runtime'; export function registerHandlebarHelpers(): void { Handlebars.registerHelper('equals', function (a: string, b: string, options: Handlebars.HelperOptions): string {