@shepherdjerred/helm-types 1.7.0 → 2.0.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.
Files changed (96) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/LICENSE +674 -0
  3. package/README.md +82 -63
  4. package/demos/argo-cd-cli.cast +50 -0
  5. package/demos/record-cli-demo.sh +132 -0
  6. package/dist/chart-fetcher.d.ts +14 -0
  7. package/dist/chart-fetcher.d.ts.map +1 -0
  8. package/dist/chart-fetcher.js +105 -0
  9. package/dist/chart-fetcher.js.map +1 -0
  10. package/dist/chart-info-parser.d.ts +6 -0
  11. package/dist/chart-info-parser.d.ts.map +1 -0
  12. package/dist/chart-info-parser.js +50 -0
  13. package/dist/chart-info-parser.js.map +1 -0
  14. package/dist/cli.d.ts +7 -0
  15. package/dist/cli.d.ts.map +1 -0
  16. package/dist/cli.js +140 -22841
  17. package/dist/cli.js.map +1 -0
  18. package/dist/comment-parser.d.ts +10 -0
  19. package/dist/comment-parser.d.ts.map +1 -0
  20. package/dist/comment-parser.js +150 -0
  21. package/dist/comment-parser.js.map +1 -0
  22. package/dist/config.d.ts +24 -0
  23. package/dist/config.d.ts.map +1 -0
  24. package/dist/config.js +169 -0
  25. package/dist/config.js.map +1 -0
  26. package/dist/helm-types.d.ts +16 -0
  27. package/dist/helm-types.d.ts.map +1 -0
  28. package/{src/helm-types.ts → dist/helm-types.js} +1 -1
  29. package/dist/helm-types.js.map +1 -0
  30. package/dist/index.d.ts +25 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +22 -23
  33. package/dist/index.js.map +1 -0
  34. package/dist/interface-generator.d.ts +6 -0
  35. package/dist/interface-generator.d.ts.map +1 -0
  36. package/dist/interface-generator.js +181 -0
  37. package/dist/interface-generator.js.map +1 -0
  38. package/dist/schemas.d.ts +13 -0
  39. package/dist/schemas.d.ts.map +1 -0
  40. package/{src/schemas.ts → dist/schemas.js} +12 -23
  41. package/dist/schemas.js.map +1 -0
  42. package/dist/type-converter-helpers.d.ts +20 -0
  43. package/dist/type-converter-helpers.d.ts.map +1 -0
  44. package/dist/type-converter-helpers.js +75 -0
  45. package/dist/type-converter-helpers.js.map +1 -0
  46. package/dist/type-converter.d.ts +26 -0
  47. package/dist/type-converter.d.ts.map +1 -0
  48. package/dist/type-converter.js +378 -0
  49. package/dist/type-converter.js.map +1 -0
  50. package/dist/types.d.ts +35 -0
  51. package/dist/types.d.ts.map +1 -0
  52. package/dist/types.js +3 -0
  53. package/dist/types.js.map +1 -0
  54. package/dist/utils.d.ts +17 -0
  55. package/dist/utils.d.ts.map +1 -0
  56. package/dist/utils.js +69 -0
  57. package/dist/utils.js.map +1 -0
  58. package/dist/yaml-comment-filters.d.ts +7 -0
  59. package/dist/yaml-comment-filters.d.ts.map +1 -0
  60. package/dist/yaml-comment-filters.js +91 -0
  61. package/dist/yaml-comment-filters.js.map +1 -0
  62. package/dist/yaml-comment-regex-parser.d.ts +8 -0
  63. package/dist/yaml-comment-regex-parser.d.ts.map +1 -0
  64. package/dist/yaml-comment-regex-parser.js +120 -0
  65. package/dist/yaml-comment-regex-parser.js.map +1 -0
  66. package/dist/yaml-comments.d.ts +74 -0
  67. package/dist/yaml-comments.d.ts.map +1 -0
  68. package/dist/yaml-comments.js +406 -0
  69. package/dist/yaml-comments.js.map +1 -0
  70. package/dist/yaml-preprocess.d.ts +15 -0
  71. package/dist/yaml-preprocess.d.ts.map +1 -0
  72. package/dist/yaml-preprocess.js +170 -0
  73. package/dist/yaml-preprocess.js.map +1 -0
  74. package/examples/argo-cd/generate.mjs +23 -0
  75. package/package.json +17 -12
  76. package/src/__fixtures__/sample-chart/Chart.yaml +0 -6
  77. package/src/__fixtures__/sample-chart/values.schema.json +0 -32
  78. package/src/__fixtures__/sample-chart/values.yaml +0 -22
  79. package/src/chart-fetcher.ts +0 -221
  80. package/src/chart-info-parser.ts +0 -64
  81. package/src/cli.ts +0 -217
  82. package/src/code-generator.ts +0 -226
  83. package/src/comment-parser.ts +0 -180
  84. package/src/config.ts +0 -195
  85. package/src/index.ts +0 -28
  86. package/src/interface-generator.ts +0 -238
  87. package/src/reset.d.ts +0 -1
  88. package/src/type-converter-helpers.ts +0 -108
  89. package/src/type-converter.ts +0 -520
  90. package/src/type-inference.ts +0 -548
  91. package/src/types.ts +0 -41
  92. package/src/utils.ts +0 -76
  93. package/src/yaml-comment-filters.ts +0 -103
  94. package/src/yaml-comment-regex-parser.ts +0 -150
  95. package/src/yaml-comments.ts +0 -507
  96. package/src/yaml-preprocess.ts +0 -235
