swaggular 0.3.0 → 0.6.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.
package/dist/cli/args.js CHANGED
@@ -18,6 +18,12 @@ function getParseArgs(argv) {
18
18
  args[k] = true;
19
19
  }
20
20
  else {
21
+ // Special handling for --config to allow relative paths
22
+ if (k === 'config') {
23
+ args[k] = next;
24
+ i++;
25
+ continue;
26
+ }
21
27
  args[k] = next;
22
28
  i++;
23
29
  }
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.toVariables = toVariables;
4
+ const config_loader_1 = require("../utils/config-loader");
4
5
  function toVariables(parsed) {
5
6
  const variables = {};
6
7
  if (parsed.args.mode) {
@@ -11,11 +12,25 @@ function toVariables(parsed) {
11
12
  variables.segmentsToIgnore = parsed.args.segmentsToIgnore.split(',');
12
13
  }
13
14
  }
15
+ const configPath = parsed.args.config;
16
+ const fileConfig = (0, config_loader_1.loadConfig)(configPath);
17
+ const mergedConfig = { ...fileConfig, ...variables };
14
18
  return {
15
- input: parsed.args.input || 'swagger.json',
16
- output: parsed.args.output || 'results',
19
+ input: parsed.args.input ||
20
+ parsed.args.i ||
21
+ parsed.positional[0] ||
22
+ mergedConfig.input ||
23
+ 'swagger.json',
24
+ output: parsed.args.output ||
25
+ parsed.args.o ||
26
+ parsed.positional[1] ||
27
+ mergedConfig.output ||
28
+ 'results',
17
29
  noGenerate: parsed.args.noGenerate || false,
18
- groupingMode: variables.groupingMode || 'path',
19
- segmentsToIgnore: variables.segmentsToIgnore || ['api'],
30
+ groupingMode: variables.groupingMode || mergedConfig.groupingMode || 'path',
31
+ segmentsToIgnore: variables.segmentsToIgnore || mergedConfig.segmentsToIgnore || ['api'],
32
+ // Pass entire config if needed for templates
33
+ templates: mergedConfig.templates,
34
+ types: mergedConfig.types,
20
35
  };
21
36
  }
