diff --git a/README.md b/README.md
index 33df2cf..62c0f30 100644
--- a/README.md
+++ b/README.md
@@ -10,6 +10,21 @@ TypeType is designed to generate complex typescript type with ease.
> npm i -D @mistlog/typetype
```
+### CLI
+
+> example: [typetype-examples/package.json](https://github.com/mistlog/typetype-examples/blob/main/package.json)
+
+```bash
+typetype build
: build all *.type files in
+typetype build -w : watch all *.type files in
+typetype clean : remove all generated *.ts files in
+typetype debug : build in debug mode(backtrace will be available)
+```
+
+### API
+
+> example: [typetype-examples/index.ts](https://github.com/mistlog/typetype-examples/blob/main/index.ts)
+
```ts
import { transform } from "@mistlog/typetype";
@@ -27,6 +42,32 @@ console.log(output);
// output: type TypeName = T extends string ? "string" : "number";
```
+Debug mode:
+
+```ts
+const output = transform(input, { debug: true }).code;
+```
+
+when `debug` is true, backtrace will be available:
+
+```log
+Expected end of input but ";" found.
+x 1:11-1:11 MultiLineComment
+| type a = 1;
+| ^
+o 1:11-1:11 _
+| type a = 1;
+| ^
+x 1:11-1:11 TypeFunctionDeclaration
+| type a = 1;
+...
+|/ /
+| |
+|/
+o 1:1-1:11 TypeFile
+ type a = 1;
+```
+
## Examples
- all examples: https://github.com/mistlog/typetype-examples
diff --git a/cli/cli.ts b/cli/cli.ts
new file mode 100644
index 0000000..d2a26eb
--- /dev/null
+++ b/cli/cli.ts
@@ -0,0 +1,54 @@
+import { default as traverse } from "filewalker";
+import { default as watch } from "node-watch";
+import { readFileSync } from "fs";
+import { transform } from "../src"
+import { outputFileSync, removeSync } from "fs-extra";
+
+function TraverseDirectory(path: string, callback: (relative: string, absolute: string) => void) {
+ const action = (relative: string, stats, absolute: string) => callback(relative, absolute);
+ traverse(path)
+ .on("file", action)
+ .on("error", error => console.log(error))
+ .walk();
+}
+
+function transformFile(absolute: string, config = { debug: false }) {
+ const input = readFileSync(absolute, "utf8");
+ const output = transform(input, config).code;
+ outputFileSync(absolute.replace(".type", ".ts"), output, "utf8");
+}
+
+export function build(dir: string, options: { watch: boolean }) {
+ if (options.watch) {
+ watch(dir, { recursive: true }, (event, absolute: string) => {
+ if (absolute.endsWith(".type")) {
+ console.log(event, absolute);
+ debug(absolute);
+ }
+ });
+ } else {
+ TraverseDirectory(dir, (relative, absolute) => {
+ if (absolute.endsWith(".type")) {
+ transformFile(absolute);
+ }
+ })
+ }
+}
+
+export function clean(dir: string) {
+ TraverseDirectory(dir, (relative, absolute) => {
+ if (absolute.endsWith(".type")) {
+ removeSync(absolute.replace(".type", ".ts"));
+ }
+ })
+}
+
+export function debug(absolute: string) {
+ try {
+ transformFile(absolute, { debug: true });
+ } catch (error) {
+ console.log(`build type failed: ${absolute}`);
+ console.log(error.message);
+ console.log(error.backtrace);
+ }
+}
\ No newline at end of file
diff --git a/cli/index.ts b/cli/index.ts
new file mode 100644
index 0000000..39e30d0
--- /dev/null
+++ b/cli/index.ts
@@ -0,0 +1,44 @@
+#!/usr/bin/env node
+import { default as program } from "commander";
+import { readJSONSync, lstatSync } from "fs-extra";
+import { resolve } from "path";
+import { build, clean, debug } from "./cli";
+
+const packageJSON = readJSONSync(resolve(__dirname, "../../package.json"));
+program.version(packageJSON.version);
+
+program
+ .option('-w, --watch', "watch mode")
+
+program
+ .command("build ")
+ .description("build ts type")
+ .action((dir: string) => {
+ const path = resolve(process.cwd(), dir);
+ if (lstatSync(path).isDirectory()) {
+ const options = program.opts();
+ build(path, { watch: options.watch });
+ }
+ });
+
+program
+ .command("clean ")
+ .description("clean ts type")
+ .action((dir: string) => {
+ const path = resolve(process.cwd(), dir);
+ if (lstatSync(path).isDirectory()) {
+ clean(path);
+ }
+ });
+
+program
+ .command("debug ")
+ .description("debug ts type")
+ .action((file: string) => {
+ const path = resolve(process.cwd(), file);
+ if (!lstatSync(path).isDirectory()) {
+ debug(path);
+ }
+ });
+
+program.parse(process.argv);
diff --git a/package-lock.json b/package-lock.json
index 4effc03..738d4ad 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -864,6 +864,15 @@
"@babel/types": "^7.3.0"
}
},
+ "@types/fs-extra": {
+ "version": "9.0.10",
+ "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.10.tgz",
+ "integrity": "sha512-O9T2LLkRDiTlalOBdjEkcnT0MRdT2+wglCl7pJUJ3mkWkR8hX4K+5bg2raQNJcLv4V8zGuTXe7Ud3wSqkTyuyQ==",
+ "dev": true,
+ "requires": {
+ "@types/node": "*"
+ }
+ },
"@types/istanbul-lib-coverage": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz",
@@ -1078,6 +1087,11 @@
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
"dev": true
},
+ "at-least-node": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
+ "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg=="
+ },
"atob": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
@@ -1450,6 +1464,11 @@
"delayed-stream": "~1.0.0"
}
},
+ "commander": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
+ "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="
+ },
"component-emitter": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
@@ -1964,6 +1983,14 @@
"dev": true,
"optional": true
},
+ "filewalker": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/filewalker/-/filewalker-0.1.3.tgz",
+ "integrity": "sha1-1jv52BO6NTRLgYJ0eCT2/3VL9MU=",
+ "requires": {
+ "fqueue": "0.0.x"
+ }
+ },
"fill-range": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
@@ -2028,6 +2055,11 @@
"mime-types": "^2.1.12"
}
},
+ "fqueue": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/fqueue/-/fqueue-0.0.0.tgz",
+ "integrity": "sha1-UzIFpPmtIbuqOPxhzvOpMML1SDY="
+ },
"fragment-cache": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
@@ -2037,6 +2069,17 @@
"map-cache": "^0.2.2"
}
},
+ "fs-extra": {
+ "version": "9.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
+ "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
+ "requires": {
+ "at-least-node": "^1.0.0",
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^2.0.0"
+ }
+ },
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@@ -2128,8 +2171,7 @@
"graceful-fs": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
- "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
- "dev": true
+ "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw=="
},
"growly": {
"version": "1.3.0",
@@ -3105,6 +3147,15 @@
"minimist": "^1.2.5"
}
},
+ "jsonfile": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
+ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
+ "requires": {
+ "graceful-fs": "^4.1.6",
+ "universalify": "^2.0.0"
+ }
+ },
"jsprim": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
@@ -3402,6 +3453,11 @@
"which": "^1.3.0"
}
},
+ "node-watch": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/node-watch/-/node-watch-0.7.1.tgz",
+ "integrity": "sha512-UWblPYuZYrkCQCW5PxAwYSxaELNBLUckrTBBk8xr1/bUgyOkYYTsUcV4e3ytcazFEOyiRyiUrsG37pu6I0I05g=="
+ },
"normalize-package-data": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
@@ -4582,6 +4638,11 @@
"set-value": "^2.0.1"
}
},
+ "universalify": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
+ "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ=="
+ },
"unset-value": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
diff --git a/package.json b/package.json
index d5878fb..b03c837 100644
--- a/package.json
+++ b/package.json
@@ -22,8 +22,12 @@
"files": [
"build"
],
+ "bin": {
+ "typetype": "build/cli/index.js"
+ },
"license": "MIT",
"devDependencies": {
+ "@types/fs-extra": "^9.0.10",
"@types/jest": "^24.0.17",
"@types/node": "^14.14.22",
"jest": "^24.8.0",
@@ -33,6 +37,10 @@
},
"dependencies": {
"@babel/core": "^7.12.10",
+ "commander": "^7.2.0",
+ "filewalker": "^0.1.3",
+ "fs-extra": "^9.1.0",
+ "node-watch": "^0.7.1",
"pegjs-backtrace": "^0.2.0",
"react-peg": "^0.1.7"
}
diff --git a/src/core/core.tsx b/src/core/core.tsx
index 5c4fbb1..deed4fb 100644
--- a/src/core/core.tsx
+++ b/src/core/core.tsx
@@ -2,7 +2,7 @@ import { ReactPeg } from "react-peg";
import { TypeFile } from "../parser";
import { TSFile } from "../generator";
import generate from "@babel/generator";
-import * as Tracer from "pegjs-backtrace";
+import { default as Tracer } from "pegjs-backtrace";
import { IRenderConfig } from "react-peg/build/renderer/renderer";
export interface ITypeTypeConfig {
diff --git a/tsconfig.json b/tsconfig.json
index a18c868..5b058b2 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -6,9 +6,11 @@
"sourceMap": false,
"outDir": "./build",
"declaration": true,
- "module": "commonjs"
+ "module": "commonjs",
+ "esModuleInterop": true
},
"include": [
- "src/**/*"
+ "src/**/*",
+ "cli/**/*"
]
}
\ No newline at end of file