nestia 2.0.0 → 2.0.1-dev.20220412

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nestia",
3
- "version": "2.0.0",
3
+ "version": "2.0.1-dev.20220412",
4
4
  "description": "Automatic SDK and Document generator for the NestJS",
5
5
  "main": "src/index.ts",
6
6
  "bin": {
@@ -37,9 +37,11 @@
37
37
  "del": "^6.0.0",
38
38
  "glob": "^7.2.0",
39
39
  "ts-node": "^9.1.1",
40
- "tsconfig-paths": "^3.14.1",
41
40
  "tstl": "^2.5.3",
42
- "typescript": "^4.6.3"
41
+ "ttypescript": "^1.5.13",
42
+ "typescript": "^4.5.3",
43
+ "typescript-is": "^0.19.0",
44
+ "typescript-transform-paths": "^3.3.1"
43
45
  },
44
46
  "devDependencies": {
45
47
  "nestia-helper": "^2.0.0",
@@ -5,6 +5,7 @@ export interface IConfiguration
5
5
  input: string | string[] | IConfiguration.IInput;
6
6
  output: string;
7
7
  compilerOptions?: tsc.CompilerOptions;
8
+ assert?: boolean;
8
9
  }
9
10
  export namespace IConfiguration
10
11
  {
@@ -85,7 +85,7 @@ export class NestiaApplication
85
85
  }
86
86
 
87
87
  // DO GENERATE
88
- await SdkGenerator.generate(this.config_.output, routeList);
88
+ await SdkGenerator.generate(this.config_, routeList);
89
89
  }
90
90
 
91
91
  private async is_not_excluded(file: string): Promise<boolean>
@@ -1,4 +1,4 @@
1
- import Pather from "path";
1
+ import * as Pather from "path";
2
2
 
3
3
  import { ArrayUtil } from "../utils/ArrayUtil";
4
4
  import { StringUtil } from "../utils/StringUtil";
@@ -1,6 +1,6 @@
1
- import fs from "fs";
1
+ import * as fs from "fs";
2
2
  import glob from "glob";
3
- import path from "path";
3
+ import * as path from "path";
4
4
 
5
5
  import { IConfiguration } from "../IConfiguration";
6
6
 
package/src/bin/nestia.ts CHANGED
@@ -1,80 +1,123 @@
1
1
  #!/usr/bin/env ts-node
2
2
 
3
- import cp from "child_process";
4
- import fs from "fs";
5
- import tsc from "typescript";
3
+ import * as cp from "child_process";
4
+ import * as fs from "fs";
5
+ import { CompilerOptions } from "../internal/CompilerOptions";
6
6
 
7
7
  import { stripJsonComments } from "../utils/stripJsonComments";
8
8
 
9
+ interface IConfig
10
+ {
11
+ compilerOptions?: CompilerOptions;
12
+ }
13
+
9
14
  function install(): void
10
15
  {
11
- const command: string = "npm install --save nestia-fetcher";
12
- cp.execSync(command, { stdio: "inherit" });
16
+ // INSTALL DEPENDENCIES
17
+ for (const lib of ["nestia-fetcher", "typescript-is"])
18
+ {
19
+ const command: string = `npm install ${lib}`;
20
+ cp.execSync(command, { stdio: "inherit" });
21
+ }
13
22
  }
14
23
 
15
- function sdk(alias: boolean): void
24
+ function sdk(): void
16
25
  {
26
+ // PREPARE COMMAND
17
27
  const parameters: string[] = [
18
- alias ? "npx ts-node -r tsconfig-paths/register" : "npx ts-node",
28
+ "npx ts-node -C ttypescript",
19
29
  __dirname + "/../executable/sdk",
20
30
  ...process.argv.slice(3)
21
31
  ];
22
32
  const command: string = parameters.join(" ");
23
- cp.execSync(command, { stdio: "inherit" });
33
+
34
+ // EXECUTE THE COMMAND, BUT IGNORE WARNINGS
35
+ cp.execSync
36
+ (
37
+ command,
38
+ {
39
+ stdio: "inherit",
40
+ env: { "NODE_NO_WARNINGS": "1" }
41
+ }
42
+ );
24
43
  }
25
44
 
