@stripe/extensibility-sdk 0.22.4

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 (113) hide show
  1. package/LICENSE.md +19 -0
  2. package/dist/config-values/generate.cjs +262 -0
  3. package/dist/config-values/generate.d.ts +38 -0
  4. package/dist/config-values/generate.d.ts.map +1 -0
  5. package/dist/config-values/generate.js +232 -0
  6. package/dist/config-values/parse.d.ts +87 -0
  7. package/dist/config-values/parse.d.ts.map +1 -0
  8. package/dist/extensibility-sdk-alpha.d.ts +542 -0
  9. package/dist/extensibility-sdk-beta.d.ts +542 -0
  10. package/dist/extensibility-sdk-config-values-alpha.d.ts +27 -0
  11. package/dist/extensibility-sdk-config-values-beta.d.ts +27 -0
  12. package/dist/extensibility-sdk-config-values-internal.d.ts +118 -0
  13. package/dist/extensibility-sdk-config-values-public.d.ts +27 -0
  14. package/dist/extensibility-sdk-extensions-alpha.d.ts +1592 -0
  15. package/dist/extensibility-sdk-extensions-beta.d.ts +1592 -0
  16. package/dist/extensibility-sdk-extensions-internal.d.ts +1655 -0
  17. package/dist/extensibility-sdk-extensions-public.d.ts +1592 -0
  18. package/dist/extensibility-sdk-internal-alpha.d.ts +9 -0
  19. package/dist/extensibility-sdk-internal-beta.d.ts +9 -0
  20. package/dist/extensibility-sdk-internal-internal.d.ts +23 -0
  21. package/dist/extensibility-sdk-internal-public.d.ts +9 -0
  22. package/dist/extensibility-sdk-internal.d.ts +915 -0
  23. package/dist/extensibility-sdk-jsonschema-alpha.d.ts +3 -0
  24. package/dist/extensibility-sdk-jsonschema-beta.d.ts +3 -0
  25. package/dist/extensibility-sdk-jsonschema-internal.d.ts +15 -0
  26. package/dist/extensibility-sdk-jsonschema-public.d.ts +3 -0
  27. package/dist/extensibility-sdk-public.d.ts +542 -0
  28. package/dist/extensibility-sdk-stdlib-alpha.d.ts +531 -0
  29. package/dist/extensibility-sdk-stdlib-beta.d.ts +531 -0
  30. package/dist/extensibility-sdk-stdlib-internal.d.ts +904 -0
  31. package/dist/extensibility-sdk-stdlib-public.d.ts +531 -0
  32. package/dist/extensions/billing/bill/discount_calculation.d.ts +226 -0
  33. package/dist/extensions/billing/bill/discount_calculation.d.ts.map +1 -0
  34. package/dist/extensions/billing/bill/index.d.ts +2 -0
  35. package/dist/extensions/billing/bill/index.d.ts.map +1 -0
  36. package/dist/extensions/billing/customer_balance_application.d.ts +82 -0
  37. package/dist/extensions/billing/customer_balance_application.d.ts.map +1 -0
  38. package/dist/extensions/billing/index.d.ts +8 -0
  39. package/dist/extensions/billing/index.d.ts.map +1 -0
  40. package/dist/extensions/billing/invoice_collection_setting.d.ts +117 -0
  41. package/dist/extensions/billing/invoice_collection_setting.d.ts.map +1 -0
  42. package/dist/extensions/billing/prorations.d.ts +222 -0
  43. package/dist/extensions/billing/prorations.d.ts.map +1 -0
  44. package/dist/extensions/billing/recurring_billing_item_handling.d.ts +326 -0
  45. package/dist/extensions/billing/recurring_billing_item_handling.d.ts.map +1 -0
  46. package/dist/extensions/billing/types.d.ts +33 -0
  47. package/dist/extensions/billing/types.d.ts.map +1 -0
  48. package/dist/extensions/context.d.ts +9 -0
  49. package/dist/extensions/context.d.ts.map +1 -0
  50. package/dist/extensions/core/index.d.ts +3 -0
  51. package/dist/extensions/core/index.d.ts.map +1 -0
  52. package/dist/extensions/core/workflows/custom_action.d.ts +142 -0
  53. package/dist/extensions/core/workflows/custom_action.d.ts.map +1 -0
  54. package/dist/extensions/core/workflows/index.d.ts +2 -0
  55. package/dist/extensions/core/workflows/index.d.ts.map +1 -0
  56. package/dist/extensions/extend/index.d.ts +3 -0
  57. package/dist/extensions/extend/index.d.ts.map +1 -0
  58. package/dist/extensions/extend/workflows/custom_action.d.ts +142 -0
  59. package/dist/extensions/extend/workflows/custom_action.d.ts.map +1 -0
  60. package/dist/extensions/extend/workflows/index.d.ts +2 -0
  61. package/dist/extensions/extend/workflows/index.d.ts.map +1 -0
  62. package/dist/extensions/index.cjs +2356 -0
  63. package/dist/extensions/index.d.ts +9 -0
  64. package/dist/extensions/index.d.ts.map +1 -0
  65. package/dist/extensions/index.js +2435 -0
  66. package/dist/extensions/registry.d.ts +19 -0
  67. package/dist/extensions/registry.d.ts.map +1 -0
  68. package/dist/extensions/types.d.ts +10 -0
  69. package/dist/extensions/types.d.ts.map +1 -0
  70. package/dist/index.cjs +1519 -0
  71. package/dist/index.d.ts +12 -0
  72. package/dist/index.d.ts.map +1 -0
  73. package/dist/index.js +1460 -0
  74. package/dist/internal.cjs +156 -0
  75. package/dist/internal.d.ts +3 -0
  76. package/dist/internal.d.ts.map +1 -0
  77. package/dist/internal.js +128 -0
  78. package/dist/jsonschema.cjs +18 -0
  79. package/dist/jsonschema.d.ts +2 -0
  80. package/dist/jsonschema.d.ts.map +1 -0
  81. package/dist/jsonschema.js +0 -0
  82. package/dist/stdlib/brand.d.ts +27 -0
  83. package/dist/stdlib/brand.d.ts.map +1 -0
  84. package/dist/stdlib/decimal.d.ts +324 -0
  85. package/dist/stdlib/decimal.d.ts.map +1 -0
  86. package/dist/stdlib/extension-method.d.ts +27 -0
  87. package/dist/stdlib/extension-method.d.ts.map +1 -0
  88. package/dist/stdlib/generated.d.ts +15 -0
  89. package/dist/stdlib/generated.d.ts.map +1 -0
  90. package/dist/stdlib/index.cjs +1519 -0
  91. package/dist/stdlib/index.d.ts +18 -0
  92. package/dist/stdlib/index.d.ts.map +1 -0
  93. package/dist/stdlib/index.js +1460 -0
  94. package/dist/stdlib/refs.d.ts +62 -0
  95. package/dist/stdlib/refs.d.ts.map +1 -0
  96. package/dist/stdlib/scalars.d.ts +141 -0
  97. package/dist/stdlib/scalars.d.ts.map +1 -0
  98. package/dist/stdlib/transform-strategies.d.ts +74 -0
  99. package/dist/stdlib/transform-strategies.d.ts.map +1 -0
  100. package/dist/stdlib/transforms.d.ts +97 -0
  101. package/dist/stdlib/transforms.d.ts.map +1 -0
  102. package/dist/stdlib/type-utils.d.ts +9 -0
  103. package/dist/stdlib/type-utils.d.ts.map +1 -0
  104. package/dist/stdlib/types.d.ts +281 -0
  105. package/dist/stdlib/types.d.ts.map +1 -0
  106. package/dist/stdlib/utils.d.ts +7 -0
  107. package/dist/stdlib/utils.d.ts.map +1 -0
  108. package/dist/tsconfig.build.tsbuildinfo +1 -0
  109. package/package.json +111 -0
  110. package/tslibs/5.9.3/lib.es2022.egress.d.ts +4328 -0
  111. package/tslibs/5.9.3/lib.es2022.restricted.d.ts +4067 -0
  112. package/tslibs/lib.egress.globals.d.ts +112 -0
  113. package/tslibs/lib.restricted.globals.d.ts +1 -0
