@flink-app/flink 0.13.0 → 0.13.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @flink-app/flink
2
2
 
3
+ ## 0.13.2
4
+
5
+ ### Patch Changes
6
+
7
+ - - Fix schema generator to support built-in types, generic parameters, utility types, and recursive schemas.
8
+ - Prevented schema generator from attempting to import built-in TypeScript types (Array, Date, etc.) from lib files.
9
+ - Fixed generic type parameter resolution (e.g., PaginatedResponse<T> now correctly expands to concrete types)
10
+
11
+ ## 0.13.1
12
+
13
+ ### Patch Changes
14
+
15
+ - Fixed invalid types and improve typescript error message during schema compilation
16
+
3
17
  ## 0.13.0
4
18
 
5
19
  ### Minor Changes
@@ -482,9 +482,8 @@ var TypeScriptCompiler = /** @class */ (function () {
482
482
  };
483
483
  TypeScriptCompiler.prototype.saveIntermediateTsSchema = function (schema, handlerFile, suffix) {
484
484
  return __awaiter(this, void 0, void 0, function () {
485
- var handlerFileName, generatedSchemaInterfaceStr, schemaInterfaceName, schemaSymbol, interfaceName, declaration, _i, _a, typeToImport, arrayTypeArg, schemaSymbol, interfaceName, declaration, props, _b, _c, typeToImport, declarations, declaration, typeRefIdentifiers;
486
- var _this = this;
487
- return __generator(this, function (_d) {
485
+ var handlerFileName, generatedSchemaInterfaceStr, schemaInterfaceName, schemaSymbol, interfaceName, declaration, _i, _a, typeToImport, arrayTypeArg, schemaSymbol, interfaceName, declaration, props, _b, _c, typeToImport, declarations, declaration, propertySignatures, _d, _e, prop, propType, typeSymbol, typeDeclaration, elementType, elementSymbol, elementDeclaration;
486
+ return __generator(this, function (_f) {
488
487
  if (schema.isAny()) {
489
488
  return [2 /*return*/]; // 'any' indicates that no schema is used
490
489
  }
@@ -541,19 +540,50 @@ var TypeScriptCompiler = /** @class */ (function () {
541
540
  else if (schema.isObject()) {
542
541
  declarations = schema.getSymbolOrThrow().getDeclarations();
543
542
  declaration = declarations[0];
544
- // Only extract type references if declaration exists (won't exist for empty object literals like {})
545
- if (declaration) {
546
- typeRefIdentifiers = declaration
547
- .getDescendantsOfKind(ts_morph_1.SyntaxKind.TypeReference)
548
- .map(function (typeRef) { return typeRef.getFirstChildByKindOrThrow(ts_morph_1.SyntaxKind.Identifier); });
549
- typeRefIdentifiers.forEach(function (tr) {
550
- _this.tsSchemasSymbolsToImports.push(tr.getSymbolOrThrow().getDeclaredType().getSymbolOrThrow());
551
- });
543
+ propertySignatures = schema.getProperties().map(function (prop) {
544
+ var propName = prop.getName();
545
+ var propType = prop.getTypeAtLocation(handlerFile);
546
+ var propTypeText = propType.getText(undefined, ts_morph_1.ts.TypeFormatFlags.UseAliasDefinedOutsideCurrentScope);
547
+ // Check if property is optional
548
+ // For utility types (Omit, Pick, etc.), properties may not have value declarations
549
+ var valueDeclaration = prop.getValueDeclaration();
550
+ var isOptional = false;
551
+ if (valueDeclaration) {
552
+ // Property has a source declaration (normal case)
553
+ isOptional = valueDeclaration.getType().isNullable() ||
554
+ valueDeclaration.compilerNode.questionToken !== undefined;
555
+ }
556
+ else {
557
+ // Property is synthetic (from utility types like Omit, Pick, etc.)
558
+ // Check if the property itself is optional by examining the symbol flags
559
+ isOptional = !!(prop.getFlags() & ts_morph_1.ts.SymbolFlags.Optional);
560
+ }
561
+ return "".concat(propName).concat(isOptional ? '?' : '', ": ").concat(propTypeText);
562
+ });
563
+ // Extract type references for imports from resolved types
564
+ for (_d = 0, _e = schema.getProperties(); _d < _e.length; _d++) {
565
+ prop = _e[_d];
566
+ propType = prop.getTypeAtLocation(handlerFile);
567
+ typeSymbol = propType.getSymbol();
568
+ if (typeSymbol) {
569
+ typeDeclaration = typeSymbol.getDeclarations()[0];
570
+ if (typeDeclaration && typeDeclaration.getSourceFile() !== handlerFile) {
571
+ this.tsSchemasSymbolsToImports.push(typeSymbol);
572
+ }
573
+ }
574
+ // Also check for array element types
575
+ if (propType.isArray()) {
576
+ elementType = propType.getArrayElementType();
577
+ elementSymbol = elementType === null || elementType === void 0 ? void 0 : elementType.getSymbol();
578
+ if (elementSymbol) {
579
+ elementDeclaration = elementSymbol.getDeclarations()[0];
580
+ if (elementDeclaration && elementDeclaration.getSourceFile() !== handlerFile) {
581
+ this.tsSchemasSymbolsToImports.push(elementSymbol);
582
+ }
583
+ }
584
+ }
552
585
  }
553
- generatedSchemaInterfaceStr = "export interface ".concat(schemaInterfaceName, " { ").concat(schema
554
- .getProperties()
555
- .map(function (p) { return p.getValueDeclarationOrThrow().getText(); })
556
- .join("\n"), " }");
586
+ generatedSchemaInterfaceStr = "export interface ".concat(schemaInterfaceName, " { ").concat(propertySignatures.join(";\n"), " }");
557
587
  }
558
588
  else {
559
589
  console.log("[WARN] Unknown schema type", schema.getText());
@@ -590,7 +620,34 @@ var TypeScriptCompiler = /** @class */ (function () {
590
620
  console.log(" tsconfig:", tsconfigPath);
591
621
  // Create a fresh TypeScript Program that includes the schema file
592
622
  // This ensures ts-json-schema-generator can find the types we just generated
593
- var program = (0, ts_json_schema_generator_1.createProgram)(conf);
623
+ var program;
624
+ try {
625
+ program = (0, ts_json_schema_generator_1.createProgram)(conf);
626
+ }
627
+ catch (error) {
628
+ // Format the error in a more developer-friendly way
629
+ console.error("\n❌ Schema generation failed due to TypeScript compilation errors:\n");
630
+ if (error.diagnostic && error.diagnostic.relatedInformation) {
631
+ // Extract and display only the relevant error messages
632
+ for (var _i = 0, _a = error.diagnostic.relatedInformation; _i < _a.length; _i++) {
633
+ var info = _a[_i];
634
+ if (info.file) {
635
+ var _b = info.file.getLineAndCharacterOfPosition(info.start), line = _b.line, character = _b.character;
636
+ var fileName = info.file.fileName.replace(this.cwd, ".");
637
+ var message = typeof info.messageText === "string"
638
+ ? info.messageText
639
+ : info.messageText.messageText;
640
+ console.error(" ".concat(fileName, ":").concat(line + 1, ":").concat(character + 1));
641
+ console.error(" ".concat(message, "\n"));
642
+ }
643
+ }
644
+ }
645
+ else if (error.message) {
646
+ console.error(" ".concat(error.message, "\n"));
647
+ }
648
+ console.error("💡 Tip: Fix the TypeScript errors above and try again.\n");
649
+ process.exit(1);
650
+ }
594
651
  console.log(" TypeScript version:", ts_morph_1.ts.version);
595
652
  console.log(" Program root files:", program.getRootFileNames().length);
596
653
  var formatter = (0, ts_json_schema_generator_1.createFormatter)(conf);
@@ -71,6 +71,42 @@ function addImport(toSourceFile, symbol) {
71
71
  });
72
72
  }
73
73
  }
74
+ /**
75
+ * Checks if a symbol should be filtered out from imports.
76
+ * Returns true for built-in types, TypeScript lib types, and generic type parameters.
77
+ * @param symbol
78
+ * @returns
79
+ */
80
+ function shouldFilterSymbolFromImport(symbol) {
81
+ var symbolDeclaration = symbol.getDeclarations()[0];
82
+ if (!symbolDeclaration) {
83
+ return true; // Filter out symbols without declarations
84
+ }
85
+ var symbolSourceFile = symbolDeclaration.getSourceFile();
86
+ var sourceFilePath = symbolSourceFile.getFilePath();
87
+ // Filter out TypeScript lib files (lib.*.d.ts)
88
+ if (sourceFilePath.includes("/node_modules/typescript/lib/")) {
89
+ return true;
90
+ }
91
+ // Filter out common built-in global types by name
92
+ var symbolName = symbol.getEscapedName();
93
+ var builtInTypes = new Set([
94
+ "Array", "Date", "String", "Number", "Boolean", "Object", "Function",
95
+ "RegExp", "Error", "Promise", "Set", "Map", "WeakMap", "WeakSet",
96
+ "ArrayBuffer", "DataView", "Int8Array", "Uint8Array", "Uint8ClampedArray",
97
+ "Int16Array", "Uint16Array", "Int32Array", "Uint32Array", "Float32Array", "Float64Array",
98
+ "Readonly", "Partial", "Required", "Pick", "Record", "Exclude", "Extract", "Omit", "NonNullable",
99
+ "ReadonlyArray", "ReadonlyMap", "ReadonlySet"
100
+ ]);
101
+ if (builtInTypes.has(symbolName)) {
102
+ return true;
103
+ }
104
+ // Filter out single-letter type parameters (generic parameters like T, K, V, etc.)
105
+ if (symbolName.length === 1 && symbolName.match(/^[A-Z]$/)) {
106
+ return true;
107
+ }
108
+ return false;
109
+ }
74
110
  /**
75
111
  * Adds imports to modules where provided symbols resides.
76
112
  * Imports are added to provided source file.
@@ -81,6 +117,10 @@ function addImports(toSourceFile, symbols) {
81
117
  var importsByModuleSpecifier = new Map();
82
118
  for (var _i = 0, symbols_1 = symbols; _i < symbols_1.length; _i++) {
83
119
  var symbol = symbols_1[_i];
120
+ // Filter out built-in types and generic parameters
121
+ if (shouldFilterSymbolFromImport(symbol)) {
122
+ continue;
123
+ }
84
124
  var symbolDeclaration = symbol.getDeclarations()[0];
85
125
  if (!symbolDeclaration) {
86
126
  throw new Error("Missing declaration for symbol " + symbol.getFullyQualifiedName());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flink-app/flink",
3
- "version": "0.13.0",
3
+ "version": "0.13.2",
4
4
  "description": "Typescript only framework for creating REST-like APIs on top of Express and mongodb",
5
5
  "types": "dist/src/index.d.ts",
6
6
  "main": "dist/src/index.js",
@@ -480,21 +480,58 @@ export default {}; // Export an empty object to make it a module
480
480
  const declarations = schema.getSymbolOrThrow().getDeclarations();
481
481
  const declaration = declarations[0];
482
482
 
483
- // Only extract type references if declaration exists (won't exist for empty object literals like {})
484
- if (declaration) {
485
- const typeRefIdentifiers = declaration
486
- .getDescendantsOfKind(SyntaxKind.TypeReference)
487
- .map((typeRef) => typeRef.getFirstChildByKindOrThrow(SyntaxKind.Identifier));
488
-
489
- typeRefIdentifiers.forEach((tr) => {
490
- this.tsSchemasSymbolsToImports.push(tr.getSymbolOrThrow().getDeclaredType().getSymbolOrThrow());
491
- });
483
+ // Build property signatures using resolved types instead of source text
484
+ // This ensures generic type parameters are properly expanded
485
+ const propertySignatures = schema.getProperties().map((prop) => {
486
+ const propName = prop.getName();
487
+ const propType = prop.getTypeAtLocation(handlerFile);
488
+ const propTypeText = propType.getText(undefined, ts.TypeFormatFlags.UseAliasDefinedOutsideCurrentScope);
489
+
490
+ // Check if property is optional
491
+ // For utility types (Omit, Pick, etc.), properties may not have value declarations
492
+ const valueDeclaration = prop.getValueDeclaration();
493
+ let isOptional = false;
494
+
495
+ if (valueDeclaration) {
496
+ // Property has a source declaration (normal case)
497
+ isOptional = valueDeclaration.getType().isNullable() ||
498
+ (valueDeclaration.compilerNode as any).questionToken !== undefined;
499
+ } else {
500
+ // Property is synthetic (from utility types like Omit, Pick, etc.)
501
+ // Check if the property itself is optional by examining the symbol flags
502
+ isOptional = !!(prop.getFlags() & ts.SymbolFlags.Optional);
503
+ }
504
+
505
+ return `${propName}${isOptional ? '?' : ''}: ${propTypeText}`;
506
+ });
507
+
508
+ // Extract type references for imports from resolved types
509
+ for (const prop of schema.getProperties()) {
510
+ const propType = prop.getTypeAtLocation(handlerFile);
511
+
512
+ // Get symbol for the property type
513
+ const typeSymbol = propType.getSymbol();
514
+ if (typeSymbol) {
515
+ const typeDeclaration = typeSymbol.getDeclarations()[0];
516
+ if (typeDeclaration && typeDeclaration.getSourceFile() !== handlerFile) {
517
+ this.tsSchemasSymbolsToImports.push(typeSymbol);
518
+ }
519
+ }
520
+
521
+ // Also check for array element types
522
+ if (propType.isArray()) {
523
+ const elementType = propType.getArrayElementType();
524
+ const elementSymbol = elementType?.getSymbol();
525
+ if (elementSymbol) {
526
+ const elementDeclaration = elementSymbol.getDeclarations()[0];
527
+ if (elementDeclaration && elementDeclaration.getSourceFile() !== handlerFile) {
528
+ this.tsSchemasSymbolsToImports.push(elementSymbol);
529
+ }
530
+ }
531
+ }
492
532
  }
493
533
 
494
- generatedSchemaInterfaceStr = `export interface ${schemaInterfaceName} { ${schema
495
- .getProperties()
496
- .map((p) => p.getValueDeclarationOrThrow().getText())
497
- .join("\n")} }`;
534
+ generatedSchemaInterfaceStr = `export interface ${schemaInterfaceName} { ${propertySignatures.join(";\n")} }`;
498
535
  } else {
499
536
  console.log("[WARN] Unknown schema type", schema.getText());
500
537
  }
@@ -533,7 +570,34 @@ export default {}; // Export an empty object to make it a module
533
570
 
534
571
  // Create a fresh TypeScript Program that includes the schema file
535
572
  // This ensures ts-json-schema-generator can find the types we just generated
536
- const program = createProgram(conf);
573
+ let program;
574
+ try {
575
+ program = createProgram(conf);
576
+ } catch (error: any) {
577
+ // Format the error in a more developer-friendly way
578
+ console.error("\n❌ Schema generation failed due to TypeScript compilation errors:\n");
579
+
580
+ if (error.diagnostic && error.diagnostic.relatedInformation) {
581
+ // Extract and display only the relevant error messages
582
+ for (const info of error.diagnostic.relatedInformation) {
583
+ if (info.file) {
584
+ const { line, character } = info.file.getLineAndCharacterOfPosition(info.start);
585
+ const fileName = info.file.fileName.replace(this.cwd, ".");
586
+ const message = typeof info.messageText === "string"
587
+ ? info.messageText
588
+ : info.messageText.messageText;
589
+
590
+ console.error(` ${fileName}:${line + 1}:${character + 1}`);
591
+ console.error(` ${message}\n`);
592
+ }
593
+ }
594
+ } else if (error.message) {
595
+ console.error(` ${error.message}\n`);
596
+ }
597
+
598
+ console.error("💡 Tip: Fix the TypeScript errors above and try again.\n");
599
+ process.exit(1);
600
+ }
537
601
 
538
602
  console.log(" TypeScript version:", ts.version);
539
603
  console.log(" Program root files:", program.getRootFileNames().length);
@@ -71,6 +71,50 @@ export function addImport(toSourceFile: SourceFile, symbol: Symbol) {
71
71
  }
72
72
  }
73
73
 
74
+ /**
75
+ * Checks if a symbol should be filtered out from imports.
76
+ * Returns true for built-in types, TypeScript lib types, and generic type parameters.
77
+ * @param symbol
78
+ * @returns
79
+ */
80
+ function shouldFilterSymbolFromImport(symbol: Symbol): boolean {
81
+ const symbolDeclaration = symbol.getDeclarations()[0];
82
+
83
+ if (!symbolDeclaration) {
84
+ return true; // Filter out symbols without declarations
85
+ }
86
+
87
+ const symbolSourceFile = symbolDeclaration.getSourceFile();
88
+ const sourceFilePath = symbolSourceFile.getFilePath();
89
+
90
+ // Filter out TypeScript lib files (lib.*.d.ts)
91
+ if (sourceFilePath.includes("/node_modules/typescript/lib/")) {
92
+ return true;
93
+ }
94
+
95
+ // Filter out common built-in global types by name
96
+ const symbolName = symbol.getEscapedName();
97
+ const builtInTypes = new Set([
98
+ "Array", "Date", "String", "Number", "Boolean", "Object", "Function",
99
+ "RegExp", "Error", "Promise", "Set", "Map", "WeakMap", "WeakSet",
100
+ "ArrayBuffer", "DataView", "Int8Array", "Uint8Array", "Uint8ClampedArray",
101
+ "Int16Array", "Uint16Array", "Int32Array", "Uint32Array", "Float32Array", "Float64Array",
102
+ "Readonly", "Partial", "Required", "Pick", "Record", "Exclude", "Extract", "Omit", "NonNullable",
103
+ "ReadonlyArray", "ReadonlyMap", "ReadonlySet"
104
+ ]);
105
+
106
+ if (builtInTypes.has(symbolName)) {
107
+ return true;
108
+ }
109
+
110
+ // Filter out single-letter type parameters (generic parameters like T, K, V, etc.)
111
+ if (symbolName.length === 1 && symbolName.match(/^[A-Z]$/)) {
112
+ return true;
113
+ }
114
+
115
+ return false;
116
+ }
117
+
74
118
  /**
75
119
  * Adds imports to modules where provided symbols resides.
76
120
  * Imports are added to provided source file.
@@ -81,6 +125,11 @@ export function addImports(toSourceFile: SourceFile, symbols: Symbol[]) {
81
125
  const importsByModuleSpecifier = new Map<string, { defaultImportName?: string; namedImports: string[] }>();
82
126
 
83
127
  for (const symbol of symbols) {
128
+ // Filter out built-in types and generic parameters
129
+ if (shouldFilterSymbolFromImport(symbol)) {
130
+ continue;
131
+ }
132
+
84
133
  const symbolDeclaration = symbol.getDeclarations()[0];
85
134
 
86
135
  if (!symbolDeclaration) {