@dorval/custom 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,24 @@
1
+ import { ClientGeneratorBuilder, ClientBuilder, ClientHeaderBuilder, ClientDependenciesBuilder, ClientFooterBuilder } from '@dorval/core';
2
+
3
+ /**
4
+ * Generate custom client builder with service registration
5
+ */
6
+ declare const generateCustomClient: ClientBuilder;
7
+ /**
8
+ * Generate enhanced custom client header
9
+ */
10
+ declare const generateCustomHeader: ClientHeaderBuilder;
11
+ /**
12
+ * Get custom client dependencies
13
+ */
14
+ declare const getCustomDependencies: ClientDependenciesBuilder;
15
+ /**
16
+ * Generate custom client footer
17
+ */
18
+ declare const generateCustomFooter: ClientFooterBuilder;
19
+ /**
20
+ * Builder factory function (following Orval pattern)
21
+ */
22
+ declare const builder: () => () => ClientGeneratorBuilder;
23
+
24
+ export { builder, builder as default, generateCustomClient, generateCustomFooter, generateCustomHeader, getCustomDependencies };
package/dist/index.js ADDED
@@ -0,0 +1,143 @@
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/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ builder: () => builder,
24
+ default: () => index_default,
25
+ generateCustomClient: () => generateCustomClient,
26
+ generateCustomFooter: () => generateCustomFooter,
27
+ generateCustomHeader: () => generateCustomHeader,
28
+ getCustomDependencies: () => getCustomDependencies
29
+ });
30
+ module.exports = __toCommonJS(index_exports);
31
+ var generateCustomImplementation = ({
32
+ verb,
33
+ route,
34
+ operationName,
35
+ response,
36
+ body,
37
+ headers,
38
+ queryParams,
39
+ pathParams,
40
+ props,
41
+ mutator,
42
+ override
43
+ }, { output }) => {
44
+ const httpMethod = verb.toLowerCase();
45
+ const hasBody = ["post", "put", "patch"].includes(httpMethod) && body;
46
+ const hasQueryParams = !!queryParams;
47
+ const hasHeaders = !!headers;
48
+ const hasPathParams = pathParams && pathParams.length > 0;
49
+ let pathConstruction = hasPathParams ? `final path = '${route}'${pathParams.map((p) => `.replaceAll('{${p.name}}', ${p.dartName}.toString())`).join("")};` : `const path = '${route}';`;
50
+ let queryParamsConstruction = "";
51
+ if (hasQueryParams) {
52
+ queryParamsConstruction = `
53
+ final queryParameters = <String, dynamic>{
54
+ ${queryParams.map((q) => `if (${q.dartName} != null) '${q.name}': ${q.dartName},`).join("\n ")}
55
+ };`;
56
+ }
57
+ let headersConstruction = "";
58
+ if (hasHeaders) {
59
+ headersConstruction = `
60
+ final requestHeaders = <String, String>{
61
+ ${headers.map((h) => `if (${h.dartName} != null) '${h.name}': ${h.dartName}.toString(),`).join("\n ")}
62
+ };`;
63
+ }
64
+ let responseHandling = "";
65
+ if (response.isVoid) {
66
+ responseHandling = "return;";
67
+ } else if (response.isList) {
68
+ responseHandling = `
69
+ return (response.data as List<dynamic>)
70
+ .map((item) => ${response.itemType}.fromJson(item as Map<String, dynamic>))
71
+ .toList();`;
72
+ } else if (response.isModel) {
73
+ responseHandling = `
74
+ return ${response.type}.fromJson(response.data as Map<String, dynamic>);`;
75
+ } else if (response.isPrimitive) {
76
+ responseHandling = `
77
+ return response.data as ${response.type};`;
78
+ } else {
79
+ responseHandling = `
80
+ return response.data;`;
81
+ }
82
+ return `
83
+ Future<${response.dartType}> ${operationName}(${props.map((p) => `${p.type} ${p.name}`).join(", ")}) async {
84
+ ${pathConstruction}
85
+ ${queryParamsConstruction}
86
+ ${headersConstruction}
87
+
88
+ try {
89
+ final response = await client.${httpMethod}(
90
+ path,${hasBody ? `
91
+ data: ${body.dartName}${body.isModel ? ".toJson()" : ""},` : ""}${hasQueryParams ? `
92
+ queryParameters: queryParameters,` : ""}${hasHeaders ? `
93
+ options: Options(headers: requestHeaders),` : ""}
94
+ );
95
+
96
+ ${responseHandling}
97
+ } on DioException catch (e) {
98
+ throw ApiException(
99
+ statusCode: e.response?.statusCode,
100
+ message: e.message ?? 'Unknown error occurred',
101
+ error: e,
102
+ );
103
+ }
104
+ }`;
105
+ };
106
+ var generateCustomClient = (verbOptions, options) => {
107
+ const implementation = generateCustomImplementation(verbOptions, options);
108
+ const imports = [
109
+ "import 'package:dio/dio.dart';",
110
+ "import '../api_client.dart';",
111
+ "import 'api_exception.dart';",
112
+ "import '../models/index.dart';"
113
+ ];
114
+ return { implementation, imports };
115
+ };
116
+ var generateCustomHeader = ({ title, isMutator }) => {
117
+ return `
118
+ /// ${title ? `${title} - ` : ""}Service with enhanced custom client
119
+ /// This service uses the enhanced API client with service registration pattern
120
+ `;
121
+ };
122
+ var getCustomDependencies = () => {
123
+ return [];
124
+ };
125
+ var generateCustomFooter = () => {
126
+ return "";
127
+ };
128
+ var customClientBuilder = {
129
+ client: generateCustomClient,
130
+ header: generateCustomHeader,
131
+ dependencies: getCustomDependencies,
132
+ footer: generateCustomFooter
133
+ };
134
+ var builder = () => () => customClientBuilder;
135
+ var index_default = builder;
136
+ // Annotate the CommonJS export names for ESM import in node:
137
+ 0 && (module.exports = {
138
+ builder,
139
+ generateCustomClient,
140
+ generateCustomFooter,
141
+ generateCustomHeader,
142
+ getCustomDependencies
143
+ });
package/package.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "@dorval/custom",
3
+ "version": "0.2.1",
4
+ "description": "Custom client implementation for Dorval",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "scripts": {
8
+ "build": "tsup src/index.ts --dts",
9
+ "dev": "tsup src/index.ts --dts --watch",
10
+ "test": "vitest run"
11
+ },
12
+ "dependencies": {
13
+ "@dorval/core": "*"
14
+ },
15
+ "devDependencies": {
16
+ "tsup": "^8.0.1",
17
+ "typescript": "^5.3.3",
18
+ "vitest": "^0.6.3"
19
+ },
20
+ "peerDependencies": {
21
+ "@dorval/core": "*"
22
+ }
23
+ }
@@ -0,0 +1,18 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { generateCustomClient } from './index';
3
+
4
+ describe('@dorval/custom', () => {
5
+ it('should export generateCustomClient function', () => {
6
+ expect(generateCustomClient).toBeDefined();
7
+ expect(typeof generateCustomClient).toBe('function');
8
+ });
9
+
10
+ it('should be a client builder function', () => {
11
+ // generateCustomClient is a ClientGeneratorBuilder function
12
+ // It returns a builder that will be called by the core generator
13
+ const builder = generateCustomClient;
14
+ expect(builder).toBeDefined();
15
+ expect(typeof builder).toBe('function');
16
+ expect(builder.name).toBe('generateCustomClient');
17
+ });
18
+ });
package/src/index.ts ADDED
@@ -0,0 +1,166 @@
1
+ import {
2
+ ClientBuilder,
3
+ ClientGeneratorBuilder,
4
+ ClientHeaderBuilder,
5
+ ClientDependenciesBuilder,
6
+ ClientFooterBuilder,
7
+ GeneratorVerbOptions,
8
+ GeneratorOptions,
9
+ GeneratorDependency,
10
+ } from '@dorval/core';
11
+
12
+ /**
13
+ * Generate enhanced custom client implementation
14
+ * This creates a client with service registration pattern like Supabase/Firebase
15
+ */
16
+ const generateCustomImplementation = (
17
+ {
18
+ verb,
19
+ route,
20
+ operationName,
21
+ response,
22
+ body,
23
+ headers,
24
+ queryParams,
25
+ pathParams,
26
+ props,
27
+ mutator,
28
+ override,
29
+ }: GeneratorVerbOptions,
30
+ { output }: GeneratorOptions,
31
+ ): string => {
32
+ const httpMethod = verb.toLowerCase();
33
+ const hasBody = ['post', 'put', 'patch'].includes(httpMethod) && body;
34
+ const hasQueryParams = !!queryParams;
35
+ const hasHeaders = !!headers;
36
+ const hasPathParams = pathParams && pathParams.length > 0;
37
+
38
+ // Build path with parameters
39
+ let pathConstruction = hasPathParams
40
+ ? `final path = '${route}'${pathParams.map((p: any) => `.replaceAll('{${p.name}}', ${p.dartName}.toString())`).join('')};`
41
+ : `const path = '${route}';`;
42
+
43
+ // Build query parameters
44
+ let queryParamsConstruction = '';
45
+ if (hasQueryParams) {
46
+ queryParamsConstruction = `
47
+ final queryParameters = <String, dynamic>{
48
+ ${queryParams.map((q: any) => `if (${q.dartName} != null) '${q.name}': ${q.dartName},`).join('\n ')}
49
+ };`;
50
+ }
51
+
52
+ // Build headers
53
+ let headersConstruction = '';
54
+ if (hasHeaders) {
55
+ headersConstruction = `
56
+ final requestHeaders = <String, String>{
57
+ ${headers.map((h: any) => `if (${h.dartName} != null) '${h.name}': ${h.dartName}.toString(),`).join('\n ')}
58
+ };`;
59
+ }
60
+
61
+ // Build response handling
62
+ let responseHandling = '';
63
+ if (response.isVoid) {
64
+ responseHandling = 'return;';
65
+ } else if (response.isList) {
66
+ responseHandling = `
67
+ return (response.data as List<dynamic>)
68
+ .map((item) => ${response.itemType}.fromJson(item as Map<String, dynamic>))
69
+ .toList();`;
70
+ } else if (response.isModel) {
71
+ responseHandling = `
72
+ return ${response.type}.fromJson(response.data as Map<String, dynamic>);`;
73
+ } else if (response.isPrimitive) {
74
+ responseHandling = `
75
+ return response.data as ${response.type};`;
76
+ } else {
77
+ responseHandling = `
78
+ return response.data;`;
79
+ }
80
+
81
+ // Build complete implementation using the enhanced client
82
+ return `
83
+ Future<${response.dartType}> ${operationName}(${props.map((p: any) => `${p.type} ${p.name}`).join(', ')}) async {
84
+ ${pathConstruction}
85
+ ${queryParamsConstruction}
86
+ ${headersConstruction}
87
+
88
+ try {
89
+ final response = await client.${httpMethod}(
90
+ path,${hasBody ? `
91
+ data: ${body.dartName}${body.isModel ? '.toJson()' : ''},` : ''}${hasQueryParams ? `
92
+ queryParameters: queryParameters,` : ''}${hasHeaders ? `
93
+ options: Options(headers: requestHeaders),` : ''}
94
+ );
95
+
96
+ ${responseHandling}
97
+ } on DioException catch (e) {
98
+ throw ApiException(
99
+ statusCode: e.response?.statusCode,
100
+ message: e.message ?? 'Unknown error occurred',
101
+ error: e,
102
+ );
103
+ }
104
+ }`;
105
+ };
106
+
107
+ /**
108
+ * Generate custom client builder with service registration
109
+ */
110
+ export const generateCustomClient: ClientBuilder = (
111
+ verbOptions: GeneratorVerbOptions,
112
+ options: GeneratorOptions,
113
+ ) => {
114
+ const implementation = generateCustomImplementation(verbOptions, options);
115
+
116
+ const imports = [
117
+ "import 'package:dio/dio.dart';",
118
+ "import '../api_client.dart';",
119
+ "import 'api_exception.dart';",
120
+ "import '../models/index.dart';",
121
+ ];
122
+
123
+ return { implementation, imports };
124
+ };
125
+
126
+ /**
127
+ * Generate enhanced custom client header
128
+ */
129
+ export const generateCustomHeader: ClientHeaderBuilder = ({ title, isMutator }) => {
130
+ return `
131
+ /// ${title ? `${title} - ` : ''}Service with enhanced custom client
132
+ /// This service uses the enhanced API client with service registration pattern
133
+ `;
134
+ };
135
+
136
+ /**
137
+ * Get custom client dependencies
138
+ */
139
+ export const getCustomDependencies: ClientDependenciesBuilder = () => {
140
+ return []; // Dependencies are managed by the user's custom client
141
+ };
142
+
143
+ /**
144
+ * Generate custom client footer
145
+ */
146
+ export const generateCustomFooter: ClientFooterBuilder = () => {
147
+ return '';
148
+ };
149
+
150
+
151
+ /**
152
+ * Custom client builder configuration
153
+ */
154
+ const customClientBuilder: ClientGeneratorBuilder = {
155
+ client: generateCustomClient,
156
+ header: generateCustomHeader,
157
+ dependencies: getCustomDependencies,
158
+ footer: generateCustomFooter,
159
+ };
160
+
161
+ /**
162
+ * Builder factory function (following Orval pattern)
163
+ */
164
+ export const builder = () => () => customClientBuilder;
165
+
166
+ export default builder;
package/tsconfig.json ADDED
@@ -0,0 +1,12 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "outDir": "./dist",
5
+ "rootDir": "./src",
6
+ "composite": false,
7
+ "declaration": true
8
+ },
9
+ "include": ["src/**/*"],
10
+ "exclude": ["node_modules", "dist", "**/*.test.ts"],
11
+ "references": []
12
+ }