From 86334d469d446b7ed90db542ac1f1e047d79042f Mon Sep 17 00:00:00 2001 From: Philipp A Date: Wed, 16 Nov 2016 19:39:36 +0100 Subject: [PATCH] Improved new-package script. * Add more info (homepage and version) * Handle errors more gracefully (Handle existing module and clean up otherwise) --- scripts/new-package.js | 134 +++++++++++++++++++++++++++++-------- scripts/new-package.ts | 145 ++++++++++++++++++++++++++++++++--------- 2 files changed, 220 insertions(+), 59 deletions(-) diff --git a/scripts/new-package.js b/scripts/new-package.js index 5adcdae176..e235714fe0 100644 --- a/scripts/new-package.js +++ b/scripts/new-package.js @@ -1,42 +1,120 @@ /// "use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + 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) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments)).next()); + }); +}; +const http_1 = require("http"); const fs_1 = require("fs"); const path = require("path"); const newPackageName = process.argv[2]; if (!newPackageName) { throw new Error("Usage: node scripts/new-package.js new-package-name"); } -fs_1.mkdirSync(newPackageName); -write("index.d.ts", `// Type definitions for ${newPackageName} 1.2 -// Project: https://github.com/baz/foo (Does not have to be to GitHub, but prefer linking to a source code repository rather than to a project website.) +run().catch(e => { + console.error(e); + process.exit(1); +}); +function run() { + return __awaiter(this, void 0, void 0, function* () { + const files = [ + ["index.d.ts", yield getIndex()], + [`${newPackageName}-tests.ts`, ""], + ["tsconfig.json", `${JSON.stringify(getTSConfig(), undefined, 4)}\n`], + ["tslint.json", '{ "extends": "../tslint.json" }\n'], + ]; + try { + yield pify1(fs_1.mkdir, newPackageName); + yield Promise.all(files.map(([name, text]) => write(name, text))); + } + catch (e) { + if (e.code === "EEXIST") { + console.warn(`Module “${newPackageName}” already exists!`); + } + else { + console.error(`Error creating module files: ${e}\nCleaning Up.`); + yield Promise.all(files.map(([name]) => rm(name))); + yield pify1(fs_1.rmdir, newPackageName); + } + process.exit(1); + } + }); +} +function getIndex() { + return __awaiter(this, void 0, void 0, function* () { + let version = "x.x"; + let project = "https://github.com/baz/foo (Does not have to be to GitHub, but prefer linking to a source code repository rather than to a project website.)"; + try { + const reg = yield loadString(`http://registry.npmjs.org/${newPackageName}`).then(JSON.parse); + const { latest } = reg["dist-tags"]; + const { homepage } = reg.versions[latest]; + version = latest.split(".").slice(0, 2).join("."); + if (homepage !== undefined) + project = homepage; + } + catch (e) { + console.warn(`Could not retrieve version/homepage information: ${e.stack}`); + } + return `// Type definitions for ${newPackageName} ${version} +// Project: ${project} // Definitions by: My Self // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped Fill the header in! -`); -const testsFile = `${newPackageName}-tests.ts`; -write(testsFile, ""); -const tsconfig = { - "compilerOptions": { - "module": "commonjs", - "target": "es6", - "noImplicitAny": true, - "strictNullChecks": true, - "baseUrl": "../", - "typeRoots": [ - "../" - ], - "types": [], - "noEmit": true, - "forceConsistentCasingInFileNames": true - }, - "files": [ - "index.d.ts", - `${newPackageName}-tests.ts` - ] -}; -write("tsconfig.json", JSON.stringify(tsconfig, undefined, 4)); -write("tslint.json", '{ "extends": "../tslint.json" }'); +`; + }); +} +function getTSConfig() { + return { + "compilerOptions": { + "module": "commonjs", + "target": "es6", + "noImplicitAny": true, + "strictNullChecks": true, + "baseUrl": "../", + "typeRoots": [ + "../" + ], + "types": [], + "noEmit": true, + "forceConsistentCasingInFileNames": true + }, + "files": [ + "index.d.ts", + `${newPackageName}-tests.ts` + ] + }; +} function write(name, content) { - fs_1.writeFileSync(path.join(newPackageName, name), content); + return new Promise((resolve, reject) => { + fs_1.writeFile(path.join(newPackageName, name), content, err => err ? reject(err) : resolve()); + }); +} +function rm(name) { + return pify1(fs_1.unlink, path.join(newPackageName, name)).catch((e) => { + if (e.code === "ENOENT") + return; + throw e; + }); +} +function pify1(fn, arg) { + return new Promise((resolve, reject) => { + fn(arg, err => err ? reject(err) : resolve()); + }); +} +function loadString(url) { + return new Promise((resolve, reject) => { + http_1.get(url, (res) => { + if (res.statusCode !== 200) { + return reject(new Error(`HTTP Error ${res.statusCode}: ${http_1.STATUS_CODES[res.statusCode || 500]} for ${url}`)); + } + let rawData = ""; + res.on("data", chunk => rawData += chunk); + res.on("end", () => resolve(rawData)); + }).on("error", e => reject(e)); + }); } diff --git a/scripts/new-package.ts b/scripts/new-package.ts index 1818111a74..be8b081f3f 100644 --- a/scripts/new-package.ts +++ b/scripts/new-package.ts @@ -1,47 +1,130 @@ /// -import { mkdirSync, writeFileSync } from "fs"; -import * as path from "path"; +import { get, STATUS_CODES } from "http" +import { mkdir, writeFile, unlink, rmdir } from "fs" +import * as path from "path" -const newPackageName = process.argv[2]; +interface Package { + name: string + description: string + version: string + homepage?: string +} + +interface Registry { + name: string + description: string + "dist-tags": { latest: string } + versions: { [version: string]: Package } +} + +const newPackageName = process.argv[2] if (!newPackageName) { throw new Error("Usage: node scripts/new-package.js new-package-name") } -mkdirSync(newPackageName); +run().catch(e => { + console.error(e) + process.exit(1) +}) -write("index.d.ts", `// Type definitions for ${newPackageName} 1.2 -// Project: https://github.com/baz/foo (Does not have to be to GitHub, but prefer linking to a source code repository rather than to a project website.) +async function run() { + const files: [string, string][] = [ + ["index.d.ts", await getIndex()], + [`${newPackageName}-tests.ts`, ""], + ["tsconfig.json", `${JSON.stringify(getTSConfig(), undefined, 4)}\n`], + ["tslint.json", '{ "extends": "../tslint.json" }\n'], + ] + + try { + await pify1(mkdir, newPackageName) + await Promise.all(files.map(([name, text]) => write(name, text))) + } catch (e) { + if (e.code === "EEXIST") { + console.warn(`Module “${newPackageName}” already exists!`) + } else { + console.error(`Error creating module files: ${e}\nCleaning Up.`) + await Promise.all(files.map(([name]) => rm(name))) + await pify1(rmdir, newPackageName) + } + process.exit(1) + } +} + +async function getIndex() { + let version = "x.x" + let project = "https://github.com/baz/foo (Does not have to be to GitHub, but prefer linking to a source code repository rather than to a project website.)" + try { + const reg: Registry = await loadString(`http://registry.npmjs.org/${newPackageName}`).then(JSON.parse) + + const { latest } = reg["dist-tags"] + const { homepage } = reg.versions[latest] + + version = latest.split(".").slice(0, 2).join(".") + if (homepage !== undefined) project = homepage + } catch (e) { + console.warn(`Could not retrieve version/homepage information: ${e.stack}`) + } + + return `// Type definitions for ${newPackageName} ${version} +// Project: ${project} // Definitions by: My Self // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped Fill the header in! -`); -const testsFile = `${newPackageName}-tests.ts`; -write(testsFile, ""); -const tsconfig = { - "compilerOptions": { - "module": "commonjs", - "target": "es6", - "noImplicitAny": true, - "strictNullChecks": true, - "baseUrl": "../", - "typeRoots": [ - "../" - ], - "types": [], - "noEmit": true, - "forceConsistentCasingInFileNames": true - }, - "files": [ - "index.d.ts", - `${newPackageName}-tests.ts` - ] -}; -write("tsconfig.json", JSON.stringify(tsconfig, undefined, 4)); +` +} -write("tslint.json", '{ "extends": "../tslint.json" }'); +function getTSConfig() { + return { + "compilerOptions": { + "module": "commonjs", + "target": "es6", + "noImplicitAny": true, + "strictNullChecks": true, + "baseUrl": "../", + "typeRoots": [ + "../" + ], + "types": [], + "noEmit": true, + "forceConsistentCasingInFileNames": true + }, + "files": [ + "index.d.ts", + `${newPackageName}-tests.ts` + ] + } +} function write(name: string, content: string) { - writeFileSync(path.join(newPackageName, name), content); + return new Promise((resolve, reject) => { + writeFile(path.join(newPackageName, name), content, err => err ? reject(err): resolve()) + }) +} + +function rm(name: string) { + return pify1(unlink, path.join(newPackageName, name)).catch((e: NodeJS.ErrnoException) => { + if (e.code === "ENOENT") return + throw e + }) +} + +function pify1 void) => void, A>(fn: F, arg: A) { + return new Promise((resolve, reject) => { + fn(arg, err => err ? reject(err): resolve()) + }) +} + +function loadString(url: string): Promise { + return new Promise((resolve, reject) => { + get(url, (res) => { + if (res.statusCode !== 200) { + return reject(new Error(`HTTP Error ${res.statusCode}: ${STATUS_CODES[res.statusCode || 500]} for ${url}`)) + } + let rawData = "" + res.on("data", chunk => rawData += chunk) + res.on("end", () => resolve(rawData)) + }).on("error", e => reject(e)) + }) }