@flink-app/flink 0.12.1-alpha.0 → 0.12.1-alpha.10
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/bin/flink.ts +6 -13
- package/dist/bin/flink.js +3 -10
- package/dist/cli/build.js +3 -3
- package/dist/cli/clean.js +2 -2
- package/dist/cli/cli-utils.js +1 -1
- package/dist/cli/run.js +2 -2
- package/dist/src/FlinkApp.d.ts +6 -3
- package/dist/src/FlinkApp.js +109 -78
- package/dist/src/FlinkErrors.d.ts +1 -1
- package/dist/src/FlinkErrors.js +5 -5
- package/dist/src/FlinkHttpHandler.d.ts +7 -7
- package/dist/src/FlinkHttpHandler.js +1 -1
- package/dist/src/FlinkJob.d.ts +2 -2
- package/dist/src/FlinkLog.d.ts +2 -2
- package/dist/src/FlinkRepo.d.ts +17 -8
- package/dist/src/FlinkRepo.js +44 -20
- package/dist/src/FlinkResponse.d.ts +2 -2
- package/dist/src/FsUtils.js +7 -7
- package/dist/src/TypeScriptCompiler.js +83 -68
- package/dist/src/TypeScriptUtils.js +11 -33
- package/dist/src/index.js +5 -1
- package/dist/src/mock-data-generator.js +1 -1
- package/dist/src/utils.js +6 -6
- package/package.json +7 -7
- package/spec/FlinkRepo.spec.ts +11 -0
- package/spec/mock-project/dist/src/handlers/GetCar.js +10 -12
- package/spec/mock-project/dist/src/handlers/GetCar2.js +11 -13
- package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema.js +8 -10
- package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema2.js +8 -10
- package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema3.js +8 -10
- package/spec/mock-project/dist/src/handlers/GetCarWithLiteralSchema.js +10 -12
- package/spec/mock-project/dist/src/handlers/GetCarWithLiteralSchema2.js +10 -12
- package/spec/mock-project/dist/src/handlers/GetCarWithSchemaInFile.js +10 -12
- package/spec/mock-project/dist/src/handlers/GetCarWithSchemaInFile2.js +10 -12
- package/spec/mock-project/dist/src/handlers/ManuallyAddedHandler.js +10 -12
- package/spec/mock-project/dist/src/handlers/ManuallyAddedHandler2.js +10 -12
- package/spec/mock-project/dist/src/handlers/PostCar.js +10 -12
- package/spec/mock-project/dist/src/handlers/PostLogin.js +11 -13
- package/spec/mock-project/dist/src/handlers/PutCar.js +10 -12
- package/spec/mock-project/dist/src/index.js +6 -2
- package/src/FlinkApp.ts +33 -8
- package/src/FlinkRepo.ts +30 -11
- package/src/TypeScriptCompiler.ts +13 -2
- package/src/TypeScriptUtils.ts +110 -164
- package/cli/generate-schemas.ts +0 -153
package/src/FlinkApp.ts
CHANGED
|
@@ -2,9 +2,9 @@ import Ajv, { ValidateFunction } from "ajv";
|
|
|
2
2
|
import addFormats from "ajv-formats";
|
|
3
3
|
import bodyParser, { OptionsJson } from "body-parser";
|
|
4
4
|
import cors from "cors";
|
|
5
|
-
import express, { Express, Request } from "express";
|
|
5
|
+
import express, { Express, Request, RequestHandler } from "express";
|
|
6
6
|
import { JSONSchema7 } from "json-schema";
|
|
7
|
-
import
|
|
7
|
+
import { Db, MongoClient, ServerApiVersion } from "mongodb";
|
|
8
8
|
import morgan from "morgan";
|
|
9
9
|
import ms from "ms";
|
|
10
10
|
import { AsyncTask, CronJob, SimpleIntervalJob, ToadScheduler } from "toad-scheduler";
|
|
@@ -217,6 +217,7 @@ export class FlinkApp<C extends FlinkContext> {
|
|
|
217
217
|
public name: string;
|
|
218
218
|
public expressApp?: Express;
|
|
219
219
|
public db?: Db;
|
|
220
|
+
public dbClient?: MongoClient;
|
|
220
221
|
public handlers: HandlerConfig[] = [];
|
|
221
222
|
public port?: number;
|
|
222
223
|
public started = false;
|
|
@@ -227,13 +228,14 @@ export class FlinkApp<C extends FlinkContext> {
|
|
|
227
228
|
private onDbConnection?: FlinkOptions["onDbConnection"];
|
|
228
229
|
|
|
229
230
|
private plugins: FlinkPlugin[] = [];
|
|
230
|
-
|
|
231
|
+
public auth?: FlinkAuthPlugin;
|
|
231
232
|
private corsOpts: FlinkOptions["cors"];
|
|
232
233
|
private routingConfigured = false;
|
|
233
234
|
private jsonOptions?: OptionsJson;
|
|
234
235
|
private rawContentTypes?: string[];
|
|
235
236
|
private schedulingOptions?: FlinkOptions["scheduling"];
|
|
236
237
|
private disableHttpServer = false;
|
|
238
|
+
private expressServer: any; // for simplicity, we don't want to import types from express/node here
|
|
237
239
|
|
|
238
240
|
private repos: { [x: string]: FlinkRepo<C, any> } = {};
|
|
239
241
|
|
|
@@ -303,14 +305,14 @@ export class FlinkApp<C extends FlinkContext> {
|
|
|
303
305
|
|
|
304
306
|
if (this.rawContentTypes) {
|
|
305
307
|
for (const type of this.rawContentTypes) {
|
|
306
|
-
this.expressApp.use(express.raw({ type }));
|
|
308
|
+
this.expressApp.use(express.raw({ type }) as RequestHandler);
|
|
307
309
|
}
|
|
308
310
|
}
|
|
309
311
|
|
|
310
|
-
this.expressApp.use(bodyParser.json(this.jsonOptions));
|
|
312
|
+
this.expressApp.use(bodyParser.json(this.jsonOptions) as RequestHandler);
|
|
311
313
|
|
|
312
314
|
if (this.accessLog.enabled) {
|
|
313
|
-
this.expressApp.use(morgan(this.accessLog.format));
|
|
315
|
+
this.expressApp.use(morgan(this.accessLog.format) as RequestHandler);
|
|
314
316
|
}
|
|
315
317
|
|
|
316
318
|
this.expressApp.use((req, res, next) => {
|
|
@@ -367,7 +369,7 @@ export class FlinkApp<C extends FlinkContext> {
|
|
|
367
369
|
log.info("🚧 HTTP server is disabled, but flink app is running");
|
|
368
370
|
this.started = true;
|
|
369
371
|
} else {
|
|
370
|
-
this.expressApp?.listen(this.port, () => {
|
|
372
|
+
this.expressServer = this.expressApp?.listen(this.port, () => {
|
|
371
373
|
log.fontColorLog("magenta", `⚡️ HTTP server '${this.name}' is running and waiting for connections on ${this.port}`);
|
|
372
374
|
this.started = true;
|
|
373
375
|
});
|
|
@@ -376,6 +378,28 @@ export class FlinkApp<C extends FlinkContext> {
|
|
|
376
378
|
return this;
|
|
377
379
|
}
|
|
378
380
|
|
|
381
|
+
async stop() {
|
|
382
|
+
log.info("🛑 Stopping Flink app...");
|
|
383
|
+
|
|
384
|
+
if (this.scheduler) {
|
|
385
|
+
await this.scheduler.stop();
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
if (this.expressServer) {
|
|
389
|
+
return new Promise<void>((resolve, reject) => {
|
|
390
|
+
const int = setTimeout(() => {
|
|
391
|
+
reject("Failed to stop HTTP server in time");
|
|
392
|
+
}, 2000);
|
|
393
|
+
|
|
394
|
+
this.expressServer.close(() => {
|
|
395
|
+
clearInterval(int);
|
|
396
|
+
log.info("HTTP server stopped");
|
|
397
|
+
resolve();
|
|
398
|
+
});
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
379
403
|
/**
|
|
380
404
|
* Manually registers a handler.
|
|
381
405
|
*
|
|
@@ -717,7 +741,7 @@ export class FlinkApp<C extends FlinkContext> {
|
|
|
717
741
|
private async buildContext() {
|
|
718
742
|
if (this.dbOpts) {
|
|
719
743
|
for (const { collectionName, repoInstanceName, Repo } of autoRegisteredRepos) {
|
|
720
|
-
const repoInstance: FlinkRepo<C, any> = new Repo(collectionName, this.db);
|
|
744
|
+
const repoInstance: FlinkRepo<C, any> = new Repo(collectionName, this.db, this.dbClient);
|
|
721
745
|
|
|
722
746
|
this.repos[repoInstanceName] = repoInstance;
|
|
723
747
|
|
|
@@ -755,6 +779,7 @@ export class FlinkApp<C extends FlinkContext> {
|
|
|
755
779
|
log.debug("Connecting to db");
|
|
756
780
|
const client = await MongoClient.connect(this.dbOpts.uri, this.getMongoConnectionOptions());
|
|
757
781
|
this.db = client.db();
|
|
782
|
+
this.dbClient = client;
|
|
758
783
|
} catch (err) {
|
|
759
784
|
log.error("Failed to connect to db: " + err);
|
|
760
785
|
process.exit(1);
|
package/src/FlinkRepo.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
import { Collection, Db, Document, InsertOneResult, ObjectId } from "mongodb";
|
|
1
|
+
import { Collection, Db, Document, InsertOneResult, MongoClient, ObjectId } from "mongodb";
|
|
2
2
|
import { FlinkContext } from "./FlinkContext";
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Partial model to have intellisense for partial updates but
|
|
6
|
+
* also allow any other properties to be set such as nested objects etc.
|
|
7
|
+
*/
|
|
8
|
+
type PartialModel<Model> = Partial<Model> & { [x: string]: any };
|
|
9
|
+
|
|
4
10
|
export abstract class FlinkRepo<C extends FlinkContext, Model extends Document> {
|
|
5
11
|
collection: Collection;
|
|
6
12
|
|
|
@@ -15,23 +21,29 @@ export abstract class FlinkRepo<C extends FlinkContext, Model extends Document>
|
|
|
15
21
|
return this._ctx;
|
|
16
22
|
}
|
|
17
23
|
|
|
18
|
-
constructor(
|
|
24
|
+
constructor(public collectionName: string, public db: Db, public client?: MongoClient) {
|
|
19
25
|
this.collection = db.collection(this.collectionName);
|
|
20
26
|
}
|
|
21
27
|
|
|
22
28
|
async findAll(query = {}): Promise<Model[]> {
|
|
23
29
|
const res = await this.collection.find<Model>(query).toArray();
|
|
24
|
-
return res.map(this.objectIdToString);
|
|
30
|
+
return res.map(this.objectIdToString) as Model[];
|
|
25
31
|
}
|
|
26
32
|
|
|
27
33
|
async getById(id: string | ObjectId) {
|
|
28
34
|
const res = await this.collection.findOne<Model>({ _id: this.buildId(id) });
|
|
29
|
-
|
|
35
|
+
if (res) {
|
|
36
|
+
return this.objectIdToString(res) as Model;
|
|
37
|
+
}
|
|
38
|
+
return null;
|
|
30
39
|
}
|
|
31
40
|
|
|
32
41
|
async getOne(query = {}) {
|
|
33
42
|
const res = await this.collection.findOne<Model>(query);
|
|
34
|
-
|
|
43
|
+
if (res) {
|
|
44
|
+
return this.objectIdToString(res) as Model;
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
35
47
|
}
|
|
36
48
|
|
|
37
49
|
async create<C = Omit<Model, "_id">>(model: C): Promise<C & { _id: string }> {
|
|
@@ -39,19 +51,26 @@ export abstract class FlinkRepo<C extends FlinkContext, Model extends Document>
|
|
|
39
51
|
return { ...model, _id: result.insertedId.toString() };
|
|
40
52
|
}
|
|
41
53
|
|
|
42
|
-
async updateOne(id: string | ObjectId, model:
|
|
54
|
+
async updateOne(id: string | ObjectId, model: PartialModel<Model>): Promise<Model | null> {
|
|
43
55
|
const oid = this.buildId(id);
|
|
44
56
|
|
|
45
|
-
|
|
57
|
+
const { _id, ...modelWithoutId } = model;
|
|
58
|
+
|
|
59
|
+
await this.collection.updateOne({ _id: oid }, { $set: modelWithoutId });
|
|
46
60
|
|
|
47
61
|
const res = await this.collection.findOne<Model>({ _id: oid });
|
|
48
62
|
|
|
49
|
-
|
|
63
|
+
if (res) {
|
|
64
|
+
return this.objectIdToString(res) as Model;
|
|
65
|
+
}
|
|
66
|
+
return null;
|
|
50
67
|
}
|
|
51
68
|
|
|
52
|
-
async updateMany<U =
|
|
69
|
+
async updateMany<U = PartialModel<Model>>(query: any, model: U): Promise<number> {
|
|
70
|
+
const { _id, ...modelWithoutId } = model as any;
|
|
71
|
+
|
|
53
72
|
const { modifiedCount } = await this.collection.updateMany(query, {
|
|
54
|
-
$set:
|
|
73
|
+
$set: modelWithoutId as any,
|
|
55
74
|
});
|
|
56
75
|
return modifiedCount;
|
|
57
76
|
}
|
|
@@ -77,7 +96,7 @@ export abstract class FlinkRepo<C extends FlinkContext, Model extends Document>
|
|
|
77
96
|
return oid;
|
|
78
97
|
}
|
|
79
98
|
|
|
80
|
-
private objectIdToString(doc:
|
|
99
|
+
private objectIdToString<T>(doc: T & { _id?: any }) {
|
|
81
100
|
if (doc && doc._id) {
|
|
82
101
|
doc._id = doc._id.toString();
|
|
83
102
|
}
|
|
@@ -2,7 +2,7 @@ import { promises as fsPromises } from "fs";
|
|
|
2
2
|
import { JSONSchema7 } from "json-schema";
|
|
3
3
|
import { join } from "path";
|
|
4
4
|
import glob from "tiny-glob";
|
|
5
|
-
import { Config, createFormatter, createParser, Schema, SchemaGenerator } from "ts-json-schema-generator";
|
|
5
|
+
import { CompletedConfig, Config, createFormatter, createParser, Schema, SchemaGenerator } from "ts-json-schema-generator";
|
|
6
6
|
import {
|
|
7
7
|
ArrayLiteralExpression,
|
|
8
8
|
DiagnosticCategory,
|
|
@@ -437,9 +437,20 @@ import "..${appEntryScript.replace(/\.ts/g, "")}";
|
|
|
437
437
|
}
|
|
438
438
|
|
|
439
439
|
private initJsonSchemaGenerator() {
|
|
440
|
-
const conf:
|
|
440
|
+
const conf: CompletedConfig = {
|
|
441
441
|
expose: "none", // Do not create shared $ref definitions.
|
|
442
442
|
topRef: false, // Removes the wrapper object around the schema.
|
|
443
|
+
additionalProperties: false,
|
|
444
|
+
jsDoc: "basic",
|
|
445
|
+
sortProps: false,
|
|
446
|
+
strictTuples: false,
|
|
447
|
+
minify: false,
|
|
448
|
+
markdownDescription: false,
|
|
449
|
+
skipTypeCheck: false,
|
|
450
|
+
encodeRefs: false,
|
|
451
|
+
extraTags: [],
|
|
452
|
+
functions: "fail",
|
|
453
|
+
discriminatorType: "json-schema",
|
|
443
454
|
};
|
|
444
455
|
const formatter = createFormatter(conf);
|
|
445
456
|
const parser = createParser(this.project.getProgram().compilerObject, conf);
|
package/src/TypeScriptUtils.ts
CHANGED
|
@@ -1,13 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ImportDeclarationStructure,
|
|
3
|
-
Node,
|
|
4
|
-
OptionalKind,
|
|
5
|
-
SourceFile,
|
|
6
|
-
Symbol,
|
|
7
|
-
SyntaxKind,
|
|
8
|
-
ts,
|
|
9
|
-
Type,
|
|
10
|
-
} from "ts-morph";
|
|
1
|
+
import { ImportDeclarationStructure, Node, OptionalKind, SourceFile, Symbol, SyntaxKind, ts, Type } from "ts-morph";
|
|
11
2
|
import { getJsDocComment } from "./utils";
|
|
12
3
|
|
|
13
4
|
/**
|
|
@@ -18,85 +9,66 @@ import { getJsDocComment } from "./utils";
|
|
|
18
9
|
* Declared types of those are returned.
|
|
19
10
|
*/
|
|
20
11
|
export function getTypesToImport(node: Node<ts.Node>) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
)
|
|
26
|
-
.map((typeRefNode) =>
|
|
27
|
-
typeRefNode.getFirstChildIfKindOrThrow(SyntaxKind.Identifier)
|
|
28
|
-
);
|
|
12
|
+
const typeRefIdentifiers = node
|
|
13
|
+
.getDescendantsOfKind(SyntaxKind.TypeReference)
|
|
14
|
+
.filter((typeRefNode) => !!typeRefNode.getFirstChildIfKind(SyntaxKind.Identifier))
|
|
15
|
+
.map((typeRefNode) => typeRefNode.getFirstChildIfKindOrThrow(SyntaxKind.Identifier));
|
|
29
16
|
|
|
30
|
-
|
|
17
|
+
const typesToImport: Type<ts.Type>[] = [];
|
|
31
18
|
|
|
32
|
-
|
|
33
|
-
|
|
19
|
+
for (const typeRefIdentifier of typeRefIdentifiers) {
|
|
20
|
+
const typeSymbol = typeRefIdentifier.getSymbolOrThrow();
|
|
34
21
|
|
|
35
|
-
|
|
36
|
-
|
|
22
|
+
const declaredType = typeSymbol.getDeclaredType();
|
|
23
|
+
const declaration = declaredType.getSymbol()?.getDeclarations()[0];
|
|
37
24
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
25
|
+
if (!declaration) {
|
|
26
|
+
continue; // should not happen, right?
|
|
27
|
+
}
|
|
41
28
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
29
|
+
if (declaration.getSourceFile() !== node.getSourceFile()) {
|
|
30
|
+
typesToImport.push(declaration.getSymbolOrThrow().getDeclaredType());
|
|
31
|
+
} else {
|
|
32
|
+
typesToImport.push(...getTypesToImport(declaration));
|
|
33
|
+
}
|
|
46
34
|
}
|
|
47
|
-
}
|
|
48
35
|
|
|
49
|
-
|
|
36
|
+
return typesToImport;
|
|
50
37
|
}
|
|
51
38
|
|
|
52
39
|
export function addImport(toSourceFile: SourceFile, symbol: Symbol) {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
if (!symbolDeclaration) {
|
|
56
|
-
throw new Error(
|
|
57
|
-
"Missing declaration for symbol " + symbol.getFullyQualifiedName()
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const importName = symbol.getEscapedName();
|
|
62
|
-
const symbolSourceFile = symbolDeclaration.getSourceFile();
|
|
40
|
+
const symbolDeclaration = symbol.getDeclarations()[0];
|
|
63
41
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
.endsWith(".default");
|
|
42
|
+
if (!symbolDeclaration) {
|
|
43
|
+
throw new Error("Missing declaration for symbol " + symbol.getFullyQualifiedName());
|
|
44
|
+
}
|
|
68
45
|
|
|
69
|
-
|
|
70
|
-
.
|
|
71
|
-
.find(
|
|
72
|
-
(importDeclarataion) =>
|
|
73
|
-
importDeclarataion.getModuleSpecifierSourceFile() === symbolSourceFile
|
|
74
|
-
);
|
|
46
|
+
const importName = symbol.getEscapedName();
|
|
47
|
+
const symbolSourceFile = symbolDeclaration.getSourceFile();
|
|
75
48
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
49
|
+
const isDefaultExport = symbol.getDeclaredType().getText().endsWith(".default");
|
|
50
|
+
|
|
51
|
+
const importDec = toSourceFile.getImportDeclarations().find((importDeclarataion) => importDeclarataion.getModuleSpecifierSourceFile() === symbolSourceFile);
|
|
52
|
+
|
|
53
|
+
if (importDec) {
|
|
54
|
+
// File already has import to file
|
|
55
|
+
if (isDefaultExport) {
|
|
56
|
+
if (!importDec.getDefaultImport()) {
|
|
57
|
+
importDec.setDefaultImport(importName);
|
|
58
|
+
}
|
|
59
|
+
} else {
|
|
60
|
+
if (!importDec.getNamedImports().find((specifier) => specifier.getText() === importName)) {
|
|
61
|
+
importDec.addNamedImport(importName);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
82
64
|
} else {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
65
|
+
// Add new import declaration
|
|
66
|
+
toSourceFile.addImportDeclaration({
|
|
67
|
+
moduleSpecifier: toSourceFile.getRelativePathAsModuleSpecifierTo(symbolSourceFile),
|
|
68
|
+
defaultImport: isDefaultExport ? symbol.getEscapedName() : undefined,
|
|
69
|
+
namedImports: isDefaultExport ? undefined : [symbol.getEscapedName()],
|
|
70
|
+
});
|
|
90
71
|
}
|
|
91
|
-
} else {
|
|
92
|
-
// Add new import declaration
|
|
93
|
-
toSourceFile.addImportDeclaration({
|
|
94
|
-
moduleSpecifier:
|
|
95
|
-
toSourceFile.getRelativePathAsModuleSpecifierTo(symbolSourceFile),
|
|
96
|
-
defaultImport: isDefaultExport ? symbol.getEscapedName() : undefined,
|
|
97
|
-
namedImports: isDefaultExport ? undefined : [symbol.getEscapedName()],
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
72
|
}
|
|
101
73
|
|
|
102
74
|
/**
|
|
@@ -106,63 +78,47 @@ export function addImport(toSourceFile: SourceFile, symbol: Symbol) {
|
|
|
106
78
|
* @param symbols
|
|
107
79
|
*/
|
|
108
80
|
export function addImports(toSourceFile: SourceFile, symbols: Symbol[]) {
|
|
109
|
-
|
|
110
|
-
string,
|
|
111
|
-
{ defaultImportName?: string; namedImports: string[] }
|
|
112
|
-
>();
|
|
81
|
+
const importsByModuleSpecifier = new Map<string, { defaultImportName?: string; namedImports: string[] }>();
|
|
113
82
|
|
|
114
|
-
|
|
115
|
-
|
|
83
|
+
for (const symbol of symbols) {
|
|
84
|
+
const symbolDeclaration = symbol.getDeclarations()[0];
|
|
116
85
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
);
|
|
121
|
-
}
|
|
86
|
+
if (!symbolDeclaration) {
|
|
87
|
+
throw new Error("Missing declaration for symbol " + symbol.getFullyQualifiedName());
|
|
88
|
+
}
|
|
122
89
|
|
|
123
|
-
|
|
124
|
-
? getInterfaceName(symbol)
|
|
125
|
-
: symbol.getEscapedName();
|
|
90
|
+
const importName = symbol.getDeclaredType().isInterface() ? getInterfaceName(symbol) : symbol.getEscapedName();
|
|
126
91
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
.getDeclaredType()
|
|
130
|
-
.getText()
|
|
131
|
-
.endsWith(".default");
|
|
92
|
+
const symbolSourceFile = symbolDeclaration.getSourceFile();
|
|
93
|
+
const isDefaultExport = symbol.getDeclaredType().getText().endsWith(".default");
|
|
132
94
|
|
|
133
|
-
|
|
134
|
-
toSourceFile.getRelativePathAsModuleSpecifierTo(symbolSourceFile);
|
|
95
|
+
const moduleSpecifier = toSourceFile.getRelativePathAsModuleSpecifierTo(symbolSourceFile);
|
|
135
96
|
|
|
136
|
-
|
|
97
|
+
let aImport = importsByModuleSpecifier.get(moduleSpecifier);
|
|
137
98
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
99
|
+
if (!aImport) {
|
|
100
|
+
importsByModuleSpecifier.set(moduleSpecifier, {
|
|
101
|
+
defaultImportName: isDefaultExport ? importName : undefined,
|
|
102
|
+
namedImports: isDefaultExport ? [] : [importName],
|
|
103
|
+
});
|
|
104
|
+
} else {
|
|
105
|
+
if (isDefaultExport) {
|
|
106
|
+
aImport.defaultImportName = importName;
|
|
107
|
+
} else if (!aImport.namedImports.includes(importName)) {
|
|
108
|
+
aImport.namedImports.push(importName);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
149
111
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
namedImports: aImport.namedImports.length
|
|
161
|
-
? aImport.namedImports
|
|
162
|
-
: undefined,
|
|
163
|
-
})
|
|
164
|
-
)
|
|
165
|
-
);
|
|
112
|
+
|
|
113
|
+
toSourceFile.addImportDeclarations(
|
|
114
|
+
Array.from(importsByModuleSpecifier.entries()).map(
|
|
115
|
+
([moduleSpecifier, aImport]): OptionalKind<ImportDeclarationStructure> => ({
|
|
116
|
+
moduleSpecifier,
|
|
117
|
+
defaultImport: aImport.defaultImportName,
|
|
118
|
+
namedImports: aImport.namedImports.length ? aImport.namedImports : undefined,
|
|
119
|
+
})
|
|
120
|
+
)
|
|
121
|
+
);
|
|
166
122
|
}
|
|
167
123
|
|
|
168
124
|
/**
|
|
@@ -171,21 +127,17 @@ export function addImports(toSourceFile: SourceFile, symbols: Symbol[]) {
|
|
|
171
127
|
* @returns
|
|
172
128
|
*/
|
|
173
129
|
export function getDefaultExport(sf: SourceFile) {
|
|
174
|
-
|
|
175
|
-
SyntaxKind.ExportAssignment
|
|
176
|
-
);
|
|
130
|
+
const exportAssignment = sf.getFirstDescendantByKind(SyntaxKind.ExportAssignment);
|
|
177
131
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
SyntaxKind.Identifier
|
|
181
|
-
);
|
|
132
|
+
if (exportAssignment) {
|
|
133
|
+
const identifier = exportAssignment.getFirstChildByKind(SyntaxKind.Identifier);
|
|
182
134
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
135
|
+
if (identifier) {
|
|
136
|
+
return identifier.getSymbolOrThrow().getDeclarations()[0];
|
|
137
|
+
} else {
|
|
138
|
+
return exportAssignment.getFirstChild();
|
|
139
|
+
}
|
|
187
140
|
}
|
|
188
|
-
}
|
|
189
141
|
}
|
|
190
142
|
|
|
191
143
|
/**
|
|
@@ -195,48 +147,42 @@ export function getDefaultExport(sf: SourceFile) {
|
|
|
195
147
|
* @returns
|
|
196
148
|
*/
|
|
197
149
|
export function getInterfaceName(symbol: Symbol) {
|
|
198
|
-
|
|
150
|
+
const declaration = symbol.getDeclarations()[0];
|
|
199
151
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
152
|
+
if (!declaration) {
|
|
153
|
+
throw new Error("Missing declaration of interface symbol");
|
|
154
|
+
}
|
|
203
155
|
|
|
204
|
-
|
|
205
|
-
.getFirstChildByKindOrThrow(SyntaxKind.Identifier)
|
|
206
|
-
.getText();
|
|
156
|
+
return declaration.getFirstChildByKindOrThrow(SyntaxKind.Identifier).getText();
|
|
207
157
|
}
|
|
208
158
|
|
|
209
159
|
export function getSymbolOrAlias(type: Type<ts.Type>) {
|
|
210
|
-
|
|
160
|
+
return type.getAliasSymbol() || type.getSymbol();
|
|
211
161
|
}
|
|
212
162
|
|
|
213
163
|
export function getTypeMetadata(type: Type<ts.Type>) {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
164
|
+
if (!type || ["void", "any"].includes(type.getText())) {
|
|
165
|
+
return [];
|
|
166
|
+
}
|
|
217
167
|
|
|
218
|
-
|
|
168
|
+
const symbol = getSymbolOrAlias(type);
|
|
219
169
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
170
|
+
if (!symbol) {
|
|
171
|
+
throw new Error("Could not get type symbol for type: " + type.getText());
|
|
172
|
+
}
|
|
223
173
|
|
|
224
|
-
|
|
174
|
+
const [declaration] = symbol.getDeclarations();
|
|
225
175
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
176
|
+
if (!declaration) {
|
|
177
|
+
throw new Error("Could not get declaration for type: " + type.getText());
|
|
178
|
+
}
|
|
229
179
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
.map((prop) => {
|
|
233
|
-
const description = getJsDocComment(
|
|
234
|
-
prop.getLeadingCommentRanges()[0]?.getText() || ""
|
|
235
|
-
);
|
|
180
|
+
return declaration.getDescendantsOfKind(SyntaxKind.PropertySignature).map((prop) => {
|
|
181
|
+
const description = getJsDocComment(prop.getLeadingCommentRanges()[0]?.getText() || "");
|
|
236
182
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
183
|
+
return {
|
|
184
|
+
description,
|
|
185
|
+
name: prop.getName(),
|
|
186
|
+
};
|
|
241
187
|
});
|
|
242
188
|
}
|