From d8bcf85531b7ae9661cb60e86d658b2d18afb7b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Sun, 5 Sep 2021 22:27:05 +0200 Subject: [PATCH] Extract from devtools project --- .editorconfig | 10 ++ .gitignore | 4 + .vscode/launch.json | 22 ++++ .vscode/settings.json | 1 + .vscode/tasks.json | 11 ++ README.md | 3 + cli.ts | 6 ++ config/run.flags | 1 + deps.ts | 1 + run | 20 ++++ src/normalize.test.ts | 0 src/normalize.ts | 231 ++++++++++++++++++++++++++++++++++++++++++ tsconfig.json | 10 ++ 13 files changed, 320 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitignore create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 .vscode/tasks.json create mode 100644 README.md create mode 100755 cli.ts create mode 100644 config/run.flags create mode 100644 deps.ts create mode 100755 run create mode 100644 src/normalize.test.ts create mode 100755 src/normalize.ts create mode 100644 tsconfig.json diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..f1b4eb3 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,10 @@ +root = true + + [*.{ts,json}] + charset = utf-8 + end_of_line = lf + insert_final_newline = true + indent_style = space + indent_size = 2 + trim_trailing_whitespace = true + \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9ab1dc5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +deno.d.ts + .vscode + .local + \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..5bc14c6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,22 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Deno", + "type": "node", + "request": "launch", + "cwd": "${workspaceFolder}", + "program": "cli.ts", + "console": "externalTerminal", + "attachSimplePort": 9229, + "runtimeExecutable": "deno", + "runtimeArgs": [ + "run", + "--inspect", + "--allow-run=./run", + "--allow-read=.", + "--allow-write=." + ] + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..650f9a7 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1 @@ +{ "deno.enable": true } diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..8802f7d --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,11 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "test", + "type": "shell", + "group": { "kind": "test", "isDefault": true }, + "command": "./run test" + } + ] +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..f0438d5 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# typescript/scaffold + +[![Build Status](https://thunderk.visualstudio.com/typescript/_apis/build/status/scaffold?branchName=master)](https://dev.azure.com/thunderk/typescript/_build?pipelineNameFilter=scaffold) diff --git a/cli.ts b/cli.ts new file mode 100755 index 0000000..fe5b3a1 --- /dev/null +++ b/cli.ts @@ -0,0 +1,6 @@ +#!./run +import { normalize } from "./src/normalize.ts"; + +if (import.meta.main) { + await normalize(); +} diff --git a/config/run.flags b/config/run.flags new file mode 100644 index 0000000..8f994fb --- /dev/null +++ b/config/run.flags @@ -0,0 +1 @@ +--allow-run=./run --allow-read=. --allow-write=. \ No newline at end of file diff --git a/deps.ts b/deps.ts new file mode 100644 index 0000000..c42ae91 --- /dev/null +++ b/deps.ts @@ -0,0 +1 @@ +export { Sys } from "https://js.thunderk.net/system@1.0.0/mod.ts"; diff --git a/run b/run new file mode 100755 index 0000000..a9c2fd6 --- /dev/null +++ b/run @@ -0,0 +1,20 @@ +#!/bin/sh + # Simplified run tool for deno commands + + if test $# -eq 0 + then + echo "Usage: $0 [file or command]" + exit 1 + elif echo $1 | grep -q '.*.ts' + then + denocmd=run + denoargs=$1 + shift + else + denocmd=$1 + shift + fi + + denoargs="$(cat config/$denocmd.flags 2> /dev/null) $denoargs $@" + exec deno $denocmd $denoargs + \ No newline at end of file diff --git a/src/normalize.test.ts b/src/normalize.test.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/normalize.ts b/src/normalize.ts new file mode 100755 index 0000000..68cfd8e --- /dev/null +++ b/src/normalize.ts @@ -0,0 +1,231 @@ +import { Sys } from "../deps.ts"; + +export class ProjectNormalizer { + constructor(readonly sys = Sys) { + } + + async isDirectory(path: string): Promise { + try { + return (await this.sys.stat(path)).isDirectory; + } catch { + return false; + } + } + + async isFile(path: string): Promise { + try { + return (await this.sys.stat(path)).isFile; + } catch { + return false; + } + } + + async readContent(path: string): Promise { + try { + return await this.sys.readTextFile(path); + } catch { + return ""; + } + } + + async ensureDirectory(path: string) { + if (!await this.isDirectory(path)) { + await this.sys.mkdir(path, { recursive: true }); + } + } + + async writeJsonFile(path: string, content: any) { + await this.sys.writeTextFile( + path, + JSON.stringify(content), + ); + await this.formatPath(path); + } + + async formatPath(path: string) { + await this.sys.run({ + cmd: ["./run", "fmt", "-q", path], + }).status(); + } + + async updateRunScript() { + await this.sys.writeTextFile( + "run", + `#!/bin/sh + # Simplified run tool for deno commands + + if test $# -eq 0 + then + echo "Usage: $0 [file or command]" + exit 1 + elif echo $1 | grep -q '.*\.ts' + then + denocmd=run + denoargs=$1 + shift + else + denocmd=$1 + shift + fi + + denoargs="$(cat config/$denocmd.flags 2> /dev/null) $denoargs $@" + exec deno $denocmd $denoargs + `, + ); + await this.sys.chmod("run", 0o755); + } + + async updateDenoDefs() { + const process = this.sys.run({ + cmd: ["./run", "types"], + stdout: "piped", + }); + const defs = new TextDecoder("utf-8").decode(await process.output()); + await this.sys.writeTextFile("deno.d.ts", defs); + } + + async updateEditorConfig() { + await this.sys.writeTextFile( + ".editorconfig", + `root = true + + [*.{ts,json}] + charset = utf-8 + end_of_line = lf + insert_final_newline = true + indent_style = space + indent_size = 2 + trim_trailing_whitespace = true + `, + ); + } + + async updateTsConfig() { + await this.writeJsonFile("tsconfig.json", { + compilerOptions: { + module: "esnext", + target: "ESNext", + strict: true, + noImplicitReturns: true, + noFallthroughCasesInSwitch: true, + preserveConstEnums: true, + }, + }); + } + + async updateVscodeConf() { + await this.ensureDirectory(".vscode"); + const path = ".vscode/settings.json"; + const json_config = await this.readContent(path); + const config = JSON.parse(json_config || "{}"); + if (!config["deno.enable"]) { + config["deno.enable"] = true; + await this.writeJsonFile(path, config); + } + + await this.writeJsonFile(".vscode/tasks.json", { + version: "2.0.0", + tasks: [ + { + label: "test", + type: "shell", + group: { + kind: "test", + isDefault: true, + }, + command: "./run test", + }, + ], + }); + + if (await this.isFile("cli.ts")) { + await this.writeJsonFile(".vscode/launch.json", { + version: "0.2.0", + configurations: [ + { + name: "Deno", + type: "node", + request: "launch", + cwd: "\${workspaceFolder}", + program: "cli.ts", + console: "externalTerminal", + attachSimplePort: 9229, + runtimeExecutable: "deno", + runtimeArgs: [ + "run", + "--inspect", + ].concat( + (await this.readContent("config/run.flags")) + .split(" ") + .filter((part) => !!part), + ), + }, + ], + }); + } + } + + async updateGitIgnore() { + await this.sys.writeTextFile( + ".gitignore", + `deno.d.ts + .vscode + .local + `, + ); + } + + async updateGitHooks() { + await this.sys.writeTextFile( + ".git/hooks/pre-commit", + `#!/bin/sh + set -e + ./run fmt --check + ./run test + `, + ); + await this.sys.chmod(".git/hooks/pre-commit", 0o755); + } + + async updateReadme() { + const project = this.sys.cwd().split("/").pop(); + let sections = ""; + if (await this.isDirectory("doc")) { + const index = await this.readContent("doc/index"); + for (let section of index.split("\n")) { + if (section?.trim()) { + sections += "\n" + + (await this.readContent(`doc/${section.trim()}.md`)); + } + } + } + await this.sys.writeTextFile( + "README.md", + `# typescript/${project} + + [![Build Status](https://thunderk.visualstudio.com/typescript/_apis/build/status/${project}?branchName=master)](https://dev.azure.com/thunderk/typescript/_build?pipelineNameFilter=${project}) + ${sections}`, + ); + await this.formatPath("README.md"); + } + + async normalize() { + if (!await this.isDirectory(".git")) { + throw new Error("Not in a git repository"); + } + + await this.updateRunScript(); + await this.updateDenoDefs(); + await this.updateVscodeConf(); + await this.updateTsConfig(); + await this.updateEditorConfig(); + await this.updateGitIgnore(); + await this.updateGitHooks(); + await this.updateReadme(); + } +} + +export async function normalize(sys = Sys) { + const normalizer = new ProjectNormalizer(sys); + await normalizer.normalize(); +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..e28737f --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "module": "esnext", + "target": "ESNext", + "strict": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "preserveConstEnums": true + } +}