package/LICENSE.md ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (C) 2026 Stripe, Inc. (https://stripe.com)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
@@ -0,0 +1,262 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/config-values/generate.ts
21
+ var generate_exports = {};
22
+ __export(generate_exports, {
23
+ STDLIB_IMPORT_PATH: () => STDLIB_IMPORT_PATH,
24
+ analyzeConfigType: () => analyzeConfigType,
25
+ analyzeConfigTypeInProject: () => analyzeConfigTypeInProject,
26
+ generateConfigDescriptor: () => generateConfigDescriptor
27
+ });
28
+ module.exports = __toCommonJS(generate_exports);
29
+
30
+ // src/config-values/parse.ts
31
+ var import_ts_morph = require("ts-morph");
32
+ function analyzeConfigType(options) {
33
+ const project = new import_ts_morph.Project({
34
+ compilerOptions: { strict: true, skipLibCheck: true },
35
+ skipAddingFilesFromTsConfig: true
36
+ });
37
+ project.addSourceFileAtPath(options.filePath);
38
+ project.resolveSourceFileDependencies();
39
+ return analyzeConfigTypeInProject(project, options.filePath, options.typeName);
40
+ }
41
+ function analyzeConfigTypeInProject(project, filePath, typeName) {
42
+ const sourceFile = project.getSourceFileOrThrow(filePath);
43
+ const target = sourceFile.getInterface(typeName) ?? sourceFile.getTypeAlias(typeName) ?? sourceFile.getClass(typeName);
44
+ if (!target) {
45
+ throw new Error(`Type "${typeName}" not found in "${filePath}"`);
46
+ }
47
+ const state = { interfaces: [], enums: [] };
48
+ const type = target.getType();
49
+ const fields = walkObjectType(type, typeName, state);
50
+ state.interfaces.push({ name: typeName, fields });
51
+ return { rootTypeName: typeName, interfaces: state.interfaces, enums: state.enums };
52
+ }
53
+ function walkObjectType(type, context, state) {
54
+ const fields = [];
55
+ for (const sym of type.getProperties()) {
56
+ const decl = sym.getValueDeclaration();
57
+ if (!decl || !import_ts_morph.Node.isPropertySignature(decl) && !import_ts_morph.Node.isPropertyDeclaration(decl))
58
+ continue;
59
+ const hasQuestionMark = decl.hasQuestionToken();
60
+ const rawType = decl.getType();
61
+ const { classification, optional } = classifyType(
62
+ rawType,
63
+ `${context}.${sym.getName()}`,
64
+ state
65
+ );
66
+ fields.push({
67
+ name: sym.getName(),
68
+ classification,
69
+ optional: optional || hasQuestionMark
70
+ });
71
+ }
72
+ return fields;
73
+ }
74
+ function classifyType(type, context, state) {
75
+ if (type.isUnion()) {
76
+ const members = type.getUnionTypes();
77
+ const hasNullable = members.some((m) => m.isUndefined() || m.isNull());
78
+ const nonNullable = members.filter((m) => !m.isUndefined() && !m.isNull());
79
+ if (nonNullable.length === 0) {
80
+ throw new Error(
81
+ `${context}: Type is only null/undefined, which is not a valid config type`
82
+ );
83
+ }
84
+ if (nonNullable.every((m) => m.isBooleanLiteral())) {
85
+ return { classification: { kind: "primitive" }, optional: hasNullable };
86
+ }
87
+ if (nonNullable.every((m) => m.isStringLiteral())) {
88
+ const aliasSymbol = type.getAliasSymbol();
89
+ const typeName = aliasSymbol ? aliasSymbol.getName() : context.replace(/\./g, "_");
90
+ if (!state.enums.some((e) => e.name === typeName)) {
91
+ const values = nonNullable.map((m) => m.getLiteralValue());
92
+ state.enums.push({ name: typeName, values });
93
+ }
94
+ return { classification: { kind: "enum", typeName }, optional: hasNullable };
95
+ }
96
+ if (nonNullable.length === 1) {
97
+ const [sole] = nonNullable;
98
+ if (sole) {
99
+ const { classification } = classifyType(sole, context, state);
100
+ return { classification, optional: hasNullable };
101
+ }
102
+ }
103
+ throw new Error(
104
+ `${context}: Union types are not supported in config types (only T | undefined or T | null is allowed)`
105
+ );
106
+ }
107
+ if (type.isStringLiteral()) {
108
+ const value = type.getLiteralValue();
109
+ const typeName = context.replace(/\./g, "_");
110
+ if (!state.enums.some((e) => e.name === typeName)) {
111
+ state.enums.push({ name: typeName, values: [value] });
112
+ }
113
+ return { classification: { kind: "enum", typeName }, optional: false };
114
+ }
115
+ if (isStdlibDecimalType(type)) {
116
+ return { classification: { kind: "decimal" }, optional: false };
117
+ }
118
+ const dateSym = type.getSymbol();
119
+ if (dateSym?.getName() === "Date") {
120
+ const srcPath = dateSym.getDeclarations()[0]?.getSourceFile().getFilePath() ?? "";
121
+ const basename = srcPath.slice(srcPath.lastIndexOf("/") + 1);
122
+ if (basename.startsWith("lib.") && basename.endsWith(".d.ts")) {
123
+ return { classification: { kind: "datetime" }, optional: false };
124
+ }
125
+ }
126
+ if (type.isString()) return { classification: { kind: "primitive" }, optional: false };
127
+ if (type.isNumber()) return { classification: { kind: "primitive" }, optional: false };
128
+ if (type.isBoolean()) return { classification: { kind: "primitive" }, optional: false };
129
+ if (type.isArray()) {
130
+ const elementType = type.getArrayElementTypeOrThrow();
131
+ const { classification: element } = classifyType(elementType, `${context}[]`, state);
132
+ return { classification: { kind: "array", element }, optional: false };
133
+ }
134
+ const stringIndexType = type.getStringIndexType();
135
+ if (stringIndexType) {
136
+ const { classification: value } = classifyType(
137
+ stringIndexType,
138
+ `${context}[string]`,
139
+ state
140
+ );
141
+ return { classification: { kind: "map", value }, optional: false };
142
+ }
143
+ if (type.isObject()) {
144
+ const typeSym = type.getSymbol();
145
+ const symName = typeSym?.getName();
146
+ const typeName = symName && !symName.startsWith("__") ? symName : context.replace(/\./g, "_");
147
+ if (!state.interfaces.some((i) => i.name === typeName)) {
148
+ const shapeFields = walkObjectType(type, typeName, state);
149
+ state.interfaces.push({ name: typeName, fields: shapeFields });
150
+ }
151
+ return { classification: { kind: "interface", typeName }, optional: false };
152
+ }
153
+ throw new Error(`${context}: Unsupported config field type: ${type.getText()}`);
154
+ }
155
+ function isStdlibDecimalType(type) {
156
+ return [type.getAliasSymbol(), type.getSymbol()].some((symbol) => {
157
+ if (symbol?.getName() !== "Decimal") return false;
158
+ return symbol.getDeclarations().some((declaration) => {
159
+ const srcPath = declaration.getSourceFile().getFilePath();
160
+ return srcPath.includes("stdlib/decimal") || srcPath.includes("stdlib/index");
161
+ });
162
+ });
163
+ }
164
+
165
+ // src/config-values/generate.ts
166
+ var STDLIB_IMPORT_PATH = "@stripe/extensibility-sdk/stdlib";
167
+ function generateConfigDescriptor(result) {
168
+ const usedImports = /* @__PURE__ */ new Set();
169
+ const usedTypeImports = /* @__PURE__ */ new Set();
170
+ const lines = [];
171
+ if (result.enums.length > 0) usedImports.add("_ConfigEnum");
172
+ for (const enumDesc of result.enums) {
173
+ const values = enumDesc.values.map((v) => JSON.stringify(v)).join(", ");
174
+ lines.push(`const ${enumDesc.name}_ConfigValues = new _ConfigEnum([${values}]);`);
175
+ lines.push("");
176
+ }
177
+ usedImports.add("_ShapeDescriptor");
178
+ usedImports.add("_JsonWireToType");
179
+ for (const iface of result.interfaces) {
180
+ const constVarName = `${iface.name}_FromConfig`;
181
+ const entries = [];
182
+ for (const field of iface.fields) {
183
+ const inner = fieldTransformExpr(field.classification, usedImports);
184
+ const transform = wrapConfigTransform(inner, field.optional, usedImports);
185
+ entries.push(` { type: ${JSON.stringify(field.name)}, transform: ${transform} },`);
186
+ }
187
+ lines.push(
188
+ `const ${constVarName} = new _ShapeDescriptor<typeof _JsonWireToType, ${iface.name}>(${JSON.stringify(iface.name)}, [`
189
+ );
190
+ lines.push(...entries);
191
+ lines.push(`]);`);
192
+ lines.push("");
193
+ }
194
+ const rootTypeName = result.rootTypeName;
195
+ const rootConstVarName = `${rootTypeName}_FromConfig`;
196
+ usedImports.add("_applyConfig");
197
+ usedTypeImports.add("_ConfigApplicationContext");
198
+ lines.push(
199
+ `export function transform${rootTypeName}(raw: unknown, appCtx?: _ConfigApplicationContext): ${rootTypeName} {`
200
+ );
201
+ lines.push(` return _applyConfig(${rootConstVarName}, raw, appCtx);`);
202
+ lines.push(`}`);
203
+ return { lines, requiredImports: usedImports, requiredTypeImports: usedTypeImports };
204
+ }
205
+ function wrapConfigTransform(expr, isOptional, usedImports) {
206
+ if (isOptional) return expr;
207
+ if (expr === "_identity") {
208
+ usedImports.add("_required");
209
+ return "_required()";
210
+ }
211
+ usedImports.add("_required");
212
+ return `_required(${expr})`;
213
+ }
214
+ function fieldTransformExpr(classification, usedImports) {
215
+ switch (classification.kind) {
216
+ case "primitive": {
217
+ usedImports.add("_identity");
218
+ return "_identity";
219
+ }
220
+ case "decimal": {
221
+ usedImports.add("_translateDecimal");
222
+ return "_translateDecimal";
223
+ }
224
+ case "datetime": {
225
+ usedImports.add("_translateDateTime");
226
+ return "_translateDateTime";
227
+ }
228
+ case "enum": {
229
+ usedImports.add("_translateEnum");
230
+ return `_translateEnum(${classification.typeName}_ConfigValues)`;
231
+ }
232
+ case "array": {
233
+ usedImports.add("_translateArray");
234
+ const elemExpr = fieldTransformExpr(classification.element, usedImports);
235
+ return `_translateArray(${elemExpr})`;
236
+ }
237
+ case "map": {
238
+ usedImports.add("_translateMap");
239
+ usedImports.add("_identity");
240
+ const valueExpr = fieldTransformExpr(classification.value, usedImports);
241
+ return `_translateMap(_identity, ${valueExpr})`;
242
+ }
243
+ case "interface": {
244
+ usedImports.add("_translateShape");
245
+ const { typeName } = classification;
246
+ return `_translateShape(() => ${typeName}_FromConfig)`;
247
+ }
248
+ case "union":
249
+ throw new Error(`union types are not supported in config field descriptors`);
250
+ default: {
251
+ const _exhaustive = classification;
252
+ return _exhaustive;
253
+ }
254
+ }
255
+ }
256
+ // Annotate the CommonJS export names for ESM import in node:
257
+ 0 && (module.exports = {
258
+ STDLIB_IMPORT_PATH,
259
+ analyzeConfigType,
260
+ analyzeConfigTypeInProject,
261
+ generateConfigDescriptor
262
+ });
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Emits TypeScript code for a config field descriptor constant and its
3
+ * corresponding `transformX` function.
4
+ *
5
+ * @see ./parse.ts — produces the ConfigAnalysisResult input
6
+ */
7
+ import type { ConfigAnalysisResult } from './parse.js';
8
+ export { analyzeConfigType, analyzeConfigTypeInProject, type ConfigAnalysisResult, type ConfigField, type ConfigInterfaceDescriptor, type ConfigEnumDescriptor, type FieldClassification, type ScalarFieldClassification, type StructuralFieldClassification, } from './parse.js';
9
+ /**
10
+ * The package specifier for the stdlib module used in generated import lines.
11
+ *
12
+ * @internal
13
+ */
14
+ export declare const STDLIB_IMPORT_PATH = "@stripe/extensibility-sdk/stdlib";
15
+ /**
16
+ * Generated TypeScript source and imports for a config descriptor.
17
+ *
18
+ * @internal
19
+ */
20
+ export interface GeneratedConfigDescriptor {
21
+ /** TypeScript code lines for the descriptor constant(s) and transform function */
22
+ lines: string[];
23
+ /** Value symbol names required from the stdlib module */
24
+ requiredImports: ReadonlySet<string>;
25
+ /** Type-only symbol names required from the stdlib module */
26
+ requiredTypeImports: ReadonlySet<string>;
27
+ }
28
+ /**
29
+ * Generates TypeScript code for a config descriptor.
30
+ *
31
+ * Emits enum value constants first, then one `_ShapeDescriptor` constant per
32
+ * interface (in DFS post-order, so inner types appear before their references),
33
+ * followed by an exported `transformX(raw: unknown): X` function.
34
+ *
35
+ * @internal
36
+ */
37
+ export declare function generateConfigDescriptor(result: ConfigAnalysisResult): GeneratedConfigDescriptor;
38
+ //# sourceMappingURL=generate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/config-values/generate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAuB,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAG5E,OAAO,EACL,iBAAiB,EACjB,0BAA0B,EAC1B,KAAK,oBAAoB,EACzB,KAAK,WAAW,EAChB,KAAK,yBAAyB,EAC9B,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,EAC9B,KAAK,6BAA6B,GACnC,MAAM,YAAY,CAAC;AAMpB;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,qCAAqC,CAAC;AAErE;;;;GAIG;AACH,MAAM,WAAW,yBAAyB;IACxC,kFAAkF;IAClF,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,yDAAyD;IACzD,eAAe,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACrC,6DAA6D;IAC7D,mBAAmB,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CAC1C;AAED;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,oBAAoB,GAC3B,yBAAyB,CA8C3B"}
@@ -0,0 +1,232 @@
1
+ // src/config-values/parse.ts
2
+ import { Node, Project } from "ts-morph";
3
+ function analyzeConfigType(options) {
4
+ const project = new Project({
5
+ compilerOptions: { strict: true, skipLibCheck: true },
6
+ skipAddingFilesFromTsConfig: true
7
+ });
8
+ project.addSourceFileAtPath(options.filePath);
9
+ project.resolveSourceFileDependencies();
10
+ return analyzeConfigTypeInProject(project, options.filePath, options.typeName);
11
+ }
12
+ function analyzeConfigTypeInProject(project, filePath, typeName) {
13
+ const sourceFile = project.getSourceFileOrThrow(filePath);
14
+ const target = sourceFile.getInterface(typeName) ?? sourceFile.getTypeAlias(typeName) ?? sourceFile.getClass(typeName);
15
+ if (!target) {
16
+ throw new Error(`Type "${typeName}" not found in "${filePath}"`);
17
+ }
18
+ const state = { interfaces: [], enums: [] };
19
+ const type = target.getType();
20
+ const fields = walkObjectType(type, typeName, state);
21
+ state.interfaces.push({ name: typeName, fields });
22
+ return { rootTypeName: typeName, interfaces: state.interfaces, enums: state.enums };
23
+ }
24
+ function walkObjectType(type, context, state) {
25
+ const fields = [];
26
+ for (const sym of type.getProperties()) {
27
+ const decl = sym.getValueDeclaration();
28
+ if (!decl || !Node.isPropertySignature(decl) && !Node.isPropertyDeclaration(decl))
29
+ continue;
30
+ const hasQuestionMark = decl.hasQuestionToken();
31
+ const rawType = decl.getType();
32
+ const { classification, optional } = classifyType(
33
+ rawType,
34
+ `${context}.${sym.getName()}`,
35
+ state
36
+ );
37
+ fields.push({
38
+ name: sym.getName(),
39
+ classification,
40
+ optional: optional || hasQuestionMark
41
+ });
42
+ }
43
+ return fields;
44
+ }
45
+ function classifyType(type, context, state) {
46
+ if (type.isUnion()) {
47
+ const members = type.getUnionTypes();
48
+ const hasNullable = members.some((m) => m.isUndefined() || m.isNull());
49
+ const nonNullable = members.filter((m) => !m.isUndefined() && !m.isNull());
50
+ if (nonNullable.length === 0) {
51
+ throw new Error(
52
+ `${context}: Type is only null/undefined, which is not a valid config type`
53
+ );
54
+ }
55
+ if (nonNullable.every((m) => m.isBooleanLiteral())) {
56
+ return { classification: { kind: "primitive" }, optional: hasNullable };
57
+ }
58
+ if (nonNullable.every((m) => m.isStringLiteral())) {
59
+ const aliasSymbol = type.getAliasSymbol();
60
+ const typeName = aliasSymbol ? aliasSymbol.getName() : context.replace(/\./g, "_");
61
+ if (!state.enums.some((e) => e.name === typeName)) {
62
+ const values = nonNullable.map((m) => m.getLiteralValue());
63
+ state.enums.push({ name: typeName, values });
64
+ }
65
+ return { classification: { kind: "enum", typeName }, optional: hasNullable };
66
+ }
67
+ if (nonNullable.length === 1) {
68
+ const [sole] = nonNullable;
69
+ if (sole) {
70
+ const { classification } = classifyType(sole, context, state);
71
+ return { classification, optional: hasNullable };
72
+ }
73
+ }
74
+ throw new Error(
75
+ `${context}: Union types are not supported in config types (only T | undefined or T | null is allowed)`
76
+ );
77
+ }
78
+ if (type.isStringLiteral()) {
79
+ const value = type.getLiteralValue();
80
+ const typeName = context.replace(/\./g, "_");
81
+ if (!state.enums.some((e) => e.name === typeName)) {
82
+ state.enums.push({ name: typeName, values: [value] });
83
+ }
84
+ return { classification: { kind: "enum", typeName }, optional: false };
85
+ }
86
+ if (isStdlibDecimalType(type)) {
87
+ return { classification: { kind: "decimal" }, optional: false };
88
+ }
89
+ const dateSym = type.getSymbol();
90
+ if (dateSym?.getName() === "Date") {
91
+ const srcPath = dateSym.getDeclarations()[0]?.getSourceFile().getFilePath() ?? "";
92
+ const basename = srcPath.slice(srcPath.lastIndexOf("/") + 1);
93
+ if (basename.startsWith("lib.") && basename.endsWith(".d.ts")) {
94
+ return { classification: { kind: "datetime" }, optional: false };
95
+ }
96
+ }
97
+ if (type.isString()) return { classification: { kind: "primitive" }, optional: false };
98
+ if (type.isNumber()) return { classification: { kind: "primitive" }, optional: false };
99
+ if (type.isBoolean()) return { classification: { kind: "primitive" }, optional: false };
100
+ if (type.isArray()) {
101
+ const elementType = type.getArrayElementTypeOrThrow();
102
+ const { classification: element } = classifyType(elementType, `${context}[]`, state);
103
+ return { classification: { kind: "array", element }, optional: false };
104
+ }
105
+ const stringIndexType = type.getStringIndexType();
106
+ if (stringIndexType) {
107
+ const { classification: value } = classifyType(
108
+ stringIndexType,
109
+ `${context}[string]`,
110
+ state
111
+ );
112
+ return { classification: { kind: "map", value }, optional: false };
113
+ }
114
+ if (type.isObject()) {
115
+ const typeSym = type.getSymbol();
116
+ const symName = typeSym?.getName();
117
+ const typeName = symName && !symName.startsWith("__") ? symName : context.replace(/\./g, "_");
118
+ if (!state.interfaces.some((i) => i.name === typeName)) {
119
+ const shapeFields = walkObjectType(type, typeName, state);
120
+ state.interfaces.push({ name: typeName, fields: shapeFields });
121
+ }
122
+ return { classification: { kind: "interface", typeName }, optional: false };
123
+ }
124
+ throw new Error(`${context}: Unsupported config field type: ${type.getText()}`);
125
+ }
126
+ function isStdlibDecimalType(type) {
127
+ return [type.getAliasSymbol(), type.getSymbol()].some((symbol) => {
128
+ if (symbol?.getName() !== "Decimal") return false;
129
+ return symbol.getDeclarations().some((declaration) => {
130
+ const srcPath = declaration.getSourceFile().getFilePath();
131
+ return srcPath.includes("stdlib/decimal") || srcPath.includes("stdlib/index");
132
+ });
133
+ });
134
+ }
135
+
136
+ // src/config-values/generate.ts
137
+ var STDLIB_IMPORT_PATH = "@stripe/extensibility-sdk/stdlib";
138
+ function generateConfigDescriptor(result) {
139
+ const usedImports = /* @__PURE__ */ new Set();
140
+ const usedTypeImports = /* @__PURE__ */ new Set();
141
+ const lines = [];
142
+ if (result.enums.length > 0) usedImports.add("_ConfigEnum");
143
+ for (const enumDesc of result.enums) {
144
+ const values = enumDesc.values.map((v) => JSON.stringify(v)).join(", ");
145
+ lines.push(`const ${enumDesc.name}_ConfigValues = new _ConfigEnum([${values}]);`);
146
+ lines.push("");
147
+ }
148
+ usedImports.add("_ShapeDescriptor");
149
+ usedImports.add("_JsonWireToType");
150
+ for (const iface of result.interfaces) {
151
+ const constVarName = `${iface.name}_FromConfig`;
152
+ const entries = [];
153
+ for (const field of iface.fields) {
154
+ const inner = fieldTransformExpr(field.classification, usedImports);
155
+ const transform = wrapConfigTransform(inner, field.optional, usedImports);
156
+ entries.push(` { type: ${JSON.stringify(field.name)}, transform: ${transform} },`);
157
+ }
158
+ lines.push(
159
+ `const ${constVarName} = new _ShapeDescriptor<typeof _JsonWireToType, ${iface.name}>(${JSON.stringify(iface.name)}, [`
160
+ );
161
+ lines.push(...entries);
162
+ lines.push(`]);`);
163
+ lines.push("");
164
+ }
165
+ const rootTypeName = result.rootTypeName;
166
+ const rootConstVarName = `${rootTypeName}_FromConfig`;
167
+ usedImports.add("_applyConfig");
168
+ usedTypeImports.add("_ConfigApplicationContext");
169
+ lines.push(
170
+ `export function transform${rootTypeName}(raw: unknown, appCtx?: _ConfigApplicationContext): ${rootTypeName} {`
171
+ );
172
+ lines.push(` return _applyConfig(${rootConstVarName}, raw, appCtx);`);
173
+ lines.push(`}`);
174
+ return { lines, requiredImports: usedImports, requiredTypeImports: usedTypeImports };
175
+ }
176
+ function wrapConfigTransform(expr, isOptional, usedImports) {
177
+ if (isOptional) return expr;
178
+ if (expr === "_identity") {
179
+ usedImports.add("_required");
180
+ return "_required()";
181
+ }
182
+ usedImports.add("_required");
183
+ return `_required(${expr})`;
184
+ }
185
+ function fieldTransformExpr(classification, usedImports) {
186
+ switch (classification.kind) {
187
+ case "primitive": {
188
+ usedImports.add("_identity");
189
+ return "_identity";
190
+ }
191
+ case "decimal": {
192
+ usedImports.add("_translateDecimal");
193
+ return "_translateDecimal";
194
+ }
195
+ case "datetime": {
196
+ usedImports.add("_translateDateTime");
197
+ return "_translateDateTime";
198
+ }
199
+ case "enum": {
200
+ usedImports.add("_translateEnum");
201
+ return `_translateEnum(${classification.typeName}_ConfigValues)`;
202
+ }
203
+ case "array": {
204
+ usedImports.add("_translateArray");
205
+ const elemExpr = fieldTransformExpr(classification.element, usedImports);
206
+ return `_translateArray(${elemExpr})`;
207
+ }
208
+ case "map": {
209
+ usedImports.add("_translateMap");
210
+ usedImports.add("_identity");
211
+ const valueExpr = fieldTransformExpr(classification.value, usedImports);
212
+ return `_translateMap(_identity, ${valueExpr})`;
213
+ }
214
+ case "interface": {
215
+ usedImports.add("_translateShape");
216
+ const { typeName } = classification;
217
+ return `_translateShape(() => ${typeName}_FromConfig)`;
218
+ }
219
+ case "union":
220
+ throw new Error(`union types are not supported in config field descriptors`);
221
+ default: {
222
+ const _exhaustive = classification;
223
+ return _exhaustive;
224
+ }
225
+ }
226
+ }
227
+ export {
228
+ STDLIB_IMPORT_PATH,
229
+ analyzeConfigType,
230
+ analyzeConfigTypeInProject,
231
+ generateConfigDescriptor
232
+ };
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Analyzes a config type using ts-morph and produces a field classification
3
+ * descriptor for runtime transformer generation.
4
+ *
5
+ * @see ./generate.ts — converts the descriptor to TypeScript code
6
+ */
7
+ import type { Project as MorphProject } from 'ts-morph';
8
+ /** @internal */
9
+ export type ScalarFieldClassification = {
10
+ kind: 'primitive';
11
+ } | {
12
+ kind: 'decimal';
13
+ } | {
14
+ kind: 'datetime';
15
+ } | {
16
+ kind: 'enum';
17
+ typeName: string;
18
+ };
19
+ /** @internal */
20
+ export type StructuralFieldClassification = {
21
+ kind: 'interface';
22
+ typeName: string;
23
+ } | {
24
+ kind: 'union';
25
+ typeName: string;
26
+ } | {
27
+ kind: 'array';
28
+ element: FieldClassification;
29
+ } | {
30
+ kind: 'map';
31
+ value: FieldClassification;
32
+ };
33
+ /** @internal */
34
+ export type FieldClassification = ScalarFieldClassification | StructuralFieldClassification;
35
+ /** @internal */
36
+ export interface ConfigField {
37
+ name: string;
38
+ classification: FieldClassification;
39
+ optional: boolean;
40
+ }
41
+ /** @internal */
42
+ export interface ConfigInterfaceDescriptor {
43
+ name: string;
44
+ fields: ConfigField[];
45
+ }
46
+ /** @internal */
47
+ export interface ConfigEnumDescriptor {
48
+ name: string;
49
+ values: readonly string[];
50
+ }
51
+ /**
52
+ * The result of analyzing a config type.
53
+ *
54
+ * `interfaces` is in DFS post-order: inner types appear before the types that
55
+ * reference them, so the root type is always last.
56
+ * `enums` is in discovery order, deduplicated by name.
57
+ * @internal
58
+ */
59
+ export interface ConfigAnalysisResult {
60
+ rootTypeName: string;
61
+ interfaces: ConfigInterfaceDescriptor[];
62
+ enums: ConfigEnumDescriptor[];
63
+ }
64
+ /**
65
+ * Analyzes a named config type in a source file, producing a descriptor
66
+ * for runtime transformation.
67
+ *
68
+ * Creates a ts-morph Project from the file system. For testing with
69
+ * in-memory files, use `analyzeConfigTypeInProject` directly.
70
+ * @internal
71
+ */
72
+ export declare function analyzeConfigType(options: {
73
+ filePath: string;
74
+ typeName: string;
75
+ }): ConfigAnalysisResult;
76
+ /**
77
+ * Analyzes a named config type using a caller-supplied ts-morph Project.
78
+ * Use this in tests to pass an in-memory project.
79
+ * @internal
80
+ */
81
+ export declare function analyzeConfigTypeInProject(project: MorphProject, filePath: string, typeName: string): ConfigAnalysisResult;
82
+ /** @internal */
83
+ export interface AccumulatorState {
84
+ interfaces: ConfigInterfaceDescriptor[];
85
+ enums: ConfigEnumDescriptor[];
86
+ }
87
+ //# sourceMappingURL=parse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../src/config-values/parse.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAQ,OAAO,IAAI,YAAY,EAAE,MAAM,UAAU,CAAC;AAM9D,gBAAgB;AAChB,MAAM,MAAM,yBAAyB,GACjC;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,GACpB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvC,gBAAgB;AAChB,MAAM,MAAM,6BAA6B,GACrC;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACvC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,mBAAmB,CAAA;CAAE,GAC/C;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,mBAAmB,CAAA;CAAE,CAAC;AAEhD,gBAAgB;AAChB,MAAM,MAAM,mBAAmB,GAC3B,yBAAyB,GACzB,6BAA6B,CAAC;AAMlC,gBAAgB;AAChB,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,mBAAmB,CAAC;IACpC,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,gBAAgB;AAChB,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,WAAW,EAAE,CAAC;CACvB;AAED,gBAAgB;AAChB,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3B;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,oBAAoB;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,yBAAyB,EAAE,CAAC;IACxC,KAAK,EAAE,oBAAoB,EAAE,CAAC;CAC/B;AAMD;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,oBAAoB,CAQvB;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,YAAY,EACrB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,oBAAoB,CAiBtB;AAMD,gBAAgB;AAChB,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,yBAAyB,EAAE,CAAC;IACxC,KAAK,EAAE,oBAAoB,EAAE,CAAC;CAC/B"}