File without changes
@@ -0,0 +1 @@
1
+ "use strict";
@@ -7,12 +7,15 @@ export interface InterfaceStateI {
7
7
  declare class InterfaceState implements InterfaceStateI {
8
8
  generatedInterfaces: Record<string, InterfaceData>;
9
9
  generatedEnums: Record<string, InterfaceData>;
10
+ typeMappings: Record<string, string>;
10
11
  componentsSchemas: Record<string, IJsonSchema>;
11
12
  constructor();
12
13
  setComponentsSchemas(componentsSchemas: Record<string, IJsonSchema>): void;
13
14
  getComponentsSchema(name: string): IJsonSchema | undefined;
14
15
  addInterfaces(interfacesData: InterfaceData[]): void;
15
16
  getInterface(name: string): InterfaceData | undefined;
17
+ addTypeMapping(original: string, mapped: string): void;
18
+ getTypeMapping(original: string): string | undefined;
16
19
  }
17
20
  export declare const interfaceState: InterfaceState;
18
21
  export {};
@@ -4,6 +4,7 @@ exports.interfaceState = void 0;
4
4
  class InterfaceState {
5
5
  generatedInterfaces = {};
6
6
  generatedEnums = {};
7
+ typeMappings = {};
7
8
  componentsSchemas = {};
8
9
  constructor() { }
9
10
  setComponentsSchemas(componentsSchemas) {
@@ -20,5 +21,11 @@ class InterfaceState {
20
21
  getInterface(name) {
21
22
  return this.generatedInterfaces[name] || this.generatedEnums[name];
22
23
  }
24
+ addTypeMapping(original, mapped) {
25
+ this.typeMappings[original] = mapped;
26
+ }
27
+ getTypeMapping(original) {
28
+ return this.typeMappings[original];
29
+ }
23
30
  }
24
31
  exports.interfaceState = new InterfaceState();
@@ -8,6 +8,7 @@ export declare class SwaggerState {
8
8
  setPathsGroupedByScope(pathsGroupedByScope: GroupedPaths): void;
9
9
  getPaths(): OpenAPIV3.PathsObject | undefined;
10
10
  getSchemas(): Record<string, OpenAPIV3.ReferenceObject | OpenAPIV3.SchemaObject> | undefined;
11
+ getParameters(): Record<string, OpenAPIV3.ReferenceObject | OpenAPIV3.ParameterObject> | undefined;
11
12
  getPathsGroupedByScope(): GroupedPaths | undefined;
12
13
  getGroupByPath(path: string): import("../../types/grouped-paths").GroupedPath | undefined;
13
14
  }
@@ -19,6 +19,9 @@ class SwaggerState {
19
19
  getSchemas() {
20
20
  return this.swagger?.components?.schemas;
21
21
  }
22
+ getParameters() {
23
+ return this.swagger?.components?.parameters;
24
+ }
22
25
  getPathsGroupedByScope() {
23
26
  return this.pathsGroupedByScope;
24
27
  }
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.main = main;
5
5
  const swagger_parser_1 = require("./parsers/swagger-parser");
6
+ const location_factory_1 = require("./utils/location-factory");
6
7
  const generate_interface_1 = require("./renderers/generate-interface");
7
8
  const generate_service_1 = require("./renderers/generate-service");
8
9
  const args_1 = require("./cli/args");
@@ -18,10 +19,11 @@ async function main() {
18
19
  segmentsToIgnore: variables.segmentsToIgnore,
19
20
  ignoreVariables: true,
20
21
  });
21
- (0, generate_interface_1.generateInterfaces)();
22
+ const locations = (0, location_factory_1.computeLocations)();
23
+ (0, generate_interface_1.generateInterfaces)(variables);
22
24
  (0, generate_service_1.generateServices)();
23
- const interfaceFiles = (0, generate_interface_1.generateInterfacesFiles)();
24
- const serviceFiles = (0, generate_service_1.generateServiceFiles)();
25
+ const interfaceFiles = (0, generate_interface_1.generateInterfacesFiles)(locations, variables);
26
+ const serviceFiles = (0, generate_service_1.generateServiceFiles)(locations, variables.templates);
25
27
  if (variables.noGenerate) {
26
28
  console.log('Files not generated');
27
29
  return;
@@ -20,7 +20,7 @@ function generateInterfaceComments(param) {
20
20
  comments.push(`maximum: ${param.maximum}`);
21
21
  }
22
22
  if (comments.length > 0) {
23
- return ` /**\n * ${comments.join('\n * ')}\n */`;
23
+ return `/**\n * ${comments.join('\n * ')}\n */`;
24
24
  }
25
25
  return '';
26
26
  }
@@ -1,12 +1,11 @@
1
1
  import { OpenAPIV3 } from 'openapi-types';
2
2
  import { FileContent } from '../types/file-content';
3
- import { GroupedPath } from '../types/grouped-paths';
4
3
  import { InterfaceData, InterfaceDataProperty } from '../types/interface-data';
4
+ import { SwaggularConfig } from '../types/config';
5
5
  export declare function parametersToIProperties(parameters: (OpenAPIV3.ParameterObject | OpenAPIV3.ReferenceObject)[]): InterfaceDataProperty[];
6
6
  export declare function propertiesToIProperties(properties: Record<string, OpenAPIV3.ReferenceObject | OpenAPIV3.SchemaObject>): InterfaceDataProperty[];
7
- export declare function generateInterfaces(): void;
8
- export declare function generateWithParameters(): void;
9
- export declare function computeParametersName(method: string, innerPath: string, groupedPath: GroupedPath): string;
10
- export declare function generateComponentsSchemas(): void;
11
- export declare function generateInterfacesFiles(locations?: Record<string, string[]>): FileContent[];
7
+ export declare function generateInterfaces(templatesConfig?: SwaggularConfig): void;
8
+ export declare function generateWithParameters(templatesConfig?: SwaggularConfig): void;
9
+ export declare function generateComponentsSchemas(templatesConfig?: SwaggularConfig): void;
10
+ export declare function generateInterfacesFiles(locations?: Record<string, string[]>, templatesConfig?: SwaggularConfig): FileContent[];
12
11
  export declare function generateContent(interfaceData: InterfaceData, deep?: number): string;
@@ -4,14 +4,11 @@ exports.parametersToIProperties = parametersToIProperties;
4
4
  exports.propertiesToIProperties = propertiesToIProperties;
5
5
  exports.generateInterfaces = generateInterfaces;
6
6
  exports.generateWithParameters = generateWithParameters;
7
- exports.computeParametersName = computeParametersName;
8
7
  exports.generateComponentsSchemas = generateComponentsSchemas;
9
8
  exports.generateInterfacesFiles = generateInterfacesFiles;
10
9
  exports.generateContent = generateContent;
11
10
  const interface_state_1 = require("../core/state/interface-state");
12
11
  const swagger_state_1 = require("../core/state/swagger-state");
13
- const extends_from_types_1 = require("../templates/types/extends-from-types");
14
- const generic_types_1 = require("../templates/types/generic-types");
15
12
  const build_types_1 = require("../utils/build-types");
16
13
  const object_utils_1 = require("../utils/object-utils");
17
14
  const path_utils_1 = require("../utils/path-utils");
@@ -23,12 +20,22 @@ function parametersToIProperties(parameters) {
23
20
  for (const param of parameters) {
24
21
  if ((0, type_guard_1.isReference)(param)) {
25
22
  const ref = param.$ref.split('/').pop();
26
- properties.push({
27
- name: (0, string_utils_1.lowerFirst)(ref),
28
- type: ref,
29
- optional: false,
30
- comments: '',
31
- });
23
+ if (param.$ref.includes('/components/parameters/')) {
24
+ const parameters = swagger_state_1.swaggerState.getParameters();
25
+ const parameter = parameters?.[ref];
26
+ if (parameter && !(0, type_guard_1.isReference)(parameter)) {
27
+ if (parameter.in !== 'query')
28
+ continue;
29
+ const tsType = parameter.schema ? (0, build_types_1.switchTypeJson)(parameter.schema) : 'any';
30
+ properties.push({
31
+ name: (0, string_utils_1.lowerFirst)(parameter.name),
32
+ type: tsType,
33
+ optional: !parameter.required,
34
+ comments: (0, generate_comments_1.generateInterfaceComments)(parameter.schema),
35
+ });
36
+ continue;
37
+ }
38
+ }
32
39
  continue;
33
40
  }
34
41
  if (param.in !== 'query')
@@ -65,16 +72,52 @@ function propertiesToIProperties(properties) {
65
72
  }
66
73
  return interfaceDataProperties;
67
74
  }
68
- function generateInterfaces() {
69
- generateComponentsSchemas();
70
- generateWithParameters();
75
+ function isGenericType(data, genericTypes) {
76
+ for (const genericType of genericTypes) {
77
+ if (genericType.properties.length !== data.properties.length)
78
+ continue;
79
+ const dataProperties = data.properties.map((p) => p.name);
80
+ const genericTypeProperties = genericType.properties.map((p) => p.name);
81
+ if (genericTypeProperties.some((p) => !dataProperties.includes(p)))
82
+ continue;
83
+ return true; // Match found
84
+ }
85
+ return false;
86
+ }
87
+ function computeExtendsFromType(data, extendsTypes) {
88
+ for (const extendsFromType of extendsTypes) {
89
+ const dataPropertiesReq = data.properties.filter((p) => !p.optional).map((p) => p.name);
90
+ const extendsFromTypePropertiesReq = extendsFromType.properties
91
+ .filter((p) => !p.optional)
92
+ .map((p) => p.name);
93
+ if (extendsFromTypePropertiesReq.some((p) => !dataPropertiesReq.includes(p))) {
94
+ continue;
95
+ }
96
+ if (!extendsFromType.properties.some((ep) => data.properties.some((dp) => dp.name === ep.name))) {
97
+ continue;
98
+ }
99
+ const extensionProperties = extendsFromType.properties.map((p) => p.name.toLowerCase());
100
+ return {
101
+ ...data,
102
+ properties: data.properties.filter((p) => !extensionProperties.includes(p.name.toLowerCase())),
103
+ imports: [...data.imports, extendsFromType.name],
104
+ extendsFrom: [...(data.extendsFrom ?? []), extendsFromType.name],
105
+ };
106
+ }
107
+ return data;
71
108
  }
72
- function generateWithParameters() {
109
+ function generateInterfaces(templatesConfig) {
110
+ generateComponentsSchemas(templatesConfig);
111
+ generateWithParameters(templatesConfig);
112
+ }
113
+ function generateWithParameters(templatesConfig) {
73
114
  const paths = swagger_state_1.swaggerState.getPaths();
74
115
  const groupedPaths = swagger_state_1.swaggerState.getPathsGroupedByScope();
75
116
  if (!paths || !groupedPaths)
76
117
  return;
77
118
  const interfacesData = [];
119
+ const genericTypes = templatesConfig?.types?.generic ?? [];
120
+ const extendsTypes = templatesConfig?.types?.extendsFrom ?? [];
78
121
  for (const groupedPath of Object.values(groupedPaths)) {
79
122
  for (const innerPath of groupedPath.paths) {
80
123
  const pathInfo = paths[innerPath];
@@ -94,40 +137,31 @@ function generateWithParameters() {
94
137
  const properties = parametersToIProperties(parameters);
95
138
  if (properties.length === 0)
96
139
  continue;
97
- const interfaceName = computeParametersName(httpMethod, innerPath, groupedPath);
140
+ const interfaceName = (0, path_utils_1.computeParametersName)(httpMethod, innerPath, groupedPath);
98
141
  const interData = {
99
142
  name: interfaceName,
100
143
  type: 'interface',
101
144
  imports: properties.filter((p) => !(0, type_guard_1.isNativeType)(p.type)).map((p) => p.type),
102
145
  properties,
103
146
  };
104
- const generic = (0, generic_types_1.isGenericType)(interData);
147
+ const generic = isGenericType(interData, genericTypes);
105
148
  if (generic)
106
149
  continue;
107
- const interDataWithExtendsFrom = (0, extends_from_types_1.computeExtendsFromType)(interData);
150
+ const interDataWithExtendsFrom = computeExtendsFromType(interData, extendsTypes);
108
151
  interfacesData.push(interDataWithExtendsFrom);
109
152
  }
110
153
  }
111
154
  }
112
155
  interface_state_1.interfaceState.addInterfaces(interfacesData);
113
156
  }
114
- function computeParametersName(method, innerPath, groupedPath) {
115
- const dict = {
116
- get: '',
117
- post: 'Create',
118
- put: 'Update',
119
- delete: 'Delete',
120
- patch: 'Patch',
121
- };
122
- const name = dict[method];
123
- const extra = (0, string_utils_1.kebabToPascalCase)((0, path_utils_1.removeVariablesFromPath)((0, path_utils_1.getExtraSegments)(innerPath, (0, path_utils_1.createBaseUrl)(groupedPath.baseSegments)).join('')));
124
- return name + groupedPath.groupName + (0, string_utils_1.upFirst)(extra) + 'Params';
125
- }
126
- function generateComponentsSchemas() {
157
+ function generateComponentsSchemas(templatesConfig) {
127
158
  const schemas = swagger_state_1.swaggerState.getSchemas();
128
159
  if (!schemas)
129
160
  return;
130
161
  const interfaces = [];
162
+ const genericMappings = new Map();
163
+ const genericTypes = templatesConfig?.types?.generic ?? [];
164
+ const extendsTypes = templatesConfig?.types?.extendsFrom ?? [];
131
165
  for (const [key, value] of Object.entries(schemas)) {
132
166
  if ((0, type_guard_1.isReference)(value))
133
167
  continue;
@@ -147,6 +181,29 @@ function generateComponentsSchemas() {
147
181
  }),
148
182
  };
149
183
  interfaces.push(interData);
184
+ continue;
185
+ }
186
+ const targetType = (0, build_types_1.switchTypeJson)(value);
187
+ if (targetType) {
188
+ const imports = [];
189
+ const baseType = targetType.replace('[]', '');
190
+ if (!(0, type_guard_1.isNativeType)(baseType)) {
191
+ imports.push(baseType);
192
+ }
193
+ interfaces.push({
194
+ name: key,
195
+ type: 'type',
196
+ imports,
197
+ properties: [
198
+ {
199
+ name: '',
200
+ type: targetType,
201
+ optional: false,
202
+ comments: (0, generate_comments_1.generateInterfaceComments)(value),
203
+ },
204
+ ],
205
+ });
206
+ continue;
150
207
  }
151
208
  continue;
152
209
  }
@@ -161,24 +218,56 @@ function generateComponentsSchemas() {
161
218
  }),
162
219
  properties,
163
220
  };
164
- const generic = (0, generic_types_1.isGenericType)(interData);
221
+ const generic = isGenericType(interData, genericTypes);
165
222
  if (generic) {
223
+ const genericType = genericTypes.find((g) => {
224
+ if (g.properties.length !== interData.properties.length)
225
+ return false;
226
+ const gProps = g.properties.map((p) => p.name);
227
+ const dProps = interData.properties.map((p) => p.name);
228
+ return !gProps.some((p) => !dProps.includes(p));
229
+ });
230
+ if (genericType) {
231
+ const genericName = computeGenericType(interData, genericType);
232
+ genericMappings.set(key, genericName);
233
+ interface_state_1.interfaceState.addTypeMapping(key, genericName);
234
+ }
166
235
  continue;
167
236
  }
168
- const interDataWithExtendsFrom = (0, extends_from_types_1.computeExtendsFromType)(interData);
237
+ const interDataWithExtendsFrom = computeExtendsFromType(interData, extendsTypes);
169
238
  interfaces.push(interDataWithExtendsFrom);
170
239
  }
240
+ // Update properties of all interfaces to use generic mappings
241
+ for (const inter of interfaces) {
242
+ inter.properties.forEach((p) => {
243
+ if (genericMappings.has(p.type)) {
244
+ p.type = genericMappings.get(p.type);
245
+ }
246
+ else if (p.type.endsWith('[]')) {
247
+ const base = p.type.replace('[]', '');
248
+ if (genericMappings.has(base)) {
249
+ p.type = genericMappings.get(base) + '[]';
250
+ }
251
+ }
252
+ });
253
+ }
171
254
  interface_state_1.interfaceState.addInterfaces(interfaces);
172
255
  }
173
- function generateInterfacesFiles(locations) {
256
+ function computeGenericType(newInterface, genericType) {
257
+ const typeParam = newInterface.name.replace(genericType.name, '');
258
+ return `${genericType.name}<${typeParam}>`;
259
+ }
260
+ function generateInterfacesFiles(locations, templatesConfig) {
261
+ const genericTypes = templatesConfig?.types?.generic ?? [];
262
+ const extendsTypes = templatesConfig?.types?.extendsFrom ?? [];
174
263
  const interfacesData = [
175
- ...generic_types_1.genericTypesData,
176
- ...extends_from_types_1.extendsFromTypes,
264
+ ...genericTypes,
265
+ ...extendsTypes,
177
266
  ...Array.from(Object.values(interface_state_1.interfaceState.generatedInterfaces)),
178
267
  ];
179
268
  const filesContent = [];
180
- for (const [key, value] of Object.entries(interfacesData)) {
181
- const location = [value.type === 'enum' ? 'enums' : 'dtos', ...(locations?.[key] ?? [])];
269
+ for (const value of interfacesData) {
270
+ const location = [value.type === 'enum' ? 'enums' : 'dtos', ...(locations?.[value.name] ?? [])];
182
271
  const content = generateContent(value, location.length + 1);
183
272
  const extraName = value.type === 'enum' ? 'enum' : 'dto';
184
273
  filesContent.push({
@@ -200,16 +289,20 @@ function generateContent(interfaceData, deep = 0) {
200
289
  .map((p) => p.type.replace('[]', ''));
201
290
  const content = `${importsTemplate}\n\nexport interface ${interfaceData.name}${genericTypes.length > 0 ? `<${genericTypes.join(', ')}>` : ''} ${interfaceData.extendsFrom && interfaceData.extendsFrom.length > 0 ? `extends ${interfaceData.extendsFrom.join(', ')}` : ''} {
202
291
  ${interfaceData.properties
203
- .map((p) => `${p.comments}\n\t${(0, string_utils_1.lowerFirst)(p.name)}${p.optional ? '?' : ''}: ${p.type};`)
292
+ .map((p) => `${p.comments}\n ${(0, string_utils_1.lowerFirst)(p.name)}${p.optional ? '?' : ''}: ${p.type};`)
204
293
  .join('\n')}
205
294
  }`;
206
295
  return content;
207
296
  }
208
297
  if (interfaceData.type === 'enum') {
209
298
  const content = `export enum ${interfaceData.name} {
210
- ${interfaceData.properties.map((p) => `${p.comments}\n\t${p.name} = '${p.type}',`).join('\n')}
299
+ ${interfaceData.properties.map((p) => `${p.comments}\n ${p.name} = '${p.type}',`).join('\n')}
211
300
  }`;
212
301
  return content;
213
302
  }
303
+ if (interfaceData.type === 'type') {
304
+ const targetType = interfaceData.properties[0].type;
305
+ return `${importsTemplate}\n\nexport type ${interfaceData.name} = ${targetType};`;
306
+ }
214
307
  return '';
215
308
  }
@@ -2,9 +2,10 @@ import { OpenAPIV3 } from 'openapi-types';
2
2
  import { FileContent } from '../types/file-content';
3
3
  import { GroupedPath } from '../types/grouped-paths';
4
4
  import { ServiceDataMethod } from '../types/service-data';
5
+ import { SwaggularConfig } from '../types/config';
5
6
  /**
6
7
  * Pick the paths grouped by scope and generate services for them.
7
8
  */
8
9
  export declare function generateServices(): void;
9
- export declare function generateServiceFiles(locations?: Record<string, string[]>): FileContent[];
10
+ export declare function generateServiceFiles(locations?: Record<string, string[]>, templatesConfig?: SwaggularConfig['templates']): FileContent[];
10
11
  export declare function buildMethods(groupedPath: GroupedPath, pathData: OpenAPIV3.PathsObject, serviceName: string): ServiceDataMethod[];
@@ -5,16 +5,15 @@ exports.generateServiceFiles = generateServiceFiles;
5
5
  exports.buildMethods = buildMethods;
6
6
  const service_state_1 = require("../core/state/service-state");
7
7
  const swagger_state_1 = require("../core/state/swagger-state");
8
- const angular_template_1 = require("../templates/services/angular-template");
9
8
  const build_types_1 = require("../utils/build-types");
10
9
  const path_utils_1 = require("../utils/path-utils");
11
10
  const string_utils_1 = require("../utils/string-utils");
12
11
  const type_guard_1 = require("../utils/type-guard");
13
12
  const generate_comments_1 = require("./generate-comments");
14
13
  const object_utils_1 = require("../utils/object-utils");
15
- const generate_interface_1 = require("./generate-interface");
16
- const http_params_handler_1 = require("../templates/services/http-params-handler");
14
+ const path_utils_2 = require("../utils/path-utils");
17
15
  const interface_state_1 = require("../core/state/interface-state");
16
+ const template_renderer_1 = require("../utils/template-renderer");
18
17
  /**
19
18
  * Pick the paths grouped by scope and generate services for them.
20
19
  */
@@ -64,24 +63,36 @@ function addTypeToImports(type, imports) {
64
63
  imports.add(baseType);
65
64
  }
66
65
  }
67
- function generateServiceFiles(locations) {
66
+ function generateServiceFiles(locations, templatesConfig) {
68
67
  const services = Object.values(service_state_1.serviceState.services);
69
68
  const filesContent = [];
70
69
  for (const service of services) {
71
70
  const location = ['services', ...(locations?.[service.name] ?? [])];
71
+ const serviceTemplateConfig = templatesConfig?.service;
72
+ const templatePath = serviceTemplateConfig?.path || 'templates/angular-service.template';
72
73
  const methods = service.methods
73
74
  .map((method) => {
74
- return buildMethodTemplate(method);
75
+ return buildMethodTemplate(method, serviceTemplateConfig?.options?.httpParamsHandler);
75
76
  })
76
77
  .join('\n\n');
78
+ const allImports = Array.from(new Set([...service.imports])).sort();
79
+ const hasHttpParams = service.methods.some((m) => !!m.queryParamType);
77
80
  const templateParams = {
78
81
  name: service.name,
79
82
  baseUrl: service.baseUrl,
80
83
  methods: methods,
81
- imports: service.imports.join(', '),
82
- hasHttpParamsHandler: service.methods.some((m) => !!m.queryParamType),
84
+ imports: allImports.join(', '),
85
+ modelImports: allImports.length > 0
86
+ ? `import { ${allImports.join(', ')} } from '${'../'.repeat(location.length)}models';`
87
+ : '',
88
+ hasHttpParamsHandler: hasHttpParams,
89
+ httpParamsHandler: serviceTemplateConfig?.options?.httpParamsHandler,
90
+ httpParamsHandlerImport: hasHttpParams
91
+ ? serviceTemplateConfig?.options?.httpParamsHandlerImport
92
+ : '',
93
+ extraAngularImports: hasHttpParams && !serviceTemplateConfig?.options?.httpParamsHandler ? ', HttpParams' : '',
83
94
  };
84
- const content = (0, angular_template_1.angularTemplate)(templateParams);
95
+ const content = (0, template_renderer_1.renderServiceTemplate)(templatePath, templateParams);
85
96
  filesContent.push({
86
97
  location: location,
87
98
  content,
@@ -107,7 +118,7 @@ function buildMethods(groupedPath, pathData, serviceName) {
107
118
  const queryParams = parameters.filter((p) => p.in === 'query');
108
119
  let queryParamType;
109
120
  if (queryParams.length > 0) {
110
- queryParamType = (0, generate_interface_1.computeParametersName)(method, path, groupedPath);
121
+ queryParamType = (0, path_utils_2.computeParametersName)(method, path, groupedPath);
111
122
  }
112
123
  const commentParams = parameters.filter((p) => p.in !== 'query');
113
124
  if (queryParamType) {
@@ -140,18 +151,7 @@ function pathItemToMethods(pathItem) {
140
151
  patch: pathItem.patch,
141
152
  });
142
153
  }
143
- /**
144
- * buildMethodName: High-performance semantic naming algorithm.
145
- *
146
- * This engine generates clean, non-redundant, and intuitive method names by
147
- * analyzing the relationship between the base URL and extra path segments.
148
- *
149
- * For Mutation methods (POST, PUT, PATCH, DELETE), it prioritizes using the
150
- * path segments as the method name itself if they describe an action,
151
- * avoiding generic "create" or "update" prefixes where possible.
152
- */
153
154
  function buildMethodName(method, path, groupedPath, usedNames, serviceName) {
154
- // 1. Core mapping of HTTP verbs to professional action prefixes
155
155
  const verbMap = {
156
156
  get: 'get',
157
157
  post: 'create',
@@ -161,7 +161,6 @@ function buildMethodName(method, path, groupedPath, usedNames, serviceName) {
161
161
  };
162
162
  const defaultVerb = verbMap[method.toLowerCase()] || method.toLowerCase();
163
163
  const segments = (0, path_utils_1.getExtraSegments)(path, groupedPath.baseUrl);
164
- // 2. Redundancy Filtering: Remove segments already implied by the service name
165
164
  const serviceWords = serviceName.split(/(?=[A-Z])/).map((w) => w.toLowerCase());
166
165
  const cleanSegments = segments.filter((seg) => {
167
166
  if ((0, path_utils_1.isVariable)(seg))
@@ -169,7 +168,6 @@ function buildMethodName(method, path, groupedPath, usedNames, serviceName) {
169
168
  const segWords = seg.split('-').map((w) => w.toLowerCase());
170
169
  return !segWords.every((sw) => serviceWords.includes(sw));
171
170
  });
172
- // 3. Structural Analysis: Identify resources and variable positioning
173
171
  const staticBefore = [];
174
172
  const variableParts = [];
175
173
  const staticAfter = [];
@@ -187,7 +185,6 @@ function buildMethodName(method, path, groupedPath, usedNames, serviceName) {
187
185
  }
188
186
  }
189
187
  const nameParts = [];
190
- // 4. Logic specific to data fetching (GET)
191
188
  if (method.toLowerCase() === 'get') {
192
189
  nameParts.push('get');
193
190
  if (staticAfter.length > 0) {
@@ -203,22 +200,18 @@ function buildMethodName(method, path, groupedPath, usedNames, serviceName) {
203
200
  nameParts.push('ById');
204
201
  }
205
202
  }
206
- // 5. Logic for state mutation (POST, PUT, PATCH, DELETE)
207
203
  else {
208
204
  const actionParts = [...staticBefore, ...staticAfter];
209
205
  if (actionParts.length > 0) {
210
- // If the path contains an action (e.g., /assign, /send-to-user), use it directly.
211
206
  nameParts.push((0, string_utils_1.toPascalCase)(actionParts));
212
207
  }
213
208
  else {
214
- // No extra segments, use the default verb prefix (e.g., create, update)
215
209
  nameParts.push((0, string_utils_1.upFirst)(defaultVerb));
216
210
  }
217
211
  if (variableParts.length > 0) {
218
212
  nameParts.push('ById');
219
213
  }
220
214
  }
221
- // 6. Pattern-based Refinement: Detect and prioritize standard REST suffixes
222
215
  const normalizedPath = path.toLowerCase();
223
216
  const suffixes = [
224
217
  { pattern: '/all', label: 'All' },
@@ -236,17 +229,13 @@ function buildMethodName(method, path, groupedPath, usedNames, serviceName) {
236
229
  break;
237
230
  }
238
231
  }
239
- // 7. Base candidate assembly
240
232
  let candidateName = (0, string_utils_1.lowerFirst)(nameParts.join(''));
241
- // Simplification for the primary resource GET
242
233
  if (candidateName === 'getById' && !usedNames.includes('get')) {
243
234
  candidateName = 'get';
244
235
  }
245
- // Fallback for empty/ambiguous names
246
236
  if (candidateName === '' || (candidateName === defaultVerb && segments.length > 0)) {
247
237
  candidateName = (0, string_utils_1.lowerFirst)(defaultVerb + (0, string_utils_1.toPascalCase)(segments.map((s) => s.replace(/[{}]/g, ''))));
248
238
  }
249
- // 8. Multi-strategy Collision Resolution
250
239
  let finalName = candidateName;
251
240
  let counter = 0;
252
241
  while (usedNames.includes(finalName)) {
@@ -271,14 +260,26 @@ function buildParameters(operation, pathParameters) {
271
260
  for (const param of allParams) {
272
261
  if ((0, type_guard_1.isReference)(param)) {
273
262
  const ref = param.$ref.split('/').pop();
274
- console.log('🚀 ~ buildParameters ~ ref:', ref);
275
263
  const interfaceData = interface_state_1.interfaceState.getInterface(ref);
276
- console.log('🚀 ~ buildParameters ~ interfaceData:', interfaceData);
264
+ let paramType = interface_state_1.interfaceState.getTypeMapping(ref) || ref;
265
+ let inType = interfaceData?.type !== undefined ? 'query' : 'path';
266
+ let required = true;
267
+ if (param.$ref.includes('/components/parameters/')) {
268
+ const parameters = swagger_state_1.swaggerState.getParameters();
269
+ const parameter = parameters?.[ref];
270
+ if (parameter && !(0, type_guard_1.isReference)(parameter)) {
271
+ inType = parameter.in;
272
+ required = parameter.required ?? false;
273
+ if (parameter.schema) {
274
+ paramType = (0, build_types_1.switchTypeJson)(parameter.schema);
275
+ }
276
+ }
277
+ }
277
278
  results.push({
278
279
  name: (0, string_utils_1.lowerFirst)(ref),
279
- in: interfaceData?.type !== undefined ? 'query' : 'path',
280
- required: true,
281
- type: ref,
280
+ in: inType,
281
+ required,
282
+ type: paramType,
282
283
  });
283
284
  continue;
284
285
  }
@@ -308,21 +309,22 @@ function buildParameters(operation, pathParameters) {
308
309
  type: bodyType,
309
310
  });
310
311
  }
311
- console.log('🚀 ~ buildParameters ~ results:', results);
312
312
  return results;
313
313
  }
314
314
  function buildResponseType(responses) {
315
315
  const success = responses['200'] || responses['201'] || responses['204'] || responses['default'];
316
316
  if (!success)
317
317
  return 'any';
318
- if ((0, type_guard_1.isReference)(success))
319
- return success.$ref.split('/').pop();
318
+ if ((0, type_guard_1.isReference)(success)) {
319
+ const name = success.$ref.split('/').pop();
320
+ return interface_state_1.interfaceState.getTypeMapping(name) || name;
321
+ }
320
322
  const content = success.content?.['application/json'];
321
323
  if (!content || !content.schema)
322
324
  return 'any';
323
325
  return (0, build_types_1.switchTypeJson)(content.schema);
324
326
  }
325
- function buildMethodTemplate(method) {
327
+ function buildMethodTemplate(method, httpParamsHandlerTemplate) {
326
328
  const pathParams = method.parameters.filter((p) => p.in === 'path');
327
329
  const bodyParam = method.parameters.find((p) => p.in === 'body');
328
330
  const methodArgs = [];
@@ -339,10 +341,8 @@ function buildMethodTemplate(method) {
339
341
  .map((s) => ((0, path_utils_1.isVariable)(s) ? `\${${(0, string_utils_1.lowerFirst)(s.replace(/[{}]/g, ''))}}` : s))
340
342
  .join('/');
341
343
  const url = `\`\${this.baseUrl}${pathStr ? '/' + pathStr : ''}\``;
342
- let handler = '';
343
344
  const optionsList = [];
344
345
  if (method.queryParamType) {
345
- handler = `\n\t\t${(0, http_params_handler_1.httpParamsHandler)('queryParams')}`;
346
346
  optionsList.push('params');
347
347
  }
348
348
  if (['Blob', 'File'].includes(method.responseType)) {
@@ -358,8 +358,30 @@ function buildMethodTemplate(method) {
358
358
  : ['post', 'put', 'patch'].includes(method.method)
359
359
  ? `this.http.${method.method}${genericType}(${url}, {}${options})`
360
360
  : `this.http.${method.method}${genericType}(${url}${options})`;
361
- return `${method.comments}
362
- ${method.name}(${argsString}): Observable<${method.responseType}> {${handler}
363
- return ${methodCall};
361
+ let paramsLogic = '';
362
+ if (method.queryParamType) {
363
+ if (httpParamsHandlerTemplate) {
364
+ paramsLogic = `\n ${httpParamsHandlerTemplate.replace('${params}', 'queryParams')}`;
365
+ }
366
+ else {
367
+ paramsLogic = `
368
+ let params = new HttpParams();
369
+ if (queryParams) {
370
+ for (const [key, value] of Object.entries(queryParams)) {
371
+ if (value === undefined || value === null) continue;
372
+ if (Array.isArray(value)) {
373
+ value.forEach((v) => (params = params.append(key, v)));
374
+ } else if (typeof value === 'object' && !(value instanceof Date) && !(value instanceof Blob)) {
375
+ params = params.set(key, JSON.stringify(value));
376
+ } else {
377
+ params = params.set(key, value as any);
378
+ }
379
+ }
380
+ }`;
381
+ }
382
+ }
383
+ return `${method.comments}
384
+ ${method.name}(${argsString}): Observable<${method.responseType}> {${paramsLogic}
385
+ return ${methodCall};
364
386
  }`;
365
387
  }
@@ -7,12 +7,8 @@ export interface AngularServiceTemplate {
7
7
  methods: string;
8
8
  imports: string;
9
9
  hasHttpParamsHandler: boolean;
10
- }
11
- export interface AngularServiceResult {
12
- forTemplate: AngularServiceTemplate[];
13
- parametersTypes: Record<string, {
14
- method: string;
15
- parameterType: string;
16
- }>;
10
+ configImports?: string[];
11
+ httpParamsHandler?: string;
12
+ httpParamsHandlerImport?: string;
17
13
  }
18
14
  export declare const angularTemplate: (params: AngularServiceTemplate) => string;
@@ -1,14 +1,22 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.angularTemplate = void 0;
4
- const http_params_handler_1 = require("./http-params-handler");
5
4
  const angularTemplate = (params) => {
5
+ const configImports = params.configImports
6
+ ? params.configImports.map((i) => `import { ${i} } from '@angular/core';`).join('\n') // Placeholder logic, actual imports might be more complex
7
+ : '';
8
+ // Actually, let's keep it simple. The config imports should probably be raw strings or structured.
9
+ // For now, let's assume the template receives the RAW import strings from the config if provided,
10
+ // OR we construct them here.
11
+ // User wants: "can make it so it can work without any custom template (just the most generic one)"
12
+ // and "make it so it works with a JSON configuration".
13
+ const httpParamsHandlerImport = params.httpParamsHandlerImport || '';
6
14
  return `
7
15
  import { HttpClient } from "@angular/common/http";
8
16
  import { Observable } from "rxjs";
9
17
  import { inject, Injectable } from '@angular/core';
10
18
  import { ${params.imports} } from '../models';
11
- ${params.hasHttpParamsHandler ? (0, http_params_handler_1.httpParamsHandlerImport)() : ''}
19
+ ${httpParamsHandlerImport}
12
20
 
13
21
  @Injectable({
14
22
  providedIn: "root"
@@ -0,0 +1,22 @@
1
+ import { ServiceTemplateParams } from './template';
2
+ import { InterfaceData } from './interface-data';
3
+ export interface SwaggularConfig {
4
+ types?: {
5
+ extendsFrom?: InterfaceData[];
6
+ generic?: InterfaceData[];
7
+ };
8
+ templates?: {
9
+ service?: {
10
+ path: string;
11
+ options?: Partial<ServiceTemplateParams>;
12
+ transform?: (options: ServiceTemplateParams) => string;
13
+ content?: string;
14
+ httpParamsHandler?: string;
15
+ httpParamsHandlerImport?: string;
16
+ };
17
+ };
18
+ input?: string;
19
+ output?: string;
20
+ groupingMode?: 'tags' | 'path';
21
+ segmentsToIgnore?: string[];
22
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,11 +1,14 @@
1
+ import { SwaggularConfig } from './config';
1
2
  export type ParsedArgs = {
2
3
  args: Record<string, string | boolean>;
3
4
  positional: string[];
4
5
  };
5
6
  export interface ArgsVariables {
6
- groupingMode: 'tags' | 'path';
7
- segmentsToIgnore: string[];
8
7
  input: string;
9
8
  output: string;
10
9
  noGenerate: boolean;
10
+ groupingMode: 'tags' | 'path';
11
+ segmentsToIgnore: string[];
12
+ templates?: SwaggularConfig['templates'];
13
+ types?: SwaggularConfig['types'];
11
14
  }
@@ -0,0 +1,11 @@
1
+ export interface ServiceTemplateParams {
2
+ name: string;
3
+ baseUrl: string;
4
+ methods: string;
5
+ imports: string;
6
+ hasHttpParamsHandler: boolean;
7
+ httpParamsHandler?: string;
8
+ httpParamsHandlerImport?: string;
9
+ modelImports?: string;
10
+ extraAngularImports?: string;
11
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.buildTypes = buildTypes;
4
4
  exports.switchTypeJson = switchTypeJson;
5
+ const interface_state_1 = require("../core/state/interface-state");
5
6
  function buildTypes(masterSchema, defaultType = 'any') {
6
7
  if (!masterSchema)
7
8
  return defaultType;
@@ -18,12 +19,8 @@ function buildTypes(masterSchema, defaultType = 'any') {
18
19
  return defaultType;
19
20
  const ref = schema?.['$ref'];
20
21
  if (ref) {
21
- const iface = ref.split('/').pop();
22
- const isPagedResultDto = iface.endsWith('PagedResultDto');
23
- if (isPagedResultDto) {
24
- return `PagedResultDto<${iface.replace('PagedResultDto', '')}>`;
25
- }
26
- return iface;
22
+ const name = ref.split('/').pop();
23
+ return interface_state_1.interfaceState.getTypeMapping(name) || name;
27
24
  }
28
25
  return switchTypeJson(schema);
29
26
  }
@@ -34,12 +31,8 @@ function switchTypeJson(schema) {
34
31
  const type = schema?.['type'];
35
32
  const format = schema?.['format'];
36
33
  if (ref) {
37
- const iface = ref.split('/').pop();
38
- const isPagedResultDto = iface.endsWith('PagedResultDto');
39
- if (isPagedResultDto) {
40
- return `PagedResultDto<${iface.replace('PagedResultDto', '')}>`;
41
- }
42
- return iface;
34
+ const name = ref.split('/').pop();
35
+ return interface_state_1.interfaceState.getTypeMapping(name) || name;
43
36
  }
44
37
  if (type === 'object') {
45
38
  return 'any';
@@ -0,0 +1,2 @@
1
+ import { SwaggularConfig } from '../types/config';
2
+ export declare function loadConfig(configPath?: string): SwaggularConfig;
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.loadConfig = loadConfig;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ function loadConfig(configPath) {
40
+ const defaultConfigPath = 'swaggular.config.json';
41
+ const resolvedPath = path.resolve(configPath || defaultConfigPath);
42
+ if (fs.existsSync(resolvedPath)) {
43
+ try {
44
+ const fileContent = fs.readFileSync(resolvedPath, 'utf-8');
45
+ return JSON.parse(fileContent);
46
+ }
47
+ catch (error) {
48
+ console.error(`Error parsing config file at ${resolvedPath}:`, error);
49
+ return {};
50
+ }
51
+ }
52
+ return {};
53
+ }
@@ -0,0 +1 @@
1
+ export declare function computeLocations(): Record<string, string[]>;
@@ -0,0 +1,137 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.computeLocations = computeLocations;
4
+ const swagger_state_1 = require("../core/state/swagger-state");
5
+ const string_utils_1 = require("./string-utils");
6
+ const path_utils_1 = require("./path-utils");
7
+ function computeLocations() {
8
+ const swagger = swagger_state_1.swaggerState.getSwagger();
9
+ const groupedPaths = swagger_state_1.swaggerState.getPathsGroupedByScope();
10
+ const locations = {};
11
+ if (!swagger || !swagger.paths) {
12
+ return locations;
13
+ }
14
+ const processSchema = (dtoName, location) => {
15
+ if (locations[dtoName])
16
+ return;
17
+ if (isEnum(dtoName))
18
+ return;
19
+ locations[dtoName] = location;
20
+ const schemas = swagger_state_1.swaggerState.getSchemas();
21
+ if (!schemas || !schemas[dtoName])
22
+ return;
23
+ const schema = schemas[dtoName];
24
+ const refs = getReferences(schema);
25
+ for (const ref of refs) {
26
+ const childName = ref.split('/').pop();
27
+ if (childName) {
28
+ processSchema(childName, location);
29
+ }
30
+ }
31
+ };
32
+ if (groupedPaths) {
33
+ for (const [groupName, group] of Object.entries(groupedPaths)) {
34
+ if (group.baseSegments && group.baseSegments.length > 0) {
35
+ const folder = (0, string_utils_1.toKebabCase)(group.baseSegments[0]);
36
+ if (!locations[groupName]) {
37
+ locations[groupName] = [folder];
38
+ }
39
+ }
40
+ }
41
+ }
42
+ // 1. Map Generated Parameter Interfaces
43
+ if (groupedPaths) {
44
+ for (const groupedPath of Object.values(groupedPaths)) {
45
+ for (const innerPath of groupedPath.paths) {
46
+ const pathInfo = swagger.paths[innerPath];
47
+ if (!pathInfo)
48
+ continue;
49
+ const methods = ['get', 'post', 'put', 'delete', 'patch'];
50
+ for (const method of methods) {
51
+ const operation = pathInfo[method];
52
+ if (!operation)
53
+ continue;
54
+ // Check if parameters exist (similar condition to generate-interface)
55
+ if (operation.parameters && operation.parameters.length > 0) {
56
+ const interfaceName = (0, path_utils_1.computeParametersName)(method, innerPath, groupedPath);
57
+ if (operation.tags && operation.tags.length > 0) {
58
+ const tag = operation.tags[0];
59
+ const folder = (0, string_utils_1.toKebabCase)(tag);
60
+ if (!locations[interfaceName]) {
61
+ locations[interfaceName] = [folder];
62
+ }
63
+ }
64
+ }
65
+ }
66
+ }
67
+ }
68
+ }
69
+ // 2. Map DTOs and Services
70
+ for (const pathItem of Object.values(swagger.paths)) {
71
+ if (!pathItem)
72
+ continue;
73
+ const operations = [
74
+ pathItem.get,
75
+ pathItem.put,
76
+ pathItem.post,
77
+ pathItem.delete,
78
+ pathItem.options,
79
+ pathItem.head,
80
+ pathItem.patch,
81
+ pathItem.trace,
82
+ ];
83
+ for (const operation of operations) {
84
+ if (!operation || !operation.tags || operation.tags.length === 0) {
85
+ continue;
86
+ }
87
+ const tag = operation.tags[0];
88
+ const folder = (0, string_utils_1.toKebabCase)(tag);
89
+ const location = [folder];
90
+ // Map Service (Tag) to location
91
+ if (!locations[tag]) {
92
+ locations[tag] = location;
93
+ }
94
+ // Map DTOs used in this operation
95
+ const refs = getReferences(operation);
96
+ for (const ref of refs) {
97
+ const dtoName = ref.split('/').pop();
98
+ if (dtoName) {
99
+ processSchema(dtoName, location);
100
+ }
101
+ }
102
+ }
103
+ }
104
+ return locations;
105
+ }
106
+ function isEnum(name) {
107
+ const schemas = swagger_state_1.swaggerState.getSchemas();
108
+ if (!schemas)
109
+ return false;
110
+ const schema = schemas[name];
111
+ if (!schema)
112
+ return false;
113
+ if ('$ref' in schema)
114
+ return false;
115
+ return !!schema.enum;
116
+ }
117
+ function getReferences(obj) {
118
+ const refs = [];
119
+ if (!obj || typeof obj !== 'object') {
120
+ return refs;
121
+ }
122
+ if (Array.isArray(obj)) {
123
+ for (const item of obj) {
124
+ refs.push(...getReferences(item));
125
+ }
126
+ return refs;
127
+ }
128
+ for (const key of Object.keys(obj)) {
129
+ if (key === '$ref' && typeof obj[key] === 'string') {
130
+ refs.push(obj[key]);
131
+ }
132
+ else {
133
+ refs.push(...getReferences(obj[key]));
134
+ }
135
+ }
136
+ return refs;
137
+ }
@@ -1,6 +1,8 @@
1
+ import { GroupedPath } from '../types/grouped-paths';
1
2
  export declare function isVariable(segment: string): boolean;
2
3
  export declare function getExtraSegments(fullPath: string, baseUrl: string): string[];
3
4
  export declare function removeVariablesFromPath(path: string): string;
4
5
  export declare function createBaseUrl(baseSegments: string[]): string;
5
6
  export declare function findCommonBaseUrl(paths: string[]): string;
6
7
  export declare function standarizedPath(path: string): string;
8
+ export declare function computeParametersName(method: string, innerPath: string, groupedPath: GroupedPath): string;
@@ -6,6 +6,8 @@ exports.removeVariablesFromPath = removeVariablesFromPath;
6
6
  exports.createBaseUrl = createBaseUrl;
7
7
  exports.findCommonBaseUrl = findCommonBaseUrl;
8
8
  exports.standarizedPath = standarizedPath;
9
+ exports.computeParametersName = computeParametersName;
10
+ const string_utils_1 = require("./string-utils");
9
11
  function isVariable(segment) {
10
12
  return /^\{.+\}$/.test(segment);
11
13
  }
@@ -63,3 +65,21 @@ function standarizedPath(path) {
63
65
  const filtered = splitted.filter((p) => p !== '').map((p) => p.toLowerCase());
64
66
  return filtered.join('/');
65
67
  }
68
+ function computeParametersName(method, innerPath, groupedPath) {
69
+ const dict = {
70
+ get: '',
71
+ post: 'Create',
72
+ put: 'Update',
73
+ delete: 'Delete',
74
+ patch: 'Patch',
75
+ };
76
+ const name = dict[method];
77
+ const extra = (0, string_utils_1.kebabToPascalCase)(removeVariablesFromPath(getExtraSegments(innerPath, createBaseUrl(groupedPath.baseSegments)).join('')));
78
+ // Avoid duplication if extra starts with groupName
79
+ let suffix = extra;
80
+ const groupName = groupedPath.groupName;
81
+ if (suffix.startsWith(groupName)) {
82
+ suffix = suffix.substring(groupName.length);
83
+ }
84
+ return name + groupName + (0, string_utils_1.upFirst)(suffix) + 'Params';
85
+ }
@@ -1,9 +1,4 @@
1
1
  export declare function kebabToCamelCase(str: string): string;
2
- /**
3
- *
4
- * @param str :
5
- * @returns
6
- */
7
2
  export declare function kebabToPascalCase(str: string): string;
8
3
  export declare function removeAllWhitespace(text: string): string;
9
4
  export declare function lowerFirst(str: string): string;
@@ -11,11 +11,6 @@ exports.toPascalCase = toPascalCase;
11
11
  function kebabToCamelCase(str) {
12
12
  return str.replace(/-([a-z])/g, (_, char) => char.toUpperCase());
13
13
  }
14
- /**
15
- *
16
- * @param str :
17
- * @returns
18
- */
19
14
  function kebabToPascalCase(str) {
20
15
  const camel = str.replace(/-([a-z])/g, (_, char) => char.toUpperCase());
21
16
  return camel.charAt(0).toUpperCase() + camel.slice(1);
@@ -0,0 +1,2 @@
1
+ import { ServiceTemplateParams } from '../types/template';
2
+ export declare function renderServiceTemplate(templatePath: string, params: ServiceTemplateParams): string;
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.renderServiceTemplate = renderServiceTemplate;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ function renderServiceTemplate(templatePath, params) {
40
+ // 1. Read the template file
41
+ const absolutePath = path.resolve(templatePath);
42
+ let templateContent;
43
+ try {
44
+ if (fs.existsSync(absolutePath)) {
45
+ templateContent = fs.readFileSync(absolutePath, 'utf-8');
46
+ }
47
+ else {
48
+ console.error(`Template file not found at ${absolutePath}`);
49
+ return '';
50
+ }
51
+ }
52
+ catch (err) {
53
+ console.error(`Error reading template file at ${absolutePath}`, err);
54
+ return '';
55
+ }
56
+ // 2. Perform replacements
57
+ // Simple mustache-like replacement: {{variable}}
58
+ // We can use a regex or simple replaceAll if available (Node 15+) or split/join.
59
+ let result = templateContent;
60
+ // Replace known params
61
+ result = result.replace(/{{name}}/g, params.name);
62
+ result = result.replace(/{{baseUrl}}/g, params.baseUrl);
63
+ result = result.replace(/{{methods}}/g, params.methods);
64
+ result = result.replace(/{{modelImports}}/g, params.modelImports || '');
65
+ result = result.replace(/{{imports}}/g, params.imports);
66
+ // Handle conditional logic for httpParamsHandlerImport
67
+ result = result.replace(/{{httpParamsHandlerImport}}/g, params.httpParamsHandlerImport || '');
68
+ result = result.replace(/{{extraAngularImports}}/g, params.extraAngularImports || '');
69
+ // Cleanup excessive newlines (3 or more, potentially with spaces) to just 2
70
+ result = result.replace(/(\r?\n\s*){3,}/g, '\n\n');
71
+ return result;
72
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "swaggular",
3
- "version": "0.3.0",
3
+ "version": "0.6.1",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "bin": {