From c3164e4936571523a6e932527c617e8cbce76456 Mon Sep 17 00:00:00 2001 From: Colin Eberhardt Date: Sat, 22 Apr 2023 18:17:29 +0100 Subject: [PATCH 1/7] chore: removed validation step This should be moved into the resolver --- src/generate.js | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/generate.js b/src/generate.js index 02be1b3..3edb1a4 100644 --- a/src/generate.js +++ b/src/generate.js @@ -51,20 +51,6 @@ function cloneSchema(schema) { return JSON.parse(JSON.stringify(schema)); } -function validateGenerator(generatorPath) { - if (!fs.existsSync(generatorPath)) { - throw new Error( - `Generator path ${generatorPath} does not exist, check that the path points to a valid generator` - ); - } - - if (!fs.existsSync(`${generatorPath}/template`)) { - throw new Error( - `Generator path ${generatorPath} does not contain a template folder, check that the path points to a valid generator` - ); - } -} - function getFileName(fileName, tagName = "") { let newFileName = fileName.slice(0, fileName.indexOf(".")); if (tagName !== "") newFileName += helpers.capitalizeFirst(tagName); @@ -175,9 +161,6 @@ async function generate(schemaPathOrUrl, generatorPathOrUrl, options) { let generatorPath = generatorResolver.getGenerator(generatorPathOrUrl); - log.standard("Validating generator"); - validateGenerator(generatorPath); - // load the OpenAPI schema log.standard(`Loading schema from '${schemaPathOrUrl}'`); let schema = From fac1a50c32070a34d5319b7a8f472d2846acbd7e Mon Sep 17 00:00:00 2001 From: Colin Eberhardt Date: Sat, 22 Apr 2023 19:10:11 +0100 Subject: [PATCH 2/7] refactor: generator resolver returns a dispose method --- src/common/generatorResolver.js | 42 +++++++++++++----------- src/forge/index.js | 2 +- src/generate.js | 6 ++-- src/generatorOptions/generatorOptions.js | 7 ++-- test/generate.test.js | 5 ++- test/generatorOptions.test.js | 5 ++- 6 files changed, 40 insertions(+), 27 deletions(-) diff --git a/src/common/generatorResolver.js b/src/common/generatorResolver.js index 0e70eb8..2dca0f3 100644 --- a/src/common/generatorResolver.js +++ b/src/common/generatorResolver.js @@ -27,7 +27,28 @@ function getGenerator(generatorPathOrUrl) { generatorPath = installGeneratorFromNPM(generatorPathOrUrl); } } - return generatorPath; + return { + path: generatorPath, + dispose: () => { + cleanup(); + }, + }; +} + +function cleanup() { + if (temporaryFolder) { + log.verbose(`Removing temporary folder ${temporaryFolder}`); + fs.rmSync(temporaryFolder, { recursive: true }); + temporaryFolder = null; + } + if (npmPackage) { + const currentPath = process.cwd(); + shell.cd(__dirname, log.shellOptions); + log.verbose(`Removing npm package ${npmPackage}`); + shell.exec(`npm uninstall ${npmPackage}`, log.shellOptions); + shell.cd(currentPath, log.shellOptions); + npmPackage = null; + } } function cloneGenerator(generatorPathOrUrl) { @@ -92,24 +113,7 @@ function installGeneratorDependencies() { shell.exec(`npm install`, log.shellOptions); } -function cleanup() { - if (temporaryFolder) { - log.verbose(`Removing temporary folder ${temporaryFolder}`); - fs.rmSync(temporaryFolder, { recursive: true }); - temporaryFolder = null; - } - if (npmPackage) { - const currentPath = process.cwd(); - shell.cd(__dirname, log.shellOptions); - log.verbose(`Removing npm package ${npmPackage}`); - shell.exec(`npm uninstall ${npmPackage}`, log.shellOptions); - shell.cd(currentPath, log.shellOptions); - npmPackage = null; - } -} - module.exports = { isUrl, - getGenerator, - cleanup, + getGenerator }; diff --git a/src/forge/index.js b/src/forge/index.js index 62e7855..6603cc7 100644 --- a/src/forge/index.js +++ b/src/forge/index.js @@ -41,7 +41,7 @@ const forgeCommand = function (program) { log.setLogLevel(options.logLevel); const generatorPath = generatorResolver.getGenerator(generatorPathOrUrl); - const configFile = path.join(generatorPath, "config.json"); + const configFile = path.join(generatorPath.path, "config.json"); // re-configure the command to generate the API command.allowUnknownOption(false).action(async (_, __, options) => { diff --git a/src/generate.js b/src/generate.js index 3edb1a4..fdd3e0a 100644 --- a/src/generate.js +++ b/src/generate.js @@ -154,12 +154,14 @@ function getFilesInFolders(basePath, partialPath = "") { async function generate(schemaPathOrUrl, generatorPathOrUrl, options) { log.logTitle(); let exception = null; + let generator = null; let numberOfDiscoveredModels = 0; let numberOfDiscoveredEndpoints = 0; try { log.standard(`Loading generator from '${generatorPathOrUrl}'`); - let generatorPath = generatorResolver.getGenerator(generatorPathOrUrl); + generator = generatorResolver.getGenerator(generatorPathOrUrl); + const generatorPath = generator.path; // load the OpenAPI schema log.standard(`Loading schema from '${schemaPathOrUrl}'`); @@ -270,7 +272,7 @@ async function generate(schemaPathOrUrl, generatorPathOrUrl, options) { } catch (e) { exception = e; } finally { - generatorResolver.cleanup(); + generator.dispose(); } if (exception === null) { diff --git a/src/generatorOptions/generatorOptions.js b/src/generatorOptions/generatorOptions.js index 4422082..ba70f41 100644 --- a/src/generatorOptions/generatorOptions.js +++ b/src/generatorOptions/generatorOptions.js @@ -3,14 +3,15 @@ const path = require("path"); const { Option, Command } = require("commander"); -const generatorResolver = require("../common/generatorResolver"); +const { getGenerator } = require("../common/generatorResolver"); const generatorOptionsPrefix = "generator."; // generates the help text for the additional options that a generator supports async function generatorOptionsHelp(generatorPathOrUrl) { let optionsHelp = ""; - const generatorPath = generatorResolver.getGenerator(generatorPathOrUrl); + const generator = getGenerator(generatorPathOrUrl); + const generatorPath = generator.path; const configFile = path.join(generatorPath, "config.json"); if (!fs.existsSync(configFile)) { @@ -34,7 +35,7 @@ async function generatorOptionsHelp(generatorPathOrUrl) { optionsHelp += lines.join("\n"); } - generatorResolver.cleanup(); + generator.dispose(); return optionsHelp; } diff --git a/test/generate.test.js b/test/generate.test.js index 9765d47..916e0e4 100644 --- a/test/generate.test.js +++ b/test/generate.test.js @@ -26,7 +26,10 @@ describe("generate", () => { fs.existsSync.mockReturnValue(true); fs.readFileSync.mockReturnValue(fakeSchema); generatorResolver.isUrl.mockReturnValue(false); - generatorResolver.getGenerator.mockImplementation((path) => path); + generatorResolver.getGenerator.mockImplementation((path) => ({ + path, + dispose: () => {}, + })); Handlebars.compile.mockReturnValue(() => outCode); const generatorPackage = { diff --git a/test/generatorOptions.test.js b/test/generatorOptions.test.js index bc6c7bd..1f89578 100644 --- a/test/generatorOptions.test.js +++ b/test/generatorOptions.test.js @@ -11,7 +11,10 @@ jest.mock("../src/common/generatorResolver"); describe("generate", () => { beforeAll(() => { - generatorResolver.getGenerator.mockImplementation((path) => path); + generatorResolver.getGenerator.mockImplementation((path) => ({ + path, + dispose: () => {}, + })); }); beforeEach(() => { From c62238394de4fc1b2f3e9686cfa285a86e977b00 Mon Sep 17 00:00:00 2001 From: Colin Eberhardt Date: Tue, 25 Apr 2023 13:51:40 +0100 Subject: [PATCH 3/7] refactor: moved the shell commands into a separate file --- src/common/generatorResolver.js | 55 ++++++++++------------------ src/common/shell.js | 65 +++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 36 deletions(-) create mode 100644 src/common/shell.js diff --git a/src/common/generatorResolver.js b/src/common/generatorResolver.js index 2dca0f3..ae7810e 100644 --- a/src/common/generatorResolver.js +++ b/src/common/generatorResolver.js @@ -1,10 +1,15 @@ const fs = require("fs"); const path = require("path"); const os = require("os"); -const shell = require("shelljs"); const URL = require("url").URL; - const log = require("./log"); +const { + gitClone, + listInstalledPackages, + installPackage, + installDependencies, + uninstallPackage, +} = require("./shell").shellWithOptions(log.shellOptions); let npmPackage; let temporaryFolder; @@ -42,11 +47,7 @@ function cleanup() { temporaryFolder = null; } if (npmPackage) { - const currentPath = process.cwd(); - shell.cd(__dirname, log.shellOptions); - log.verbose(`Removing npm package ${npmPackage}`); - shell.exec(`npm uninstall ${npmPackage}`, log.shellOptions); - shell.cd(currentPath, log.shellOptions); + uninstallPackage(npmPackage, __dirname); npmPackage = null; } } @@ -62,36 +63,25 @@ function cloneGenerator(generatorPathOrUrl) { log.verbose( `Cloning generator from ${generatorPathOrUrl} to ${temporaryFolder}` ); - shell.exec( - `git clone ${generatorPathOrUrl} ${temporaryFolder}`, - log.shellOptions - ); - const currentPath = process.cwd(); - shell.cd(temporaryFolder, log.shellOptions); - installGeneratorDependencies(); - shell.cd(currentPath, log.shellOptions); + gitClone(generatorPathOrUrl, temporaryFolder); + + log.verbose("Installing generator dependencies"); + installDependencies(temporaryFolder); return temporaryFolder; } function installGeneratorFromNPM(generatorPathOrUrl) { log.verbose(`Checking if npm package ${generatorPathOrUrl} is installed`); - const currentPath = process.cwd(); - shell.cd(__dirname, log.shellOptions); if ( - !shell - .exec(`npm list --depth=0`, log.shellOptions) - .stdout.match( - new RegExp(`^.*${generatorPathOrUrl}@\\d+\\.\\d+\\.\\d+$`, "m") - ) + !listInstalledPackages(__dirname).stdout.match( + new RegExp(`^.*${generatorPathOrUrl}@\\d+\\.\\d+\\.\\d+$`, "m") + ) ) { npmPackage = generatorPathOrUrl; log.verbose( `npm package ${generatorPathOrUrl} doesn't exist, installing package` ); - if ( - shell.exec(`npm install ${generatorPathOrUrl}`, log.shellOptions).code !== - 0 - ) { + if (installPackage(__dirname, generatorPathOrUrl).code !== 0) { throw new Error( `No local generator or npm package found using '${generatorPathOrUrl}', check that it points to a local generator or npm package` ); @@ -101,19 +91,12 @@ function installGeneratorFromNPM(generatorPathOrUrl) { __dirname, path.join("..", "node_modules", generatorPathOrUrl) ); - shell.cd(generatorPath, log.shellOptions); - installGeneratorDependencies(); - shell.cd(currentPath, log.shellOptions); - return generatorPath; -} - -function installGeneratorDependencies() { log.verbose("Installing generator dependencies"); - shell.exec(`npm pkg delete scripts.prepare`, log.shellOptions); // Do not run husky preparation script as it will cause unnecessary errors - shell.exec(`npm install`, log.shellOptions); + installDependencies(generatorPath); + return generatorPath; } module.exports = { isUrl, - getGenerator + getGenerator, }; diff --git a/src/common/shell.js b/src/common/shell.js new file mode 100644 index 0000000..93192d9 --- /dev/null +++ b/src/common/shell.js @@ -0,0 +1,65 @@ +// This module exports a number of functions that are used to execute shell commands. Each function +// ensures that the working directory is restored to its original value after the command has executed. + +const shell = require("shelljs"); + +function gitClone(url, path, shellOptions) { + shell.exec(`git clone ${url} ${path}`, shellOptions); +} + +function listInstalledPackages(path, shellOptions) { + const currentPath = process.cwd(); + shell.cd(path, shellOptions); + const code = shell.exec(`npm list --depth=0`, shellOptions); + shell.cd(currentPath, shellOptions); + return code; +} + +function installPackage(packageName, path, shellOptions) { + const currentPath = process.cwd(); + shell.cd(path, shellOptions); + const code = shell.exec(`npm install ${packageName}`, shellOptions); + shell.cd(currentPath, shellOptions); + return code; +} + +function installDependencies(path, shellOptions) { + const currentPath = process.cwd(); + shell.cd(path, shellOptions); + // Do not run husky preparation script as it will cause unnecessary errors + shell.exec(`npm pkg delete scripts.prepare`, shellOptions); + shell.exec(`npm install`, shellOptions); + shell.cd(currentPath, shellOptions); +} + +function uninstallPackage(npmPackage, path, shellOptions) { + const currentPath = process.cwd(); + shell.cd(path, shellOptions); + shell.exec(`npm uninstall ${npmPackage}`, shellOptions); + shell.cd(currentPath, shellOptions); +} + +// use partial application to adapt a function to a new signature, with a 'fixed' value +// for the first argument +const partial = + (fn, lastArg) => + (...args) => + fn(...args, lastArg); + +const exportedFns = { + gitClone, + listInstalledPackages, + installPackage, + installDependencies, + uninstallPackage, +}; + +module.exports = { + ...exportedFns, + // export a version of each function that has the shellOptions argument pre-filled + shellWithOptions: (options) => + Object.keys(exportedFns).reduce((acc, key) => { + acc[key] = partial(exportedFns[key], options); + return acc; + }, {}), +}; From eb05bd69ec5846a1cff41da7d969b2d1a0295b27 Mon Sep 17 00:00:00 2001 From: Colin Eberhardt Date: Fri, 5 May 2023 17:15:09 +0100 Subject: [PATCH 4/7] feat: generator resolver now uses temp folders throughout --- src/common/generatorResolver.js | 122 +++++++----------- test/common/generatorResolver.test.js | 67 ++++++++++ .../common/validGenerator/template/.gitignore | 4 + 3 files changed, 119 insertions(+), 74 deletions(-) create mode 100644 test/common/generatorResolver.test.js create mode 100644 test/common/validGenerator/template/.gitignore diff --git a/src/common/generatorResolver.js b/src/common/generatorResolver.js index ae7810e..3749933 100644 --- a/src/common/generatorResolver.js +++ b/src/common/generatorResolver.js @@ -3,16 +3,8 @@ const path = require("path"); const os = require("os"); const URL = require("url").URL; const log = require("./log"); -const { - gitClone, - listInstalledPackages, - installPackage, - installDependencies, - uninstallPackage, -} = require("./shell").shellWithOptions(log.shellOptions); - -let npmPackage; -let temporaryFolder; +const { gitClone, installPackage, installDependencies } = + require("./shell").shellWithOptions(log.shellOptions); function isUrl(maybeUrl) { try { @@ -23,80 +15,62 @@ function isUrl(maybeUrl) { } } -function getGenerator(generatorPathOrUrl) { - let generatorPath = path.resolve(generatorPathOrUrl); +function validateGenerator(generatorPath) { if (!fs.existsSync(generatorPath)) { - if (isUrl(generatorPathOrUrl)) { - generatorPath = cloneGenerator(generatorPathOrUrl); - } else { - generatorPath = installGeneratorFromNPM(generatorPathOrUrl); - } + throw new Error( + `Generator path ${generatorPath} does not exist, check that the path points to a valid generator` + ); + } + if (!fs.existsSync(`${generatorPath}/template`)) { + throw new Error( + `Generator path ${generatorPath} does not contain a template folder, check that the path points to a valid generator` + ); } - return { - path: generatorPath, - dispose: () => { - cleanup(); - }, - }; } -function cleanup() { - if (temporaryFolder) { - log.verbose(`Removing temporary folder ${temporaryFolder}`); - fs.rmSync(temporaryFolder, { recursive: true }); - temporaryFolder = null; - } - if (npmPackage) { - uninstallPackage(npmPackage, __dirname); - npmPackage = null; +function getGenerator(generatorPathOrUrl) { + // if this is a folder, and contains a template sub-folder, assume that the generator + // has been supplied as a path + if (fs.existsSync(generatorPathOrUrl)) { + validateGenerator(generatorPathOrUrl); + return { + path: generatorPathOrUrl, + dispose: () => {}, + }; } -} -function cloneGenerator(generatorPathOrUrl) { // if the generator is specified as a git URL, clone it into a temporary directory - if (!generatorPathOrUrl.endsWith(".git")) { - throw new Error( - `Generator URL ${generatorPathOrUrl} does not end with ".git", check that the URL points to a valid generator` + if (isUrl(generatorPathOrUrl)) { + const temporaryFolder = fs.mkdtempSync(path.join(os.tmpdir(), "generator")); + log.verbose( + `Cloning generator from ${generatorPathOrUrl} to ${temporaryFolder}` ); + gitClone(generatorPathOrUrl, temporaryFolder); + + log.verbose("Installing generator dependencies"); + installDependencies(temporaryFolder); + return { + path: temporaryFolder, + dispose: () => { + log.verbose(`Removing temporary folder ${temporaryFolder}`); + fs.rmSync(temporaryFolder, { recursive: true }); + }, + }; } - temporaryFolder = fs.mkdtempSync(path.join(os.tmpdir(), "generator")); - log.verbose( - `Cloning generator from ${generatorPathOrUrl} to ${temporaryFolder}` - ); - gitClone(generatorPathOrUrl, temporaryFolder); - log.verbose("Installing generator dependencies"); - installDependencies(temporaryFolder); - return temporaryFolder; -} + // assume that this must be an npm package, installing into a temporary directory + const temporaryFolder = fs.mkdtempSync(path.join(os.tmpdir(), "generator")); + log.verbose(`Installing generator from npm into ${temporaryFolder}`); + const code = installPackage(generatorPathOrUrl, temporaryFolder); -function installGeneratorFromNPM(generatorPathOrUrl) { - log.verbose(`Checking if npm package ${generatorPathOrUrl} is installed`); - if ( - !listInstalledPackages(__dirname).stdout.match( - new RegExp(`^.*${generatorPathOrUrl}@\\d+\\.\\d+\\.\\d+$`, "m") - ) - ) { - npmPackage = generatorPathOrUrl; - log.verbose( - `npm package ${generatorPathOrUrl} doesn't exist, installing package` - ); - if (installPackage(__dirname, generatorPathOrUrl).code !== 0) { - throw new Error( - `No local generator or npm package found using '${generatorPathOrUrl}', check that it points to a local generator or npm package` - ); - } - } - const generatorPath = path.resolve( - __dirname, - path.join("..", "node_modules", generatorPathOrUrl) - ); - log.verbose("Installing generator dependencies"); - installDependencies(generatorPath); - return generatorPath; + // NOTE, there is no need to install dependencies, these will automatically be installed + return { + path: path.join(temporaryFolder, "node_modules", generatorPathOrUrl), + dispose: () => { + log.verbose(`Removing temporary folder ${temporaryFolder}`); + fs.rmSync(temporaryFolder, { recursive: true }); + }, + }; } -module.exports = { - isUrl, - getGenerator, -}; +module.exports = { getGenerator, isUrl }; diff --git a/test/common/generatorResolver.test.js b/test/common/generatorResolver.test.js new file mode 100644 index 0000000..d36c637 --- /dev/null +++ b/test/common/generatorResolver.test.js @@ -0,0 +1,67 @@ +const path = require("path"); +const fs = require("fs"); +const { getGenerator } = require("../../src/common/generatorResolver"); +const log = require("../../src/common/log"); +log.setLogLevel("quiet"); + +describe("generatorResolver", () => { + describe("generator specified as a filepath", () => { + it("should return the filepath given", async () => { + const generatorPath = path.join(__dirname, "validGenerator"); + const generator = await getGenerator(generatorPath); + expect(generator.path).toEqual(generatorPath); + }); + + it("should throw an error if the filepath doesn't point to a valid generator", async () => { + // we'll just point to some random directory + const generatorPath = path.join(__dirname); + expect(() => { + getGenerator(generatorPath); + }).toThrow(); + }); + }); + + describe("generator specified as a git repo", () => { + it("should clone the repo into a temporary directory", async () => { + const generator = await getGenerator( + "https://github.com/ScottLogic/openapi-forge-csharp.git" + ); + // validate via the presence of a package.json file + const packageJsonPath = path.join(generator.path, "package.json"); + expect(fs.existsSync(packageJsonPath)).toEqual(true); + const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8")); + expect(packageJson.name).toEqual("openapi-forge-csharp"); + + // clean up + generator.dispose(); + }); + + it("should cleanup on disposal", async () => { + const generator = await getGenerator( + "https://github.com/ScottLogic/openapi-forge-csharp.git" + ); + generator.dispose(); + expect(fs.existsSync(generator.path)).toEqual(false); + }); + }); + + describe("generator specified as an npm package", () => { + it("should install the package in a temporary folder", async () => { + const generator = await getGenerator("openapi-forge-typescript"); + // validate via the presence of a package.json file + const packageJsonPath = path.join(generator.path, "package.json"); + expect(fs.existsSync(packageJsonPath)).toEqual(true); + const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8")); + expect(packageJson.name).toEqual("openapi-forge-typescript"); + + // clean up + generator.dispose(); + }); + + it("should cleanup on disposal", async () => { + const generator = await getGenerator("openapi-forge-typescript"); + generator.dispose(); + expect(fs.existsSync(generator.path)).toEqual(false); + }); + }); +}); diff --git a/test/common/validGenerator/template/.gitignore b/test/common/validGenerator/template/.gitignore new file mode 100644 index 0000000..86d0cb2 --- /dev/null +++ b/test/common/validGenerator/template/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except this file +!.gitignore \ No newline at end of file From b813c318761eb499dc8df680eebdf5121e806cd7 Mon Sep 17 00:00:00 2001 From: Colin Eberhardt Date: Sun, 7 May 2023 15:22:56 +0100 Subject: [PATCH 5/7] refactor: moved isUrl into a util module --- src/common/generatorResolver.js | 13 ++----------- src/common/util.js | 14 ++++++++++++++ src/generate.js | 3 ++- test/generate.test.js | 4 +++- 4 files changed, 21 insertions(+), 13 deletions(-) create mode 100644 src/common/util.js diff --git a/src/common/generatorResolver.js b/src/common/generatorResolver.js index 3749933..f6503be 100644 --- a/src/common/generatorResolver.js +++ b/src/common/generatorResolver.js @@ -1,20 +1,11 @@ const fs = require("fs"); const path = require("path"); const os = require("os"); -const URL = require("url").URL; const log = require("./log"); +const { isUrl } = require("./util"); const { gitClone, installPackage, installDependencies } = require("./shell").shellWithOptions(log.shellOptions); -function isUrl(maybeUrl) { - try { - new URL(maybeUrl); - return true; - } catch (err) { - return false; - } -} - function validateGenerator(generatorPath) { if (!fs.existsSync(generatorPath)) { throw new Error( @@ -73,4 +64,4 @@ function getGenerator(generatorPathOrUrl) { }; } -module.exports = { getGenerator, isUrl }; +module.exports = { getGenerator }; diff --git a/src/common/util.js b/src/common/util.js new file mode 100644 index 0000000..fc11388 --- /dev/null +++ b/src/common/util.js @@ -0,0 +1,14 @@ +const URL = require("url").URL; + +function isUrl(maybeUrl) { + try { + new URL(maybeUrl); + return true; + } catch (err) { + return false; + } +} + +module.exports = { + isUrl, +}; diff --git a/src/generate.js b/src/generate.js index fdd3e0a..cb90921 100644 --- a/src/generate.js +++ b/src/generate.js @@ -12,6 +12,7 @@ const { parse } = require("yaml"); const generatorResolver = require("./common/generatorResolver"); const helpers = require("./helpers"); +const { isUrl } = require("./common/util"); const log = require("./common/log"); const transformers = require("./transformers"); const SwaggerParser = require("@apidevtools/swagger-parser"); @@ -25,7 +26,7 @@ Object.keys(helpers).forEach((helperName) => { async function loadSchema(schemaPathOrUrl) { const isYml = schemaPathOrUrl.endsWith(".yml") || schemaPathOrUrl.endsWith(".yaml"); - const schema = generatorResolver.isUrl(schemaPathOrUrl) + const schema = isUrl(schemaPathOrUrl) ? await fetch(schemaPathOrUrl).then((d) => { if (d.status === 200) { return d.text(); diff --git a/test/generate.test.js b/test/generate.test.js index 916e0e4..5ee48bd 100644 --- a/test/generate.test.js +++ b/test/generate.test.js @@ -2,6 +2,7 @@ const fs = require("fs"); const path = require("path"); const Handlebars = require("handlebars"); +const util = require("../src/common/util"); const generate = require("../src/generate"); const generatorResolver = require("../src/common/generatorResolver"); const minimatch = require("minimatch"); @@ -10,6 +11,7 @@ jest.mock("fs"); jest.mock("path"); jest.mock("handlebars"); jest.mock("minimatch"); +jest.mock("../src/common/util"); jest.mock("../src/common/generatorResolver"); describe("generate", () => { @@ -25,7 +27,7 @@ describe("generate", () => { path.resolve.mockImplementation((path) => path); fs.existsSync.mockReturnValue(true); fs.readFileSync.mockReturnValue(fakeSchema); - generatorResolver.isUrl.mockReturnValue(false); + util.isUrl.mockReturnValue(false); generatorResolver.getGenerator.mockImplementation((path) => ({ path, dispose: () => {}, From f55791f7c52126a5c2ef8434d72fd78d4d332c68 Mon Sep 17 00:00:00 2001 From: Colin Eberhardt Date: Sun, 7 May 2023 15:24:49 +0100 Subject: [PATCH 6/7] chore: fixed linting issues --- src/common/generatorResolver.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/generatorResolver.js b/src/common/generatorResolver.js index f6503be..f1b9e2d 100644 --- a/src/common/generatorResolver.js +++ b/src/common/generatorResolver.js @@ -52,7 +52,7 @@ function getGenerator(generatorPathOrUrl) { // assume that this must be an npm package, installing into a temporary directory const temporaryFolder = fs.mkdtempSync(path.join(os.tmpdir(), "generator")); log.verbose(`Installing generator from npm into ${temporaryFolder}`); - const code = installPackage(generatorPathOrUrl, temporaryFolder); + installPackage(generatorPathOrUrl, temporaryFolder); // NOTE, there is no need to install dependencies, these will automatically be installed return { From 473f51f6e49a05aecbc342a7e56cecd28b9842a3 Mon Sep 17 00:00:00 2001 From: Colin Eberhardt Date: Mon, 15 May 2023 08:47:07 +0100 Subject: [PATCH 7/7] feat: ensure resolver returns absolute paths --- src/common/generatorResolver.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/common/generatorResolver.js b/src/common/generatorResolver.js index f1b9e2d..27b3663 100644 --- a/src/common/generatorResolver.js +++ b/src/common/generatorResolver.js @@ -64,4 +64,12 @@ function getGenerator(generatorPathOrUrl) { }; } -module.exports = { getGenerator }; +function resolveAndValidate(generatorPathOrUrl) { + const generator = getGenerator(generatorPathOrUrl); + // ensure paths are absolute, and validate contents + generator.path = path.resolve(generator.path); + validateGenerator(generator.path); + return generator; +} + +module.exports = { getGenerator: resolveAndValidate };