26
- async function tsconfig(task: (alias: boolean) => void): Promise<void>
45
+ function configure(config: IConfig): boolean
27
46
  {
28
- // NO TSCONFIG.JSON?
29
- if (fs.existsSync("tsconfig.json") === false)
47
+ if (!config.compilerOptions)
30
48
  {
31
- task(false);
32
- return;
33
- }
34
-
35
- const content: string = await fs.promises.readFile("tsconfig.json", "utf8");
36
- const json: any = JSON.parse(stripJsonComments(content));
37
- const options: tsc.CompilerOptions = json.compilerOptions;
38
-
39
- // NO ALIAS PATHS
40
- if (!options.paths || !Object.entries(options.paths).length)
41
- {
42
- task(false);
43
- return;
49
+ config.compilerOptions = CompilerOptions.DEFAULT;
50
+ return true;
44
51
  }
52
+ else
53
+ return CompilerOptions.emend(config.compilerOptions);
54
+ }
45
55
 
46
- let closer: null | (() => Promise<void>) = null;
47
- let error: Error | null = null;
56
+ async function tsconfig(task: () => void): Promise<void>
57
+ {
58
+ //----
59
+ // PREPARE ASSETS
60
+ //----
61
+ let prepare: null | (() => Promise<void>) = null;
62
+ let restore: null | (() => Promise<void>) = null;
48
63
 
49
- if (!options.baseUrl)
64
+ if (fs.existsSync("tsconfig.json") === false)
50
65
  {
51
- options.baseUrl = "./";
52
- await fs.promises.writeFile
66
+ // NO TSCONFIG.JSON
67
+ const config: IConfig = {
68
+ compilerOptions: CompilerOptions.DEFAULT
69
+ };
70
+ prepare = () => fs.promises.writeFile
53
71
  (
54
- "tsconfig.json",
55
- JSON.stringify(json, null, 2),
72
+ "tsconfig.json",
73
+ JSON.stringify(config, null, 2),
56
74
  "utf8"
57
75
  );
76
+ restore = () => fs.promises.unlink("tsconfig.json")
77
+ }
78
+ else
79
+ {
80
+ // HAS TSCONFIG.JSON
81
+ const content: string = await fs.promises.readFile("tsconfig.json", "utf8");
82
+ const config: IConfig = JSON.parse(stripJsonComments(content));
83
+ const changed: boolean = configure(config);
58
84
 
59
- closer = () => fs.promises.writeFile
60
- (
61
- "tsconfig.json",
62
- content,
63
- "utf8"
64
- );
85
+ if (changed === true)
86
+ {
87
+ // NEED TO ADD TRANSFORM PLUGINS
88
+ prepare = () => fs.promises.writeFile
89
+ (
90
+ "tsconfig.json",
91
+ JSON.stringify(config, null, 2),
92
+ "utf8"
93
+ );
94
+ restore = () => fs.promises.writeFile("tsconfig.json", content, "utf8");
95
+ }
65
96
  }
66
97
 
98
+ //----
99
+ // EXECUTION
100
+ //----
101
+ // PREPARE SOMETHING
102
+ if (prepare !== null)
103
+ await prepare();
104
+
105
+ // EXECUTE THE TASK
106
+ let error: Error | null = null;
67
107
  try
68
108
  {
69
- task(true);
109
+ task();
70
110
  }
71
111
  catch (exp)
72
112
  {
73
113
  error = exp as Error;
74
114
  }
75
115
 
76
- if (closer)
77
- await closer();
116
+ // RESTORE THE TSCONFIG.JSON
117
+ if (restore !== null)
118
+ await restore();
119
+
120
+ // THROW ERROR IF EXISTS
78
121
  if (error)
79
122
  throw error;
80
123
  }
@@ -1,7 +1,7 @@
1
- import cli from "cli";
2
- import fs from "fs";
3
- import path from "path";
4
- import tsc from "typescript";
1
+ import * as cli from "cli";
2
+ import * as fs from "fs";
3
+ import * as path from "path";
4
+ import * as tsc from "typescript";
5
5
  import { Primitive } from "nestia-fetcher";
6
6
 
7
7
  import { IConfiguration } from "../IConfiguration";
@@ -1,5 +1,6 @@
1
1
  import * as fs from "fs";
2
2
  import { HashMap } from "tstl/container/HashMap";
3
+ import { IConfiguration } from "../IConfiguration";
3
4
 
4
5
  import { IRoute } from "../structures/IRoute";
5
6
  import { ImportDictionary } from "../utils/ImportDictionary";
