pepr 1.2.0 → 1.2.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.
@@ -1,13 +1,14 @@
1
- import { Project, SourceFile } from "ts-morph";
1
+ import ts from "typescript";
2
2
  import { V1JSONSchemaProps } from "@kubernetes/client-node";
3
3
  export declare function generateCRDs(options: {
4
4
  output: string;
5
5
  }): Promise<void>;
6
6
  export declare function getAPIVersions(apiRoot: string): string[];
7
- export declare function loadVersionFiles(project: Project, versionDir: string): SourceFile[];
8
- export declare function processSourceFile(sourceFile: SourceFile, version: string, outputDir: string): void;
7
+ export declare function loadVersionFilePaths(versionDir: string): string[];
8
+ export declare function createProgram(filePaths: string[]): ts.Program;
9
+ export declare function processSourceFile(sourceFile: ts.SourceFile, checker: ts.TypeChecker, version: string, outputDir: string): void;
9
10
  export declare function extractSingleLineComment(content: string, label: string): string | undefined;
10
- export declare function extractDetails(sourceFile: SourceFile): {
11
+ export declare function extractDetails(sourceFile: ts.SourceFile): {
11
12
  plural: string;
12
13
  scope: "Cluster" | "Namespaced";
13
14
  shortName: string;
@@ -1 +1 @@
1
- {"version":3,"file":"generators.d.ts","sourceRoot":"","sources":["../../../../src/cli/crd/generate/generators.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,OAAO,EAKP,UAAU,EAEX,MAAM,UAAU,CAAC;AAGlB,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AA0B5D,wBAAsB,YAAY,CAAC,OAAO,EAAE;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAe7E;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAExD;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,GAAG,UAAU,EAAE,CAInF;AAED,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAChB,IAAI,CAiCN;AAGD,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAI3F;AAED,wBAAgB,cAAc,CAAC,UAAU,EAAE,UAAU,GAAG;IACtD,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,SAAS,GAAG,YAAY,CAAC;IAChC,SAAS,EAAE,MAAM,CAAC;CACnB,CA2BA;AAoFD,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,wBAAgB,WAAW,IAAI;IAC7B,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IAC9C,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB,CAEA"}
1
+ {"version":3,"file":"generators.d.ts","sourceRoot":"","sources":["../../../../src/cli/crd/generate/generators.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,YAAY,CAAC;AAK5B,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AA8B5D,wBAAsB,YAAY,CAAC,OAAO,EAAE;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAqB7E;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAExD;AAED,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,CAGjE;AAED,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,OAAO,CAM7D;AAED,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,EAAE,CAAC,UAAU,EACzB,OAAO,EAAE,EAAE,CAAC,WAAW,EACvB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAChB,IAAI,CAiCN;AAGD,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAI3F;AAED,wBAAgB,cAAc,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,GAAG;IACzD,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,SAAS,GAAG,YAAY,CAAC;IAChC,SAAS,EAAE,MAAM,CAAC;CACnB,CA2CA;AA4ID,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,wBAAgB,WAAW,IAAI;IAC7B,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IAC9C,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB,CAEA"}
@@ -18,14 +18,9 @@ export declare const dependencies: {
18
18
  "prom-client": string;
19
19
  "quicktype-core": string;
20
20
  ramda: string;
21
- "ts-morph": string;
22
21
  }, devDependencies: {
23
22
  "@commitlint/cli": string;
24
23
  "@commitlint/config-conventional": string;
25
- "@semantic-release/commit-analyzer": string;
26
- "@semantic-release/git": string;
27
- "@semantic-release/npm": string;
28
- "@semantic-release/release-notes-generator": string;
29
24
  "@types/command-line-args": string;
30
25
  "@types/express": string;
31
26
  "@types/json-pointer": string;
@@ -1 +1 @@
1
- {"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../../src/cli/init/templates.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,YAAY,IAAI,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAIrE,eAAO,MAAQ,YAAY;;;;;;;;;;;;;;;;;GAAE,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;GAAE,gBAAgB;;;;;;;;GAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAAE,OAAO,QAAgB,CAAC;AAEjG,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,MAAM,EAAE,CAAC;QACnB,OAAO,EAAE;YAAE,IAAI,EAAE,MAAM,CAAA;SAAE,CAAC;QAC1B,IAAI,EAAE;YACJ,IAAI,EAAE,MAAM,CAAC;YACb,OAAO,EAAE,OAAO,CAAC;YACjB,cAAc,EAAE,MAAM,CAAC;YACvB,YAAY,EAAE,YAAY,CAAC;YAC3B,YAAY,EAAE;gBAAE,UAAU,EAAE,MAAM,EAAE,CAAA;aAAE,CAAC;YACvC,SAAS,EAAE;gBAAE,YAAY,EAAE;oBAAE,UAAU,EAAE,MAAM,EAAE,CAAA;iBAAE,CAAA;aAAE,CAAC;YACtD,KAAK,EAAE;gBAAE,YAAY,EAAE;oBAAE,UAAU,EAAE,MAAM,EAAE,CAAA;iBAAE,CAAA;aAAE,CAAC;YAClD,aAAa,EAAE,MAAM,EAAE,CAAC;YACxB,GAAG,EAAE,MAAM,CAAC;YACZ,IAAI,CAAC,EAAE,UAAU,EAAE,CAAC;YACpB,QAAQ,CAAC,EAAE,QAAQ,CAAC;SACrB,CAAC;QACF,OAAO,EAAE;YAAE,WAAW,EAAE,MAAM,CAAA;SAAE,CAAC;QACjC,YAAY,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,CAAC;QAC/C,eAAe,EAAE;YAAE,UAAU,EAAE,MAAM,CAAA;SAAE,CAAC;KACzC,CAAC;IACF,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,wBAAgB,UAAU,CAAC,IAAI,EAAE,WAAW,GAAG,eAAe,CA4D7D;AAED,eAAO,MAAM,cAAc;;;CAG1B,CAAC;AAEF,eAAO,MAAM,MAAM;;;CAGlB,CAAC;AAEF,eAAO,MAAM,SAAS;;;CAGrB,CAAC;AAEF,eAAO,MAAM,SAAS;;;CAGrB,CAAC;AAEF,eAAO,MAAM,WAAW;;;CAGvB,CAAC;AAEF,eAAO,MAAM,OAAO;;;;;;;;;CAGnB,CAAC;AAEF,eAAO,MAAM,YAAY;;;;;;;;CAGxB,CAAC;AAEF,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;CAGpB,CAAC;AAEF,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;CAGpB,CAAC;AAEF,eAAO,MAAM,MAAM;;;CAgBlB,CAAC"}
1
+ {"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../../src/cli/init/templates.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,YAAY,IAAI,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAIrE,eAAO,MAAQ,YAAY;;;;;;;;;;;;;;;;GAAE,eAAe;;;;;;;;;;;;;;;;;;;;;;GAAE,gBAAgB;;;;;;;;GAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAAE,OAAO,QAAgB,CAAC;AAEjG,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,MAAM,EAAE,CAAC;QACnB,OAAO,EAAE;YAAE,IAAI,EAAE,MAAM,CAAA;SAAE,CAAC;QAC1B,IAAI,EAAE;YACJ,IAAI,EAAE,MAAM,CAAC;YACb,OAAO,EAAE,OAAO,CAAC;YACjB,cAAc,EAAE,MAAM,CAAC;YACvB,YAAY,EAAE,YAAY,CAAC;YAC3B,YAAY,EAAE;gBAAE,UAAU,EAAE,MAAM,EAAE,CAAA;aAAE,CAAC;YACvC,SAAS,EAAE;gBAAE,YAAY,EAAE;oBAAE,UAAU,EAAE,MAAM,EAAE,CAAA;iBAAE,CAAA;aAAE,CAAC;YACtD,KAAK,EAAE;gBAAE,YAAY,EAAE;oBAAE,UAAU,EAAE,MAAM,EAAE,CAAA;iBAAE,CAAA;aAAE,CAAC;YAClD,aAAa,EAAE,MAAM,EAAE,CAAC;YACxB,GAAG,EAAE,MAAM,CAAC;YACZ,IAAI,CAAC,EAAE,UAAU,EAAE,CAAC;YACpB,QAAQ,CAAC,EAAE,QAAQ,CAAC;SACrB,CAAC;QACF,OAAO,EAAE;YAAE,WAAW,EAAE,MAAM,CAAA;SAAE,CAAC;QACjC,YAAY,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,CAAC;QAC/C,eAAe,EAAE;YAAE,UAAU,EAAE,MAAM,CAAA;SAAE,CAAC;KACzC,CAAC;IACF,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,wBAAgB,UAAU,CAAC,IAAI,EAAE,WAAW,GAAG,eAAe,CA4D7D;AAED,eAAO,MAAM,cAAc;;;CAG1B,CAAC;AAEF,eAAO,MAAM,MAAM;;;CAGlB,CAAC;AAEF,eAAO,MAAM,SAAS;;;CAGrB,CAAC;AAEF,eAAO,MAAM,SAAS;;;CAGrB,CAAC;AAEF,eAAO,MAAM,WAAW;;;CAGvB,CAAC;AAEF,eAAO,MAAM,OAAO;;;;;;;;;CAGnB,CAAC;AAEF,eAAO,MAAM,YAAY;;;;;;;;CAGxB,CAAC;AAEF,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;CAGpB,CAAC;AAEF,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;CAGpB,CAAC;AAEF,eAAO,MAAM,MAAM;;;CAgBlB,CAAC"}
package/dist/cli.js CHANGED
@@ -29,13 +29,13 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
29
29
  var require_identity = __commonJS({
30
30
  "node_modules/yaml/dist/nodes/identity.js"(exports2) {
31
31
  "use strict";
32
- var ALIAS = Symbol.for("yaml.alias");
33
- var DOC = Symbol.for("yaml.document");
34
- var MAP = Symbol.for("yaml.map");
35
- var PAIR = Symbol.for("yaml.pair");
36
- var SCALAR = Symbol.for("yaml.scalar");
37
- var SEQ = Symbol.for("yaml.seq");
38
- var NODE_TYPE = Symbol.for("yaml.node.type");
32
+ var ALIAS = /* @__PURE__ */ Symbol.for("yaml.alias");
33
+ var DOC = /* @__PURE__ */ Symbol.for("yaml.document");
34
+ var MAP = /* @__PURE__ */ Symbol.for("yaml.map");
35
+ var PAIR = /* @__PURE__ */ Symbol.for("yaml.pair");
36
+ var SCALAR = /* @__PURE__ */ Symbol.for("yaml.scalar");
37
+ var SEQ = /* @__PURE__ */ Symbol.for("yaml.seq");
38
+ var NODE_TYPE = /* @__PURE__ */ Symbol.for("yaml.node.type");
39
39
  var isAlias = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === ALIAS;
40
40
  var isDocument = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === DOC;
41
41
  var isMap = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === MAP;
@@ -87,9 +87,9 @@ var require_visit = __commonJS({
87
87
  "node_modules/yaml/dist/visit.js"(exports2) {
88
88
  "use strict";
89
89
  var identity = require_identity();
90
- var BREAK = Symbol("break visit");
91
- var SKIP = Symbol("skip children");
92
- var REMOVE = Symbol("remove node");
90
+ var BREAK = /* @__PURE__ */ Symbol("break visit");
91
+ var SKIP = /* @__PURE__ */ Symbol("skip children");
92
+ var REMOVE = /* @__PURE__ */ Symbol("remove node");
93
93
  function visit(node, visitor) {
94
94
  const visitor_ = initVisitor(visitor);
95
95
  if (identity.isDocument(node)) {
@@ -609,9 +609,9 @@ var require_Alias = __commonJS({
609
609
  var anchors = require_anchors();
610
610
  var visit = require_visit();
611
611
  var identity = require_identity();
612
- var Node2 = require_Node();
612
+ var Node = require_Node();
613
613
  var toJS = require_toJS();
614
- var Alias = class extends Node2.NodeBase {
614
+ var Alias = class extends Node.NodeBase {
615
615
  constructor(source) {
616
616
  super(identity.ALIAS);
617
617
  this.source = source;
@@ -721,10 +721,10 @@ var require_Scalar = __commonJS({
721
721
  "node_modules/yaml/dist/nodes/Scalar.js"(exports2) {
722
722
  "use strict";
723
723
  var identity = require_identity();
724
- var Node2 = require_Node();
724
+ var Node = require_Node();
725
725
  var toJS = require_toJS();
726
726
  var isScalarValue = (value) => !value || typeof value !== "function" && typeof value !== "object";
727
- var Scalar = class extends Node2.NodeBase {
727
+ var Scalar = class extends Node.NodeBase {
728
728
  constructor(value) {
729
729
  super(identity.SCALAR);
730
730
  this.value = value;
@@ -827,7 +827,7 @@ var require_Collection = __commonJS({
827
827
  "use strict";
828
828
  var createNode = require_createNode();
829
829
  var identity = require_identity();
830
- var Node2 = require_Node();
830
+ var Node = require_Node();
831
831
  function collectionFromPath(schema, path4, value) {
832
832
  let v = value;
833
833
  for (let i = path4.length - 1; i >= 0; --i) {
@@ -851,7 +851,7 @@ var require_Collection = __commonJS({
851
851
  });
852
852
  }
853
853
  var isEmptyPath = (path4) => path4 == null || typeof path4 === "object" && !!path4[Symbol.iterator]().next().done;
854
- var Collection = class extends Node2.NodeBase {
854
+ var Collection = class extends Node.NodeBase {
855
855
  constructor(type, schema) {
856
856
  super(type);
857
857
  Object.defineProperty(this, "schema", {
@@ -2104,8 +2104,8 @@ var require_YAMLMap = __commonJS({
2104
2104
  * @param {Class} Type - If set, forces the returned collection type
2105
2105
  * @returns Instance of Type, Map, or Object
2106
2106
  */
2107
- toJSON(_, ctx, Type2) {
2108
- const map = Type2 ? new Type2() : ctx?.mapAsMap ? /* @__PURE__ */ new Map() : {};
2107
+ toJSON(_, ctx, Type) {
2108
+ const map = Type ? new Type() : ctx?.mapAsMap ? /* @__PURE__ */ new Map() : {};
2109
2109
  if (ctx?.onCreate)
2110
2110
  ctx.onCreate(map);
2111
2111
  for (const item of this.items)
@@ -4584,9 +4584,9 @@ var require_resolve_block_scalar = __commonJS({
4584
4584
  default: {
4585
4585
  const message = `Unexpected token in block scalar header: ${token.type}`;
4586
4586
  onError(token, "UNEXPECTED_TOKEN", message);
4587
- const ts = token.source;
4588
- if (ts && typeof ts === "string")
4589
- length += ts.length;
4587
+ const ts2 = token.source;
4588
+ if (ts2 && typeof ts2 === "string")
4589
+ length += ts2.length;
4590
4590
  }
4591
4591
  }
4592
4592
  }
@@ -4894,9 +4894,9 @@ var require_compose_scalar = __commonJS({
4894
4894
  if (schema.compat) {
4895
4895
  const compat = schema.compat.find((tag2) => tag2.default && tag2.test?.test(value)) ?? schema[identity.SCALAR];
4896
4896
  if (tag.tag !== compat.tag) {
4897
- const ts = directives.tagString(tag.tag);
4897
+ const ts2 = directives.tagString(tag.tag);
4898
4898
  const cs = directives.tagString(compat.tag);
4899
- const msg = `Value may be parsed as either ${ts} or ${cs}`;
4899
+ const msg = `Value may be parsed as either ${ts2} or ${cs}`;
4900
4900
  onError(token, "TAG_RESOLVE_FAILED", msg, true);
4901
4901
  }
4902
4902
  }
@@ -5541,9 +5541,9 @@ var require_cst_stringify = __commonJS({
5541
5541
  var require_cst_visit = __commonJS({
5542
5542
  "node_modules/yaml/dist/parse/cst-visit.js"(exports2) {
5543
5543
  "use strict";
5544
- var BREAK = Symbol("break visit");
5545
- var SKIP = Symbol("skip children");
5546
- var REMOVE = Symbol("remove item");
5544
+ var BREAK = /* @__PURE__ */ Symbol("break visit");
5545
+ var SKIP = /* @__PURE__ */ Symbol("skip children");
5546
+ var REMOVE = /* @__PURE__ */ Symbol("remove item");
5547
5547
  function visit(cst, visitor) {
5548
5548
  if ("type" in cst && cst.type === "document")
5549
5549
  cst = { start: cst.start, value: cst.value };
@@ -9645,7 +9645,7 @@ var packageJSON = {
9645
9645
  "!src/fixtures/**",
9646
9646
  "!dist/**/*.test.d.ts*"
9647
9647
  ],
9648
- version: "1.2.0",
9648
+ version: "1.2.1",
9649
9649
  main: "dist/lib.js",
9650
9650
  types: "dist/lib.d.ts",
9651
9651
  scripts: {
@@ -9679,8 +9679,8 @@ var packageJSON = {
9679
9679
  },
9680
9680
  dependencies: {
9681
9681
  "@types/ramda": "0.31.1",
9682
- "@typescript-eslint/eslint-plugin": "8.59.1",
9683
- "@typescript-eslint/parser": "8.59.1",
9682
+ "@typescript-eslint/eslint-plugin": "8.59.4",
9683
+ "@typescript-eslint/parser": "8.59.4",
9684
9684
  commander: "14.0.3",
9685
9685
  eslint: "9.39.4",
9686
9686
  express: "5.2.1",
@@ -9692,16 +9692,11 @@ var packageJSON = {
9692
9692
  "pino-pretty": "13.1.3",
9693
9693
  "prom-client": "15.1.3",
9694
9694
  "quicktype-core": "^23.2.6",
9695
- ramda: "0.32.0",
9696
- "ts-morph": "^27.0.2"
9695
+ ramda: "0.32.0"
9697
9696
  },
9698
9697
  devDependencies: {
9699
- "@commitlint/cli": "20.5.0",
9700
- "@commitlint/config-conventional": "20.5.0",
9701
- "@semantic-release/commit-analyzer": "^13.0.1",
9702
- "@semantic-release/git": "^10.0.1",
9703
- "@semantic-release/npm": "^13.0.0",
9704
- "@semantic-release/release-notes-generator": "^14.1.0",
9698
+ "@commitlint/cli": "21.0.1",
9699
+ "@commitlint/config-conventional": "21.0.1",
9705
9700
  "@types/command-line-args": "^5.2.3",
9706
9701
  "@types/express": "5.0.6",
9707
9702
  "@types/json-pointer": "^1.0.34",
@@ -9727,13 +9722,13 @@ var packageJSON = {
9727
9722
  rollup: "4.59.0"
9728
9723
  },
9729
9724
  peerDependencies: {
9730
- "@types/prompts": "2.4.9",
9731
- esbuild: "0.25.10",
9732
- "node-forge": "1.4.0",
9733
- prettier: "3.6.2",
9734
- prompts: "2.4.2",
9735
- typescript: "5.8.3",
9736
- uuid: "13.0.0"
9725
+ "@types/prompts": "^2.4.9",
9726
+ esbuild: "^0.28.0",
9727
+ "node-forge": "^1.4.0",
9728
+ prettier: "^3.6.2",
9729
+ prompts: "^2.4.2",
9730
+ typescript: "^5.8.3",
9731
+ uuid: "^13.0.0"
9737
9732
  }
9738
9733
  };
9739
9734
 
@@ -11100,8 +11095,8 @@ var import_commander4 = require("commander");
11100
11095
  // src/cli/crd/generate/generators.ts
11101
11096
  var import_fs14 = __toESM(require("fs"));
11102
11097
  var import_path8 = __toESM(require("path"));
11098
+ var import_typescript = __toESM(require("typescript"));
11103
11099
  var import_yaml = __toESM(require_dist());
11104
- var import_ts_morph = require("ts-morph");
11105
11100
 
11106
11101
  // src/cli/crd/generate/messages.ts
11107
11102
  var ErrorMessages = {
@@ -11118,6 +11113,9 @@ var WarningMessages = {
11118
11113
  // src/cli/crd/generate/generators.ts
11119
11114
  function extractCRDDetails(content, sourceFile) {
11120
11115
  const kind8 = extractSingleLineComment(content, "Kind");
11116
+ if (!kind8) {
11117
+ return { kind: void 0, fqdn: "", scope: "Namespaced", plural: "", shortNames: void 0 };
11118
+ }
11121
11119
  const group2 = extractSingleLineComment(content, "Group") ?? "example";
11122
11120
  const domain = extractSingleLineComment(content, "Domain") ?? "pepr.dev";
11123
11121
  const details = extractDetails(sourceFile);
@@ -11130,39 +11128,50 @@ async function generateCRDs(options) {
11130
11128
  logger_default.warn("This feature is currently in alpha.\n");
11131
11129
  const outputDir = import_path8.default.resolve(options.output);
11132
11130
  await createDirectoryIfNotExists(outputDir);
11133
- const project = new import_ts_morph.Project();
11134
11131
  const apiRoot = import_path8.default.resolve("api");
11135
11132
  const versions = getAPIVersions(apiRoot);
11136
11133
  for (const version3 of versions) {
11137
- const sourceFiles = loadVersionFiles(project, import_path8.default.join(apiRoot, version3));
11138
- for (const sourceFile of sourceFiles) {
11139
- processSourceFile(sourceFile, version3, outputDir);
11134
+ const versionDir = import_path8.default.join(apiRoot, version3);
11135
+ const filePaths = loadVersionFilePaths(versionDir);
11136
+ const program2 = createProgram(filePaths);
11137
+ const checker = program2.getTypeChecker();
11138
+ for (const filePath of filePaths) {
11139
+ const sourceFile = program2.getSourceFile(filePath);
11140
+ if (sourceFile) {
11141
+ processSourceFile(sourceFile, checker, version3, outputDir);
11142
+ }
11140
11143
  }
11141
11144
  }
11142
11145
  }
11143
11146
  function getAPIVersions(apiRoot) {
11144
11147
  return import_fs14.default.readdirSync(apiRoot).filter((v) => import_fs14.default.statSync(import_path8.default.join(apiRoot, v)).isDirectory());
11145
11148
  }
11146
- function loadVersionFiles(project, versionDir) {
11149
+ function loadVersionFilePaths(versionDir) {
11147
11150
  const files = import_fs14.default.readdirSync(versionDir).filter((f) => f.endsWith(".ts"));
11148
- const filePaths = files.map((f) => import_path8.default.join(versionDir, f));
11149
- return project.addSourceFilesAtPaths(filePaths);
11151
+ return files.map((f) => import_path8.default.join(versionDir, f));
11150
11152
  }
11151
- function processSourceFile(sourceFile, version3, outputDir) {
11153
+ function createProgram(filePaths) {
11154
+ return import_typescript.default.createProgram(filePaths, {
11155
+ target: import_typescript.default.ScriptTarget.ESNext,
11156
+ module: import_typescript.default.ModuleKind.ESNext,
11157
+ strict: true
11158
+ });
11159
+ }
11160
+ function processSourceFile(sourceFile, checker, version3, outputDir) {
11152
11161
  const content = sourceFile.getFullText();
11153
11162
  const { kind: kind8, fqdn, scope, plural: plural2, shortNames } = extractCRDDetails(content, sourceFile);
11154
11163
  if (!kind8) {
11155
- logger_default.warn(WarningMessages.MISSING_KIND_COMMENT(sourceFile.getBaseName()));
11164
+ logger_default.warn(WarningMessages.MISSING_KIND_COMMENT(import_path8.default.basename(sourceFile.fileName)));
11156
11165
  return;
11157
11166
  }
11158
- const spec = sourceFile.getInterface(`${kind8}Spec`);
11167
+ const spec = findInterface(sourceFile, `${kind8}Spec`);
11159
11168
  if (!spec) {
11160
- logger_default.warn(WarningMessages.MISSING_INTERFACE(sourceFile.getBaseName(), kind8));
11169
+ logger_default.warn(WarningMessages.MISSING_INTERFACE(import_path8.default.basename(sourceFile.fileName), kind8));
11161
11170
  return;
11162
11171
  }
11163
- const condition = sourceFile.getTypeAlias(`${kind8}StatusCondition`);
11164
- const specSchema = getSchemaFromType(spec);
11165
- const conditionSchema = condition ? getSchemaFromType(condition) : emptySchema();
11172
+ const condition = findTypeAlias(sourceFile, `${kind8}StatusCondition`);
11173
+ const specSchema = getSchemaFromType(spec, checker);
11174
+ const conditionSchema = condition ? getSchemaFromType(condition, checker) : emptySchema();
11166
11175
  const crd = buildCRD({
11167
11176
  kind: kind8,
11168
11177
  fqdn,
@@ -11182,18 +11191,31 @@ function extractSingleLineComment(content, label) {
11182
11191
  return match?.[1].trim();
11183
11192
  }
11184
11193
  function extractDetails(sourceFile) {
11185
- const decl = sourceFile.getVariableDeclaration("details");
11186
- if (!decl) {
11194
+ let detailsDecl;
11195
+ import_typescript.default.forEachChild(sourceFile, (node) => {
11196
+ if (import_typescript.default.isVariableStatement(node)) {
11197
+ for (const decl of node.declarationList.declarations) {
11198
+ if (import_typescript.default.isIdentifier(decl.name) && decl.name.text === "details") {
11199
+ detailsDecl = decl;
11200
+ }
11201
+ }
11202
+ }
11203
+ });
11204
+ if (!detailsDecl) {
11205
+ throw new Error(ErrorMessages.MISSING_DETAILS);
11206
+ }
11207
+ const init = detailsDecl.initializer;
11208
+ if (!init || !import_typescript.default.isObjectLiteralExpression(init)) {
11187
11209
  throw new Error(ErrorMessages.MISSING_DETAILS);
11188
11210
  }
11189
- const init = decl.getInitializerIfKindOrThrow(import_ts_morph.SyntaxKind.ObjectLiteralExpression);
11190
11211
  const getStr = (key) => {
11191
- const prop = init.getProperty(key);
11192
- const value = prop?.getFirstChildByKind(import_ts_morph.SyntaxKind.StringLiteral)?.getLiteralText();
11193
- if (!value) {
11194
- throw new Error(ErrorMessages.MISSING_OR_INVALID_KEY(key));
11212
+ const match = init.properties.find(
11213
+ (prop) => import_typescript.default.isPropertyAssignment(prop) && import_typescript.default.isIdentifier(prop.name) && prop.name.text === key
11214
+ );
11215
+ if (match && import_typescript.default.isStringLiteral(match.initializer) && match.initializer.text) {
11216
+ return match.initializer.text;
11195
11217
  }
11196
- return value;
11218
+ throw new Error(ErrorMessages.MISSING_OR_INVALID_KEY(key));
11197
11219
  };
11198
11220
  const scope = getStr("scope");
11199
11221
  if (scope === "Cluster" || scope === "Namespaced") {
@@ -11205,62 +11227,104 @@ function extractDetails(sourceFile) {
11205
11227
  }
11206
11228
  throw new Error(ErrorMessages.INVALID_SCOPE(scope));
11207
11229
  }
11208
- function getJsDocDescription(node) {
11209
- if (!import_ts_morph.Node.isPropertySignature(node) && !import_ts_morph.Node.isPropertyDeclaration(node)) return "";
11210
- return node.getJsDocs().map((doc) => doc.getComment()).filter(Boolean).join(" ").trim();
11230
+ function findInterface(sourceFile, name2) {
11231
+ let result;
11232
+ import_typescript.default.forEachChild(sourceFile, (node) => {
11233
+ if (import_typescript.default.isInterfaceDeclaration(node) && node.name.text === name2) {
11234
+ result = node;
11235
+ }
11236
+ });
11237
+ return result;
11211
11238
  }
11212
- function getSchemaFromType(decl) {
11213
- const type = decl.getType();
11214
- const properties = {};
11215
- const required = [];
11216
- for (const prop of type.getProperties()) {
11217
- const name2 = uncapitalize(prop.getName());
11218
- const declarations = prop.getDeclarations();
11219
- if (!declarations.length) continue;
11220
- const declaration = declarations[0];
11221
- const description = getJsDocDescription(declaration);
11222
- const valueType = declaration.getType();
11223
- properties[name2] = {
11224
- ...mapTypeToSchema(valueType),
11225
- ...description ? { description } : {}
11226
- };
11227
- if (!prop.isOptional()) required.push(name2);
11239
+ function findTypeAlias(sourceFile, name2) {
11240
+ let result;
11241
+ import_typescript.default.forEachChild(sourceFile, (node) => {
11242
+ if (import_typescript.default.isTypeAliasDeclaration(node) && node.name.text === name2) {
11243
+ result = node;
11244
+ }
11245
+ });
11246
+ return result;
11247
+ }
11248
+ function getJsDocDescription(node) {
11249
+ const jsDocs = import_typescript.default.getJSDocCommentsAndTags(node);
11250
+ const comments = [];
11251
+ for (const doc of jsDocs) {
11252
+ if (import_typescript.default.isJSDoc(doc) && doc.comment) {
11253
+ if (typeof doc.comment === "string") {
11254
+ comments.push(doc.comment);
11255
+ } else {
11256
+ comments.push(doc.comment.map((part) => part.text).join(""));
11257
+ }
11258
+ }
11228
11259
  }
11260
+ return comments.join(" ").trim();
11261
+ }
11262
+ function getSchemaFromType(decl, checker) {
11263
+ const type = checker.getTypeAtLocation(decl);
11264
+ const { properties, required } = extractObjectProperties(type, checker);
11229
11265
  return { properties, required };
11230
11266
  }
11231
- function mapTypeToSchema(type) {
11232
- if (type.getText() === "Date") return { type: "string", format: "date-time" };
11233
- if (type.isString()) return { type: "string" };
11234
- if (type.isNumber()) return { type: "number" };
11235
- if (type.isBoolean()) return { type: "boolean" };
11236
- if (type.isArray()) {
11237
- return {
11238
- type: "array",
11239
- items: mapTypeToSchema(type.getArrayElementTypeOrThrow())
11240
- };
11267
+ function getPrimitiveSchemaType(type) {
11268
+ const { flags } = type;
11269
+ if (flags & import_typescript.default.TypeFlags.String || flags & import_typescript.default.TypeFlags.StringLiteral) {
11270
+ return { type: "string" };
11271
+ }
11272
+ if (flags & import_typescript.default.TypeFlags.Number || flags & import_typescript.default.TypeFlags.NumberLiteral) {
11273
+ return { type: "number" };
11241
11274
  }
11242
- if (type.isObject()) return buildObjectSchema(type);
11275
+ if (flags & import_typescript.default.TypeFlags.Boolean || flags & import_typescript.default.TypeFlags.BooleanLiteral || flags & import_typescript.default.TypeFlags.BooleanLike) {
11276
+ return { type: "boolean" };
11277
+ }
11278
+ return void 0;
11279
+ }
11280
+ function unwrapOptionalType(type) {
11281
+ if (type.isUnion()) {
11282
+ const filtered = type.types.filter(
11283
+ (t) => !(t.flags & (import_typescript.default.TypeFlags.Undefined | import_typescript.default.TypeFlags.Null))
11284
+ );
11285
+ if (filtered.length === 1) return filtered[0];
11286
+ }
11287
+ return type;
11288
+ }
11289
+ function mapTypeToSchema(type, checker) {
11290
+ const resolved = unwrapOptionalType(type);
11291
+ if (checker.typeToString(resolved) === "Date") return { type: "string", format: "date-time" };
11292
+ const primitive = getPrimitiveSchemaType(resolved);
11293
+ if (primitive) return primitive;
11294
+ if (checker.isArrayType(resolved)) {
11295
+ const typeArgs = checker.getTypeArguments(resolved);
11296
+ if (typeArgs && typeArgs.length > 0) {
11297
+ return { type: "array", items: mapTypeToSchema(typeArgs[0], checker) };
11298
+ }
11299
+ return { type: "array" };
11300
+ }
11301
+ if (resolved.flags & import_typescript.default.TypeFlags.Object) return buildObjectSchema(resolved, checker);
11302
+ logger_default.warn(`Unsupported type "${checker.typeToString(resolved)}", defaulting to string`);
11243
11303
  return { type: "string" };
11244
11304
  }
11245
- function buildObjectSchema(type) {
11246
- const props = {};
11305
+ function extractObjectProperties(type, checker) {
11306
+ const properties = {};
11247
11307
  const required = [];
11248
11308
  for (const prop of type.getProperties()) {
11249
11309
  const name2 = uncapitalize(prop.getName());
11250
11310
  const declarations = prop.getDeclarations();
11251
- if (!declarations.length) continue;
11311
+ if (!declarations || !declarations.length) continue;
11252
11312
  const decl = declarations[0];
11253
11313
  const description = getJsDocDescription(decl);
11254
- const subType = decl.getType();
11255
- props[name2] = {
11256
- ...mapTypeToSchema(subType),
11314
+ const subType = checker.getTypeOfSymbolAtLocation(prop, decl);
11315
+ properties[name2] = {
11316
+ ...mapTypeToSchema(subType, checker),
11257
11317
  ...description ? { description } : {}
11258
11318
  };
11259
- if (!prop.isOptional()) required.push(name2);
11319
+ if (!(prop.flags & import_typescript.default.SymbolFlags.Optional)) required.push(name2);
11260
11320
  }
11321
+ return { properties, required };
11322
+ }
11323
+ function buildObjectSchema(type, checker) {
11324
+ const { properties, required } = extractObjectProperties(type, checker);
11261
11325
  return {
11262
11326
  type: "object",
11263
- properties: props,
11327
+ properties,
11264
11328
  ...required.length > 0 ? { required } : {}
11265
11329
  };
11266
11330
  }
@@ -78,7 +78,7 @@ var packageJSON = {
78
78
  "!src/fixtures/**",
79
79
  "!dist/**/*.test.d.ts*"
80
80
  ],
81
- version: "1.2.0",
81
+ version: "1.2.1",
82
82
  main: "dist/lib.js",
83
83
  types: "dist/lib.d.ts",
84
84
  scripts: {
@@ -112,8 +112,8 @@ var packageJSON = {
112
112
  },
113
113
  dependencies: {
114
114
  "@types/ramda": "0.31.1",
115
- "@typescript-eslint/eslint-plugin": "8.59.1",
116
- "@typescript-eslint/parser": "8.59.1",
115
+ "@typescript-eslint/eslint-plugin": "8.59.4",
116
+ "@typescript-eslint/parser": "8.59.4",
117
117
  commander: "14.0.3",
118
118
  eslint: "9.39.4",
119
119
  express: "5.2.1",
@@ -125,16 +125,11 @@ var packageJSON = {
125
125
  "pino-pretty": "13.1.3",
126
126
  "prom-client": "15.1.3",
127
127
  "quicktype-core": "^23.2.6",
128
- ramda: "0.32.0",
129
- "ts-morph": "^27.0.2"
128
+ ramda: "0.32.0"
130
129
  },
131
130
  devDependencies: {
132
- "@commitlint/cli": "20.5.0",
133
- "@commitlint/config-conventional": "20.5.0",
134
- "@semantic-release/commit-analyzer": "^13.0.1",
135
- "@semantic-release/git": "^10.0.1",
136
- "@semantic-release/npm": "^13.0.0",
137
- "@semantic-release/release-notes-generator": "^14.1.0",
131
+ "@commitlint/cli": "21.0.1",
132
+ "@commitlint/config-conventional": "21.0.1",
138
133
  "@types/command-line-args": "^5.2.3",
139
134
  "@types/express": "5.0.6",
140
135
  "@types/json-pointer": "^1.0.34",
@@ -160,13 +155,13 @@ var packageJSON = {
160
155
  rollup: "4.59.0"
161
156
  },
162
157
  peerDependencies: {
163
- "@types/prompts": "2.4.9",
164
- esbuild: "0.25.10",
165
- "node-forge": "1.4.0",
166
- prettier: "3.6.2",
167
- prompts: "2.4.2",
168
- typescript: "5.8.3",
169
- uuid: "13.0.0"
158
+ "@types/prompts": "^2.4.9",
159
+ esbuild: "^0.28.0",
160
+ "node-forge": "^1.4.0",
161
+ prettier: "^3.6.2",
162
+ prompts: "^2.4.2",
163
+ typescript: "^5.8.3",
164
+ uuid: "^13.0.0"
170
165
  }
171
166
  };
172
167
 
package/package.json CHANGED
@@ -16,7 +16,7 @@
16
16
  "!src/fixtures/**",
17
17
  "!dist/**/*.test.d.ts*"
18
18
  ],
19
- "version": "1.2.0",
19
+ "version": "1.2.1",
20
20
  "main": "dist/lib.js",
21
21
  "types": "dist/lib.d.ts",
22
22
  "scripts": {
@@ -50,8 +50,8 @@
50
50
  },
51
51
  "dependencies": {
52
52
  "@types/ramda": "0.31.1",
53
- "@typescript-eslint/eslint-plugin": "8.59.1",
54
- "@typescript-eslint/parser": "8.59.1",
53
+ "@typescript-eslint/eslint-plugin": "8.59.4",
54
+ "@typescript-eslint/parser": "8.59.4",
55
55
  "commander": "14.0.3",
56
56
  "eslint": "9.39.4",
57
57
  "express": "5.2.1",
@@ -63,16 +63,11 @@
63
63
  "pino-pretty": "13.1.3",
64
64
  "prom-client": "15.1.3",
65
65
  "quicktype-core": "^23.2.6",
66
- "ramda": "0.32.0",
67
- "ts-morph": "^27.0.2"
66
+ "ramda": "0.32.0"
68
67
  },
69
68
  "devDependencies": {
70
- "@commitlint/cli": "20.5.0",
71
- "@commitlint/config-conventional": "20.5.0",
72
- "@semantic-release/commit-analyzer": "^13.0.1",
73
- "@semantic-release/git": "^10.0.1",
74
- "@semantic-release/npm": "^13.0.0",
75
- "@semantic-release/release-notes-generator": "^14.1.0",
69
+ "@commitlint/cli": "21.0.1",
70
+ "@commitlint/config-conventional": "21.0.1",
76
71
  "@types/command-line-args": "^5.2.3",
77
72
  "@types/express": "5.0.6",
78
73
  "@types/json-pointer": "^1.0.34",
@@ -98,12 +93,12 @@
98
93
  "rollup": "4.59.0"
99
94
  },
100
95
  "peerDependencies": {
101
- "@types/prompts": "2.4.9",
102
- "esbuild": "0.25.10",
103
- "node-forge": "1.4.0",
104
- "prettier": "3.6.2",
105
- "prompts": "2.4.2",
106
- "typescript": "5.8.3",
107
- "uuid": "13.0.0"
96
+ "@types/prompts": "^2.4.9",
97
+ "esbuild": "^0.28.0",
98
+ "node-forge": "^1.4.0",
99
+ "prettier": "^3.6.2",
100
+ "prompts": "^2.4.2",
101
+ "typescript": "^5.8.3",
102
+ "uuid": "^13.0.0"
108
103
  }
109
104
  }
@@ -1,16 +1,8 @@
1
1
  import fs from "fs";
2
2
  import path from "path";
3
+ import ts from "typescript";
3
4
  import Log from "../../../lib/telemetry/logger";
4
5
  import { stringify } from "yaml";
5
- import {
6
- Project,
7
- InterfaceDeclaration,
8
- TypeAliasDeclaration,
9
- SyntaxKind,
10
- Node,
11
- SourceFile,
12
- Type,
13
- } from "ts-morph";
14
6
  import { createDirectoryIfNotExists } from "../../../lib/filesystemService";
15
7
  import { kind as k } from "kubernetes-fluent-client";
16
8
  import { V1JSONSchemaProps } from "@kubernetes/client-node";
@@ -18,7 +10,7 @@ import { WarningMessages, ErrorMessages } from "./messages";
18
10
 
19
11
  function extractCRDDetails(
20
12
  content: string,
21
- sourceFile: SourceFile,
13
+ sourceFile: ts.SourceFile,
22
14
  ): {
23
15
  kind: string | undefined;
24
16
  fqdn: string;
@@ -27,6 +19,10 @@ function extractCRDDetails(
27
19
  shortNames?: string[];
28
20
  } {
29
21
  const kind = extractSingleLineComment(content, "Kind");
22
+ if (!kind) {
23
+ return { kind: undefined, fqdn: "", scope: "Namespaced", plural: "", shortNames: undefined };
24
+ }
25
+
30
26
  const group = extractSingleLineComment(content, "Group") ?? "example";
31
27
  const domain = extractSingleLineComment(content, "Domain") ?? "pepr.dev";
32
28
  const details = extractDetails(sourceFile);
@@ -44,14 +40,20 @@ export async function generateCRDs(options: { output: string }): Promise<void> {
44
40
  const outputDir = path.resolve(options.output);
45
41
  await createDirectoryIfNotExists(outputDir);
46
42
 
47
- const project = new Project();
48
43
  const apiRoot = path.resolve("api");
49
44
  const versions = getAPIVersions(apiRoot);
50
45
 
51
46
  for (const version of versions) {
52
- const sourceFiles = loadVersionFiles(project, path.join(apiRoot, version));
53
- for (const sourceFile of sourceFiles) {
54
- processSourceFile(sourceFile, version, outputDir);
47
+ const versionDir = path.join(apiRoot, version);
48
+ const filePaths = loadVersionFilePaths(versionDir);
49
+ const program = createProgram(filePaths);
50
+ const checker = program.getTypeChecker();
51
+
52
+ for (const filePath of filePaths) {
53
+ const sourceFile = program.getSourceFile(filePath);
54
+ if (sourceFile) {
55
+ processSourceFile(sourceFile, checker, version, outputDir);
56
+ }
55
57
  }
56
58
  }
57
59
  }
@@ -60,14 +62,22 @@ export function getAPIVersions(apiRoot: string): string[] {
60
62
  return fs.readdirSync(apiRoot).filter(v => fs.statSync(path.join(apiRoot, v)).isDirectory());
61
63
  }
62
64
 
63
- export function loadVersionFiles(project: Project, versionDir: string): SourceFile[] {
65
+ export function loadVersionFilePaths(versionDir: string): string[] {
64
66
  const files = fs.readdirSync(versionDir).filter(f => f.endsWith(".ts"));
65
- const filePaths = files.map(f => path.join(versionDir, f));
66
- return project.addSourceFilesAtPaths(filePaths);
67
+ return files.map(f => path.join(versionDir, f));
68
+ }
69
+
70
+ export function createProgram(filePaths: string[]): ts.Program {
71
+ return ts.createProgram(filePaths, {
72
+ target: ts.ScriptTarget.ESNext,
73
+ module: ts.ModuleKind.ESNext,
74
+ strict: true,
75
+ });
67
76
  }
68
77
 
69
78
  export function processSourceFile(
70
- sourceFile: SourceFile,
79
+ sourceFile: ts.SourceFile,
80
+ checker: ts.TypeChecker,
71
81
  version: string,
72
82
  outputDir: string,
73
83
  ): void {
@@ -75,19 +85,19 @@ export function processSourceFile(
75
85
  const { kind, fqdn, scope, plural, shortNames } = extractCRDDetails(content, sourceFile);
76
86
 
77
87
  if (!kind) {
78
- Log.warn(WarningMessages.MISSING_KIND_COMMENT(sourceFile.getBaseName()));
88
+ Log.warn(WarningMessages.MISSING_KIND_COMMENT(path.basename(sourceFile.fileName)));
79
89
  return;
80
90
  }
81
91
 
82
- const spec = sourceFile.getInterface(`${kind}Spec`);
92
+ const spec = findInterface(sourceFile, `${kind}Spec`);
83
93
  if (!spec) {
84
- Log.warn(WarningMessages.MISSING_INTERFACE(sourceFile.getBaseName(), kind));
94
+ Log.warn(WarningMessages.MISSING_INTERFACE(path.basename(sourceFile.fileName), kind));
85
95
  return;
86
96
  }
87
97
 
88
- const condition = sourceFile.getTypeAlias(`${kind}StatusCondition`);
89
- const specSchema = getSchemaFromType(spec);
90
- const conditionSchema = condition ? getSchemaFromType(condition) : emptySchema();
98
+ const condition = findTypeAlias(sourceFile, `${kind}StatusCondition`);
99
+ const specSchema = getSchemaFromType(spec, checker);
100
+ const conditionSchema = condition ? getSchemaFromType(condition, checker) : emptySchema();
91
101
 
92
102
  const crd = buildCRD({
93
103
  kind,
@@ -112,25 +122,41 @@ export function extractSingleLineComment(content: string, label: string): string
112
122
  return match?.[1].trim();
113
123
  }
114
124
 
115
- export function extractDetails(sourceFile: SourceFile): {
125
+ export function extractDetails(sourceFile: ts.SourceFile): {
116
126
  plural: string;
117
127
  scope: "Cluster" | "Namespaced";
118
128
  shortName: string;
119
129
  } {
120
- const decl = sourceFile.getVariableDeclaration("details");
121
- if (!decl) {
130
+ let detailsDecl: ts.VariableDeclaration | undefined;
131
+ ts.forEachChild(sourceFile, node => {
132
+ if (ts.isVariableStatement(node)) {
133
+ for (const decl of node.declarationList.declarations) {
134
+ if (ts.isIdentifier(decl.name) && decl.name.text === "details") {
135
+ detailsDecl = decl;
136
+ }
137
+ }
138
+ }
139
+ });
140
+
141
+ if (!detailsDecl) {
122
142
  throw new Error(ErrorMessages.MISSING_DETAILS);
123
143
  }
124
144
 
125
- const init = decl.getInitializerIfKindOrThrow(SyntaxKind.ObjectLiteralExpression);
145
+ const init = detailsDecl.initializer;
146
+ if (!init || !ts.isObjectLiteralExpression(init)) {
147
+ throw new Error(ErrorMessages.MISSING_DETAILS);
148
+ }
126
149
 
127
150
  const getStr = (key: string): string => {
128
- const prop = init.getProperty(key);
129
- const value = prop?.getFirstChildByKind(SyntaxKind.StringLiteral)?.getLiteralText();
130
- if (!value) {
131
- throw new Error(ErrorMessages.MISSING_OR_INVALID_KEY(key));
151
+ const match = init.properties.find(
152
+ (prop): prop is ts.PropertyAssignment =>
153
+ ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name) && prop.name.text === key,
154
+ );
155
+
156
+ if (match && ts.isStringLiteral(match.initializer) && match.initializer.text) {
157
+ return match.initializer.text;
132
158
  }
133
- return value;
159
+ throw new Error(ErrorMessages.MISSING_OR_INVALID_KEY(key));
134
160
  };
135
161
 
136
162
  const scope = getStr("scope");
@@ -145,84 +171,140 @@ export function extractDetails(sourceFile: SourceFile): {
145
171
  throw new Error(ErrorMessages.INVALID_SCOPE(scope));
146
172
  }
147
173
 
148
- function getJsDocDescription(node: Node): string {
149
- if (!Node.isPropertySignature(node) && !Node.isPropertyDeclaration(node)) return "";
150
- return node
151
- .getJsDocs()
152
- .map(doc => doc.getComment())
153
- .filter(Boolean)
154
- .join(" ")
155
- .trim();
174
+ function findInterface(
175
+ sourceFile: ts.SourceFile,
176
+ name: string,
177
+ ): ts.InterfaceDeclaration | undefined {
178
+ let result: ts.InterfaceDeclaration | undefined;
179
+ ts.forEachChild(sourceFile, node => {
180
+ if (ts.isInterfaceDeclaration(node) && node.name.text === name) {
181
+ result = node;
182
+ }
183
+ });
184
+ return result;
185
+ }
186
+
187
+ function findTypeAlias(
188
+ sourceFile: ts.SourceFile,
189
+ name: string,
190
+ ): ts.TypeAliasDeclaration | undefined {
191
+ let result: ts.TypeAliasDeclaration | undefined;
192
+ ts.forEachChild(sourceFile, node => {
193
+ if (ts.isTypeAliasDeclaration(node) && node.name.text === name) {
194
+ result = node;
195
+ }
196
+ });
197
+ return result;
198
+ }
199
+
200
+ function getJsDocDescription(node: ts.Node): string {
201
+ const jsDocs = ts.getJSDocCommentsAndTags(node);
202
+ const comments: string[] = [];
203
+ for (const doc of jsDocs) {
204
+ if (ts.isJSDoc(doc) && doc.comment) {
205
+ if (typeof doc.comment === "string") {
206
+ comments.push(doc.comment);
207
+ } else {
208
+ comments.push(doc.comment.map(part => part.text).join(""));
209
+ }
210
+ }
211
+ }
212
+ return comments.join(" ").trim();
156
213
  }
157
214
 
158
- function getSchemaFromType(decl: InterfaceDeclaration | TypeAliasDeclaration): {
215
+ function getSchemaFromType(
216
+ decl: ts.InterfaceDeclaration | ts.TypeAliasDeclaration,
217
+ checker: ts.TypeChecker,
218
+ ): {
159
219
  properties: Record<string, V1JSONSchemaProps>;
160
220
  required: string[];
161
221
  } {
162
- const type = decl.getType();
163
- const properties: Record<string, V1JSONSchemaProps> = {};
164
- const required: string[] = [];
222
+ const type = checker.getTypeAtLocation(decl);
223
+ const { properties, required } = extractObjectProperties(type, checker);
224
+ return { properties, required };
225
+ }
165
226
 
166
- for (const prop of type.getProperties()) {
167
- const name = uncapitalize(prop.getName());
168
- const declarations = prop.getDeclarations();
169
- if (!declarations.length) continue;
227
+ function getPrimitiveSchemaType(type: ts.Type): V1JSONSchemaProps | undefined {
228
+ const { flags } = type;
229
+ if (flags & ts.TypeFlags.String || flags & ts.TypeFlags.StringLiteral) {
230
+ return { type: "string" };
231
+ }
232
+ if (flags & ts.TypeFlags.Number || flags & ts.TypeFlags.NumberLiteral) {
233
+ return { type: "number" };
234
+ }
235
+ if (
236
+ flags & ts.TypeFlags.Boolean ||
237
+ flags & ts.TypeFlags.BooleanLiteral ||
238
+ flags & ts.TypeFlags.BooleanLike
239
+ ) {
240
+ return { type: "boolean" };
241
+ }
242
+ return undefined;
243
+ }
170
244
 
171
- const declaration = declarations[0];
172
- const description = getJsDocDescription(declaration);
173
- const valueType = declaration.getType();
245
+ function unwrapOptionalType(type: ts.Type): ts.Type {
246
+ if (type.isUnion()) {
247
+ const filtered = type.types.filter(
248
+ t => !(t.flags & (ts.TypeFlags.Undefined | ts.TypeFlags.Null)),
249
+ );
250
+ if (filtered.length === 1) return filtered[0];
251
+ }
252
+ return type;
253
+ }
174
254
 
175
- properties[name] = {
176
- ...mapTypeToSchema(valueType),
177
- ...(description ? { description } : {}),
178
- };
255
+ function mapTypeToSchema(type: ts.Type, checker: ts.TypeChecker): V1JSONSchemaProps {
256
+ const resolved = unwrapOptionalType(type);
179
257
 
180
- if (!prop.isOptional()) required.push(name);
181
- }
258
+ if (checker.typeToString(resolved) === "Date") return { type: "string", format: "date-time" };
182
259
 
183
- return { properties, required };
184
- }
260
+ const primitive = getPrimitiveSchemaType(resolved);
261
+ if (primitive) return primitive;
185
262
 
186
- function mapTypeToSchema(type: Type): V1JSONSchemaProps {
187
- if (type.getText() === "Date") return { type: "string", format: "date-time" };
188
- if (type.isString()) return { type: "string" };
189
- if (type.isNumber()) return { type: "number" };
190
- if (type.isBoolean()) return { type: "boolean" };
191
- if (type.isArray()) {
192
- return {
193
- type: "array",
194
- items: mapTypeToSchema(type.getArrayElementTypeOrThrow()),
195
- };
263
+ if (checker.isArrayType(resolved)) {
264
+ const typeArgs = checker.getTypeArguments(resolved as ts.TypeReference);
265
+ if (typeArgs && typeArgs.length > 0) {
266
+ return { type: "array", items: mapTypeToSchema(typeArgs[0], checker) };
267
+ }
268
+ return { type: "array" };
196
269
  }
197
270
 
198
- if (type.isObject()) return buildObjectSchema(type);
271
+ if (resolved.flags & ts.TypeFlags.Object) return buildObjectSchema(resolved, checker);
272
+ Log.warn(`Unsupported type "${checker.typeToString(resolved)}", defaulting to string`);
199
273
  return { type: "string" };
200
274
  }
201
275
 
202
- function buildObjectSchema(type: Type): V1JSONSchemaProps {
203
- const props: Record<string, V1JSONSchemaProps> = {};
276
+ function extractObjectProperties(
277
+ type: ts.Type,
278
+ checker: ts.TypeChecker,
279
+ ): { properties: Record<string, V1JSONSchemaProps>; required: string[] } {
280
+ const properties: Record<string, V1JSONSchemaProps> = {};
204
281
  const required: string[] = [];
205
282
 
206
283
  for (const prop of type.getProperties()) {
207
284
  const name = uncapitalize(prop.getName());
208
285
  const declarations = prop.getDeclarations();
209
- if (!declarations.length) continue;
286
+ if (!declarations || !declarations.length) continue;
210
287
 
211
288
  const decl = declarations[0];
212
289
  const description = getJsDocDescription(decl);
213
- const subType = decl.getType();
290
+ const subType = checker.getTypeOfSymbolAtLocation(prop, decl);
214
291
 
215
- props[name] = {
216
- ...mapTypeToSchema(subType),
292
+ properties[name] = {
293
+ ...mapTypeToSchema(subType, checker),
217
294
  ...(description ? { description } : {}),
218
295
  };
219
296
 
220
- if (!prop.isOptional()) required.push(name);
297
+ if (!(prop.flags & ts.SymbolFlags.Optional)) required.push(name);
221
298
  }
222
299
 
300
+ return { properties, required };
301
+ }
302
+
303
+ function buildObjectSchema(type: ts.Type, checker: ts.TypeChecker): V1JSONSchemaProps {
304
+ const { properties, required } = extractObjectProperties(type, checker);
223
305
  return {
224
306
  type: "object",
225
- properties: props,
307
+ properties,
226
308
  ...(required.length > 0 ? { required } : {}),
227
309
  };
228
310
  }