nestia 0.2.2 → 0.3.1

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/README.md CHANGED
@@ -6,21 +6,42 @@ Automatic SDK generator for the NestJS.
6
6
  [![Downloads](https://img.shields.io/npm/dm/nestia.svg)](https://www.npmjs.com/package/nestia)
7
7
  [![Build Status](https://github.com/samchon/nestia/workflows/build/badge.svg)](https://github.com/samchon/nestia/actions?query=workflow%3Abuild)
8
8
 
9
- ## Outline
10
- If you're making a backend server with the **TypeScript** and **NestJS**, you don't need any extra dedication, for delivering Rest API to the client (front-end) developers, like writing `swagger.json` comments.
11
-
12
- Just generate a SDK library through the **Nestia** and deliver the SDK library to the client developers. The client developers can call your backend server API just by calling the SDK library functions with *await* symbol, re-using the interfaces what you've defined.
13
-
14
9
  ```bash
15
10
  npm install --save-dev nestia
16
11
  npx nestia sdk "src/controller" --out "src/api"
17
12
  ```
18
13
 
19
- If you want to see an example project using the **Nestia**, click below links:
14
+ Don't write any `swagger` comment. Just deliver the SDK.
15
+
16
+ When you're developing a backend server using the `NestJS`, you don't need any extra dedication, for delivering the Rest API to the client developers, like writing the `swagger` comments. You just run this **Nestia** up, then **Nestia** would generate the SDK automatically, by analyzing your controller classes in the compliation and runtime level.
17
+
18
+ With the automatically generated SDK through this **Nestia**, client developer also does not need any extra work, like reading `swagger` and writing the duplicated interaction code. Client developer only needs to import the SDK and calls matched function with the `await` symbol.
20
19
 
21
- - [Controllers of the NestJS](https://github.surf/samchon/nestia/blob/HEAD/src/test/controllers/base/SaleCommentsController.ts)
22
- - [Structures used in the RestAPI](https://github.surf/samchon/nestia/blob/HEAD/api/structures/sales/articles/ISaleArticle.ts)
23
- - [**SDK generated by the Nestia**](https://github.surf/samchon/nestia/blob/HEAD/api/functional/consumers/sales/reviews/index.ts)
20
+ ```typescript
21
+ import api from "@samchon/bbs-api";
22
+ import { IBbsArticle } from "@samchon/bbs-api/lib/structures/bbs/IBbsArticle";
23
+ import { IPage } from "@samchon/bbs-api/lib/structures/common/IPage";
24
+
25
+ export async function test_article_read(connection: api.IConnection): Promise<void>
26
+ {
27
+ // LIST UP ARTICLE SUMMARIES
28
+ const index: IPage<IBbsArticle.ISummary> = await api.functional.bbs.articles.index
29
+ (
30
+ connection,
31
+ "free",
32
+ { limit: 100, page: 1 }
33
+ );
34
+
35
+ // READ AN ARTICLE DETAILY
36
+ const article: IBbsArticle = await api.functional.bbs.articles.at
37
+ (
38
+ connection,
39
+ "free",
40
+ index.data[0].id
41
+ );
42
+ console.log(article.title, aritlce.body, article.files);
43
+ }
44
+ ```
24
45
 
25
46
 
26
47
 
@@ -29,29 +50,215 @@ If you want to see an example project using the **Nestia**, click below links:
29
50
  ### Installation
30
51
  ```bash
31
52
  npm install --save-dev nestia
32
- npx nestia sdk "src/controllers" --out "src/api"
33
53
  ```
34
54
 
35
55
  Installing the **Nestia** is very easy.
36
56
 
37
57
  Just type the `npm install --save-dev nestia` command in your NestJS backend project.
38
58
 
39
- ### CLI options
59
+ ### SDK generation
40
60
  ```bash
41
61
  npx nestia sdk <source_controller_directory> --out <output_sdk_directory>
42
62
 
43
63
  npx nestia sdk "src/controllers" --out "src/api"
44
- npx nestia sdk "src/consumers/controllers" "src/sellers/controllers" --out "src/api
64
+ npx nestia sdk "src/controllers/consumers" "src/controllers/sellers" --out "src/api
45
65
  ```
46
66
 
47
- To generate a SDK library through the **Nestia** is very easy. Just type the `nestia sdk <input> --out <output>` command in the console. If there're multiple source directories containing the NestJS controller classes, type all of them separating by a `space` word.
67
+ To generate a SDK library through the **Nestia** is very easy.
68
+
69
+ Just type the `nestia sdk <input> --out <output>` command in the console. If there're multiple source directories containing the NestJS controller classes, type all of them separating by a `space` word.
48
70
 
71
+ Also, when generating a SDK using the cli options, `compilerOptions` would follow the `tsconfig.json`, that is configured for the backend server. If no `tsconfig.json` file exists in your project, the configuration would be default option (`ES5` with `strict` mode). If you want to use different `compilerOptions` with the `tsconfig.json`, you should configure the [nestia.config.ts](#nestiaconfigts).
49
72
 
50
73
  ```bash
51
74
  npx nestia install
52
75
  ```
53
76
 
54
- Also, SDK library generated by the **Nestia** has some dependencies like below. When you type the `nestia install` command in the console, those dependencies would be automatically install and would be enrolled to the `dependencies` field in the `package.json`
77
+ ### Dependencies
78
+ SDK library generated by the **Nestia** has some dependencies like below.
79
+
80
+ When you type the `nestia install` command in the console, those dependencies would be automatically installed and enrolled to the `dependencies` and `devDependencies` fields in the `package.json`
55
81
 
56
82
  - [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node)
57
- - [node-fetch](https://github.com/node-fetch/node-fetch)
83
+ - [node-fetch](https://github.com/node-fetch/node-fetch)
84
+
85
+
86
+
87
+
88
+ ## Advanced
89
+ ### `nestia.config.ts`
90
+ ```typescript
91
+ export namespace NestiaApplication
92
+ {
93
+ export interface IConfiguration
94
+ {
95
+ /**
96
+ * List of directories containing the NestJS controller classes.
97
+ */
98
+ input: string | string[];
99
+
100
+ /**
101
+ * Output directory that SDK would be placed in.
102
+ */
103
+ output: string;
104
+
105
+ /**
106
+ * Compiler options for the TypeScript.
107
+ *
108
+ * If omitted, the configuration would follow the `tsconfig.json`.
109
+ */
110
+ compilerOptions?: tsc.CompilerOptions
111
+ }
112
+ }
113
+ ```
114
+
115
+ Instead of specifying `input` and `output` directories using the cli options, you can specify those directories as an independent configuration file. It's the `nestia.config.ts` and with the `nestia.config.ts` file, you also configure independent TypeScript compiler option from the `tsconfig.json`.
116
+
117
+ Write below content as the `nestia.config.ts` file and place it onto the root directory of your backend project. After the configuration, you can generate the SDK only with the `npx nestia sdk` command, without any directory specification.
118
+
119
+ ```typescript
120
+ export = {
121
+ input: "src/controllers`",
122
+ output: "src/api"
123
+ };
124
+ ```
125
+
126
+
127
+
128
+ ### Recommended Structures
129
+ When developing a NestJS backend server with this **Nestia**, I recommend you to follow below directory structure. The key princinple of below structure is to gathering all of the DTO interface structures into the `src/api/structures` directory and gather all of the controller classes into the `src/controllers` directory.
130
+
131
+ If you place the SDK onto the `src/api` directory and gather all of the DTO interface structures into the `src/api/structures` directory, you can publish the SDK library very easily without any special configuration. Also when you're develop the test automation program, you can implement the API testing features very convenienty through the automatically generated SDK through this **Nestia**.
132
+
133
+ - src
134
+ - api
135
+ - **functional**: automatically generated SDK functions
136
+ - **structures**: DTO structures
137
+ - controllers
138
+ - providers
139
+ - models
140
+ - **test**: Test automation program using SDK functions
141
+ - package.json
142
+ - tsconfig.json
143
+ - nestia.config.ts
144
+
145
+ For your deep understanding about this directory structure with this **Nestia**, I've prepared an example backend project. Looking around the example repository and reading the [README.md](https://github.com/samchon/backend#13-directories) of it, you can feel that such directory structure is how convenient for SDK publishing and test automation program implementation.
146
+
147
+ - https://github.com/samchon/backend
148
+
149
+
150
+
151
+
152
+ ## Demonstration
153
+ To demonstrate which SDK codes would be generated by this **Nestia**:
154
+
155
+ - [Controllers of the NestJS](https://github.surf/samchon/nestia/blob/HEAD/test/default/src/controllers/base/SaleCommentsController.ts)
156
+ - [Structures used in the RestAPI](https://github.surf/samchon/nestia/blob/HEAD/test/default/src/api/structures/sales/articles/ISaleArticle.ts)
157
+ - [SDK generated by this **Nestia**](https://github.surf/samchon/nestia/blob/HEAD/test/default/src/api/functional/consumers/sales/reviews/index.ts)
158
+
159
+ ### Controller
160
+ If you've decided to adapt this **Nestia** and you want to generate the SDK directly, you don't need any extra work. Just keep you controller class down and do noting. The only one exceptional case that you need an extra dedication is, when you want to explain about the API function to the client developers through the comments.
161
+
162
+ ```typescript
163
+ @nest.Controller("consumers/:section/sales/:saleId/questions")
164
+ export class ConsumerSaleQuestionsController
165
+ {
166
+ /**
167
+ * Store a new question.
168
+ *
169
+ * @param request Instance of the Express.Request
170
+ * @param section Code of the target section
171
+ * @param saleId ID of the target sale
172
+ * @param input Content to archive
173
+ *
174
+ * @return Newly archived question
175
+ * @throw 400 bad request error when type of the input data is not valid
176
+ * @throw 401 unauthorized error when you've not logged in yet
177
+ */
178
+ @nest.Post()
179
+ public store
180
+ (
181
+ @nest.Request() request: express.Request,
182
+ @nest.Param("section") section: string,
183
+ @nest.Param("saleId") saleId: number,
184
+ @nest.Body() input: ISaleQuestion.IStore
185
+ ): Promise<ISaleQuestion>;
186
+ }
187
+ ```
188
+
189
+ ### SDK
190
+ When you run the **Nestia** up using the upper controller class `ConsumerSaleQuestionsController`, the **Nestia** would generate below function for the client developers, by analyzing the `ConsumerSaleQuestionsController` class in the compilation and runtime level.
191
+
192
+ As you can see, the comments from the `ConsumerSaleQuestionsController.store()` are fully copied to the SDK function. Therefore, if you want to deliver detailed description about the API function, writing the detailed comment would be tne best choice.
193
+
194
+ ```typescript
195
+ /**
196
+ * Store a new question.
197
+ *
198
+ * @param connection connection Information of the remote HTTP(s) server with headers (+encryption password)
199
+ * @param request Instance of the Express.Request
200
+ * @param section Code of the target section
201
+ * @param saleId ID of the target sale
202
+ * @param input Content to archive
203
+ * @return Newly archived question
204
+ * @throw 400 bad request error when type of the input data is not valid
205
+ * @throw 401 unauthorized error when you've not logged in yet
206
+ *
207
+ * @nestia Generated by Nestia - https://github.com/samchon/nestia
208
+ * @controller ConsumerSaleQuestionsController.store()
209
+ * @path POST /consumers/:section/sales/:saleId/questions/
210
+ */
211
+ export function store
212
+ (
213
+ connection: IConnection,
214
+ section: string,
215
+ saleId: number,
216
+ input: store.Input
217
+ ): Promise<store.Output>
218
+ {
219
+ return Fetcher.fetch
220
+ (
221
+ connection,
222
+ {
223
+ input_encrypted: false,
224
+ output_encrypted: false
225
+ },
226
+ "POST",
227
+ `/consumers/${section}/sales/${saleId}/questions/`,
228
+ input
229
+ );
230
+ }
231
+ export namespace store
232
+ {
233
+ export type Input = Primitive<ISaleInquiry.IStore>;
234
+ export type Output = Primitive<ISaleInquiry<ISaleArticle.IContent>>;
235
+ }
236
+ ```
237
+
238
+
239
+
240
+
241
+ ## Appendix
242
+ ### Safe-TypeORM
243
+ https://github.com/samchon/safe-typeorm
244
+
245
+ [safe-typeorm](https://github.com/samchon/safe-typeorm) is another library that what I've developed, helping typeorm in the compilation level and optimizes DB performance automatically without any extra dedication.
246
+
247
+ Therefore, this **Nestia** makes you to be much convenient in the API interaction level and safe-typeorm helps you to be much convenient in the DB interaction level. With those **Nestia** and [safe-typeorm](https://github.com/samchon/safe-typeorm), let's implement the backend server much easily and conveniently.
248
+
249
+ ### Technial Support
250
+ samchon.github@gmail.com
251
+
252
+ I can provide technical support about those **Nestia** and [safe-typeorm](https://github.com/samchon/safe-typeorm).
253
+
254
+ Therefore, if you have any question or need help, feel free to contact me. If you want to adapt those **Nestia** and [safe-typeorm](https://github.com/samchon/safe-typeorm) in your commercial project, I can provide you the best guidance.
255
+
256
+ I also can help your backend project in the entire development level. If you're suffering by DB architecture design or API structure design, just contact me and get help. I'll help you with my best effort.
257
+
258
+ ### Archidraw
259
+ https://www.archisketch.com/
260
+
261
+ I have special thanks to the Archidraw, where I'm working for.
262
+
263
+ The Archidraw is a great IT company developing 3D interior editor and lots of solutions based on the 3D assets. Also, the Archidraw is the first company who had adopted this **Nestia** on their commercial backend project, even this **Nestia** was in the alpha level.
264
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nestia",
3
- "version": "0.2.2",
3
+ "version": "0.3.1",
4
4
  "description": "Automatic SDK and Document generator for the NestJS",
5
5
  "main": "src/index.ts",
6
6
  "bin": {
@@ -8,7 +8,7 @@
8
8
  },
9
9
  "scripts": {
10
10
  "dev": "tsc --watch",
11
- "test": "ts-node src/bin/nestia sdk src/test/controllers --out api"
11
+ "test": "cd test && bash script.sh"
12
12
  },
13
13
  "repository": {
14
14
  "type": "git",
@@ -34,7 +34,7 @@
34
34
  "cli": "^1.0.1",
35
35
  "del": "^6.0.0",
36
36
  "ts-node": "^9.1.1",
37
- "tstl": "^2.4.21",
37
+ "tstl": "^2.5.0",
38
38
  "ttypescript": "^1.5.12",
39
39
  "typescript": "^4.3.2"
40
40
  },
@@ -15,26 +15,18 @@ import { ArrayUtil } from "./utils/ArrayUtil";
15
15
 
16
16
  export class NestiaApplication
17
17
  {
18
- public readonly inputs: string[];
19
- public readonly output: string;
18
+ private readonly config_: NestiaApplication.IConfiguration;
19
+ private readonly bundle_checker_: Singleton<Promise<(str: string) => boolean>>;
20
20
 
21
- private readonly bundle_checker_: Singleton<(str: string) => boolean>;
22
-
23
- public constructor
24
- (
25
- inputs: string[],
26
- output: string
27
- )
21
+ public constructor(config: NestiaApplication.IConfiguration)
28
22
  {
29
- this.inputs = inputs.map(str => path.resolve(str));
30
- this.output = path.resolve(output);
31
-
23
+ this.config_ = config;
32
24
  this.bundle_checker_ = new Singleton(async () =>
33
25
  {
34
26
  const bundles: string[] = await fs.promises.readdir(`${__dirname}${path.sep}bundle`);
35
27
  const tuples: Pair<string, boolean>[] = await ArrayUtil.asyncMap(bundles, async file =>
36
28
  {
37
- const relative: string = `${this.output}${path.sep}${file}`;
29
+ const relative: string = `${this.config_.output}${path.sep}${file}`;
38
30
  const stats: fs.Stats = await fs.promises.stat(`${__dirname}${path.sep}bundle${path.sep}${file}`);
39
31
 
40
32
  return new Pair(relative, stats.isDirectory());
@@ -52,13 +44,17 @@ export class NestiaApplication
52
44
  });
53
45
  }
54
46
 
55
- public async sdk(): Promise<void>
47
+ public async generate(): Promise<void>
56
48
  {
57
49
  // LOAD CONTROLLER FILES
58
50
  const fileList: string[] = [];
59
- for (const input of this.inputs)
51
+ const inputList: string[] = this.config_.input instanceof Array
52
+ ? this.config_.input
53
+ : [this.config_.input];
54
+
55
+ for (const file of inputList.map(str => path.resolve(str)))
60
56
  {
61
- const found: string[] = await SourceFinder.find(input);
57
+ const found: string[] = await SourceFinder.find(file);
62
58
  const filtered: string[] = await ArrayUtil.asyncFilter(found, file => this.is_not_excluded(file));
63
59
 
64
60
  fileList.push(...filtered);
@@ -72,7 +68,11 @@ export class NestiaApplication
72
68
  controllerList.push(...await ReflectAnalyzer.analyze(unique, file));
73
69
 
74
70
  // ANALYZE TYPESCRIPT CODE
75
- const program: tsc.Program = tsc.createProgram(controllerList.map(c => c.file), {});
71
+ const program: tsc.Program = tsc.createProgram
72
+ (
73
+ controllerList.map(c => c.file),
74
+ this.config_.compilerOptions || {}
75
+ );
76
76
  const checker: tsc.TypeChecker = program.getTypeChecker();
77
77
 
78
78
  const routeList: IRoute[] = [];
@@ -86,12 +86,22 @@ export class NestiaApplication
86
86
  }
87
87
 
88
88
  // DO GENERATE
89
- await SdkGenerator.generate(this.output, routeList);
89
+ await SdkGenerator.generate(this.config_.output, routeList);
90
90
  }
91
91
 
92
92
  private async is_not_excluded(file: string): Promise<boolean>
93
93
  {
94
- return file.indexOf(`${this.output}${path.sep}functional`) === -1
94
+ return file.indexOf(`${this.config_.output}${path.sep}functional`) === -1
95
95
  && (await this.bundle_checker_.get())(file) === false;
96
96
  }
97
97
  }
98
+
99
+ export namespace NestiaApplication
100
+ {
101
+ export interface IConfiguration
102
+ {
103
+ input: string | string[];
104
+ output: string;
105
+ compilerOptions?: tsc.CompilerOptions;
106
+ }
107
+ }
package/src/bin/nestia.ts CHANGED
@@ -3,42 +3,77 @@
3
3
  import cli from "cli";
4
4
  import fs from "fs";
5
5
  import path from "path";
6
-
7
- import { Terminal } from "../utils/Terminal";
6
+ import tsc from "typescript";
8
7
 
9
8
  import { NestiaApplication } from "../NestiaApplication";
10
9
 
10
+ import { Terminal } from "../utils/Terminal";
11
+ import { stripJsonComments } from "../utils/stripJsonComments";
12
+
11
13
  interface ICommand
12
14
  {
13
- install: boolean;
14
15
  out: string | null;
15
16
  }
16
17
 
17
- async function sdk(inputList: string[], command: ICommand): Promise<void>
18
+ async function sdk(input: string[], command: ICommand): Promise<void>
18
19
  {
19
- // VALIDATE OUTPUT
20
+ let compilerOptions: tsc.CompilerOptions | undefined = {};
21
+
22
+ //----
23
+ // NESTIA.CONFIG.TS
24
+ //----
25
+ if (fs.existsSync("nestia.config.ts") === true)
26
+ {
27
+ const config: NestiaApplication.IConfiguration = await import(path.resolve("nestia.config.ts"));
28
+ compilerOptions = config.compilerOptions;
29
+ input = config.input instanceof Array ? config.input : [config.input];
30
+ command.out = config.output;
31
+ }
32
+
33
+ //----
34
+ // VALIDATIONS
35
+ //----
36
+ // CHECK OUTPUT
20
37
  if (command.out === null)
21
38
  throw new Error(`Output directory is not specified. Add the "--out <output_directory>" option.`);
22
39
 
40
+ // CHECK PARENT DIRECTORY
23
41
  const parentPath: string = path.resolve(command.out + "/..");
24
42
  const parentStats: fs.Stats = await fs.promises.stat(parentPath);
43
+
25
44
  if (parentStats.isDirectory() === false)
26
45
  throw new Error(`Unable to find parent directory of the output path: "${parentPath}".`);
27
46
 
28
- // VALIDATE INPUTS
29
- for (const input of inputList)
47
+ // CHECK INPUTS
48
+ for (const path of input)
30
49
  {
31
- const inputStats: fs.Stats = await fs.promises.stat(input);
50
+ const inputStats: fs.Stats = await fs.promises.stat(path);
32
51
  if (inputStats.isDirectory() === false)
33
- throw new Error(`Target "${inputList}" is not a directory.`);
52
+ throw new Error(`Target "${path}" is not a directory.`);
34
53
  }
35
54
 
36
55
  //----
37
- // GENERATE
56
+ // GENERATION
38
57
  //----
39
- // CALL THE APP.SDK()
40
- const app: NestiaApplication = new NestiaApplication(inputList, command.out);
41
- await app.sdk();
58
+ if (fs.existsSync("tsconfig.json") === true)
59
+ {
60
+ const content: string = await fs.promises.readFile("tsconfig.json", "utf8");
61
+ const options: tsc.CompilerOptions = JSON.parse(stripJsonComments(content)).compilerOptions;
62
+
63
+ compilerOptions = compilerOptions
64
+ ? { ...options, ...compilerOptions }
65
+ : options;
66
+ }
67
+
68
+ // CHECK NESTIA.CONFIG.TS
69
+
70
+ // CALL THE APP.GENERATE()
71
+ const app: NestiaApplication = new NestiaApplication({
72
+ output: command.out,
73
+ input,
74
+ compilerOptions,
75
+ });
76
+ await app.generate();
42
77
  }
43
78
 
44
79
  async function install(): Promise<void>
@@ -58,7 +93,6 @@ async function main(): Promise<void>
58
93
  {
59
94
  const command: ICommand = cli.parse({
60
95
  out: ["o", "Output path of the SDK files", "string", null],
61
- install: ["i", "Install Dependencies", "boolean", false]
62
96
  });
63
97
 
64
98
  try
@@ -34,7 +34,10 @@ export namespace FileGenerator
34
34
  function emplace(directory: Directory, route: IRoute): void
35
35
  {
36
36
  // SEPARATE IDENTIFIERS
37
- const identifiers: string[] = route.path.split("/").filter(str => str[0] !== ":" && str.length !== 0);
37
+ const identifiers: string[] = route.path
38
+ .split("/")
39
+ .filter(str => str[0] !== ":" && str.length !== 0)
40
+ .map(str => str.split("-").join("_").split(".").join("_"));
38
41
 
39
42
  for (const key of identifiers)
40
43
  {
@@ -14,6 +14,7 @@ export namespace FunctionGenerator
14
14
 
15
15
  return [head, body, tail]
16
16
  .map(closure => closure(route, query, input))
17
+ .filter(str => !!str)
17
18
  .join("\n");
18
19
  }
19
20
 
@@ -43,11 +44,12 @@ export namespace FunctionGenerator
43
44
  fetchArguments.push("input");
44
45
 
45
46
  // RETURNS WITH FINALIZATION
46
- return ""
47
+ return "{\n"
47
48
  + " return Fetcher.fetch\n"
48
49
  + " (\n"
49
50
  + fetchArguments.map(param => ` ${param}`).join(",\n") + "\n"
50
- + " );";
51
+ + " );\n"
52
+ + "}";
51
53
  }
52
54
 
53
55
  function get_path(route: IRoute, query: IRoute.IParameter | undefined): string
@@ -142,11 +144,10 @@ export namespace FunctionGenerator
142
144
  + `export function ${route.name}\n`
143
145
  + ` (\n`
144
146
  + `${parameters.map(str => ` ${str}`).join(",\n")}\n`
145
- + ` ): Promise<${output}>\n`
146
- + "{";
147
+ + ` ): Promise<${output}>`;
147
148
  }
148
149
 
149
- function tail(route: IRoute, query: IRoute.IParameter | undefined, input: IRoute.IParameter | undefined): string
150
+ function tail(route: IRoute, query: IRoute.IParameter | undefined, input: IRoute.IParameter | undefined): string | null
150
151
  {
151
152
  const types: Pair<string, string>[] = [];
152
153
  if (query !== undefined)
@@ -157,10 +158,9 @@ export namespace FunctionGenerator
157
158
  types.push(new Pair("Output", route.output));
158
159
 
159
160
  if (types.length === 0)
160
- return "}";
161
+ return null;
161
162
 
162
- return `}\n`
163
- + `export namespace ${route.name}\n`
163
+ return `export namespace ${route.name}\n`
164
164
  + "{\n"
165
165
  + (types.map(tuple => ` export type ${tuple.first} = Primitive<${tuple.second}>;`).join("\n")) + "\n"
166
166
  + "}";
@@ -0,0 +1,79 @@
1
+ // https://github.com/sindresorhus/strip-json-comments
2
+
3
+ const singleComment: any = Symbol('singleComment');
4
+ const multiComment: any = Symbol('multiComment');
5
+
6
+ const stripWithoutWhitespace = () => '';
7
+ const stripWithWhitespace = (string: string, start: number, end: number) => string.slice(start, end).replace(/\S/g, ' ');
8
+
9
+ const isEscaped = (jsonString: string, quotePosition: number) => {
10
+ let index = quotePosition - 1;
11
+ let backslashCount = 0;
12
+
13
+ while (jsonString[index] === '\\') {
14
+ index -= 1;
15
+ backslashCount += 1;
16
+ }
17
+
18
+ return Boolean(backslashCount % 2);
19
+ };
20
+
21
+ export function stripJsonComments(jsonString: string, {whitespace = true} = {}) {
22
+ if (typeof jsonString !== 'string') {
23
+ throw new TypeError(`Expected argument \`jsonString\` to be a \`string\`, got \`${typeof jsonString}\``);
24
+ }
25
+
26
+ const strip = whitespace ? stripWithWhitespace : stripWithoutWhitespace;
27
+
28
+ let isInsideString = false;
29
+ let isInsideComment = false;
30
+ let offset = 0;
31
+ let result = '';
32
+
33
+ for (let index = 0; index < jsonString.length; index++) {
34
+ const currentCharacter = jsonString[index];
35
+ const nextCharacter = jsonString[index + 1];
36
+
37
+ if (!isInsideComment && currentCharacter === '"') {
38
+ const escaped = isEscaped(jsonString, index);
39
+ if (!escaped) {
40
+ isInsideString = !isInsideString;
41
+ }
42
+ }
43
+
44
+ if (isInsideString) {
45
+ continue;
46
+ }
47
+
48
+ if (!isInsideComment && currentCharacter + nextCharacter === '//') {
49
+ result += jsonString.slice(offset, index);
50
+ offset = index;
51
+ isInsideComment = singleComment;
52
+ index++;
53
+ } else if (isInsideComment === singleComment && currentCharacter + nextCharacter === '\r\n') {
54
+ index++;
55
+ isInsideComment = false;
56
+ result += strip(jsonString, offset, index);
57
+ offset = index;
58
+ continue;
59
+ } else if (isInsideComment === singleComment && currentCharacter === '\n') {
60
+ isInsideComment = false;
61
+ result += strip(jsonString, offset, index);
62
+ offset = index;
63
+ } else if (!isInsideComment && currentCharacter + nextCharacter === '/*') {
64
+ result += jsonString.slice(offset, index);
65
+ offset = index;
66
+ isInsideComment = multiComment;
67
+ index++;
68
+ continue;
69
+ } else if (isInsideComment === multiComment && currentCharacter + nextCharacter === '*/') {
70
+ index++;
71
+ isInsideComment = false;
72
+ result += strip(jsonString, offset, index + 1);
73
+ offset = index + 1;
74
+ continue;
75
+ }
76
+ }
77
+
78
+ return result + (isInsideComment ? (strip as any)(jsonString.slice(offset)) : jsonString.slice(offset));
79
+ }
package/tsconfig.json CHANGED
@@ -73,5 +73,5 @@
73
73
  "skipLibCheck": true, /* Skip type checking of declaration files. */
74
74
  "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
75
75
  },
76
- "include": ["src", "api/structures"]
76
+ // "include": ["src", "test"]
77
77
  }