@@ -10,7 +11,7 @@ export namespace FileGenerator
10
11
  /* ---------------------------------------------------------
11
12
  CONSTRUCTOR
12
13
  --------------------------------------------------------- */
13
- export async function generate(outDir: string, routeList: IRoute[]): Promise<void>
14
+ export async function generate(config: IConfiguration, routeList: IRoute[]): Promise<void>
14
15
  {
15
16
  // CONSTRUCT FOLDER TREE
16
17
  const root: Directory = new Directory(null, "functional");
@@ -21,7 +22,7 @@ export namespace FileGenerator
21
22
  relocate(root);
22
23
 
23
24
  // ITERATE FILES
24
- await iterate(outDir + "/functional", root);
25
+ await iterate(!!config.assert, config.output + "/functional", root);
25
26
  }
26
27
 
27
28
  function emplace(directory: Directory, route: IRoute): void
@@ -63,7 +64,12 @@ export namespace FileGenerator
63
64
  /* ---------------------------------------------------------
64
65
  FILE ITERATOR
65
66
  --------------------------------------------------------- */
66
- async function iterate(outDir: string, directory: Directory): Promise<void>
67
+ async function iterate
68
+ (
69
+ assert: boolean,
70
+ outDir: string,
71
+ directory: Directory
72
+ ): Promise<void>
67
73
  {
68
74
  // CREATE A NEW DIRECTORY
69
75
  try
@@ -76,7 +82,7 @@ export namespace FileGenerator
76
82
  let content: string = "";
77
83
  for (const it of directory.directories)
78
84
  {
79
- await iterate(`${outDir}/${it.first}`, it.second);
85
+ await iterate(assert, `${outDir}/${it.first}`, it.second);
80
86
  content += `export * as ${it.first} from "./${it.first}";\n`;
81
87
  }
82
88
  content += "\n";
@@ -88,27 +94,34 @@ export namespace FileGenerator
88
94
  for (const tuple of route.imports)
89
95
  for (const instance of tuple[1])
90
96
  importDict.emplace(tuple[0], false, instance);
91
- content += FunctionGenerator.generate(route) + "\n\n";
97
+ content += FunctionGenerator.generate(assert, route) + "\n\n";
92
98
  }
93
99
 
94
100
  // FINALIZE THE CONTENT
95
101
  if (directory.routes.length !== 0)
102
+ {
103
+ const primitived: boolean = directory.routes.some(route => route.output !== "void"
104
+ || route.parameters.some(param => param.category !== "param")
105
+ );
106
+ const asserted: boolean = assert
107
+ && directory.routes.some(route => route.parameters.length !== 0);
108
+
109
+ const fetcher: string[] = ["Fetcher"];
110
+ if (primitived)
111
+ fetcher.push("Primitive");
112
+
96
113
  content = ""
97
- + `import { AesPkcs5, Fetcher, Primitive } from "nestia-fetcher";\n`
114
+ + `import { ${fetcher.join(", ")} } from "nestia-fetcher";\n`
98
115
  + `import type { IConnection } from "nestia-fetcher";\n`
116
+ + (asserted ? `import { assertType } from "typescript-is";\n` : "")
99
117
  +
100
118
  (
101
119
  importDict.empty()
102
120
  ? ""
103
121
  : "\n" + importDict.toScript(outDir) + "\n"
104
122
  )
105
- + content + "\n\n"
106
- + "//---------------------------------------------------------\n"
107
- + "// TO PREVENT THE UNUSED VARIABLE ERROR\n"
108
- + "//---------------------------------------------------------\n"
109
- + "AesPkcs5;\n"
110
- + "Fetcher;\n"
111
- + "Primitive;";
123
+ + content;
124
+ }
112
125
 
113
126
  content = "/**\n"
114
127
  + " * @packageDocumentation\n"
@@ -6,13 +6,13 @@ import { IRoute } from "../structures/IRoute";
6
6
 
7
7
  export namespace FunctionGenerator
