svelte-reflector 1.3.3 → 1.3.5

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 (93) hide show
  1. package/dist/core/CodegenContext.d.ts +15 -0
  2. package/dist/core/CodegenContext.js +15 -0
  3. package/dist/core/Reflector.d.ts +25 -0
  4. package/dist/core/Reflector.js +66 -0
  5. package/dist/core/api/ApiClassBuilder.d.ts +23 -0
  6. package/dist/core/api/ApiClassBuilder.js +106 -0
  7. package/dist/core/api/ApiFileBuilder.d.ts +12 -0
  8. package/dist/core/api/ApiFileBuilder.js +24 -0
  9. package/dist/core/api/ApiMethodGenerator.d.ts +17 -0
  10. package/dist/core/api/ApiMethodGenerator.js +176 -0
  11. package/dist/core/api/ApiParamProcessor.d.ts +24 -0
  12. package/dist/core/api/ApiParamProcessor.js +36 -0
  13. package/dist/core/config/ReflectorConfig.d.ts +17 -0
  14. package/dist/core/config/ReflectorConfig.js +9 -0
  15. package/dist/core/emit/RuntimeFilesEmitter.d.ts +13 -0
  16. package/dist/core/emit/RuntimeFilesEmitter.js +55 -0
  17. package/dist/core/generators/ApiCallStrategy.d.ts +9 -0
  18. package/dist/core/generators/ApiCallStrategy.js +32 -0
  19. package/dist/core/generators/CallMethodGenerator.d.ts +14 -0
  20. package/dist/core/generators/CallMethodGenerator.js +154 -0
  21. package/dist/core/generators/CallStrategy.d.ts +23 -0
  22. package/dist/core/generators/CallStrategy.js +1 -0
  23. package/dist/core/generators/ModuleCallStrategy.d.ts +9 -0
  24. package/dist/core/generators/ModuleCallStrategy.js +41 -0
  25. package/dist/core/index.d.ts +7 -0
  26. package/dist/core/index.js +8 -0
  27. package/dist/core/method/Method.d.ts +25 -9
  28. package/dist/core/method/Method.js +24 -1
  29. package/dist/core/method/MethodApiTypeAnalyzer.js +3 -0
  30. package/dist/core/method/MethodBuilder.d.ts +2 -1
  31. package/dist/core/method/MethodBuilder.js +2 -2
  32. package/dist/core/method/MethodRequestAnalyzer.d.ts +2 -1
  33. package/dist/core/method/MethodRequestAnalyzer.js +5 -4
  34. package/dist/core/method/MethodValidator.d.ts +5 -0
  35. package/dist/core/method/MethodValidator.js +26 -0
  36. package/dist/core/method/generators/MethodGenerator.d.ts +2 -6
  37. package/dist/core/method/generators/MethodGenerator.js +5 -76
  38. package/dist/core/module/Module.d.ts +36 -0
  39. package/dist/core/module/Module.js +140 -0
  40. package/dist/core/module/ModuleClassBuilder.d.ts +4 -0
  41. package/dist/core/module/ModuleClassBuilder.js +8 -6
  42. package/dist/core/module/ModuleConstructorBuilder.d.ts +3 -0
  43. package/dist/core/module/ModuleConstructorBuilder.js +17 -13
  44. package/dist/core/module/ModuleFactory.d.ts +13 -0
  45. package/dist/core/module/ModuleFactory.js +44 -0
  46. package/dist/core/module/ModuleImports.d.ts +4 -1
  47. package/dist/core/module/ModuleImports.js +13 -6
  48. package/dist/core/module/ModuleMethodProcessor.d.ts +1 -2
  49. package/dist/core/module/ModuleMethodProcessor.js +3 -25
  50. package/dist/core/module/ModuleSchemaFileBuilder.d.ts +15 -0
  51. package/dist/core/module/ModuleSchemaFileBuilder.js +37 -0
  52. package/dist/core/openapi/InlineSchemaPromoter.d.ts +33 -0
  53. package/dist/core/openapi/InlineSchemaPromoter.js +140 -0
  54. package/dist/core/schema/ReflectorInterface.d.ts +14 -0
  55. package/dist/core/schema/ReflectorInterface.js +24 -0
  56. package/dist/core/schema/Schema.d.ts +30 -0
  57. package/dist/core/schema/Schema.js +64 -0
  58. package/dist/core/schema/SchemaClassRenderer.d.ts +16 -0
  59. package/dist/core/schema/SchemaClassRenderer.js +54 -0
  60. package/dist/core/schema/SchemaDependencyCollector.d.ts +17 -0
  61. package/dist/core/schema/SchemaDependencyCollector.js +33 -0
  62. package/dist/core/schema/SchemaPropertyClassifier.d.ts +19 -0
  63. package/dist/core/schema/SchemaPropertyClassifier.js +106 -0
  64. package/dist/core/schema/SchemaRegistry.d.ts +16 -0
  65. package/dist/core/schema/SchemaRegistry.js +51 -0
  66. package/dist/generate-doc.js +9 -72
  67. package/dist/helpers/codegen.d.ts +19 -0
  68. package/dist/helpers/codegen.js +38 -0
  69. package/dist/helpers/prop-name.d.ts +10 -0
  70. package/dist/helpers/prop-name.js +13 -0
  71. package/dist/loadTemplate.d.ts +2 -0
  72. package/dist/loadTemplate.js +8 -0
  73. package/dist/loaders/ConfigLoader.d.ts +20 -0
  74. package/dist/loaders/ConfigLoader.js +70 -0
  75. package/dist/loaders/OpenAPILoader.d.ts +10 -0
  76. package/dist/loaders/OpenAPILoader.js +31 -0
  77. package/dist/main.d.ts +12 -54
  78. package/dist/main.js +39 -323
  79. package/dist/method.d.ts +2 -0
  80. package/dist/method.js +6 -0
  81. package/dist/module.d.ts +11 -2
  82. package/dist/module.js +42 -14
  83. package/dist/props/array.property.d.ts +3 -1
  84. package/dist/props/array.property.js +6 -9
  85. package/dist/props/enum.property.d.ts +2 -0
  86. package/dist/props/enum.property.js +6 -7
  87. package/dist/props/primitive.property.d.ts +0 -1
  88. package/dist/props/primitive.property.js +4 -9
  89. package/dist/reflector.js +4 -0
  90. package/dist/runtime/reflector.svelte.ts +210 -0
  91. package/dist/schema.d.ts +2 -2
  92. package/dist/schema.js +36 -132
  93. package/package.json +8 -4
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Per-run codegen state. Replaces module-level mutable globals so two
3
+ * concurrent Reflector instances don't corrupt each other's output.
4
+ *
5
+ * - `enumTypes`: maps the joined enum literal string (e.g. `'a','b','c'`) to
6
+ * its generated type name. `EnumProp` writes here on first sighting and
7
+ * reads back the stable name on repeat sightings.
8
+ * - `mockedParams`: set of path-param names that need `$state` fallbacks in
9
+ * the generated `MockedParams` class. Written by `ModuleClassBuilder` when
10
+ * it sees path params.
11
+ */
12
+ export declare class CodegenContext {
13
+ readonly enumTypes: Map<string, string>;
14
+ readonly mockedParams: Set<string>;
15
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Per-run codegen state. Replaces module-level mutable globals so two
3
+ * concurrent Reflector instances don't corrupt each other's output.
4
+ *
5
+ * - `enumTypes`: maps the joined enum literal string (e.g. `'a','b','c'`) to
6
+ * its generated type name. `EnumProp` writes here on first sighting and
7
+ * reads back the stable name on repeat sightings.
8
+ * - `mockedParams`: set of path-param names that need `$state` fallbacks in
9
+ * the generated `MockedParams` class. Written by `ModuleClassBuilder` when
10
+ * it sees path params.
11
+ */
12
+ export class CodegenContext {
13
+ enumTypes = new Map();
14
+ mockedParams = new Set();
15
+ }
@@ -0,0 +1,25 @@
1
+ import { Module } from "./module/Module.js";
2
+ import { Schema } from "./schema/Schema.js";
3
+ import type { ComponentsObject, PathsObject } from "../types/open-api-spec.interface.js";
4
+ import type { FieldConfigs, TypeImports } from "../types/types.js";
5
+ import type { ReflectorConfig } from "./config/ReflectorConfig.js";
6
+ export declare class Reflector {
7
+ readonly schemas: Schema[];
8
+ readonly modules: Module[];
9
+ readonly propertiesNames: Set<string>;
10
+ private readonly registry;
11
+ private readonly typeImports;
12
+ private readonly config;
13
+ private readonly context;
14
+ private readonly srcDir;
15
+ constructor(params: {
16
+ components: ComponentsObject;
17
+ paths: PathsObject;
18
+ fieldConfigs: FieldConfigs;
19
+ typeImports: TypeImports;
20
+ apiImport: string;
21
+ experimentalFeatures?: boolean;
22
+ config?: Partial<ReflectorConfig>;
23
+ });
24
+ build(): Promise<{}>;
25
+ }
@@ -0,0 +1,66 @@
1
+ import * as path from "node:path";
2
+ import * as fs from "node:fs";
3
+ import * as process from "node:process";
4
+ import { Source } from "../file.js";
5
+ import { Module } from "./module/Module.js";
6
+ import { Schema } from "./schema/Schema.js";
7
+ import { CodegenContext } from "./CodegenContext.js";
8
+ import { InlineSchemaPromoter } from "./openapi/InlineSchemaPromoter.js";
9
+ import { SchemaRegistry } from "./schema/SchemaRegistry.js";
10
+ import { ModuleFactory } from "./module/ModuleFactory.js";
11
+ import { ModuleSchemaFileBuilder } from "./module/ModuleSchemaFileBuilder.js";
12
+ import { RuntimeFilesEmitter } from "./emit/RuntimeFilesEmitter.js";
13
+ import { resolveReflectorConfig } from "./config/ReflectorConfig.js";
14
+ import { generatedDir } from "../vars.global.js";
15
+ export class Reflector {
16
+ schemas;
17
+ modules;
18
+ propertiesNames;
19
+ registry;
20
+ typeImports;
21
+ config;
22
+ context = new CodegenContext();
23
+ srcDir = path.resolve(process.cwd(), `${generatedDir}/controllers`);
24
+ constructor(params) {
25
+ const { components, paths, fieldConfigs, typeImports, apiImport, experimentalFeatures, config } = params;
26
+ this.typeImports = typeImports;
27
+ this.config = resolveReflectorConfig(config);
28
+ InlineSchemaPromoter.promote(components, paths);
29
+ this.modules = ModuleFactory.build({
30
+ paths,
31
+ apiImport,
32
+ experimentalFeatures: experimentalFeatures ?? false,
33
+ context: this.context,
34
+ config: this.config,
35
+ });
36
+ this.registry = new SchemaRegistry({ components, fieldConfigs, context: this.context });
37
+ this.schemas = this.registry.schemas;
38
+ this.propertiesNames = this.registry.propertiesNames;
39
+ }
40
+ async build() {
41
+ fs.rmSync(this.srcDir, { recursive: true, force: true });
42
+ fs.mkdirSync(this.srcDir, { recursive: true });
43
+ const moduleSchemaFiles = [];
44
+ for (const module of this.modules) {
45
+ if (module.methods.length === 0 || module.schemaClassNames.length === 0)
46
+ continue;
47
+ const neededSchemas = this.registry.resolveTransitiveDeps(module.schemaClassNames);
48
+ if (neededSchemas.length === 0)
49
+ continue;
50
+ const data = ModuleSchemaFileBuilder.build({ schemas: neededSchemas, typeImports: this.typeImports, config: this.config });
51
+ const schemaFilePath = module.src.path.replace(".module.svelte.ts", ".schema.svelte.ts");
52
+ moduleSchemaFiles.push(new Source({ path: schemaFilePath, data }));
53
+ }
54
+ const runtimeFiles = RuntimeFilesEmitter.build({
55
+ propertiesNames: this.propertiesNames,
56
+ context: this.context,
57
+ });
58
+ await Promise.all([
59
+ ...moduleSchemaFiles.map((f) => f.save()),
60
+ ...runtimeFiles.map((f) => f.save()),
61
+ ...this.modules.filter((m) => m.methods.length > 0).map((m) => m.src.save()),
62
+ ...this.modules.filter((m) => m.methods.length > 0 && m.apiSrc).map((m) => m.apiSrc.save()),
63
+ ]);
64
+ return {};
65
+ }
66
+ }
@@ -0,0 +1,23 @@
1
+ import type { Method } from "../method/Method.js";
2
+ import type { ModuleImports } from "../module/ModuleImports.js";
3
+ import type { ModuleClassBuilder } from "../module/ModuleClassBuilder.js";
4
+ export interface ApiEndpointBlock {
5
+ paramCode: string;
6
+ classCode: string;
7
+ schemaEntries: Set<string>;
8
+ }
9
+ export declare class ApiClassBuilder {
10
+ private readonly imports;
11
+ private readonly methodGenerator;
12
+ private readonly callStrategy;
13
+ private readonly paramProcessor;
14
+ constructor(params: {
15
+ imports: ModuleImports;
16
+ classBuilder: ModuleClassBuilder;
17
+ });
18
+ build(params: {
19
+ method: Method;
20
+ }): ApiEndpointBlock | null;
21
+ private buildStateProperties;
22
+ private buildResetLines;
23
+ }
@@ -0,0 +1,106 @@
1
+ import { capitalizeFirstLetter } from "../../helpers/helpers.js";
2
+ import { MethodValidator } from "../method/MethodValidator.js";
3
+ import { CallMethodGenerator } from "../generators/CallMethodGenerator.js";
4
+ import { ApiCallStrategy } from "../generators/ApiCallStrategy.js";
5
+ import { ApiParamProcessor } from "./ApiParamProcessor.js";
6
+ export class ApiClassBuilder {
7
+ imports;
8
+ methodGenerator = new CallMethodGenerator();
9
+ callStrategy = new ApiCallStrategy();
10
+ paramProcessor;
11
+ constructor(params) {
12
+ this.imports = params.imports;
13
+ this.paramProcessor = new ApiParamProcessor({
14
+ imports: params.imports,
15
+ classBuilder: params.classBuilder,
16
+ });
17
+ }
18
+ build(params) {
19
+ const { method } = params;
20
+ if (MethodValidator.isSkippable(method))
21
+ return null;
22
+ const { request, headers, cookies, paths, querys } = method;
23
+ const { bodyType, responseType, attributeType, isPrimitiveResponse } = request;
24
+ // Process per-endpoint params
25
+ const processedParams = this.paramProcessor.process({
26
+ methodName: capitalizeFirstLetter(method.name),
27
+ querys,
28
+ paths,
29
+ headers,
30
+ cookies,
31
+ });
32
+ // Build state properties
33
+ const stateProps = this.buildStateProperties(method);
34
+ // Build the call method
35
+ const callMethod = this.methodGenerator.generate(method, this.callStrategy);
36
+ // Build reset method
37
+ const resetLines = this.buildResetLines(method, processedParams.paramReset);
38
+ // Collect schema entries
39
+ const schemaEntries = new Set();
40
+ if (bodyType) {
41
+ schemaEntries.add(bodyType);
42
+ }
43
+ if (responseType && responseType !== "response" && !isPrimitiveResponse) {
44
+ schemaEntries.add(`type ${responseType}Interface`);
45
+ schemaEntries.add(responseType);
46
+ }
47
+ // Handle form imports
48
+ if (attributeType === "form" && bodyType) {
49
+ this.imports.addReflectorImport("isFormValid");
50
+ }
51
+ // Handle list imports
52
+ if (attributeType === "list") {
53
+ this.imports.addReflectorImport("genericArrayBundler");
54
+ }
55
+ const className = capitalizeFirstLetter(method.name);
56
+ const classCode = `
57
+ export class ${className} {
58
+ ${stateProps.join(";")}
59
+ ${processedParams.paramAttributes.map((a) => `${a};`).join("\n ")}
60
+
61
+ ${callMethod}
62
+
63
+ reset() {
64
+ ${resetLines.join(";")}
65
+ }
66
+ }
67
+ `;
68
+ const paramCode = processedParams.paramClasses.join("\n");
69
+ return { paramCode, classCode, schemaEntries };
70
+ }
71
+ buildStateProperties(method) {
72
+ const { attributeType, responseType, bodyType, isPrimitiveResponse } = method.request;
73
+ const props = ["loading = $state<boolean>(false)"];
74
+ if (attributeType === "form" && bodyType) {
75
+ // For form endpoints, the form IS the data
76
+ props.push(`form = new ${bodyType}()`);
77
+ }
78
+ else if (attributeType === "list") {
79
+ props.push(`data = $state<${responseType}['data']>([])`);
80
+ props.push("totalPages = $state<number>(1)");
81
+ }
82
+ else if (attributeType === "entity" && responseType && !isPrimitiveResponse) {
83
+ props.push(`data = $state<${responseType} | undefined>()`);
84
+ }
85
+ else {
86
+ props.push("data = $state<unknown>(undefined)");
87
+ }
88
+ return props;
89
+ }
90
+ buildResetLines(method, paramReset) {
91
+ const { attributeType, bodyType } = method.request;
92
+ const lines = [];
93
+ if (attributeType === "form" && bodyType) {
94
+ lines.push(`this.form = new ${bodyType}()`);
95
+ }
96
+ else if (attributeType === "list") {
97
+ lines.push("this.data = []");
98
+ lines.push("this.totalPages = 1");
99
+ }
100
+ else {
101
+ lines.push("this.data = undefined");
102
+ }
103
+ lines.push(...paramReset);
104
+ return lines;
105
+ }
106
+ }
@@ -0,0 +1,12 @@
1
+ import type { ModuleImports } from "../module/ModuleImports.js";
2
+ import type { ApiEndpointBlock } from "./ApiClassBuilder.js";
3
+ export declare class ApiFileBuilder {
4
+ private readonly imports;
5
+ constructor(params: {
6
+ imports: ModuleImports;
7
+ });
8
+ build(params: {
9
+ endpointBlocks: ApiEndpointBlock[];
10
+ classImports: string;
11
+ }): string;
12
+ }
@@ -0,0 +1,24 @@
1
+ export class ApiFileBuilder {
2
+ imports;
3
+ constructor(params) {
4
+ this.imports = params.imports;
5
+ }
6
+ build(params) {
7
+ const { endpointBlocks, classImports } = params;
8
+ const reflectorImports = this.imports.buildReflectorImportsLine();
9
+ const enumImports = this.imports.buildEnumImportsLine();
10
+ const mockedImports = this.imports.buildMockedImportsLine();
11
+ const sections = endpointBlocks.map((block) => {
12
+ return `${block.paramCode}\n${block.classCode}`;
13
+ });
14
+ return `
15
+ ${this.imports.getImportsArray().join(";")}
16
+ ${reflectorImports}
17
+ ${mockedImports}
18
+ ${enumImports}
19
+ ${classImports}
20
+
21
+ ${sections.join("\n\n")}
22
+ `;
23
+ }
24
+ }
@@ -0,0 +1,17 @@
1
+ import type { Method } from "../../method.js";
2
+ export declare class ApiMethodGenerator {
3
+ private readonly endpointBuilder;
4
+ generate(method: Method): string;
5
+ private buildProps;
6
+ private buildPathsInfo;
7
+ private buildApiCall;
8
+ private buildListCall;
9
+ private buildEntityCall;
10
+ private buildFormCall;
11
+ private buildDeleteCall;
12
+ private buildParamsType;
13
+ private buildDescription;
14
+ private buildMethodReturn;
15
+ private joinProps;
16
+ private buildQuerys;
17
+ }
@@ -0,0 +1,176 @@
1
+ import { MethodEndpointBuilder } from "../method/MethodEndpointBuilder.js";
2
+ export class ApiMethodGenerator {
3
+ endpointBuilder = new MethodEndpointBuilder();
4
+ generate(method) {
5
+ const description = this.buildDescription(method);
6
+ const endpoint = this.endpointBuilder.build(method.endpoint, method.paths);
7
+ const apiCall = this.buildApiCall(method);
8
+ const props = this.buildProps(method);
9
+ const pathsInfo = this.buildPathsInfo(method);
10
+ const paramsType = this.buildParamsType(method, pathsInfo);
11
+ return `
12
+ ${description}
13
+ async call(params?: ${paramsType}) {
14
+
15
+ const behavior = params?.behavior ?? new Behavior();
16
+ const { onError, onSuccess } = behavior;
17
+
18
+ this.loading = true;
19
+ ${props}
20
+ const endpoint = ${endpoint}
21
+
22
+ ${apiCall.outside}
23
+
24
+ try {
25
+ ${apiCall.inside}
26
+ await onSuccess?.(response);
27
+
28
+ return ${this.buildMethodReturn(method)};
29
+ } catch (e) {
30
+ let parsedError: ApiErrorResponse;
31
+ try {
32
+ parsedError = JSON.parse((e as Error).message) as ApiErrorResponse;
33
+ } catch {
34
+ parsedError = { error: 'unknown', message: (e as Error).message ?? String(e) };
35
+ }
36
+ return await onError?.(parsedError);
37
+ } finally {
38
+ this.loading = false;
39
+ }
40
+ }
41
+ `;
42
+ }
43
+ buildProps(method) {
44
+ const { querys, paths, cookies } = method;
45
+ const lines = [];
46
+ if (querys.length > 0) {
47
+ lines.push(`const { ${querys.map((x) => x.name).join(", ")} } = this.querys.bundle()`);
48
+ }
49
+ if (paths.length > 0) {
50
+ lines.push(`const { ${paths.map((x) => x.name).join(", ")} } = params?.paths ?? this.paths`);
51
+ }
52
+ if (cookies.length > 0) {
53
+ lines.push(`const cookies = this.cookies`);
54
+ }
55
+ return lines.join("\n");
56
+ }
57
+ buildPathsInfo(method) {
58
+ const { paths } = method;
59
+ if (paths.length === 0)
60
+ return undefined;
61
+ return `{ ${paths
62
+ .map((p) => {
63
+ const type = p.rawType ?? p.type;
64
+ return `${p.name}: ${type}`;
65
+ })
66
+ .join("; ")} }`;
67
+ }
68
+ buildApiCall(method) {
69
+ const { attributeType, apiType, responseType, bodyType, hasEnumResponse } = method.request;
70
+ const responseTypeStr = hasEnumResponse && responseType ? responseType : method.responseTypeInterface;
71
+ if (attributeType === "list") {
72
+ return this.buildListCall(method, responseTypeStr);
73
+ }
74
+ if (attributeType === "entity") {
75
+ return this.buildEntityCall(method, responseTypeStr);
76
+ }
77
+ if (apiType === "post" || apiType === "put" || apiType === "patch") {
78
+ return this.buildFormCall(method, responseTypeStr, bodyType);
79
+ }
80
+ if (apiType === "delete") {
81
+ return this.buildDeleteCall(responseTypeStr);
82
+ }
83
+ return { inside: "", outside: "" };
84
+ }
85
+ buildListCall(method, responseType) {
86
+ const querys = this.joinProps(method.querys);
87
+ const inside = `
88
+ const response = await api.get<${responseType}, unknown>({
89
+ endpoint,
90
+ queryData: { ${querys} }
91
+ })
92
+ this.data = ${method.request.responseType}.from(response.data);
93
+ this.totalPages = response.totalPages;
94
+ `;
95
+ return { inside, outside: "" };
96
+ }
97
+ buildEntityCall(method, responseType) {
98
+ const rType = method.request.responseType;
99
+ const isPrimitive = method.request.isPrimitiveResponse;
100
+ const querys = this.buildQuerys(method.querys);
101
+ const buildedThisResponseType = rType && !isPrimitive
102
+ ? `this.data = new ${rType}({ data: response })`
103
+ : "";
104
+ const inside = `
105
+ const response = await api.get<${responseType}, unknown>({
106
+ endpoint,
107
+ ${querys}
108
+ })
109
+
110
+ ${buildedThisResponseType}
111
+ `;
112
+ return { inside, outside: "" };
113
+ }
114
+ buildFormCall(method, responseType, bodyType) {
115
+ const { apiType } = method.request;
116
+ const hasHeaders = method.headers.length > 0;
117
+ const hasData = !!bodyType;
118
+ const outside = [];
119
+ if (hasData) {
120
+ outside.push(`const data = this.form.bundle()`);
121
+ }
122
+ if (hasHeaders) {
123
+ outside.push(`const headers = this.headers.bundle()`);
124
+ }
125
+ const inside = `
126
+ const response = await api.${apiType}<${responseType}>({
127
+ endpoint,
128
+ ${hasData ? "data," : ""}
129
+ ${hasHeaders ? "headers," : ""}
130
+ })
131
+ `;
132
+ return { inside, outside: outside.join("\n") };
133
+ }
134
+ buildDeleteCall(responseType) {
135
+ const inside = `
136
+ const response = await api.delete<${responseType}, unknown>({
137
+ endpoint,
138
+ })
139
+ `;
140
+ return { inside, outside: "" };
141
+ }
142
+ buildParamsType(method, paramsPaths) {
143
+ const responseType = method.responseTypeInterface;
144
+ if (paramsPaths) {
145
+ return `ApiCallParams<${responseType}, ${paramsPaths}>`;
146
+ }
147
+ return `ApiCallParams<${responseType}>`;
148
+ }
149
+ buildDescription(method) {
150
+ return `/** ${method.description ?? ""} */`;
151
+ }
152
+ buildMethodReturn(method) {
153
+ const { attributeType, responseType, hasEnumResponse, isPrimitiveResponse } = method.request;
154
+ if (attributeType === "list") {
155
+ return "this.data";
156
+ }
157
+ if (!responseType) {
158
+ return "null";
159
+ }
160
+ if (hasEnumResponse) {
161
+ return "response.data";
162
+ }
163
+ if (isPrimitiveResponse) {
164
+ return "response";
165
+ }
166
+ return `new ${responseType}({ data: response })`;
167
+ }
168
+ joinProps(props) {
169
+ return props.map((x) => x.name).join(",");
170
+ }
171
+ buildQuerys(querys) {
172
+ if (querys.length === 0)
173
+ return "";
174
+ return `queryData: {${querys.map((q) => q.name).join(",")}}`;
175
+ }
176
+ }
@@ -0,0 +1,24 @@
1
+ import type { AttributeProp } from "../../types/types.js";
2
+ import type { PrimitiveProp } from "../../props/primitive.property.js";
3
+ import type { ModuleImports } from "../module/ModuleImports.js";
4
+ import type { ModuleClassBuilder } from "../module/ModuleClassBuilder.js";
5
+ export interface ApiProcessedParams {
6
+ paramClasses: string[];
7
+ paramAttributes: string[];
8
+ paramReset: string[];
9
+ }
10
+ export declare class ApiParamProcessor {
11
+ private readonly imports;
12
+ private readonly classBuilder;
13
+ constructor(params: {
14
+ imports: ModuleImports;
15
+ classBuilder: ModuleClassBuilder;
16
+ });
17
+ process(params: {
18
+ methodName: string;
19
+ querys: AttributeProp[];
20
+ paths: PrimitiveProp[];
21
+ headers: PrimitiveProp[];
22
+ cookies: PrimitiveProp[];
23
+ }): ApiProcessedParams;
24
+ }
@@ -0,0 +1,36 @@
1
+ import { capitalizeFirstLetter } from "../../helpers/helpers.js";
2
+ export class ApiParamProcessor {
3
+ imports;
4
+ classBuilder;
5
+ constructor(params) {
6
+ this.imports = params.imports;
7
+ this.classBuilder = params.classBuilder;
8
+ }
9
+ process(params) {
10
+ const { methodName, cookies, headers, paths, querys } = params;
11
+ const paramClasses = [];
12
+ const paramAttributes = [];
13
+ const paramReset = [];
14
+ const processParam = (paramData) => {
15
+ const { paramType, attrName, props } = paramData;
16
+ const className = `${capitalizeFirstLetter(methodName)}${capitalizeFirstLetter(paramType)}`;
17
+ paramClasses.push(this.classBuilder.buildClassProps({ props, name: paramType, className }));
18
+ paramAttributes.push(`${attrName} = new ${className}()`);
19
+ paramReset.push(`this.${attrName} = new ${className}()`);
20
+ };
21
+ const argEntries = [
22
+ { attrName: "querys", props: querys },
23
+ { attrName: "headers", props: headers },
24
+ { attrName: "paths", props: paths },
25
+ { attrName: "cookies", props: cookies },
26
+ ];
27
+ for (const { attrName, props } of argEntries) {
28
+ if (!props.length)
29
+ continue;
30
+ this.imports.addReflectorImport("QueryBuilder");
31
+ const paramType = capitalizeFirstLetter(attrName);
32
+ processParam({ paramType, attrName, props });
33
+ }
34
+ return { paramClasses, paramAttributes, paramReset };
35
+ }
36
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Isolates the consumer's framework conventions (import aliases, env flag
3
+ * name) from the codegen core. Defaults reproduce the previous hard-coded
4
+ * SvelteKit paths so existing consumers don't need to change anything.
5
+ */
6
+ export interface ReflectorConfig {
7
+ /** Alias that resolves to the generated reflector folder (e.g. `$reflector`). */
8
+ reflectorAlias: string;
9
+ /** Full import path to the validators/sanitizers module. */
10
+ validatorsImport: string;
11
+ /** Module path for the environment flag (e.g. `$env/static/public`). */
12
+ environmentImport: string;
13
+ /** Name of the exported environment flag — values other than `DEV` are treated as prod. */
14
+ environmentFlag: string;
15
+ }
16
+ export declare const DEFAULT_REFLECTOR_CONFIG: ReflectorConfig;
17
+ export declare function resolveReflectorConfig(partial?: Partial<ReflectorConfig>): ReflectorConfig;
@@ -0,0 +1,9 @@
1
+ export const DEFAULT_REFLECTOR_CONFIG = {
2
+ reflectorAlias: "$reflector",
3
+ validatorsImport: "$lib/sanitizers/validateFormats",
4
+ environmentImport: "$env/static/public",
5
+ environmentFlag: "PUBLIC_ENVIRONMENT",
6
+ };
7
+ export function resolveReflectorConfig(partial) {
8
+ return { ...DEFAULT_REFLECTOR_CONFIG, ...(partial ?? {}) };
9
+ }
@@ -0,0 +1,13 @@
1
+ import { Source } from "../../file.js";
2
+ import type { CodegenContext } from "../CodegenContext.js";
3
+ /**
4
+ * Emits the shared runtime-support files that sit alongside the generated
5
+ * module files: the reflector runtime template, the FIELD_NAMES list, the
6
+ * enum unions, and the MockedParams class used by path-param stubs.
7
+ */
8
+ export declare class RuntimeFilesEmitter {
9
+ static build(params: {
10
+ propertiesNames: Set<string>;
11
+ context: CodegenContext;
12
+ }): Source[];
13
+ }
@@ -0,0 +1,55 @@
1
+ import * as path from "node:path";
2
+ import * as process from "node:process";
3
+ import { Source } from "../../file.js";
4
+ import { loadReflectorTemplate } from "../../loadTemplate.js";
5
+ import { generatedDir } from "../../vars.global.js";
6
+ import { dedent } from "../../helpers/codegen.js";
7
+ function generated(relPath) {
8
+ return path.resolve(process.cwd(), `${generatedDir}/${relPath}`);
9
+ }
10
+ /**
11
+ * Emits the shared runtime-support files that sit alongside the generated
12
+ * module files: the reflector runtime template, the FIELD_NAMES list, the
13
+ * enum unions, and the MockedParams class used by path-param stubs.
14
+ */
15
+ export class RuntimeFilesEmitter {
16
+ static build(params) {
17
+ const { propertiesNames, context } = params;
18
+ const typesSrc = new Source({
19
+ path: generated("reflector.svelte.ts"),
20
+ data: loadReflectorTemplate(),
21
+ });
22
+ const fieldLiterals = Array.from(propertiesNames).map((p) => `'${p}'`);
23
+ const fieldsFile = new Source({
24
+ path: generated("fields.ts"),
25
+ data: dedent `
26
+ export const FIELD_NAMES = [
27
+ ${fieldLiterals}
28
+ ] as const;
29
+ export type FieldName = (typeof FIELD_NAMES)[number]
30
+ `,
31
+ });
32
+ const enumss = Array.from(context.enumTypes)
33
+ .map(([types, key]) => `export const ${key} = [ ${types} ] as const; export type ${key} = typeof ${key}[number] `)
34
+ .join(";");
35
+ const enumFile = new Source({
36
+ path: generated("enums.ts"),
37
+ data: enumss,
38
+ });
39
+ const mockedFields = Array.from(context.mockedParams)
40
+ .map((paramName) => `${paramName} = $state<string | null>(null)`)
41
+ .join(";");
42
+ const mockedFile = new Source({
43
+ path: generated("mocked-params.svelte.ts"),
44
+ data: dedent `
45
+ class MockedParams {
46
+ ${mockedFields}
47
+ }
48
+
49
+ const mockedParams = new MockedParams()
50
+ export default mockedParams
51
+ `,
52
+ });
53
+ return [typesSrc, fieldsFile, enumFile, mockedFile];
54
+ }
55
+ }
@@ -0,0 +1,9 @@
1
+ import type { CallMethodInput, CallStrategy } from "./CallStrategy.js";
2
+ export declare class ApiCallStrategy implements CallStrategy {
3
+ readonly listStateAccess = "this.data";
4
+ buildSignature(method: CallMethodInput): string;
5
+ entityStateAccess(_method: CallMethodInput): string;
6
+ formStateAccess(_method: CallMethodInput): string;
7
+ private buildParamsType;
8
+ private buildPathsInfo;
9
+ }