package/src/config.ts DELETED
@@ -1,195 +0,0 @@
1
- /**
2
- * Well-known Kubernetes fields whose shape is defined by the Kubernetes API,
3
- * not by whatever subset a chart's values.yaml happens to set as defaults.
4
- *
5
- * Inferring these from defaults produces types that are too narrow — e.g. a
6
- * chart defaulting `resources: {requests: {cpu: 0.2}}` would otherwise forbid
7
- * setting a memory request at all. When a property matches one of these names
8
- * AND its default value has a compatible shape, the canonical permissive type
9
- * is emitted instead of a defaults-derived interface.
10
- */
11
- const K8S_WELL_KNOWN_FIELDS: Record<
12
- string,
13
- { type: string; allowedShapes: ("object" | "array")[]; description: string }
14
- > = {
15
- resources: {
16
- type: "{ requests?: Record<string, string | number>; limits?: Record<string, string | number> }",
17
- // RBAC rules also use a key named `resources`, but as an array of strings —
18
- // the object guard keeps those out.
19
- allowedShapes: ["object"],
20
- description:
21
- "Kubernetes container resources (standard ResourceRequirements: arbitrary resource names, string or numeric quantities)",
22
- },
23
- nodeselector: {
24
- type: "Record<string, string>",
25
- allowedShapes: ["object"],
26
- description: "Kubernetes nodeSelector (arbitrary label key/value pairs)",
27
- },
28
- tolerations: {
29
- type: "unknown[]",
30
- allowedShapes: ["array"],
31
- description: "Kubernetes tolerations (standard Toleration objects)",
32
- },
33
- affinity: {
34
- type: "Record<string, unknown>",
35
- allowedShapes: ["object"],
36
- description: "Kubernetes affinity (standard Affinity object)",
37
- },
38
- };
39
-
40
- /**
41
- * Return the canonical type for a well-known Kubernetes field, or undefined if
42
- * the property name doesn't match or the default value's shape is incompatible
43
- * (e.g. an RBAC `resources: ["secrets"]` array, which must NOT become
44
- * ResourceRequirements).
45
- */
46
- export function getWellKnownK8sFieldType(
47
- propertyName: string,
48
- value: unknown,
49
- ): { type: string; description: string } | undefined {
50
- const field = K8S_WELL_KNOWN_FIELDS[propertyName.toLowerCase()];
51
- if (!field) {
52
- return undefined;
53
- }
54
- // A null/undefined default carries no shape signal — trust the name.
55
- if (value != null) {
56
- const shape: "object" | "array" | "primitive" = Array.isArray(value)
57
- ? "array"
58
- : typeof value === "object"
59
- ? "object"
60
- : "primitive";
61
- if (shape === "primitive" || !field.allowedShapes.includes(shape)) {
62
- return undefined;
63
- }
64
- }
65
- return { type: field.type, description: field.description };
66
- }
67
-
68
- /**
69
- * Configuration for types that should allow arbitrary additional properties.
70
- * Maps chart names to array of key paths that should be extensible.
71
- *
72
- * These are typically config maps, RBAC policies, or other key-value stores
73
- * where the schema doesn't enumerate all possible keys.
74
- */
75
- export const EXTENSIBLE_TYPE_PATTERNS: Record<string, string[]> = {
76
- "argo-cd": [
77
- "configs.cm", // Allows accounts.*, and other custom config
78
- "configs.rbac", // Allows policy.*, custom RBAC rules
79
- ],
80
- "kube-prometheus-stack": [
81
- "grafana", // Allows "grafana.ini" and other quoted config keys
82
- "grafana.deploymentStrategy", // Allows Kubernetes Deployment strategy objects with flexible fields
83
- "alertmanager.config.receivers", // Allows receiver-specific config blocks on array elements
84
- "prometheus-node-exporter", // Allows extraHostVolumeMounts and other node exporter specific configs
85
- "prometheusNodeExporter", // Also support camelCase variant
86
- ],
87
- loki: [
88
- "loki.limits_config", // Allows retention_period and other limit configs (note: underscore, not camelCase)
89
- "loki.limitsConfig", // Also support camelCase variant
90
- "compactor", // Allows various compactor settings
91
- "minio.persistence", // Storage configs
92
- ],
93
- minecraft: [
94
- "persistence", // Storage class and other persistence options
95
- ],
96
- openebs: [
97
- "zfs-localpv", // ZFS-specific configs
98
- ],
99
- "postgres-operator": [
100
- "configGeneral", // General config allows various settings
101
- ],
102
- chartmuseum: [
103
- "persistence", // Storage options
104
- ],
105
- "intel-device-plugins-operator": [
106
- // Root level for device-specific settings
107
- "",
108
- ],
109
- "prometheus-adapter": [
110
- "rules", // Allows resource, custom, external and other rule configurations
111
- ],
112
- velero: [
113
- "kubectl.image", // Allows image configuration
114
- ],
115
- seaweedfs: [
116
- "volume.dataDirs", // dataDirs elements support size, storageClass when type is persistentVolumeClaim
117
- ],
118
- // OCI charts that document config keys only as commented-out examples in
119
- // values.yaml, so inference from active defaults misses valid keys.
120
- "agent-stack-k8s": [
121
- "config", // config.queue / max-in-flight / empty-job-grace-period / default-checkout-params are valid but not defaulted
122
- ],
123
- };
124
-
125
- /**
126
- * Pattern-based detection for extensible types.
127
- * Returns true if the property should allow arbitrary keys.
128
- */
129
- export function shouldAllowArbitraryProps(
130
- keyPath: string,
131
- chartName: string,
132
- propertyName: string,
133
- yamlComment?: string,
134
- ): boolean {
135
- // Check configured patterns for this chart
136
- const patterns = EXTENSIBLE_TYPE_PATTERNS[chartName];
137
- if (patterns) {
138
- for (const pattern of patterns) {
139
- if (
140
- pattern === keyPath ||
141
- (pattern === "" && keyPath.split(".").length === 1)
142
- ) {
143
- return true;
144
- }
145
- // Also match if keyPath starts with pattern
146
- if (pattern && keyPath.startsWith(`${pattern}.`)) {
147
- return true;
148
- }
149
- }
150
- }
151
-
152
- // Pattern-based detection from property names
153
- const lowerProp = propertyName.toLowerCase();
154
- const lowerPath = keyPath.toLowerCase();
155
-
156
- // Common names that suggest extensibility
157
- const extensibleNames = [
158
- "cm", // ConfigMap data
159
- "data",
160
- "config",
161
- "configs",
162
- "settings",
163
- "parameters",
164
- "options",
165
- "extraenv",
166
- "annotations",
167
- "labels",
168
- "nodeaffinity",
169
- "toleration",
170
- ];
171
-
172
- if (extensibleNames.includes(lowerProp)) {
173
- return true;
174
- }
175
-
176
- // Check for persistence/storage which often has provider-specific fields
177
- if (lowerPath.includes("persistence") || lowerPath.includes("storage")) {
178
- return true;
179
- }
180
-
181
- // Check YAML comments for hints
182
- if (yamlComment !== "" && yamlComment != null) {
183
- const commentLower = yamlComment.toLowerCase();
184
- if (
185
- /\b(?:arbitrary|custom|additional|extra|any)\s+(?:keys?|properties?|fields?|values?)\b/i.test(
186
- commentLower,
187
- ) ||
188
- /\bkey[\s-]?value\s+pairs?\b/i.test(commentLower)
189
- ) {
190
- return true;
191
- }
192
- }
193
-
194
- return false;
195
- }
package/src/index.ts DELETED
@@ -1,28 +0,0 @@
1
- /**
2
- * @homelab/helm-types
3
- *
4
- * A library for generating TypeScript types from Helm chart values.
5
- *
6
- * Core functionality:
7
- * - Fetch Helm charts from repositories
8
- * - Parse values.yaml and values.schema.json
9
- * - Generate TypeScript interfaces with JSDoc comments
10
- * - Support for nested objects, arrays, and unions
11
- *
12
- * This is a general-purpose library that can be used with any Helm chart.
13
- * Application-specific logic should be kept in your application code.
14
- *
15
- * Import directly from submodules:
16
- * - ./types.ts - Core types (ChartInfo, JSONSchemaProperty, TypeScriptInterface, TypeProperty)
17
- * - ./schemas.ts - Zod schemas (HelmValueSchema, StringSchema, etc.)
18
- * - ./config.ts - Configuration (EXTENSIBLE_TYPE_PATTERNS, shouldAllowArbitraryProps)
19
- * - ./chart-info-parser.ts - Chart info parsing (parseChartInfoFromVersions)
20
- * - ./yaml-comments.ts - YAML comments (cleanYAMLComment, parseYAMLComments)
21
- * - ./chart-fetcher.ts - Chart fetching (fetchHelmChart)
22
- * - ./type-converter.ts - Type conversion (jsonSchemaToTypeScript, inferTypeFromValue, etc.)
23
- * - ./interface-generator.ts - Code generation (generateTypeScriptCode)
24
- * - ./utils.ts - Utilities (sanitizePropertyName, sanitizeTypeName, capitalizeFirst)
25
- */
26
-
27
- /** Version marker for the helm-types package. */
28
- export const HELM_TYPES_PACKAGE_VERSION = "1.1.0";
@@ -1,238 +0,0 @@
1
- import type { TypeScriptInterface } from "./types.ts";
2
- import {
3
- ArraySchema,
4
- RecordSchema,
5
- StringSchema,
6
- ActualNumberSchema,
7
- ActualBooleanSchema,
8
- } from "./schemas.ts";
9
-
10
- /**
11
- * Generate TypeScript code from interface definition
12
- */
13
- export function generateTypeScriptCode(
14
- mainInterface: TypeScriptInterface,
15
- chartName: string,
16
- ): string {
17
- const interfaces: TypeScriptInterface[] = [];
18
-
19
- // Collect all nested interfaces
20
- collectNestedInterfaces(mainInterface, interfaces);
21
-
22
- let code = `// Generated TypeScript types for ${chartName} Helm chart\n\n`;
23
-
24
- // Generate all interfaces
25
- for (const iface of interfaces) {
26
- code += generateInterfaceCode(iface);
27
- code += "\n";
28
- }
29
-
30
- // Generate parameter type (flattened dot notation)
31
- code += generateParameterType(mainInterface, chartName);
32
-
33
- // Add header comment for generated files
34
- if (code.includes(": any")) {
35
- code = `// Generated TypeScript types for ${chartName} Helm chart
36
-
37
- ${code.slice(Math.max(0, code.indexOf("\n\n") + 2))}`;
38
- }
39
-
40
- return code;
41
- }
42
-
43
- function collectNestedInterfaces(
44
- iface: TypeScriptInterface,
45
- collected: TypeScriptInterface[],
46
- ): void {
47
- for (const prop of Object.values(iface.properties)) {
48
- if (prop.nested) {
49
- collected.push(prop.nested);
50
- collectNestedInterfaces(prop.nested, collected);
51
- }
52
- }
53
-
54
- // Add main interface last so dependencies come first
55
- if (!collected.some((i) => i.name === iface.name)) {
56
- collected.push(iface);
57
- }
58
- }
59
-
60
- function generateInterfaceCode(iface: TypeScriptInterface): string {
61
- const hasProperties = Object.keys(iface.properties).length > 0;
62
-
63
- if (!hasProperties && iface.allowArbitraryProps !== true) {
64
- // Use 'object' for empty interfaces instead of '{}'
65
- return `export type ${iface.name} = object;\n`;
66
- }
67
-
68
- let code = `export type ${iface.name} = {\n`;
69
-
70
- // Add index signature if this type allows arbitrary properties
71
- if (iface.allowArbitraryProps === true) {
72
- code += ` /**\n`;
73
- code += ` * This type allows arbitrary additional properties beyond those defined below.\n`;
74
- code += ` * This is common for config maps, custom settings, and extensible configurations.\n`;
75
- code += ` */\n`;
76
- code += ` [key: string]: unknown;\n`;
77
- }
78
-
79
- for (const [key, prop] of Object.entries(iface.properties)) {
80
- const optional = prop.optional ? "?" : "";
81
-
82
- // Generate JSDoc comment if we have description or default
83
- if (
84
- (prop.description != null && prop.description !== "") ||
85
- prop.default !== undefined
86
- ) {
87
- code += ` /**\n`;
88
-
89
- if (prop.description != null && prop.description !== "") {
90
- // Format multi-line descriptions properly with " * " prefix
91
- // Escape */ sequences to prevent premature comment closure
92
- const escapedDescription = prop.description.replaceAll(
93
- "*/",
94
- String.raw`*\/`,
95
- );
96
- const descLines = escapedDescription.split("\n");
97
- for (const line of descLines) {
98
- code += ` * ${line}\n`;
99
- }
100
- }
101
-
102
- if (prop.default !== undefined) {
103
- const defaultStr = formatDefaultValue(prop.default);
104
- const hasDescription =
105
- prop.description != null && prop.description !== "";
106
- if (defaultStr !== "" && hasDescription && defaultStr != null) {
107
- code += ` *\n`;
108
- }
109
- if (defaultStr !== "" && defaultStr != null) {
110
- code += ` * @default ${defaultStr}\n`;
111
- }
112
- }
113
-
114
- code += ` */\n`;
115
- }
116
-
117
- code += ` ${key}${optional}: ${prop.type};\n`;
118
- }
119
-
120
- code += "};\n";
121
- return code;
122
- }
123
-
124
- /**
125
- * Format a default value for display in JSDoc
126
- */
127
- function formatDefaultValue(value: unknown): string | null {
128
- if (value === null) {
129
- return "null";
130
- }
131
- if (value === undefined) {
132
- return null;
133
- }
134
-
135
- // Handle arrays
136
- const arrayCheck = ArraySchema.safeParse(value);
137
- if (arrayCheck.success) {
138
- if (arrayCheck.data.length === 0) {
139
- return "[]";
140
- }
141
- if (arrayCheck.data.length <= 3) {
142
- try {
143
- return JSON.stringify(arrayCheck.data);
144
- } catch {
145
- return "[...]";
146
- }
147
- }
148
- return `[...] (${String(arrayCheck.data.length)} items)`;
149
- }
150
-
151
- // Handle objects
152
- const recordCheck = RecordSchema.safeParse(value);
153
- if (recordCheck.success) {
154
- const keys = Object.keys(recordCheck.data);
155
- if (keys.length === 0) {
156
- return "{}";
157
- }
158
- if (keys.length <= 3) {
159
- try {
160
- return JSON.stringify(recordCheck.data);
161
- } catch {
162
- return "{...}";
163
- }
164
- }
165
- return `{...} (${String(keys.length)} keys)`;
166
- }
167
-
168
- // Primitives
169
- const stringCheck = StringSchema.safeParse(value);
170
- if (stringCheck.success) {
171
- // Truncate long strings
172
- if (stringCheck.data.length > 50) {
173
- return `"${stringCheck.data.slice(0, 47)}..."`;
174
- }
175
- return `"${stringCheck.data}"`;
176
- }
177
-
178
- // Handle other primitives (numbers, booleans, etc.)
179
- const numberCheck = ActualNumberSchema.safeParse(value);
180
- if (numberCheck.success) {
181
- return String(numberCheck.data);
182
- }
183
-
184
- const booleanCheck = ActualBooleanSchema.safeParse(value);
185
- if (booleanCheck.success) {
186
- return String(booleanCheck.data);
187
- }
188
-
189
- // Fallback for unknown types - try JSON.stringify
190
- try {
191
- return JSON.stringify(value);
192
- } catch {
193
- return "unknown";
194
- }
195
- }
196
-
197
- function generateParameterType(
198
- iface: TypeScriptInterface,
199
- chartName: string,
200
- ): string {
201
- const parameterKeys = flattenInterfaceKeys(iface);
202
-
203
- const normalizedChartName = capitalizeFirst(chartName).replaceAll("-", "");
204
- let code = `export type ${normalizedChartName}HelmParameters = {\n`;
205
-
206
- for (const key of parameterKeys) {
207
- code += ` "${key}"?: string;\n`;
208
- }
209
-
210
- code += "};\n";
211
-
212
- return code;
213
- }
214
-
215
- function flattenInterfaceKeys(
216
- iface: TypeScriptInterface,
217
- prefix = "",
218
- ): string[] {
219
- const keys: string[] = [];
220
-
221
- for (const [key, prop] of Object.entries(iface.properties)) {
222
- // Remove quotes from key for parameter names
223
- const cleanKey = key.replaceAll('"', "");
224
- const fullKey = prefix ? `${prefix}.${cleanKey}` : cleanKey;
225
-
226
- if (prop.nested) {
227
- keys.push(...flattenInterfaceKeys(prop.nested, fullKey));
228
- } else {
229
- keys.push(fullKey);
230
- }
231
- }
232
-
233
- return keys;
234
- }
235
-
236
- function capitalizeFirst(str: string): string {
237
- return str.charAt(0).toUpperCase() + str.slice(1);
238
- }
package/src/reset.d.ts DELETED
@@ -1 +0,0 @@
1
- import "@total-typescript/ts-reset";
@@ -1,108 +0,0 @@
1
- import type { JSONSchemaProperty, TypeProperty } from "./types.ts";
2
- import {
3
- StringSchema,
4
- ActualNumberSchema,
5
- ActualBooleanSchema,
6
- StringBooleanSchema,
7
- } from "./schemas.ts";
8
-
9
- export type PropertyConversionContext = {
10
- value: unknown;
11
- nestedTypeName: string;
12
- schema?: JSONSchemaProperty;
13
- propertyName?: string;
14
- yamlComment?: string;
15
- yamlComments?: Map<string, string>;
16
- fullKey?: string;
17
- chartName?: string;
18
- };
19
-
20
- /**
21
- * Merge description from schema and YAML comments
22
- */
23
- export function mergeDescriptions(
24
- schemaDescription: string | undefined,
25
- yamlComment: string | undefined,
26
- ): string | undefined {
27
- if (yamlComment === "" || yamlComment == null) {
28
- return schemaDescription;
29
- }
30
- return schemaDescription !== "" && schemaDescription != null
31
- ? `${yamlComment}\n\n${schemaDescription}`
32
- : yamlComment;
33
- }
34
-
35
- /**
36
- * Infer a primitive TypeProperty from a runtime value (no schema)
37
- */
38
- export function inferPrimitiveType(
39
- value: unknown,
40
- yamlComment?: string,
41
- ): TypeProperty {
42
- if (ActualBooleanSchema.safeParse(value).success) {
43
- return {
44
- type: "boolean",
45
- optional: true,
46
- description: yamlComment,
47
- default: value,
48
- };
49
- }
50
-
51
- if (ActualNumberSchema.safeParse(value).success) {
52
- return {
53
- type: "number",
54
- optional: true,
55
- description: yamlComment,
56
- default: value,
57
- };
58
- }
59
-
60
- if (StringBooleanSchema.safeParse(value).success) {
61
- return {
62
- type: "boolean",
63
- optional: true,
64
- description: yamlComment,
65
- default: value,
66
- };
67
- }
68
-
69
- const stringCheckForNumber = StringSchema.safeParse(value);
70
- if (stringCheckForNumber.success) {
71
- const trimmed = stringCheckForNumber.data.trim();
72
- if (
73
- trimmed !== "" &&
74
- !Number.isNaN(Number(trimmed)) &&
75
- Number.isFinite(Number(trimmed))
76
- ) {
77
- return {
78
- type: "number",
79
- optional: true,
80
- description: yamlComment,
81
- default: value,
82
- };
83
- }
84
- }
85
-
86
- const stringCheckForPlain = StringSchema.safeParse(value);
87
- if (stringCheckForPlain.success) {
88
- if (stringCheckForPlain.data === "default") {
89
- return {
90
- type: "string | number | boolean",
91
- optional: true,
92
- description: yamlComment,
93
- default: value,
94
- };
95
- }
96
- return {
97
- type: "string",
98
- optional: true,
99
- description: yamlComment,
100
- default: value,
101
- };
102
- }
103
-
104
- console.warn(
105
- `Unrecognized value type for: ${String(value)}, using 'unknown'`,
106
- );
107
- return { type: "unknown", optional: true, description: yamlComment };
108
- }