8
8
  {
9
- export function generate(route: IRoute): string
9
+ export function generate(assert: boolean, route: IRoute): string
10
10
  {
11
11
  const query: IRoute.IParameter | undefined = route.parameters.find(param => param.category === "query");
12
12
  const input: IRoute.IParameter | undefined = route.parameters.find(param => param.category === "body");
13
13
 
14
14
  return [head, body, tail]
15
- .map(closure => closure(route, query, input))
15
+ .map(closure => closure(route, query, input, assert))
16
16
  .filter(str => !!str)
17
17
  .join("\n");
18
18
  }
@@ -20,7 +20,13 @@ export namespace FunctionGenerator
20
20
  /* ---------------------------------------------------------
21
21
  BODY
22
22
  --------------------------------------------------------- */
23
- function body(route: IRoute, query: IRoute.IParameter | undefined, input: IRoute.IParameter | undefined): string
23
+ function body
24
+ (
25
+ route: IRoute,
26
+ query: IRoute.IParameter | undefined,
27
+ input: IRoute.IParameter | undefined,
28
+ assert: boolean
29
+ ): string
24
30
  {
25
31
  // FETCH ARGUMENTS WITH REQUST BODY
26
32
  const parameters = filter_parameters(route, query);
@@ -34,8 +40,15 @@ export namespace FunctionGenerator
34
40
  if (input !== undefined)
35
41
  fetchArguments.push(input.name);
36
42
 
43
+ const assertions: string = assert === true && route.parameters.length !== 0
44
+ ? route.parameters
45
+ .map(param => ` assertType<typeof ${param.name}>(${param.name});`)
46
+ .join("\n") + "\n\n"
47
+ : "";
48
+
37
49
  // RETURNS WITH FINALIZATION
38
50
  return "{\n"
51
+ + assertions
39
52
  + " return Fetcher.fetch\n"
40
53
  + " (\n"
41
54
  + fetchArguments.map(param => ` ${param}`).join(",\n") + "\n"
@@ -54,7 +67,12 @@ export namespace FunctionGenerator
54
67
  /* ---------------------------------------------------------
55
68
  HEAD & TAIL
56
69
  --------------------------------------------------------- */
57
- function head(route: IRoute, query: IRoute.IParameter | undefined, input: IRoute.IParameter | undefined): string
70
+ function head
71
+ (
72
+ route: IRoute,
73
+ query: IRoute.IParameter | undefined,
74
+ input: IRoute.IParameter | undefined
75
+ ): string
58
76
  {
59
77
  //----
60
78
  // CONSTRUCT COMMENT
@@ -132,7 +150,12 @@ export namespace FunctionGenerator
132
150
  + ` ): Promise<${output}>`;
133
151
  }
134
152
 
135
- function tail(route: IRoute, query: IRoute.IParameter | undefined, input: IRoute.IParameter | undefined): string | null
153
+ function tail
154
+ (
155
+ route: IRoute,
156
+ query: IRoute.IParameter | undefined,
157
+ input: IRoute.IParameter | undefined
158
+ ): string | null
136
159
  {
137
160
  // LIST UP TYPES
138
161
  const types: Pair<string, string>[] = [];
@@ -3,13 +3,18 @@ import { DirectoryUtil } from "../utils/DirectoryUtil";
3
3
 
4
4
  import { IRoute } from "../structures/IRoute";
5
5
  import { FileGenerator } from "./FileGenerator";
6
+ import { IConfiguration } from "../IConfiguration";
6
7
 
7
8
  export namespace SdkGenerator
8
9
  {
9
- export async function generate(outDir: string, routeList: IRoute[]): Promise<void>
10
+ export async function generate
11
+ (
12
+ config: IConfiguration,
13
+ routeList: IRoute[],
14
+ ): Promise<void>
10
15
  {
11
16
  // PREPARE NEW DIRECTORIES
12
- try { await fs.promises.mkdir(outDir); } catch {}
17
+ try { await fs.promises.mkdir(config.output); } catch {}
13
18
 
14
19
  // BUNDLING
15
20
  const bundle: string[] = await fs.promises.readdir(BUNDLE);
@@ -21,13 +26,13 @@ export namespace SdkGenerator
21
26
  if (stats.isFile() === true)
22
27
  {
23
28
  const content: string = await fs.promises.readFile(current, "utf8");
24
- await fs.promises.writeFile(`${outDir}/${file}`, content, "utf8");
29
+ await fs.promises.writeFile(`${config.output}/${file}`, content, "utf8");
25
30
  }
26
31
  }
27
- await DirectoryUtil.copy(BUNDLE + "/__internal", outDir + "/__internal");
32
+ await DirectoryUtil.copy(BUNDLE + "/__internal", config.output + "/__internal");
28
33
 
29
34
  // FUNCTIONAL
30
- await FileGenerator.generate(outDir, routeList);
35
+ await FileGenerator.generate(config, routeList);
31
36
  }
32
37
  }
33
38
 
@@ -0,0 +1,113 @@
1
+ export interface CompilerOptions
2
+ {
3
+ target: string;
4
+ module: string;
5
+ lib: string[];
6
+ strict: boolean;
7
+ downlevelIteration: boolean;
8
+ esModuleInterop?: boolean;
9
+ plugins?: Array<{
10
+ transform?: string
11
+ }>;
12
+ types?: string[];
13
+ experimentalDecorators?: boolean;
14
+ emitDecoratorMetadata?: boolean;
15
+ }
16
+ export namespace CompilerOptions
17
+ {
18
+ export const DEPENDENCIES: string[] = [
19
+ "nestia-fetcher",
20
+ "typescript-is"
21
+ ];
22
+
23
+ export const TRANSFORMERS: string[] = [
24
+ "typescript-is/lib/transform-inline/transformer",
25
+ "typescript-transform-paths"
26
+ ];
27
+
28
+ export const TYPES: string[] = []
29
+
30
+ export const DEFAULT = {
31
+ target: "es5",
32
+ module: "commonjs",
33
+ lib: [
34
+ "DOM",
35
+ "ES2015"
36
+ ],
37
+ strict: true,
38
+ downlevelIteration: true,
39
+ esModuleInterop: true,
40
+ plugins: TRANSFORMERS.map(transform => ({ transform })),
41
+ types: [
42
+ "node",
43
+ "reflect-metadata"
44
+ ],
45
+ experimentalDecorators: true,
46
+ emitDecoratorMetadata: true,
47
+ };
48
+
49
+ export function emend(options: CompilerOptions): boolean
50
+ {
51
+ // FILL ARRAY DATA
52
+ if (!options.plugins)
53
+ options.plugins = [];
54
+ if (!options.types)
55
+ options.types = [];
56
+
57
+ // CONSTRUCT CHECKERS
58
+ const emended: Required<CompilerOptions> = options as Required<CompilerOptions>;
59
+ const checkers: Array<() => boolean> = [
60
+ () =>
61
+ {
62
+ let changed: boolean = false;
63
+ for (const transform of CompilerOptions.TRANSFORMERS)
64
+ {
65
+ if (emended.plugins.find(elem => elem.transform === transform) !== undefined)
66
+ continue;
67
+
68
+ changed = true;
69
+ emended.plugins.push({ transform });
70
+ }
71
+ return changed;
72
+ },
73
+ () =>
74
+ {
75
+ let changed: boolean = false;
76
+ for (const type of CompilerOptions.TYPES)
77
+ {
78
+ if (emended.types.find(elem => elem === type) !== undefined)
79
+ continue;
80
+
81
+ changed = true;
82
+ emended.types.push(type);
83
+ }
84
+ return changed;
85
+ },
86
+ () =>
87
+ {
88
+ const changed: boolean = emended.experimentalDecorators !== true;
89
+ if (changed)
90
+ emended.experimentalDecorators = true;
91
+ return changed;
92
+ },
93
+ () =>
94
+ {
95
+ const changed: boolean = emended.emitDecoratorMetadata !== true;
96
+ if (changed)
97
+ emended.emitDecoratorMetadata = true;
98
+ return changed;
99
+ },
100
+ () =>
101
+ {
102
+ const changed: boolean = emended.esModuleInterop !== true;
103
+ if (changed)
104
+ emended.esModuleInterop = true;
105
+ return changed;
106
+ }
107
+ ];
108
+
109
+ // DO CHECK IT
110
+ const checks: boolean[] = checkers.map(func => func());
111
+ return checks.some(flag => flag);
112
+ }
113
+ }
package/tsconfig.json CHANGED
@@ -72,7 +72,11 @@
72
72
 
73
73
  /* Advanced Options */
74
74
  "skipLibCheck": true, /* Skip type checking of declaration files. */
75
- "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
75
+ "forceConsistentCasingInFileNames": true, /* Disallow inconsistently-cased references to the same file. */
76
+ "plugins": [
77
+ { "transform": "typescript-is/lib/transform-inline/transformer" },
78
+ { "transform": "typescript-transform-paths" }
79
+ ]
76
80
  },
77
81
  "include": ["src"]
78
82
  }