@prisma/generator-helper
Advanced tools
Comparing version 0.0.1 to 0.0.2
@@ -43,4 +43,13 @@ "use strict"; | ||
describe('generatorHandler', () => { | ||
test('not executable', () => __awaiter(void 0, void 0, void 0, function* () { | ||
const generator = new GeneratorProcess_1.GeneratorProcess(path_1.default.join(__dirname, 'not-executable')); | ||
expect(generator.init()).rejects.toThrow('lacks the right chmod'); | ||
})); | ||
test('parsing error', () => __awaiter(void 0, void 0, void 0, function* () { | ||
const generator = new GeneratorProcess_1.GeneratorProcess(path_1.default.join(__dirname, 'invalid-executable')); | ||
yield expect(generator.init()).rejects.toThrow(`Cannot find module 'ms-node/register'`); | ||
})); | ||
test('minimal-executable', () => __awaiter(void 0, void 0, void 0, function* () { | ||
const generator = new GeneratorProcess_1.GeneratorProcess(path_1.default.join(__dirname, 'minimal-executable')); | ||
yield generator.init(); | ||
const manifest = yield generator.getManifest(); | ||
@@ -68,6 +77,8 @@ expect(manifest).toMatchInlineSnapshot(` | ||
const generator = new GeneratorProcess_1.GeneratorProcess(path_1.default.join(__dirname, 'failing-executable')); | ||
expect(generator.getManifest()).rejects.toMatchInlineSnapshot(); | ||
expect(generator.generate(stubOptions)).rejects.toMatchInlineSnapshot(); | ||
yield generator.init(); | ||
expect(generator.getManifest()).rejects.toThrow(); | ||
expect(generator.generate(stubOptions)).rejects.toThrow(); | ||
generator.stop(); | ||
})); | ||
}); | ||
//# sourceMappingURL=generatorHandler.test.js.map |
@@ -6,7 +6,13 @@ /// <reference types="node" /> | ||
private executablePath; | ||
child: ChildProcessByStdio<any, any, any>; | ||
child?: ChildProcessByStdio<any, any, any>; | ||
listeners: { | ||
[key: string]: (result: any, err?: Error) => void; | ||
}; | ||
private exitCode; | ||
private stderrLogs; | ||
private initPromise?; | ||
private initialized; | ||
constructor(executablePath: string); | ||
init(): Promise<void>; | ||
initSingleton(): Promise<void>; | ||
private handleResponse; | ||
@@ -13,0 +19,0 @@ private registerListener; |
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
@@ -8,2 +17,4 @@ return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
const byline_1 = __importDefault(require("./byline")); | ||
const fs_1 = __importDefault(require("fs")); | ||
const chalk_1 = __importDefault(require("chalk")); | ||
let globalMessageId = 1; | ||
@@ -14,19 +25,58 @@ class GeneratorProcess { | ||
this.listeners = {}; | ||
this.child = child_process_1.spawn(executablePath, { | ||
stdio: ['pipe', 'inherit', 'pipe'], | ||
}); | ||
byline_1.default(this.child.stderr).on('data', line => { | ||
const response = String(line); | ||
let data; | ||
try { | ||
data = JSON.parse(response); | ||
this.exitCode = null; | ||
this.stderrLogs = ''; | ||
this.initialized = false; | ||
if (!fs_1.default.existsSync(executablePath)) { | ||
throw new Error(`Can't find executable ${executablePath}`); | ||
} | ||
} | ||
init() { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
if (!this.initPromise) { | ||
this.initPromise = this.initSingleton(); | ||
} | ||
catch (e) { | ||
throw new Error(`Got invalid response from generator at ${this.executablePath}:\n${response}\n${e.stack || e.message}`); | ||
} | ||
if (data) { | ||
this.handleResponse(data); | ||
} | ||
return this.initPromise; | ||
}); | ||
} | ||
initSingleton() { | ||
return new Promise((resolve, reject) => { | ||
this.child = child_process_1.spawn(this.executablePath, { | ||
stdio: ['pipe', 'inherit', 'pipe'], | ||
}); | ||
this.child.on('exit', code => { | ||
this.exitCode = code; | ||
}); | ||
this.child.on('error', err => { | ||
if (err.message.includes('EACCES')) { | ||
reject(new Error(`The executable at ${this.executablePath} lacks the right chmod. Please use ${chalk_1.default.bold(`chmod +x ${this.executablePath}`)}`)); | ||
} | ||
}); | ||
byline_1.default(this.child.stderr).on('data', line => { | ||
const response = String(line); | ||
this.stderrLogs += response + '\n'; | ||
let data; | ||
try { | ||
data = JSON.parse(response); | ||
} | ||
catch (e) { | ||
if (!this.exitCode && this.initialized) { | ||
throw new Error(`Got invalid response from generator at ${this.executablePath}:\n${response}\n${e.stack || e.message}`); | ||
} | ||
} | ||
if (data) { | ||
this.handleResponse(data); | ||
} | ||
}); | ||
// wait 200ms for the binary to fail | ||
setTimeout(() => { | ||
if (this.exitCode && this.exitCode > 0) { | ||
reject(new Error(`Generator at ${this.executablePath} could not start:\n\n${this.stderrLogs}`)); | ||
} | ||
else { | ||
this.initialized = true; | ||
resolve(); | ||
} | ||
}, 200); | ||
}); | ||
} | ||
handleResponse(data) { | ||
@@ -33,0 +83,0 @@ if (data.jsonrpc && data.id) { |
{ | ||
"name": "@prisma/generator-helper", | ||
"version": "0.0.1", | ||
"version": "0.0.2", | ||
"main": "dist/index.js", | ||
@@ -11,2 +11,3 @@ "types": "dist/index.d.ts", | ||
"dependencies": { | ||
"chalk": "^2.4.2", | ||
"debug": "^4.1.1" | ||
@@ -13,0 +14,0 @@ }, |
@@ -32,2 +32,16 @@ import { GeneratorProcess } from '../GeneratorProcess' | ||
describe('generatorHandler', () => { | ||
test('not executable', async () => { | ||
const generator = new GeneratorProcess( | ||
path.join(__dirname, 'not-executable'), | ||
) | ||
expect(generator.init()).rejects.toThrow('lacks the right chmod') | ||
}) | ||
test('parsing error', async () => { | ||
const generator = new GeneratorProcess( | ||
path.join(__dirname, 'invalid-executable'), | ||
) | ||
await expect(generator.init()).rejects.toThrow( | ||
`Cannot find module 'ms-node/register'`, | ||
) | ||
}) | ||
test('minimal-executable', async () => { | ||
@@ -37,2 +51,3 @@ const generator = new GeneratorProcess( | ||
) | ||
await generator.init() | ||
const manifest = await generator.getManifest() | ||
@@ -63,5 +78,7 @@ expect(manifest).toMatchInlineSnapshot(` | ||
) | ||
expect(generator.getManifest()).rejects.toMatchInlineSnapshot() | ||
expect(generator.generate(stubOptions)).rejects.toMatchInlineSnapshot() | ||
await generator.init() | ||
expect(generator.getManifest()).rejects.toThrow() | ||
expect(generator.generate(stubOptions)).rejects.toThrow() | ||
generator.stop() | ||
}) | ||
}) |
import { ChildProcessByStdio, spawn } from 'child_process' | ||
import byline from './byline' | ||
import { GeneratorManifest, GeneratorOptions, JsonRPC } from './types' | ||
import fs from 'fs' | ||
import chalk from 'chalk' | ||
@@ -8,24 +10,75 @@ let globalMessageId = 1 | ||
export class GeneratorProcess { | ||
child: ChildProcessByStdio<any, any, any> | ||
child?: ChildProcessByStdio<any, any, any> | ||
listeners: { [key: string]: (result: any, err?: Error) => void } = {} | ||
private exitCode: number | null = null | ||
private stderrLogs: string = '' | ||
private initPromise?: Promise<void> | ||
private initialized: boolean = false | ||
constructor(private executablePath: string) { | ||
this.child = spawn(executablePath, { | ||
stdio: ['pipe', 'inherit', 'pipe'], | ||
}) | ||
if (!fs.existsSync(executablePath)) { | ||
throw new Error(`Can't find executable ${executablePath}`) | ||
} | ||
} | ||
async init() { | ||
if (!this.initPromise) { | ||
this.initPromise = this.initSingleton() | ||
} | ||
return this.initPromise! | ||
} | ||
initSingleton(): Promise<void> { | ||
return new Promise((resolve, reject) => { | ||
this.child = spawn(this.executablePath, { | ||
stdio: ['pipe', 'inherit', 'pipe'], | ||
}) | ||
byline(this.child.stderr).on('data', line => { | ||
const response = String(line) | ||
let data | ||
try { | ||
data = JSON.parse(response) | ||
} catch (e) { | ||
throw new Error( | ||
`Got invalid response from generator at ${ | ||
this.executablePath | ||
}:\n${response}\n${e.stack || e.message}`, | ||
) | ||
} | ||
if (data) { | ||
this.handleResponse(data) | ||
} | ||
this.child.on('exit', code => { | ||
this.exitCode = code | ||
}) | ||
this.child.on('error', err => { | ||
if (err.message.includes('EACCES')) { | ||
reject( | ||
new Error( | ||
`The executable at ${ | ||
this.executablePath | ||
} lacks the right chmod. Please use ${chalk.bold( | ||
`chmod +x ${this.executablePath}`, | ||
)}`, | ||
), | ||
) | ||
} | ||
}) | ||
byline(this.child!.stderr).on('data', line => { | ||
const response = String(line) | ||
this.stderrLogs += response + '\n' | ||
let data | ||
try { | ||
data = JSON.parse(response) | ||
} catch (e) { | ||
if (!this.exitCode && this.initialized) { | ||
throw new Error( | ||
`Got invalid response from generator at ${ | ||
this.executablePath | ||
}:\n${response}\n${e.stack || e.message}`, | ||
) | ||
} | ||
} | ||
if (data) { | ||
this.handleResponse(data) | ||
} | ||
}) | ||
// wait 200ms for the binary to fail | ||
setTimeout(() => { | ||
if (this.exitCode && this.exitCode > 0) { | ||
reject( | ||
new Error( | ||
`Generator at ${this.executablePath} could not start:\n\n${this.stderrLogs}`, | ||
), | ||
) | ||
} else { | ||
this.initialized = true | ||
resolve() | ||
} | ||
}, 200) | ||
}) | ||
@@ -55,3 +108,3 @@ } | ||
private sendMessage(message: JsonRPC.Request) { | ||
this.child.stdin.write(JSON.stringify(message) + '\n') | ||
this.child!.stdin.write(JSON.stringify(message) + '\n') | ||
} | ||
@@ -62,4 +115,4 @@ private getMessageId() { | ||
stop() { | ||
if (!this.child.killed) { | ||
this.child.kill() | ||
if (!this.child!.killed) { | ||
this.child!.kill() | ||
} | ||
@@ -66,0 +119,0 @@ } |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
55744
32
1307
2
2
+ Addedchalk@^2.4.2
+ Addedansi-styles@3.2.1(transitive)
+ Addedchalk@2.4.2(transitive)
+ Addedcolor-convert@1.9.3(transitive)
+ Addedcolor-name@1.1.3(transitive)
+ Addedescape-string-regexp@1.0.5(transitive)
+ Addedhas-flag@3.0.0(transitive)
+ Addedsupports-color@5.5.0(transitive)