@honestjs/rpc-plugin 1.5.0 → 1.6.0
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 +193 -134
- package/dist/index.d.mts +69 -8
- package/dist/index.d.ts +69 -8
- package/dist/index.js +235 -64
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +232 -64
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -9,6 +9,9 @@ var DEFAULT_OPTIONS = {
|
|
|
9
9
|
tsConfigPath: "tsconfig.json",
|
|
10
10
|
outputDir: "./generated/rpc",
|
|
11
11
|
generateOnInit: true,
|
|
12
|
+
mode: "best-effort",
|
|
13
|
+
logLevel: "info",
|
|
14
|
+
artifactVersion: "1",
|
|
12
15
|
context: {
|
|
13
16
|
namespace: "rpc",
|
|
14
17
|
keys: {
|
|
@@ -36,6 +39,16 @@ var GENERIC_TYPES = /* @__PURE__ */ new Set(["Array", "Promise", "Partial"]);
|
|
|
36
39
|
import fs from "fs/promises";
|
|
37
40
|
import path from "path";
|
|
38
41
|
|
|
42
|
+
// src/utils/string-utils.ts
|
|
43
|
+
function safeToString(value) {
|
|
44
|
+
if (typeof value === "string") return value;
|
|
45
|
+
if (typeof value === "symbol") return value.description || "Symbol";
|
|
46
|
+
return String(value);
|
|
47
|
+
}
|
|
48
|
+
function camelCase(str) {
|
|
49
|
+
return str.charAt(0).toLowerCase() + str.slice(1);
|
|
50
|
+
}
|
|
51
|
+
|
|
39
52
|
// src/utils/path-utils.ts
|
|
40
53
|
function buildFullPath(basePath, parameters) {
|
|
41
54
|
if (!basePath || typeof basePath !== "string") return "/";
|
|
@@ -74,14 +87,26 @@ function buildFullApiPath(route) {
|
|
|
74
87
|
return fullPath || "/";
|
|
75
88
|
}
|
|
76
89
|
|
|
77
|
-
// src/
|
|
78
|
-
function
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
90
|
+
// src/generators/generator-utils.ts
|
|
91
|
+
function groupRoutesByController(routes) {
|
|
92
|
+
const groups = /* @__PURE__ */ new Map();
|
|
93
|
+
for (const route of routes) {
|
|
94
|
+
const controller = safeToString(route.controller);
|
|
95
|
+
if (!groups.has(controller)) {
|
|
96
|
+
groups.set(controller, []);
|
|
97
|
+
}
|
|
98
|
+
groups.get(controller).push(route);
|
|
99
|
+
}
|
|
100
|
+
return groups;
|
|
82
101
|
}
|
|
83
|
-
function
|
|
84
|
-
|
|
102
|
+
function buildNormalizedRequestPath(route) {
|
|
103
|
+
let requestPath = buildFullApiPath(route);
|
|
104
|
+
for (const parameter of route.parameters ?? []) {
|
|
105
|
+
if (parameter.decoratorType !== "param") continue;
|
|
106
|
+
const placeholder = `:${String(parameter.data ?? parameter.name)}`;
|
|
107
|
+
requestPath = requestPath.replace(placeholder, `:${parameter.name}`);
|
|
108
|
+
}
|
|
109
|
+
return requestPath;
|
|
85
110
|
}
|
|
86
111
|
|
|
87
112
|
// src/generators/typescript-client.generator.ts
|
|
@@ -122,7 +147,7 @@ var TypeScriptClientGenerator = class {
|
|
|
122
147
|
* Generates the client TypeScript content with types included.
|
|
123
148
|
*/
|
|
124
149
|
generateClientContent(routes, schemas) {
|
|
125
|
-
const controllerGroups =
|
|
150
|
+
const controllerGroups = groupRoutesByController(routes);
|
|
126
151
|
return `// ============================================================================
|
|
127
152
|
// TYPES SECTION
|
|
128
153
|
// ============================================================================
|
|
@@ -283,13 +308,21 @@ export class ApiClient {
|
|
|
283
308
|
return undefined as T
|
|
284
309
|
}
|
|
285
310
|
|
|
286
|
-
const
|
|
311
|
+
const contentType = response.headers.get('content-type') || ''
|
|
312
|
+
const isJson = contentType.includes('application/json') || contentType.includes('+json')
|
|
313
|
+
const responseData = isJson ? await response.json() : await response.text()
|
|
287
314
|
|
|
288
315
|
if (!response.ok) {
|
|
289
|
-
|
|
316
|
+
const message =
|
|
317
|
+
typeof responseData === 'object' && responseData && 'message' in (responseData as Record<string, unknown>)
|
|
318
|
+
? String((responseData as Record<string, unknown>).message)
|
|
319
|
+
: typeof responseData === 'string' && responseData.trim()
|
|
320
|
+
? responseData
|
|
321
|
+
: 'Request failed'
|
|
322
|
+
throw new ApiError(response.status, message)
|
|
290
323
|
}
|
|
291
324
|
|
|
292
|
-
return responseData
|
|
325
|
+
return responseData as T
|
|
293
326
|
} catch (error) {
|
|
294
327
|
if (error instanceof ApiError) {
|
|
295
328
|
throw error
|
|
@@ -358,14 +391,7 @@ ${this.generateControllerMethods(controllerGroups)}
|
|
|
358
391
|
methods += "undefined";
|
|
359
392
|
methods += `>) => {
|
|
360
393
|
`;
|
|
361
|
-
|
|
362
|
-
if (pathParams.length > 0) {
|
|
363
|
-
for (const pathParam of pathParams) {
|
|
364
|
-
const paramName = pathParam.name;
|
|
365
|
-
const placeholder = `:${String(pathParam.data)}`;
|
|
366
|
-
requestPath = requestPath.replace(placeholder, `:${paramName}`);
|
|
367
|
-
}
|
|
368
|
-
}
|
|
394
|
+
const requestPath = buildNormalizedRequestPath(route);
|
|
369
395
|
methods += ` return this.request<Result>('${httpMethod.toUpperCase()}', \`${requestPath}\`, options)
|
|
370
396
|
`;
|
|
371
397
|
methods += ` },
|
|
@@ -406,20 +432,6 @@ ${this.generateControllerMethods(controllerGroups)}
|
|
|
406
432
|
}
|
|
407
433
|
return content;
|
|
408
434
|
}
|
|
409
|
-
/**
|
|
410
|
-
* Groups routes by controller for better organization.
|
|
411
|
-
*/
|
|
412
|
-
groupRoutesByController(routes) {
|
|
413
|
-
const groups = /* @__PURE__ */ new Map();
|
|
414
|
-
for (const route of routes) {
|
|
415
|
-
const controller = safeToString(route.controller);
|
|
416
|
-
if (!groups.has(controller)) {
|
|
417
|
-
groups.set(controller, []);
|
|
418
|
-
}
|
|
419
|
-
groups.get(controller).push(route);
|
|
420
|
-
}
|
|
421
|
-
return groups;
|
|
422
|
-
}
|
|
423
435
|
/**
|
|
424
436
|
* Analyzes route parameters to determine their types and usage.
|
|
425
437
|
*/
|
|
@@ -469,13 +481,42 @@ async function writeChecksum(outputDir, data) {
|
|
|
469
481
|
await writeFile(checksumPath, JSON.stringify(data, null, 2), "utf-8");
|
|
470
482
|
}
|
|
471
483
|
|
|
484
|
+
// src/utils/artifact-contract.ts
|
|
485
|
+
var RPC_ARTIFACT_VERSION = "1";
|
|
486
|
+
function isRpcArtifact(value) {
|
|
487
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
488
|
+
const obj = value;
|
|
489
|
+
return typeof obj.artifactVersion === "string" && Array.isArray(obj.routes) && Array.isArray(obj.schemas);
|
|
490
|
+
}
|
|
491
|
+
function assertRpcArtifact(value) {
|
|
492
|
+
if (!isRpcArtifact(value)) {
|
|
493
|
+
throw new Error("Invalid RPC artifact: expected { artifactVersion, routes, schemas }");
|
|
494
|
+
}
|
|
495
|
+
if (value.artifactVersion !== RPC_ARTIFACT_VERSION) {
|
|
496
|
+
throw new Error(
|
|
497
|
+
`Unsupported RPC artifact version '${value.artifactVersion}'. Supported: ${RPC_ARTIFACT_VERSION}.`
|
|
498
|
+
);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
472
502
|
// src/services/route-analyzer.service.ts
|
|
473
503
|
import { RouteRegistry } from "honestjs";
|
|
474
504
|
var RouteAnalyzerService = class {
|
|
505
|
+
customClassMatcher;
|
|
506
|
+
onWarn;
|
|
507
|
+
warnings = [];
|
|
508
|
+
constructor(options = {}) {
|
|
509
|
+
this.customClassMatcher = options.customClassMatcher;
|
|
510
|
+
this.onWarn = options.onWarn;
|
|
511
|
+
}
|
|
512
|
+
getWarnings() {
|
|
513
|
+
return this.warnings;
|
|
514
|
+
}
|
|
475
515
|
/**
|
|
476
516
|
* Analyzes controller methods to extract type information
|
|
477
517
|
*/
|
|
478
518
|
async analyzeControllerMethods(project) {
|
|
519
|
+
this.warnings = [];
|
|
479
520
|
const routes = RouteRegistry.getRoutes();
|
|
480
521
|
if (!routes?.length) {
|
|
481
522
|
return [];
|
|
@@ -496,13 +537,20 @@ var RouteAnalyzerService = class {
|
|
|
496
537
|
const classes = sourceFile.getClasses();
|
|
497
538
|
for (const classDeclaration of classes) {
|
|
498
539
|
const className = classDeclaration.getName();
|
|
499
|
-
if (className
|
|
540
|
+
if (className && this.isControllerClass(classDeclaration, className)) {
|
|
500
541
|
controllers.set(className, classDeclaration);
|
|
501
542
|
}
|
|
502
543
|
}
|
|
503
544
|
}
|
|
504
545
|
return controllers;
|
|
505
546
|
}
|
|
547
|
+
isControllerClass(classDeclaration, _className) {
|
|
548
|
+
if (this.customClassMatcher) {
|
|
549
|
+
return this.customClassMatcher(classDeclaration);
|
|
550
|
+
}
|
|
551
|
+
const decoratorNames = classDeclaration.getDecorators().map((decorator) => decorator.getName());
|
|
552
|
+
return decoratorNames.includes("Controller") || decoratorNames.includes("View");
|
|
553
|
+
}
|
|
506
554
|
/**
|
|
507
555
|
* Processes all routes and extracts type information
|
|
508
556
|
*/
|
|
@@ -513,10 +561,9 @@ var RouteAnalyzerService = class {
|
|
|
513
561
|
const extendedRoute = this.createExtendedRoute(route, controllers);
|
|
514
562
|
analyzedRoutes.push(extendedRoute);
|
|
515
563
|
} catch (routeError) {
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
);
|
|
564
|
+
const warning = `Skipping route ${safeToString(route.controller)}.${safeToString(route.handler)}`;
|
|
565
|
+
this.warnings.push(warning);
|
|
566
|
+
this.onWarn?.(warning, routeError);
|
|
520
567
|
}
|
|
521
568
|
}
|
|
522
569
|
return analyzedRoutes;
|
|
@@ -536,6 +583,10 @@ var RouteAnalyzerService = class {
|
|
|
536
583
|
returns = this.getReturnType(handlerMethod);
|
|
537
584
|
parameters = this.getParametersWithTypes(handlerMethod, route.parameters || []);
|
|
538
585
|
}
|
|
586
|
+
} else {
|
|
587
|
+
const warning = `Controller class not found in source files: ${controllerName} (handler: ${handlerName})`;
|
|
588
|
+
this.warnings.push(warning);
|
|
589
|
+
this.onWarn?.(warning);
|
|
539
590
|
}
|
|
540
591
|
return {
|
|
541
592
|
controller: controllerName,
|
|
@@ -674,14 +725,23 @@ function extractNamedType(type) {
|
|
|
674
725
|
|
|
675
726
|
// src/services/schema-generator.service.ts
|
|
676
727
|
var SchemaGeneratorService = class {
|
|
677
|
-
constructor(controllerPattern, tsConfigPath) {
|
|
728
|
+
constructor(controllerPattern, tsConfigPath, options = {}) {
|
|
678
729
|
this.controllerPattern = controllerPattern;
|
|
679
730
|
this.tsConfigPath = tsConfigPath;
|
|
731
|
+
this.failOnSchemaError = options.failOnSchemaError ?? false;
|
|
732
|
+
this.onWarn = options.onWarn;
|
|
733
|
+
}
|
|
734
|
+
failOnSchemaError;
|
|
735
|
+
onWarn;
|
|
736
|
+
warnings = [];
|
|
737
|
+
getWarnings() {
|
|
738
|
+
return this.warnings;
|
|
680
739
|
}
|
|
681
740
|
/**
|
|
682
741
|
* Generates JSON schemas from types used in controllers
|
|
683
742
|
*/
|
|
684
743
|
async generateSchemas(project) {
|
|
744
|
+
this.warnings = [];
|
|
685
745
|
const sourceFiles = project.getSourceFiles(this.controllerPattern);
|
|
686
746
|
const collectedTypes = this.collectTypesFromControllers(sourceFiles);
|
|
687
747
|
return this.processTypes(collectedTypes);
|
|
@@ -728,7 +788,12 @@ var SchemaGeneratorService = class {
|
|
|
728
788
|
typescriptType
|
|
729
789
|
});
|
|
730
790
|
} catch (err) {
|
|
731
|
-
|
|
791
|
+
if (this.failOnSchemaError) {
|
|
792
|
+
throw err;
|
|
793
|
+
}
|
|
794
|
+
const warning = `Failed to generate schema for ${typeName}`;
|
|
795
|
+
this.warnings.push(warning);
|
|
796
|
+
this.onWarn?.(warning, err);
|
|
732
797
|
}
|
|
733
798
|
}
|
|
734
799
|
return schemas;
|
|
@@ -747,7 +812,12 @@ var SchemaGeneratorService = class {
|
|
|
747
812
|
});
|
|
748
813
|
return generator.createSchema(typeName);
|
|
749
814
|
} catch (error) {
|
|
750
|
-
|
|
815
|
+
if (this.failOnSchemaError) {
|
|
816
|
+
throw error;
|
|
817
|
+
}
|
|
818
|
+
const warning = `Failed to generate schema for type ${typeName}`;
|
|
819
|
+
this.warnings.push(warning);
|
|
820
|
+
this.onWarn?.(warning, error);
|
|
751
821
|
return {
|
|
752
822
|
type: "object",
|
|
753
823
|
properties: {},
|
|
@@ -765,6 +835,11 @@ var RPCPlugin = class {
|
|
|
765
835
|
generateOnInit;
|
|
766
836
|
contextNamespace;
|
|
767
837
|
contextArtifactKey;
|
|
838
|
+
mode;
|
|
839
|
+
logLevel;
|
|
840
|
+
failOnSchemaError;
|
|
841
|
+
failOnRouteAnalysisWarning;
|
|
842
|
+
customClassMatcher;
|
|
768
843
|
// Services
|
|
769
844
|
routeAnalyzer;
|
|
770
845
|
schemaGenerator;
|
|
@@ -775,16 +850,28 @@ var RPCPlugin = class {
|
|
|
775
850
|
analyzedRoutes = [];
|
|
776
851
|
analyzedSchemas = [];
|
|
777
852
|
generatedInfos = [];
|
|
853
|
+
diagnostics = null;
|
|
778
854
|
app = null;
|
|
779
855
|
constructor(options = {}) {
|
|
780
856
|
this.controllerPattern = options.controllerPattern ?? DEFAULT_OPTIONS.controllerPattern;
|
|
781
857
|
this.tsConfigPath = options.tsConfigPath ?? path3.resolve(process.cwd(), DEFAULT_OPTIONS.tsConfigPath);
|
|
782
858
|
this.outputDir = options.outputDir ?? path3.resolve(process.cwd(), DEFAULT_OPTIONS.outputDir);
|
|
783
859
|
this.generateOnInit = options.generateOnInit ?? DEFAULT_OPTIONS.generateOnInit;
|
|
860
|
+
this.mode = options.mode ?? DEFAULT_OPTIONS.mode;
|
|
861
|
+
this.logLevel = options.logLevel ?? DEFAULT_OPTIONS.logLevel;
|
|
784
862
|
this.contextNamespace = options.context?.namespace ?? DEFAULT_OPTIONS.context.namespace;
|
|
785
863
|
this.contextArtifactKey = options.context?.keys?.artifact ?? DEFAULT_OPTIONS.context.keys.artifact;
|
|
786
|
-
this.
|
|
787
|
-
this.
|
|
864
|
+
this.customClassMatcher = options.customClassMatcher;
|
|
865
|
+
this.failOnSchemaError = options.failOnSchemaError ?? this.mode === "strict";
|
|
866
|
+
this.failOnRouteAnalysisWarning = options.failOnRouteAnalysisWarning ?? this.mode === "strict";
|
|
867
|
+
this.routeAnalyzer = new RouteAnalyzerService({
|
|
868
|
+
customClassMatcher: this.customClassMatcher,
|
|
869
|
+
onWarn: (message, details) => this.logWarn(message, details)
|
|
870
|
+
});
|
|
871
|
+
this.schemaGenerator = new SchemaGeneratorService(this.controllerPattern, this.tsConfigPath, {
|
|
872
|
+
failOnSchemaError: this.failOnSchemaError,
|
|
873
|
+
onWarn: (message, details) => this.logWarn(message, details)
|
|
874
|
+
});
|
|
788
875
|
this.generators = options.generators ?? [new TypeScriptClientGenerator(this.outputDir)];
|
|
789
876
|
this.validateConfiguration();
|
|
790
877
|
}
|
|
@@ -806,6 +893,12 @@ var RPCPlugin = class {
|
|
|
806
893
|
if (!this.outputDir?.trim()) {
|
|
807
894
|
errors.push("Output directory cannot be empty");
|
|
808
895
|
}
|
|
896
|
+
if (!["strict", "best-effort"].includes(this.mode)) {
|
|
897
|
+
errors.push('Mode must be "strict" or "best-effort"');
|
|
898
|
+
}
|
|
899
|
+
if (!["silent", "error", "warn", "info", "debug"].includes(this.logLevel)) {
|
|
900
|
+
errors.push("logLevel must be one of: silent, error, warn, info, debug");
|
|
901
|
+
}
|
|
809
902
|
if (!this.contextNamespace?.trim()) {
|
|
810
903
|
errors.push("Context namespace cannot be empty");
|
|
811
904
|
}
|
|
@@ -824,7 +917,7 @@ var RPCPlugin = class {
|
|
|
824
917
|
throw new Error(`Configuration validation failed: ${errors.join(", ")}`);
|
|
825
918
|
}
|
|
826
919
|
this.log(
|
|
827
|
-
`Configuration validated: controllerPattern=${this.controllerPattern}, tsConfigPath=${this.tsConfigPath}, outputDir=${this.outputDir}`
|
|
920
|
+
`Configuration validated: controllerPattern=${this.controllerPattern}, tsConfigPath=${this.tsConfigPath}, outputDir=${this.outputDir}, mode=${this.mode}`
|
|
828
921
|
);
|
|
829
922
|
}
|
|
830
923
|
/**
|
|
@@ -833,14 +926,17 @@ var RPCPlugin = class {
|
|
|
833
926
|
afterModulesRegistered = async (app, hono) => {
|
|
834
927
|
this.app = app;
|
|
835
928
|
if (this.generateOnInit) {
|
|
836
|
-
await this.analyzeEverything();
|
|
929
|
+
await this.analyzeEverything({ force: false, dryRun: false });
|
|
837
930
|
this.publishArtifact(app);
|
|
838
931
|
}
|
|
839
932
|
};
|
|
840
933
|
/**
|
|
841
934
|
* Main analysis method that coordinates all three components
|
|
842
935
|
*/
|
|
843
|
-
async analyzeEverything(
|
|
936
|
+
async analyzeEverything(options) {
|
|
937
|
+
const { force, dryRun } = options;
|
|
938
|
+
const warnings = [];
|
|
939
|
+
let cacheState = force ? "bypass" : "miss";
|
|
844
940
|
try {
|
|
845
941
|
this.log("Starting comprehensive RPC analysis...");
|
|
846
942
|
this.dispose();
|
|
@@ -852,21 +948,50 @@ var RPCPlugin = class {
|
|
|
852
948
|
const stored = readChecksum(this.outputDir);
|
|
853
949
|
if (stored && stored.hash === currentHash && this.outputFilesExist()) {
|
|
854
950
|
if (this.loadArtifactFromDisk()) {
|
|
855
|
-
|
|
951
|
+
cacheState = "hit";
|
|
952
|
+
this.logDebug("Source files unchanged - skipping regeneration");
|
|
953
|
+
this.diagnostics = {
|
|
954
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
955
|
+
mode: this.mode,
|
|
956
|
+
dryRun,
|
|
957
|
+
cache: cacheState,
|
|
958
|
+
routesCount: this.analyzedRoutes.length,
|
|
959
|
+
schemasCount: this.analyzedSchemas.length,
|
|
960
|
+
warnings: []
|
|
961
|
+
};
|
|
856
962
|
this.dispose();
|
|
857
963
|
return;
|
|
858
964
|
}
|
|
859
|
-
this.
|
|
965
|
+
this.logDebug("Source files unchanged but cached artifact missing/invalid - regenerating");
|
|
860
966
|
}
|
|
861
967
|
}
|
|
862
968
|
this.analyzedRoutes = [];
|
|
863
969
|
this.analyzedSchemas = [];
|
|
864
970
|
this.generatedInfos = [];
|
|
865
971
|
this.analyzedRoutes = await this.routeAnalyzer.analyzeControllerMethods(this.project);
|
|
972
|
+
warnings.push(...this.routeAnalyzer.getWarnings());
|
|
866
973
|
this.analyzedSchemas = await this.schemaGenerator.generateSchemas(this.project);
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
974
|
+
warnings.push(...this.schemaGenerator.getWarnings());
|
|
975
|
+
if (this.failOnRouteAnalysisWarning && this.routeAnalyzer.getWarnings().length > 0) {
|
|
976
|
+
throw new Error(`Route analysis warnings encountered in strict mode: ${this.routeAnalyzer.getWarnings().join("; ")}`);
|
|
977
|
+
}
|
|
978
|
+
if (!dryRun) {
|
|
979
|
+
this.generatedInfos = await this.runGenerators();
|
|
980
|
+
}
|
|
981
|
+
if (!dryRun) {
|
|
982
|
+
await writeChecksum(this.outputDir, { hash: computeHash(filePaths), files: filePaths });
|
|
983
|
+
this.writeArtifactToDisk();
|
|
984
|
+
}
|
|
985
|
+
this.diagnostics = {
|
|
986
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
987
|
+
mode: this.mode,
|
|
988
|
+
dryRun,
|
|
989
|
+
cache: cacheState,
|
|
990
|
+
routesCount: this.analyzedRoutes.length,
|
|
991
|
+
schemasCount: this.analyzedSchemas.length,
|
|
992
|
+
warnings
|
|
993
|
+
};
|
|
994
|
+
this.writeDiagnosticsToDisk();
|
|
870
995
|
this.log(
|
|
871
996
|
`\u2705 RPC analysis complete: ${this.analyzedRoutes.length} routes, ${this.analyzedSchemas.length} schemas`
|
|
872
997
|
);
|
|
@@ -876,13 +1001,10 @@ var RPCPlugin = class {
|
|
|
876
1001
|
throw error;
|
|
877
1002
|
}
|
|
878
1003
|
}
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
async analyze(force = true) {
|
|
884
|
-
await this.analyzeEverything(force);
|
|
885
|
-
if (this.app) {
|
|
1004
|
+
async analyze(forceOrOptions = true) {
|
|
1005
|
+
const options = typeof forceOrOptions === "boolean" ? { force: forceOrOptions, dryRun: false } : { force: forceOrOptions.force ?? true, dryRun: forceOrOptions.dryRun ?? false };
|
|
1006
|
+
await this.analyzeEverything(options);
|
|
1007
|
+
if (this.app && !options.dryRun) {
|
|
886
1008
|
this.publishArtifact(this.app);
|
|
887
1009
|
}
|
|
888
1010
|
}
|
|
@@ -910,6 +1032,9 @@ var RPCPlugin = class {
|
|
|
910
1032
|
getGenerationInfos() {
|
|
911
1033
|
return this.generatedInfos;
|
|
912
1034
|
}
|
|
1035
|
+
getDiagnostics() {
|
|
1036
|
+
return this.diagnostics;
|
|
1037
|
+
}
|
|
913
1038
|
/**
|
|
914
1039
|
* Checks whether expected output files exist on disk
|
|
915
1040
|
*/
|
|
@@ -925,23 +1050,38 @@ var RPCPlugin = class {
|
|
|
925
1050
|
getArtifactPath() {
|
|
926
1051
|
return path3.join(this.outputDir, "rpc-artifact.json");
|
|
927
1052
|
}
|
|
1053
|
+
getDiagnosticsPath() {
|
|
1054
|
+
return path3.join(this.outputDir, "rpc-diagnostics.json");
|
|
1055
|
+
}
|
|
928
1056
|
writeArtifactToDisk() {
|
|
929
1057
|
const artifact = {
|
|
1058
|
+
artifactVersion: RPC_ARTIFACT_VERSION,
|
|
930
1059
|
routes: this.analyzedRoutes,
|
|
931
1060
|
schemas: this.analyzedSchemas
|
|
932
1061
|
};
|
|
933
1062
|
fs2.mkdirSync(this.outputDir, { recursive: true });
|
|
934
1063
|
fs2.writeFileSync(this.getArtifactPath(), JSON.stringify(artifact));
|
|
935
1064
|
}
|
|
1065
|
+
writeDiagnosticsToDisk() {
|
|
1066
|
+
if (!this.diagnostics) return;
|
|
1067
|
+
fs2.mkdirSync(this.outputDir, { recursive: true });
|
|
1068
|
+
fs2.writeFileSync(this.getDiagnosticsPath(), JSON.stringify(this.diagnostics, null, 2));
|
|
1069
|
+
}
|
|
936
1070
|
loadArtifactFromDisk() {
|
|
937
1071
|
try {
|
|
938
1072
|
const raw = fs2.readFileSync(this.getArtifactPath(), "utf8");
|
|
939
1073
|
const parsed = JSON.parse(raw);
|
|
940
|
-
if (
|
|
941
|
-
|
|
1074
|
+
if (parsed.artifactVersion === void 0) {
|
|
1075
|
+
if (!Array.isArray(parsed.routes) || !Array.isArray(parsed.schemas)) {
|
|
1076
|
+
return false;
|
|
1077
|
+
}
|
|
1078
|
+
this.analyzedRoutes = parsed.routes;
|
|
1079
|
+
this.analyzedSchemas = parsed.schemas;
|
|
1080
|
+
} else {
|
|
1081
|
+
assertRpcArtifact(parsed);
|
|
1082
|
+
this.analyzedRoutes = parsed.routes;
|
|
1083
|
+
this.analyzedSchemas = parsed.schemas;
|
|
942
1084
|
}
|
|
943
|
-
this.analyzedRoutes = parsed.routes;
|
|
944
|
-
this.analyzedSchemas = parsed.schemas;
|
|
945
1085
|
this.generatedInfos = [];
|
|
946
1086
|
return true;
|
|
947
1087
|
} catch {
|
|
@@ -966,6 +1106,7 @@ var RPCPlugin = class {
|
|
|
966
1106
|
}
|
|
967
1107
|
publishArtifact(app) {
|
|
968
1108
|
app.getContext().set(this.getArtifactContextKey(), {
|
|
1109
|
+
artifactVersion: RPC_ARTIFACT_VERSION,
|
|
969
1110
|
routes: this.analyzedRoutes,
|
|
970
1111
|
schemas: this.analyzedSchemas
|
|
971
1112
|
});
|
|
@@ -989,13 +1130,37 @@ var RPCPlugin = class {
|
|
|
989
1130
|
* Logs a message with the plugin prefix
|
|
990
1131
|
*/
|
|
991
1132
|
log(message) {
|
|
992
|
-
|
|
1133
|
+
if (this.canLog("info")) {
|
|
1134
|
+
console.log(`${LOG_PREFIX} ${message}`);
|
|
1135
|
+
}
|
|
993
1136
|
}
|
|
994
1137
|
/**
|
|
995
1138
|
* Logs an error with the plugin prefix
|
|
996
1139
|
*/
|
|
997
1140
|
logError(message, error) {
|
|
998
|
-
|
|
1141
|
+
if (this.canLog("error")) {
|
|
1142
|
+
console.error(`${LOG_PREFIX} ${message}`, error || "");
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
logWarn(message, details) {
|
|
1146
|
+
if (this.canLog("warn")) {
|
|
1147
|
+
console.warn(`${LOG_PREFIX} ${message}`, details || "");
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
logDebug(message) {
|
|
1151
|
+
if (this.canLog("debug")) {
|
|
1152
|
+
console.log(`${LOG_PREFIX} ${message}`);
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
canLog(level) {
|
|
1156
|
+
const order = {
|
|
1157
|
+
silent: 0,
|
|
1158
|
+
error: 1,
|
|
1159
|
+
warn: 2,
|
|
1160
|
+
info: 3,
|
|
1161
|
+
debug: 4
|
|
1162
|
+
};
|
|
1163
|
+
return order[this.logLevel] >= order[level];
|
|
999
1164
|
}
|
|
1000
1165
|
};
|
|
1001
1166
|
export {
|
|
@@ -1005,15 +1170,18 @@ export {
|
|
|
1005
1170
|
GENERIC_TYPES,
|
|
1006
1171
|
LOG_PREFIX,
|
|
1007
1172
|
RPCPlugin,
|
|
1173
|
+
RPC_ARTIFACT_VERSION,
|
|
1008
1174
|
RouteAnalyzerService,
|
|
1009
1175
|
SchemaGeneratorService,
|
|
1010
1176
|
TypeScriptClientGenerator,
|
|
1177
|
+
assertRpcArtifact,
|
|
1011
1178
|
buildFullApiPath,
|
|
1012
1179
|
buildFullPath,
|
|
1013
1180
|
camelCase,
|
|
1014
1181
|
computeHash,
|
|
1015
1182
|
extractNamedType,
|
|
1016
1183
|
generateTypeScriptInterface,
|
|
1184
|
+
isRpcArtifact,
|
|
1017
1185
|
mapJsonSchemaTypeToTypeScript,
|
|
1018
1186
|
readChecksum,
|
|
1019
1187
|
safeToString,
|