@dinoconfig/cli 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -0
- package/LICENSE +21 -0
- package/README.md +157 -0
- package/bin/codegen.d.ts +13 -0
- package/bin/codegen.d.ts.map +1 -0
- package/bin/codegen.js +95 -0
- package/bin/dinoconfig.d.ts +11 -0
- package/bin/dinoconfig.d.ts.map +1 -0
- package/bin/dinoconfig.js +55 -0
- package/bin/javagen.d.ts +12 -0
- package/bin/javagen.d.ts.map +1 -0
- package/bin/javagen.js +123 -0
- package/codegen-DZxM8r9k.js +1622 -0
- package/constants-Dvwyqn-J.js +9 -0
- package/index.d.ts +26 -0
- package/index.d.ts.map +1 -0
- package/index.js +17 -0
- package/lib/codegen.d.ts +117 -0
- package/lib/codegen.d.ts.map +1 -0
- package/lib/constants.d.ts +17 -0
- package/lib/constants.d.ts.map +1 -0
- package/lib/dependency-updater.d.ts +65 -0
- package/lib/dependency-updater.d.ts.map +1 -0
- package/lib/java-model-generator.d.ts +73 -0
- package/lib/java-model-generator.d.ts.map +1 -0
- package/lib/type-generator.d.ts +28 -0
- package/lib/type-generator.d.ts.map +1 -0
- package/package.json +87 -0
|
@@ -0,0 +1,1622 @@
|
|
|
1
|
+
import { b as T, C as v, a as j, D as A, c as z } from "./constants-Dvwyqn-J.js";
|
|
2
|
+
import * as f from "fs";
|
|
3
|
+
import * as p from "path";
|
|
4
|
+
class R {
|
|
5
|
+
/**
|
|
6
|
+
* Creates a new HttpClient instance.
|
|
7
|
+
*
|
|
8
|
+
* @param {string} baseUrl - The base URL of the DinoConfig API
|
|
9
|
+
* @param {number} [timeout=10000] - Default request timeout in milliseconds
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* const client = new HttpClient('https://api.dinoconfig.com', 15000);
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
constructor(e, t = 1e4) {
|
|
17
|
+
this.baseUrl = e.replace(/\/$/, ""), this.defaultTimeout = t;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Configures authorization by exchanging the API key for an access token.
|
|
21
|
+
*
|
|
22
|
+
* This method:
|
|
23
|
+
* 1. Extracts the API key from the provided headers
|
|
24
|
+
* 2. Exchanges it for a JWT access token
|
|
25
|
+
* 3. Configures the Authorization header for subsequent requests
|
|
26
|
+
*
|
|
27
|
+
* @async
|
|
28
|
+
* @method configureAuthorizationHeader
|
|
29
|
+
* @param {Record<string, string>} headers - Headers containing the X-API-Key
|
|
30
|
+
* @returns {Promise<void>}
|
|
31
|
+
* @throws {Error} If token exchange fails
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```typescript
|
|
35
|
+
* await client.configureAuthorizationHeader({
|
|
36
|
+
* 'X-API-Key': 'dino_your-api-key-here'
|
|
37
|
+
* });
|
|
38
|
+
* // Client is now authenticated
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
async configureAuthorizationHeader(e) {
|
|
42
|
+
const t = e["X-API-Key"], s = await this.exchangeApiKeyForToken(t);
|
|
43
|
+
this.defaultHeaders = {
|
|
44
|
+
"Content-Type": "application/json",
|
|
45
|
+
Authorization: `Bearer ${s}`,
|
|
46
|
+
...e
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Exchanges an API key for a JWT access token.
|
|
51
|
+
*
|
|
52
|
+
* Makes a POST request to the token exchange endpoint with the API key
|
|
53
|
+
* and returns the access token from the response.
|
|
54
|
+
*
|
|
55
|
+
* @async
|
|
56
|
+
* @private
|
|
57
|
+
* @method exchangeApiKeyForToken
|
|
58
|
+
* @param {string} apiKey - The API key to exchange
|
|
59
|
+
* @returns {Promise<string>} The JWT access token
|
|
60
|
+
* @throws {Error} If the exchange fails or the API key is invalid
|
|
61
|
+
*
|
|
62
|
+
* @remarks
|
|
63
|
+
* The API key is sent via HTTPS, which encrypts it in transit.
|
|
64
|
+
* The server validates the key and returns a short-lived access token.
|
|
65
|
+
*/
|
|
66
|
+
async exchangeApiKeyForToken(e) {
|
|
67
|
+
try {
|
|
68
|
+
const t = await fetch(`${this.baseUrl}/api/auth/sdk-token/exchange`, {
|
|
69
|
+
method: "POST",
|
|
70
|
+
headers: {
|
|
71
|
+
"Content-Type": "application/json",
|
|
72
|
+
"x-api-key": e
|
|
73
|
+
},
|
|
74
|
+
credentials: "include"
|
|
75
|
+
});
|
|
76
|
+
if (!t.ok) {
|
|
77
|
+
const n = await t.text();
|
|
78
|
+
throw new Error(`Failed to exchange API key for token: ${t.status} ${n}`);
|
|
79
|
+
}
|
|
80
|
+
return (await t.json()).access_token;
|
|
81
|
+
} catch (t) {
|
|
82
|
+
const s = t instanceof Error ? t.message : "Unknown error";
|
|
83
|
+
throw new Error(`Failed to authenticate with API key: ${s}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Makes an HTTP request to the API.
|
|
88
|
+
*
|
|
89
|
+
* Handles:
|
|
90
|
+
* - Request formatting and headers
|
|
91
|
+
* - Timeout via AbortController
|
|
92
|
+
* - Response parsing
|
|
93
|
+
* - Error handling
|
|
94
|
+
* - Retry logic with exponential backoff
|
|
95
|
+
*
|
|
96
|
+
* @async
|
|
97
|
+
* @private
|
|
98
|
+
* @method request
|
|
99
|
+
* @typeParam T - The expected response data type
|
|
100
|
+
* @param {string} method - HTTP method (GET, POST, PUT, PATCH, DELETE)
|
|
101
|
+
* @param {string} endpoint - API endpoint path (e.g., '/api/configs')
|
|
102
|
+
* @param {any} [data] - Request body data (for POST, PUT, PATCH)
|
|
103
|
+
* @param {RequestOptions} [options={}] - Request customization options
|
|
104
|
+
* @returns {Promise<ApiResponse<T>>} The API response
|
|
105
|
+
* @throws {ApiError} If the request fails after all retries
|
|
106
|
+
*/
|
|
107
|
+
async request(e, t, s, n = {}) {
|
|
108
|
+
const a = `${this.baseUrl}${t}`, r = n.timeout || this.defaultTimeout, o = n.retries || 0;
|
|
109
|
+
let l = null;
|
|
110
|
+
for (let c = 0; c <= o; c++)
|
|
111
|
+
try {
|
|
112
|
+
const u = new AbortController(), h = setTimeout(() => u.abort(), r), d = {
|
|
113
|
+
method: e,
|
|
114
|
+
headers: this.defaultHeaders,
|
|
115
|
+
signal: u.signal
|
|
116
|
+
};
|
|
117
|
+
s && (e === "POST" || e === "PUT" || e === "PATCH") && (d.body = JSON.stringify(s));
|
|
118
|
+
const m = await fetch(a, d);
|
|
119
|
+
clearTimeout(h);
|
|
120
|
+
const y = await m.json();
|
|
121
|
+
if (!m.ok)
|
|
122
|
+
throw {
|
|
123
|
+
message: y.message || m.statusText,
|
|
124
|
+
status: m.status,
|
|
125
|
+
code: y.code
|
|
126
|
+
};
|
|
127
|
+
return {
|
|
128
|
+
data: y,
|
|
129
|
+
success: !0
|
|
130
|
+
};
|
|
131
|
+
} catch (u) {
|
|
132
|
+
if (l = u, u instanceof Error && "status" in u) {
|
|
133
|
+
const h = u;
|
|
134
|
+
if (h.status >= 400 && h.status < 500)
|
|
135
|
+
throw u;
|
|
136
|
+
}
|
|
137
|
+
if (c === o)
|
|
138
|
+
throw u;
|
|
139
|
+
await new Promise((h) => setTimeout(h, Math.pow(2, c) * 1e3));
|
|
140
|
+
}
|
|
141
|
+
throw l || new Error("Request failed after all retries");
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Makes a GET request to the specified endpoint.
|
|
145
|
+
*
|
|
146
|
+
* @async
|
|
147
|
+
* @method get
|
|
148
|
+
* @typeParam T - The expected response data type
|
|
149
|
+
* @param {string} endpoint - The API endpoint path
|
|
150
|
+
* @param {RequestOptions} [options] - Optional request configuration
|
|
151
|
+
* @returns {Promise<ApiResponse<T>>} The API response
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* ```typescript
|
|
155
|
+
* const response = await client.get<Config>('/api/configs/123');
|
|
156
|
+
* console.log(response.data.name);
|
|
157
|
+
* ```
|
|
158
|
+
*/
|
|
159
|
+
async get(e, t) {
|
|
160
|
+
return this.request("GET", e, void 0, t);
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Makes a POST request to the specified endpoint.
|
|
164
|
+
*
|
|
165
|
+
* @async
|
|
166
|
+
* @method post
|
|
167
|
+
* @typeParam T - The expected response data type
|
|
168
|
+
* @param {string} endpoint - The API endpoint path
|
|
169
|
+
* @param {any} [data] - The request body data
|
|
170
|
+
* @param {RequestOptions} [options] - Optional request configuration
|
|
171
|
+
* @returns {Promise<ApiResponse<T>>} The API response
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* ```typescript
|
|
175
|
+
* const response = await client.post<Config>('/api/configs', {
|
|
176
|
+
* name: 'NewConfig',
|
|
177
|
+
* formData: { key: 'value' }
|
|
178
|
+
* });
|
|
179
|
+
* ```
|
|
180
|
+
*/
|
|
181
|
+
async post(e, t, s) {
|
|
182
|
+
return this.request("POST", e, t, s);
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Makes a PUT request to the specified endpoint.
|
|
186
|
+
*
|
|
187
|
+
* @async
|
|
188
|
+
* @method put
|
|
189
|
+
* @typeParam T - The expected response data type
|
|
190
|
+
* @param {string} endpoint - The API endpoint path
|
|
191
|
+
* @param {any} [data] - The request body data
|
|
192
|
+
* @param {RequestOptions} [options] - Optional request configuration
|
|
193
|
+
* @returns {Promise<ApiResponse<T>>} The API response
|
|
194
|
+
*
|
|
195
|
+
* @example
|
|
196
|
+
* ```typescript
|
|
197
|
+
* const response = await client.put<Config>('/api/configs/123', {
|
|
198
|
+
* name: 'UpdatedConfig'
|
|
199
|
+
* });
|
|
200
|
+
* ```
|
|
201
|
+
*/
|
|
202
|
+
async put(e, t, s) {
|
|
203
|
+
return this.request("PUT", e, t, s);
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Makes a PATCH request to the specified endpoint.
|
|
207
|
+
*
|
|
208
|
+
* @async
|
|
209
|
+
* @method patch
|
|
210
|
+
* @typeParam T - The expected response data type
|
|
211
|
+
* @param {string} endpoint - The API endpoint path
|
|
212
|
+
* @param {any} [data] - The request body data (partial update)
|
|
213
|
+
* @param {RequestOptions} [options] - Optional request configuration
|
|
214
|
+
* @returns {Promise<ApiResponse<T>>} The API response
|
|
215
|
+
*
|
|
216
|
+
* @example
|
|
217
|
+
* ```typescript
|
|
218
|
+
* const response = await client.patch<Config>('/api/configs/123', {
|
|
219
|
+
* formData: { updatedKey: 'newValue' }
|
|
220
|
+
* });
|
|
221
|
+
* ```
|
|
222
|
+
*/
|
|
223
|
+
async patch(e, t, s) {
|
|
224
|
+
return this.request("PATCH", e, t, s);
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Makes a DELETE request to the specified endpoint.
|
|
228
|
+
*
|
|
229
|
+
* @async
|
|
230
|
+
* @method delete
|
|
231
|
+
* @typeParam T - The expected response data type
|
|
232
|
+
* @param {string} endpoint - The API endpoint path
|
|
233
|
+
* @param {RequestOptions} [options] - Optional request configuration
|
|
234
|
+
* @returns {Promise<ApiResponse<T>>} The API response
|
|
235
|
+
*
|
|
236
|
+
* @example
|
|
237
|
+
* ```typescript
|
|
238
|
+
* const response = await client.delete('/api/configs/123');
|
|
239
|
+
* ```
|
|
240
|
+
*/
|
|
241
|
+
async delete(e, t) {
|
|
242
|
+
return this.request("DELETE", e, void 0, t);
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Updates the authorization token.
|
|
246
|
+
*
|
|
247
|
+
* Use this method if you need to manually update the token
|
|
248
|
+
* (e.g., after refreshing it externally).
|
|
249
|
+
*
|
|
250
|
+
* @method setToken
|
|
251
|
+
* @param {string} token - The new JWT access token
|
|
252
|
+
*
|
|
253
|
+
* @example
|
|
254
|
+
* ```typescript
|
|
255
|
+
* client.setToken('new-jwt-token');
|
|
256
|
+
* ```
|
|
257
|
+
*/
|
|
258
|
+
setToken(e) {
|
|
259
|
+
this.defaultHeaders.Authorization = `Bearer ${e}`;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Sets a custom header for all subsequent requests.
|
|
263
|
+
*
|
|
264
|
+
* @method setHeader
|
|
265
|
+
* @param {string} key - The header name
|
|
266
|
+
* @param {string} value - The header value
|
|
267
|
+
*
|
|
268
|
+
* @example
|
|
269
|
+
* ```typescript
|
|
270
|
+
* client.setHeader('X-Custom-Header', 'custom-value');
|
|
271
|
+
* ```
|
|
272
|
+
*/
|
|
273
|
+
setHeader(e, t) {
|
|
274
|
+
this.defaultHeaders[e] = t;
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Removes a custom header from subsequent requests.
|
|
278
|
+
*
|
|
279
|
+
* @method removeHeader
|
|
280
|
+
* @param {string} key - The header name to remove
|
|
281
|
+
*
|
|
282
|
+
* @example
|
|
283
|
+
* ```typescript
|
|
284
|
+
* client.removeHeader('X-Custom-Header');
|
|
285
|
+
* ```
|
|
286
|
+
*/
|
|
287
|
+
removeHeader(e) {
|
|
288
|
+
delete this.defaultHeaders[e];
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
const I = "/api/sdk/brands";
|
|
292
|
+
class M {
|
|
293
|
+
constructor(e, t) {
|
|
294
|
+
this.httpClient = e, this.cacheManager = t;
|
|
295
|
+
}
|
|
296
|
+
async get(e, t, s) {
|
|
297
|
+
const { brand: n, config: a, requestOptions: r } = this.parseConfigArgs(
|
|
298
|
+
e,
|
|
299
|
+
t,
|
|
300
|
+
s
|
|
301
|
+
), o = `config:${n}:${a}`, l = this.cacheManager && r?.cache !== !1 && !r?.forceRefresh;
|
|
302
|
+
if (l) {
|
|
303
|
+
const h = await this.cacheManager.get(o);
|
|
304
|
+
if (h !== null)
|
|
305
|
+
return h;
|
|
306
|
+
}
|
|
307
|
+
const c = await this.httpClient.get(
|
|
308
|
+
this.buildConfigUrl(n, a),
|
|
309
|
+
r
|
|
310
|
+
), u = {
|
|
311
|
+
...c,
|
|
312
|
+
data: this.transformConfigResponse(c.data)
|
|
313
|
+
};
|
|
314
|
+
return l && c.success && await this.cacheManager.set(o, u, { ttl: r?.ttl }), u;
|
|
315
|
+
}
|
|
316
|
+
async getValue(e, t, s, n) {
|
|
317
|
+
const { brand: a, config: r, key: o, requestOptions: l } = this.parseValueArgs(
|
|
318
|
+
e,
|
|
319
|
+
t,
|
|
320
|
+
s,
|
|
321
|
+
n
|
|
322
|
+
), c = `config:${a}:${r}:${o}`, u = this.cacheManager && l?.cache !== !1 && !l?.forceRefresh;
|
|
323
|
+
if (u) {
|
|
324
|
+
const d = await this.cacheManager.get(c);
|
|
325
|
+
if (d !== null)
|
|
326
|
+
return d;
|
|
327
|
+
}
|
|
328
|
+
const h = await this.httpClient.get(
|
|
329
|
+
this.buildValueUrl(a, r, o),
|
|
330
|
+
l
|
|
331
|
+
);
|
|
332
|
+
return u && h.success && await this.cacheManager.set(c, h, { ttl: l?.ttl }), h;
|
|
333
|
+
}
|
|
334
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
335
|
+
// Private helpers
|
|
336
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
337
|
+
/**
|
|
338
|
+
* Parses arguments for the get() method.
|
|
339
|
+
*/
|
|
340
|
+
parseConfigArgs(e, t, s) {
|
|
341
|
+
if (typeof t == "string")
|
|
342
|
+
return {
|
|
343
|
+
brand: e,
|
|
344
|
+
config: t,
|
|
345
|
+
requestOptions: s
|
|
346
|
+
};
|
|
347
|
+
const n = this.parsePath(e, 2);
|
|
348
|
+
return {
|
|
349
|
+
brand: n[0],
|
|
350
|
+
config: n[1],
|
|
351
|
+
requestOptions: t
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Parses arguments for the getValue() method.
|
|
356
|
+
*/
|
|
357
|
+
parseValueArgs(e, t, s, n) {
|
|
358
|
+
if (typeof t == "string")
|
|
359
|
+
return {
|
|
360
|
+
brand: e,
|
|
361
|
+
config: t,
|
|
362
|
+
key: s,
|
|
363
|
+
requestOptions: n
|
|
364
|
+
};
|
|
365
|
+
const a = this.parsePath(e, 3);
|
|
366
|
+
return {
|
|
367
|
+
brand: a[0],
|
|
368
|
+
config: a[1],
|
|
369
|
+
key: a[2],
|
|
370
|
+
requestOptions: t
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Parses a dot-notation path into components.
|
|
375
|
+
*/
|
|
376
|
+
parsePath(e, t) {
|
|
377
|
+
const s = e.split(".");
|
|
378
|
+
if (s.length !== t) {
|
|
379
|
+
const n = t === 2 ? "brandName.configName" : "brandName.configName.keyName";
|
|
380
|
+
throw new Error(`Invalid path format "${e}". Expected "${n}"`);
|
|
381
|
+
}
|
|
382
|
+
return s;
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Builds the URL for fetching an entire config.
|
|
386
|
+
*/
|
|
387
|
+
buildConfigUrl(e, t) {
|
|
388
|
+
return `${I}/${this.encode(e)}/configs/${this.encode(t)}`;
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Builds the URL for fetching a single value.
|
|
392
|
+
*/
|
|
393
|
+
buildValueUrl(e, t, s) {
|
|
394
|
+
return `${I}/${this.encode(e)}/configs/${this.encode(t)}/${this.encode(s)}`;
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* URL-encodes a path segment.
|
|
398
|
+
*/
|
|
399
|
+
encode(e) {
|
|
400
|
+
return encodeURIComponent(e);
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Transforms the backend response to the public ConfigData shape.
|
|
404
|
+
*/
|
|
405
|
+
transformConfigResponse(e) {
|
|
406
|
+
return {
|
|
407
|
+
name: e.name,
|
|
408
|
+
description: e.description,
|
|
409
|
+
values: e.formData,
|
|
410
|
+
version: e.version,
|
|
411
|
+
keys: e.keys,
|
|
412
|
+
createdAt: e.createdAt,
|
|
413
|
+
updatedAt: e.updatedAt
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
const $ = "/api/sdk";
|
|
418
|
+
class N {
|
|
419
|
+
constructor(e) {
|
|
420
|
+
this.httpClient = e;
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Lists all brands accessible by the current API key.
|
|
424
|
+
*
|
|
425
|
+
* @example
|
|
426
|
+
* ```typescript
|
|
427
|
+
* const response = await dinoconfig.discovery.listBrands();
|
|
428
|
+
* response.data.forEach(brand => {
|
|
429
|
+
* console.log(`${brand.name}: ${brand.configCount} configs`);
|
|
430
|
+
* });
|
|
431
|
+
* ```
|
|
432
|
+
*/
|
|
433
|
+
async listBrands(e) {
|
|
434
|
+
const t = await this.httpClient.get(
|
|
435
|
+
`${$}/brands`,
|
|
436
|
+
e
|
|
437
|
+
);
|
|
438
|
+
return this.extractData(t, t.data.brands);
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Lists all configurations for a specific brand.
|
|
442
|
+
*
|
|
443
|
+
* @example
|
|
444
|
+
* ```typescript
|
|
445
|
+
* const response = await dinoconfig.discovery.listConfigs('MyBrand');
|
|
446
|
+
* response.data.forEach(config => {
|
|
447
|
+
* console.log(`${config.name}: ${config.keys.length} keys`);
|
|
448
|
+
* });
|
|
449
|
+
* ```
|
|
450
|
+
*/
|
|
451
|
+
async listConfigs(e, t) {
|
|
452
|
+
const s = await this.httpClient.get(
|
|
453
|
+
this.buildBrandUrl(e, "/configs"),
|
|
454
|
+
t
|
|
455
|
+
);
|
|
456
|
+
return this.extractData(s, s.data.configs);
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* Gets the schema/structure for a specific configuration.
|
|
460
|
+
*
|
|
461
|
+
* @example
|
|
462
|
+
* ```typescript
|
|
463
|
+
* const response = await dinoconfig.discovery.getSchema('MyBrand', 'FeatureFlags');
|
|
464
|
+
* Object.entries(response.data.fields).forEach(([name, field]) => {
|
|
465
|
+
* console.log(`${name}: ${field.type}`);
|
|
466
|
+
* });
|
|
467
|
+
* ```
|
|
468
|
+
*/
|
|
469
|
+
async getSchema(e, t, s) {
|
|
470
|
+
return this.httpClient.get(
|
|
471
|
+
this.buildConfigUrl(e, t, "/schema"),
|
|
472
|
+
s
|
|
473
|
+
);
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* Performs full introspection, returning all brands, configs, and keys.
|
|
477
|
+
*
|
|
478
|
+
* @example
|
|
479
|
+
* ```typescript
|
|
480
|
+
* const response = await dinoconfig.discovery.introspect();
|
|
481
|
+
* response.data.brands.forEach(brand => {
|
|
482
|
+
* console.log(`Brand: ${brand.name}`);
|
|
483
|
+
* brand.configs.forEach(config => {
|
|
484
|
+
* console.log(` Config: ${config.name} (${config.keys.length} keys)`);
|
|
485
|
+
* });
|
|
486
|
+
* });
|
|
487
|
+
* ```
|
|
488
|
+
*/
|
|
489
|
+
async introspect(e) {
|
|
490
|
+
return this.httpClient.get(`${$}/introspect`, e);
|
|
491
|
+
}
|
|
492
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
493
|
+
// Private helpers
|
|
494
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
495
|
+
/**
|
|
496
|
+
* Builds URL path for brand-level endpoints.
|
|
497
|
+
*/
|
|
498
|
+
buildBrandUrl(e, t = "") {
|
|
499
|
+
return `${$}/brands/${this.encode(e)}${t}`;
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* Builds URL path for config-level endpoints.
|
|
503
|
+
*/
|
|
504
|
+
buildConfigUrl(e, t, s = "") {
|
|
505
|
+
return `${$}/brands/${this.encode(e)}/configs/${this.encode(t)}${s}`;
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* URL-encodes a path segment.
|
|
509
|
+
*/
|
|
510
|
+
encode(e) {
|
|
511
|
+
return encodeURIComponent(e);
|
|
512
|
+
}
|
|
513
|
+
/**
|
|
514
|
+
* Extracts and transforms response data.
|
|
515
|
+
*/
|
|
516
|
+
extractData(e, t) {
|
|
517
|
+
return {
|
|
518
|
+
...e,
|
|
519
|
+
data: t
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
class x {
|
|
524
|
+
constructor(e, t) {
|
|
525
|
+
this.ttl = e, this.maxSize = t, this.cache = /* @__PURE__ */ new Map(), this.hits = 0, this.misses = 0;
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* Get a value from the cache.
|
|
529
|
+
*
|
|
530
|
+
* @param {string} key - Cache key
|
|
531
|
+
* @returns {T | null} Cached value or null if not found/expired
|
|
532
|
+
*/
|
|
533
|
+
get(e) {
|
|
534
|
+
const t = this.cache.get(e);
|
|
535
|
+
return t ? this.isExpired(t) ? (this.cache.delete(e), this.misses++, null) : (this.hits++, t.value) : (this.misses++, null);
|
|
536
|
+
}
|
|
537
|
+
/**
|
|
538
|
+
* Set a value in the cache.
|
|
539
|
+
*
|
|
540
|
+
* @param {string} key - Cache key
|
|
541
|
+
* @param {T} value - Value to cache
|
|
542
|
+
* @param {CacheOptions} options - Optional cache options
|
|
543
|
+
*/
|
|
544
|
+
set(e, t, s) {
|
|
545
|
+
const n = s?.ttl ?? this.ttl, a = {
|
|
546
|
+
value: t,
|
|
547
|
+
timestamp: Date.now(),
|
|
548
|
+
expiresAt: Date.now() + n
|
|
549
|
+
};
|
|
550
|
+
this.cache.size >= this.maxSize && !this.cache.has(e) && this.evictOldest(), this.cache.set(e, a);
|
|
551
|
+
}
|
|
552
|
+
/**
|
|
553
|
+
* Delete a value from the cache.
|
|
554
|
+
*
|
|
555
|
+
* @param {string} key - Cache key
|
|
556
|
+
*/
|
|
557
|
+
delete(e) {
|
|
558
|
+
this.cache.delete(e);
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* Clear all entries from the cache.
|
|
562
|
+
*/
|
|
563
|
+
clear() {
|
|
564
|
+
this.cache.clear(), this.hits = 0, this.misses = 0;
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* Invalidate entries matching a pattern.
|
|
568
|
+
*
|
|
569
|
+
* @param {string} pattern - Regex pattern to match keys
|
|
570
|
+
*/
|
|
571
|
+
invalidate(e) {
|
|
572
|
+
const t = new RegExp(e);
|
|
573
|
+
for (const s of this.cache.keys())
|
|
574
|
+
t.test(s) && this.cache.delete(s);
|
|
575
|
+
}
|
|
576
|
+
/**
|
|
577
|
+
* Check if an entry exists and is not expired.
|
|
578
|
+
*
|
|
579
|
+
* @param {string} key - Cache key
|
|
580
|
+
* @returns {boolean} True if entry exists and is valid
|
|
581
|
+
*/
|
|
582
|
+
has(e) {
|
|
583
|
+
const t = this.cache.get(e);
|
|
584
|
+
return t ? this.isExpired(t) ? (this.cache.delete(e), !1) : !0 : !1;
|
|
585
|
+
}
|
|
586
|
+
/**
|
|
587
|
+
* Get cache statistics.
|
|
588
|
+
*
|
|
589
|
+
* @returns {CacheStats} Cache statistics
|
|
590
|
+
*/
|
|
591
|
+
getStats() {
|
|
592
|
+
const e = this.hits + this.misses;
|
|
593
|
+
return {
|
|
594
|
+
hits: this.hits,
|
|
595
|
+
misses: this.misses,
|
|
596
|
+
size: this.cache.size,
|
|
597
|
+
hitRate: e > 0 ? this.hits / e : 0
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
/**
|
|
601
|
+
* Check if an entry is expired.
|
|
602
|
+
*
|
|
603
|
+
* @private
|
|
604
|
+
* @param {CacheEntry} entry - Cache entry
|
|
605
|
+
* @returns {boolean} True if expired
|
|
606
|
+
*/
|
|
607
|
+
isExpired(e) {
|
|
608
|
+
return Date.now() > e.expiresAt;
|
|
609
|
+
}
|
|
610
|
+
/**
|
|
611
|
+
* Evict the oldest entry from the cache.
|
|
612
|
+
* Uses LRU-like strategy based on expiration time.
|
|
613
|
+
*
|
|
614
|
+
* @private
|
|
615
|
+
*/
|
|
616
|
+
evictOldest() {
|
|
617
|
+
let e = null, t = 1 / 0;
|
|
618
|
+
for (const [s, n] of this.cache.entries())
|
|
619
|
+
n.expiresAt < t && (t = n.expiresAt, e = s);
|
|
620
|
+
e && this.cache.delete(e);
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
class U {
|
|
624
|
+
constructor() {
|
|
625
|
+
if (typeof window > "u" || !window.localStorage)
|
|
626
|
+
throw new Error("localStorage is not available in this environment");
|
|
627
|
+
this.storage = window.localStorage;
|
|
628
|
+
}
|
|
629
|
+
getItem(e) {
|
|
630
|
+
try {
|
|
631
|
+
return this.storage.getItem(e);
|
|
632
|
+
} catch {
|
|
633
|
+
return null;
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
setItem(e, t) {
|
|
637
|
+
try {
|
|
638
|
+
this.storage.setItem(e, t);
|
|
639
|
+
} catch {
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
removeItem(e) {
|
|
643
|
+
try {
|
|
644
|
+
this.storage.removeItem(e);
|
|
645
|
+
} catch {
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
clear() {
|
|
649
|
+
try {
|
|
650
|
+
const e = Object.keys(this.storage);
|
|
651
|
+
for (const t of e)
|
|
652
|
+
t.startsWith("dinoconfig:") && this.storage.removeItem(t);
|
|
653
|
+
} catch {
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
class L {
|
|
658
|
+
constructor(e) {
|
|
659
|
+
if (this.prefix = "dinoconfig:", e === "localStorage")
|
|
660
|
+
this.adapter = new U();
|
|
661
|
+
else
|
|
662
|
+
throw new Error("IndexedDB storage is not yet implemented");
|
|
663
|
+
}
|
|
664
|
+
/**
|
|
665
|
+
* Get a value from storage cache.
|
|
666
|
+
*
|
|
667
|
+
* @param {string} key - Cache key
|
|
668
|
+
* @returns {Promise<T | null>} Cached value or null if not found/expired
|
|
669
|
+
*/
|
|
670
|
+
async get(e) {
|
|
671
|
+
try {
|
|
672
|
+
const t = this.adapter.getItem(this.prefix + e);
|
|
673
|
+
if (!t)
|
|
674
|
+
return null;
|
|
675
|
+
const s = JSON.parse(t);
|
|
676
|
+
return this.isExpired(s) ? (this.adapter.removeItem(this.prefix + e), null) : s.value;
|
|
677
|
+
} catch {
|
|
678
|
+
return null;
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
/**
|
|
682
|
+
* Set a value in storage cache.
|
|
683
|
+
*
|
|
684
|
+
* @param {string} key - Cache key
|
|
685
|
+
* @param {T} value - Value to cache
|
|
686
|
+
* @param {CacheOptions} options - Optional cache options
|
|
687
|
+
*/
|
|
688
|
+
async set(e, t, s) {
|
|
689
|
+
try {
|
|
690
|
+
const n = s?.ttl ?? 3e5, a = {
|
|
691
|
+
value: t,
|
|
692
|
+
timestamp: Date.now(),
|
|
693
|
+
expiresAt: Date.now() + n
|
|
694
|
+
};
|
|
695
|
+
this.adapter.setItem(this.prefix + e, JSON.stringify(a));
|
|
696
|
+
} catch {
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
/**
|
|
700
|
+
* Delete a value from storage cache.
|
|
701
|
+
*
|
|
702
|
+
* @param {string} key - Cache key
|
|
703
|
+
*/
|
|
704
|
+
async delete(e) {
|
|
705
|
+
try {
|
|
706
|
+
this.adapter.removeItem(this.prefix + e);
|
|
707
|
+
} catch {
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
/**
|
|
711
|
+
* Clear all entries from storage cache.
|
|
712
|
+
*/
|
|
713
|
+
async clear() {
|
|
714
|
+
try {
|
|
715
|
+
this.adapter.clear();
|
|
716
|
+
} catch {
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
/**
|
|
720
|
+
* Invalidate entries matching a pattern.
|
|
721
|
+
*
|
|
722
|
+
* @param {string} pattern - Regex pattern to match keys
|
|
723
|
+
*/
|
|
724
|
+
async invalidate(e) {
|
|
725
|
+
try {
|
|
726
|
+
const t = new RegExp(e), n = this.adapter.storage;
|
|
727
|
+
if (!n)
|
|
728
|
+
return;
|
|
729
|
+
const a = [];
|
|
730
|
+
for (let r = 0; r < n.length; r++) {
|
|
731
|
+
const o = n.key(r);
|
|
732
|
+
if (o && o.startsWith(this.prefix)) {
|
|
733
|
+
const l = o.substring(this.prefix.length);
|
|
734
|
+
t.test(l) && a.push(o);
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
for (const r of a)
|
|
738
|
+
this.adapter.removeItem(r);
|
|
739
|
+
} catch {
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
/**
|
|
743
|
+
* Check if an entry is expired.
|
|
744
|
+
*
|
|
745
|
+
* @private
|
|
746
|
+
* @param {CacheEntry} entry - Cache entry
|
|
747
|
+
* @returns {boolean} True if expired
|
|
748
|
+
*/
|
|
749
|
+
isExpired(e) {
|
|
750
|
+
return Date.now() > e.expiresAt;
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
class O {
|
|
754
|
+
constructor(e) {
|
|
755
|
+
if (this.config = e, !e.enabled) {
|
|
756
|
+
this.memoryCache = new x(0, 0);
|
|
757
|
+
return;
|
|
758
|
+
}
|
|
759
|
+
if (this.memoryCache = new x(
|
|
760
|
+
e.ttl,
|
|
761
|
+
e.maxSize
|
|
762
|
+
), e.storage && e.storage !== "memory")
|
|
763
|
+
try {
|
|
764
|
+
this.storageCache = new L(e.storage);
|
|
765
|
+
} catch {
|
|
766
|
+
this.storageCache = void 0;
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
/**
|
|
770
|
+
* Get a value from cache.
|
|
771
|
+
* Checks L1 (memory) first, then L2 (storage) if available.
|
|
772
|
+
*
|
|
773
|
+
* @param {string} key - Cache key
|
|
774
|
+
* @returns {Promise<T | null>} Cached value or null if not found
|
|
775
|
+
*/
|
|
776
|
+
async get(e) {
|
|
777
|
+
if (!this.config.enabled)
|
|
778
|
+
return null;
|
|
779
|
+
const t = this.memoryCache.get(e);
|
|
780
|
+
if (t !== null)
|
|
781
|
+
return t;
|
|
782
|
+
if (this.storageCache) {
|
|
783
|
+
const s = await this.storageCache.get(e);
|
|
784
|
+
if (s !== null)
|
|
785
|
+
return this.memoryCache.set(e, s), s;
|
|
786
|
+
}
|
|
787
|
+
return null;
|
|
788
|
+
}
|
|
789
|
+
/**
|
|
790
|
+
* Set a value in cache.
|
|
791
|
+
* Writes to both L1 (memory) and L2 (storage) if available.
|
|
792
|
+
*
|
|
793
|
+
* @param {string} key - Cache key
|
|
794
|
+
* @param {T} value - Value to cache
|
|
795
|
+
* @param {CacheOptions} options - Optional cache options
|
|
796
|
+
*/
|
|
797
|
+
async set(e, t, s) {
|
|
798
|
+
this.config.enabled && (this.memoryCache.set(e, t, s), this.storageCache && await this.storageCache.set(e, t, s));
|
|
799
|
+
}
|
|
800
|
+
/**
|
|
801
|
+
* Delete a value from cache.
|
|
802
|
+
* Removes from both L1 and L2.
|
|
803
|
+
*
|
|
804
|
+
* @param {string} key - Cache key
|
|
805
|
+
*/
|
|
806
|
+
async delete(e) {
|
|
807
|
+
this.memoryCache.delete(e), this.storageCache && await this.storageCache.delete(e);
|
|
808
|
+
}
|
|
809
|
+
/**
|
|
810
|
+
* Clear all cache entries.
|
|
811
|
+
*/
|
|
812
|
+
async clear() {
|
|
813
|
+
this.memoryCache.clear(), this.storageCache && await this.storageCache.clear();
|
|
814
|
+
}
|
|
815
|
+
/**
|
|
816
|
+
* Invalidate entries matching a pattern.
|
|
817
|
+
*
|
|
818
|
+
* @param {string} pattern - Regex pattern to match keys
|
|
819
|
+
*/
|
|
820
|
+
async invalidate(e) {
|
|
821
|
+
if (!e) {
|
|
822
|
+
await this.clear();
|
|
823
|
+
return;
|
|
824
|
+
}
|
|
825
|
+
this.memoryCache.invalidate(e), this.storageCache && await this.storageCache.invalidate(e);
|
|
826
|
+
}
|
|
827
|
+
/**
|
|
828
|
+
* Check if a key exists in cache.
|
|
829
|
+
*
|
|
830
|
+
* @param {string} key - Cache key
|
|
831
|
+
* @returns {boolean} True if key exists and is not expired
|
|
832
|
+
*/
|
|
833
|
+
has(e) {
|
|
834
|
+
return this.config.enabled ? this.memoryCache.has(e) : !1;
|
|
835
|
+
}
|
|
836
|
+
/**
|
|
837
|
+
* Get cache statistics.
|
|
838
|
+
*
|
|
839
|
+
* @returns {CacheStats} Cache statistics
|
|
840
|
+
*/
|
|
841
|
+
getStats() {
|
|
842
|
+
return this.memoryCache.getStats();
|
|
843
|
+
}
|
|
844
|
+
/**
|
|
845
|
+
* Prefetch a value into cache.
|
|
846
|
+
* This is a convenience method for warming the cache.
|
|
847
|
+
*
|
|
848
|
+
* @param {string} key - Cache key
|
|
849
|
+
* @param {() => Promise<T>} fetcher - Function to fetch the value if not cached
|
|
850
|
+
*/
|
|
851
|
+
async prefetch(e, t) {
|
|
852
|
+
const s = await this.get(e);
|
|
853
|
+
if (s !== null)
|
|
854
|
+
return s;
|
|
855
|
+
const n = await t();
|
|
856
|
+
return await this.set(e, n), n;
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
async function S(i) {
|
|
860
|
+
const {
|
|
861
|
+
apiKey: e,
|
|
862
|
+
baseUrl: t = "http://localhost:3000",
|
|
863
|
+
timeout: s = 1e4,
|
|
864
|
+
cache: n
|
|
865
|
+
} = i, a = new R(t, s);
|
|
866
|
+
await a.configureAuthorizationHeader({
|
|
867
|
+
"X-API-Key": e
|
|
868
|
+
});
|
|
869
|
+
const r = new O({
|
|
870
|
+
enabled: n?.enabled ?? !1,
|
|
871
|
+
ttl: n?.ttl ?? 6e4,
|
|
872
|
+
maxSize: n?.maxSize ?? 1e3,
|
|
873
|
+
storage: n?.storage,
|
|
874
|
+
staleWhileRevalidate: n?.staleWhileRevalidate ?? !1
|
|
875
|
+
});
|
|
876
|
+
return {
|
|
877
|
+
configs: new M(a, r),
|
|
878
|
+
discovery: new N(a),
|
|
879
|
+
cache: r
|
|
880
|
+
};
|
|
881
|
+
}
|
|
882
|
+
const _ = /* @__PURE__ */ new Set([
|
|
883
|
+
"break",
|
|
884
|
+
"case",
|
|
885
|
+
"catch",
|
|
886
|
+
"class",
|
|
887
|
+
"const",
|
|
888
|
+
"continue",
|
|
889
|
+
"debugger",
|
|
890
|
+
"default",
|
|
891
|
+
"delete",
|
|
892
|
+
"do",
|
|
893
|
+
"else",
|
|
894
|
+
"enum",
|
|
895
|
+
"export",
|
|
896
|
+
"extends",
|
|
897
|
+
"false",
|
|
898
|
+
"finally",
|
|
899
|
+
"for",
|
|
900
|
+
"function",
|
|
901
|
+
"if",
|
|
902
|
+
"import",
|
|
903
|
+
"in",
|
|
904
|
+
"instanceof",
|
|
905
|
+
"new",
|
|
906
|
+
"null",
|
|
907
|
+
"return",
|
|
908
|
+
"super",
|
|
909
|
+
"switch",
|
|
910
|
+
"this",
|
|
911
|
+
"throw",
|
|
912
|
+
"true",
|
|
913
|
+
"try",
|
|
914
|
+
"typeof",
|
|
915
|
+
"var",
|
|
916
|
+
"void",
|
|
917
|
+
"while",
|
|
918
|
+
"with"
|
|
919
|
+
]);
|
|
920
|
+
function B(i) {
|
|
921
|
+
return i === "string" || i === "number" || i === "boolean";
|
|
922
|
+
}
|
|
923
|
+
class H {
|
|
924
|
+
constructor(e = T) {
|
|
925
|
+
this.namespace = e;
|
|
926
|
+
}
|
|
927
|
+
/**
|
|
928
|
+
* Generates the complete TypeScript declaration file content.
|
|
929
|
+
*/
|
|
930
|
+
generate(e) {
|
|
931
|
+
const t = [
|
|
932
|
+
...this.generateHeader(e),
|
|
933
|
+
"",
|
|
934
|
+
`export namespace ${this.namespace} {`
|
|
935
|
+
];
|
|
936
|
+
for (const s of e.brands)
|
|
937
|
+
t.push(this.generateBrandNamespace(s)), t.push("");
|
|
938
|
+
return this.removeTrailingEmpty(t), t.push("}", "", ...this.generateHelperType(), ""), t.join(`
|
|
939
|
+
`);
|
|
940
|
+
}
|
|
941
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
942
|
+
// Private: Header & Helper Generation
|
|
943
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
944
|
+
generateHeader(e) {
|
|
945
|
+
return [
|
|
946
|
+
"/**",
|
|
947
|
+
" * DinoConfig Generated Types",
|
|
948
|
+
" *",
|
|
949
|
+
` * Auto-generated by ${v} v${j}`,
|
|
950
|
+
` * Generated at: ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
951
|
+
` * Company: ${e.company}`,
|
|
952
|
+
" *",
|
|
953
|
+
" * DO NOT EDIT THIS FILE MANUALLY",
|
|
954
|
+
" * Run the codegen command to regenerate:",
|
|
955
|
+
` * npx ${v} codegen --api-key=<your-key> --output=<this-file>`,
|
|
956
|
+
" */"
|
|
957
|
+
];
|
|
958
|
+
}
|
|
959
|
+
generateHelperType() {
|
|
960
|
+
return [
|
|
961
|
+
"/**",
|
|
962
|
+
" * Helper type to extract config type from namespace path",
|
|
963
|
+
" * @example",
|
|
964
|
+
` * type Flags = ${this.namespace}.ConfigType<'MyBrand', 'FeatureFlags'>;`,
|
|
965
|
+
" */",
|
|
966
|
+
"export type ConfigType<",
|
|
967
|
+
` Brand extends keyof typeof ${this.namespace},`,
|
|
968
|
+
` Config extends keyof (typeof ${this.namespace})[Brand]`,
|
|
969
|
+
`> = (typeof ${this.namespace})[Brand][Config];`
|
|
970
|
+
];
|
|
971
|
+
}
|
|
972
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
973
|
+
// Private: Namespace & Interface Generation
|
|
974
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
975
|
+
generateBrandNamespace(e) {
|
|
976
|
+
const t = this.sanitizeIdentifier(e.name), s = [
|
|
977
|
+
" /**",
|
|
978
|
+
` * ${e.name} brand configurations`,
|
|
979
|
+
" * @namespace",
|
|
980
|
+
" */",
|
|
981
|
+
` export namespace ${t} {`
|
|
982
|
+
];
|
|
983
|
+
for (const n of e.configs)
|
|
984
|
+
s.push(this.generateConfigInterface(n), "");
|
|
985
|
+
return this.removeTrailingEmpty(s), s.push(" }"), s.join(`
|
|
986
|
+
`);
|
|
987
|
+
}
|
|
988
|
+
generateConfigInterface(e) {
|
|
989
|
+
const t = this.sanitizeIdentifier(e.name), s = [
|
|
990
|
+
" /**",
|
|
991
|
+
` * ${e.name} configuration`
|
|
992
|
+
];
|
|
993
|
+
e.keys.length > 0 && s.push(` * @property {${e.keys.length}} keys`), s.push(" */", ` export interface ${t} {`);
|
|
994
|
+
for (const n of e.keys)
|
|
995
|
+
s.push(...this.generateProperty(n));
|
|
996
|
+
return s.push(" }"), s.join(`
|
|
997
|
+
`);
|
|
998
|
+
}
|
|
999
|
+
generateProperty(e) {
|
|
1000
|
+
const t = this.sanitizeIdentifier(e.name), s = this.toTypeScriptType(e.type, e.value);
|
|
1001
|
+
return [` /** ${e.type} */`, ` ${t}: ${s};`];
|
|
1002
|
+
}
|
|
1003
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
1004
|
+
// Private: Type Conversion & Utilities
|
|
1005
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
1006
|
+
toTypeScriptType(e, t) {
|
|
1007
|
+
switch (e) {
|
|
1008
|
+
case "boolean":
|
|
1009
|
+
case "number":
|
|
1010
|
+
case "string":
|
|
1011
|
+
return e;
|
|
1012
|
+
case "array":
|
|
1013
|
+
return this.inferArrayType(t);
|
|
1014
|
+
case "object":
|
|
1015
|
+
return "Record<string, unknown>";
|
|
1016
|
+
default:
|
|
1017
|
+
return "unknown";
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
inferArrayType(e) {
|
|
1021
|
+
if (Array.isArray(e) && e.length > 0) {
|
|
1022
|
+
const t = typeof e[0];
|
|
1023
|
+
if (B(t))
|
|
1024
|
+
return `${t}[]`;
|
|
1025
|
+
}
|
|
1026
|
+
return "unknown[]";
|
|
1027
|
+
}
|
|
1028
|
+
sanitizeIdentifier(e) {
|
|
1029
|
+
let t = e.replace(/[^a-zA-Z0-9_$]/g, "_");
|
|
1030
|
+
return /^[0-9]/.test(t) && (t = "_" + t), _.has(t.toLowerCase()) && (t += "_"), t;
|
|
1031
|
+
}
|
|
1032
|
+
removeTrailingEmpty(e) {
|
|
1033
|
+
for (; e.length > 0 && e[e.length - 1] === ""; )
|
|
1034
|
+
e.pop();
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
const k = /* @__PURE__ */ new Set([
|
|
1038
|
+
"abstract",
|
|
1039
|
+
"assert",
|
|
1040
|
+
"boolean",
|
|
1041
|
+
"break",
|
|
1042
|
+
"byte",
|
|
1043
|
+
"case",
|
|
1044
|
+
"catch",
|
|
1045
|
+
"char",
|
|
1046
|
+
"class",
|
|
1047
|
+
"const",
|
|
1048
|
+
"continue",
|
|
1049
|
+
"default",
|
|
1050
|
+
"do",
|
|
1051
|
+
"double",
|
|
1052
|
+
"else",
|
|
1053
|
+
"enum",
|
|
1054
|
+
"extends",
|
|
1055
|
+
"final",
|
|
1056
|
+
"finally",
|
|
1057
|
+
"float",
|
|
1058
|
+
"for",
|
|
1059
|
+
"goto",
|
|
1060
|
+
"if",
|
|
1061
|
+
"implements",
|
|
1062
|
+
"import",
|
|
1063
|
+
"instanceof",
|
|
1064
|
+
"int",
|
|
1065
|
+
"interface",
|
|
1066
|
+
"long",
|
|
1067
|
+
"native",
|
|
1068
|
+
"new",
|
|
1069
|
+
"null",
|
|
1070
|
+
"package",
|
|
1071
|
+
"private",
|
|
1072
|
+
"protected",
|
|
1073
|
+
"public",
|
|
1074
|
+
"return",
|
|
1075
|
+
"short",
|
|
1076
|
+
"static",
|
|
1077
|
+
"strictfp",
|
|
1078
|
+
"super",
|
|
1079
|
+
"switch",
|
|
1080
|
+
"synchronized",
|
|
1081
|
+
"this",
|
|
1082
|
+
"throw",
|
|
1083
|
+
"throws",
|
|
1084
|
+
"transient",
|
|
1085
|
+
"try",
|
|
1086
|
+
"void",
|
|
1087
|
+
"volatile",
|
|
1088
|
+
"while"
|
|
1089
|
+
]);
|
|
1090
|
+
function q(i) {
|
|
1091
|
+
return i === "string" || i === "number" || i === "boolean";
|
|
1092
|
+
}
|
|
1093
|
+
const J = "com.dinoconfig.sdk.generated";
|
|
1094
|
+
function K(i) {
|
|
1095
|
+
const e = i.replace(/\\/g, "/"), t = [
|
|
1096
|
+
"src/main/java/",
|
|
1097
|
+
"src/test/java/",
|
|
1098
|
+
"src/java/",
|
|
1099
|
+
"/java/"
|
|
1100
|
+
];
|
|
1101
|
+
for (const s of t) {
|
|
1102
|
+
const n = e.indexOf(s);
|
|
1103
|
+
if (n !== -1) {
|
|
1104
|
+
const a = e.substring(n + s.length);
|
|
1105
|
+
if (a) {
|
|
1106
|
+
const r = a.replace(/\/+$/, "").replace(/\//g, ".");
|
|
1107
|
+
if (/^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)*$/i.test(r))
|
|
1108
|
+
return r;
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
class G {
|
|
1114
|
+
/**
|
|
1115
|
+
* Creates a new JavaModelGenerator.
|
|
1116
|
+
*
|
|
1117
|
+
* @param options - Generator options
|
|
1118
|
+
*/
|
|
1119
|
+
constructor(e = {}) {
|
|
1120
|
+
this.generatedByComment = `Generated by ${v} v${j}`, this.basePackage = e.basePackage ?? J;
|
|
1121
|
+
}
|
|
1122
|
+
/**
|
|
1123
|
+
* Gets the base package used by this generator.
|
|
1124
|
+
*/
|
|
1125
|
+
getBasePackage() {
|
|
1126
|
+
return this.basePackage;
|
|
1127
|
+
}
|
|
1128
|
+
/**
|
|
1129
|
+
* Generates Java source files for each brand and config.
|
|
1130
|
+
* Returns a map of file paths (relative to output directory) to file contents.
|
|
1131
|
+
* The file paths only include brand subdirectories, not the base package path,
|
|
1132
|
+
* since the output directory already represents the base package location.
|
|
1133
|
+
*/
|
|
1134
|
+
generate(e) {
|
|
1135
|
+
const t = /* @__PURE__ */ new Map();
|
|
1136
|
+
for (const s of e.brands) {
|
|
1137
|
+
const n = this.sanitizePackageName(s.name), a = `${this.basePackage}.${n}`;
|
|
1138
|
+
for (const r of s.configs) {
|
|
1139
|
+
const o = this.sanitizeClassName(r.name), l = `${n}/${o}.java`, c = this.generateConfigClass(a, o, r, s.name);
|
|
1140
|
+
t.set(l, c);
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
return t;
|
|
1144
|
+
}
|
|
1145
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
1146
|
+
// Private: Class Generation
|
|
1147
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
1148
|
+
generateConfigClass(e, t, s, n) {
|
|
1149
|
+
const a = [
|
|
1150
|
+
this.generateHeader(s, n),
|
|
1151
|
+
"",
|
|
1152
|
+
`package ${e};`,
|
|
1153
|
+
"",
|
|
1154
|
+
"import com.fasterxml.jackson.annotation.JsonProperty;",
|
|
1155
|
+
"",
|
|
1156
|
+
"import java.util.Objects;"
|
|
1157
|
+
], r = this.collectTypesUsed(s.keys);
|
|
1158
|
+
(r.has("List") || r.has("Map")) && (r.has("List") && a.push("import java.util.List;"), r.has("Map") && a.push("import java.util.Map;"), a.push("import java.util.Collections;")), a.push("", this.generateClassDeclaration(t, s));
|
|
1159
|
+
for (const o of s.keys)
|
|
1160
|
+
a.push(this.generateField(o));
|
|
1161
|
+
a.push("", this.generateDefaultConstructor(t, s.keys)), a.push("", this.generateFullConstructor(t, s.keys));
|
|
1162
|
+
for (const o of s.keys)
|
|
1163
|
+
a.push("", this.generateGetter(o));
|
|
1164
|
+
return a.push("", this.generateEqualsMethod(t, s.keys)), a.push("", this.generateHashCodeMethod(s.keys)), a.push("", this.generateToStringMethod(t, s.keys)), a.push("}"), a.join(`
|
|
1165
|
+
`);
|
|
1166
|
+
}
|
|
1167
|
+
generateHeader(e, t) {
|
|
1168
|
+
const s = (/* @__PURE__ */ new Date()).toISOString();
|
|
1169
|
+
return `/*
|
|
1170
|
+
* DinoConfig Java SDK - Generated Model
|
|
1171
|
+
* ${this.generatedByComment}
|
|
1172
|
+
* Generated at: ${s}
|
|
1173
|
+
*
|
|
1174
|
+
* DO NOT EDIT THIS FILE MANUALLY
|
|
1175
|
+
* This file is auto-generated from DinoConfig schema.
|
|
1176
|
+
*
|
|
1177
|
+
* Brand: ${t}
|
|
1178
|
+
* Config: ${e.name}
|
|
1179
|
+
* Version: ${e.version}
|
|
1180
|
+
*/`;
|
|
1181
|
+
}
|
|
1182
|
+
generateClassDeclaration(e, t) {
|
|
1183
|
+
const s = [
|
|
1184
|
+
"/**",
|
|
1185
|
+
` * Generated model for ${t.name} configuration.`
|
|
1186
|
+
];
|
|
1187
|
+
return t.description && s.push(" *", ` * ${t.description.replace(/\n/g, " ")}`), s.push(" *", " * <p>This class represents the typed structure of the configuration.", " * All fields are immutable.", " */"), s.push(`public final class ${e} {`), s.join(`
|
|
1188
|
+
`);
|
|
1189
|
+
}
|
|
1190
|
+
generateField(e) {
|
|
1191
|
+
const t = this.sanitizeFieldName(e.name), s = this.toJavaType(e.type, e.value);
|
|
1192
|
+
return [
|
|
1193
|
+
" /**",
|
|
1194
|
+
` * ${e.type} - ${e.name}`,
|
|
1195
|
+
" */",
|
|
1196
|
+
` @JsonProperty("${e.name}")`,
|
|
1197
|
+
` private final ${s} ${t};`
|
|
1198
|
+
].join(`
|
|
1199
|
+
`);
|
|
1200
|
+
}
|
|
1201
|
+
generateDefaultConstructor(e, t) {
|
|
1202
|
+
const s = [
|
|
1203
|
+
" /**",
|
|
1204
|
+
" * Default constructor for Jackson deserialization.",
|
|
1205
|
+
" */",
|
|
1206
|
+
` public ${e}() {`
|
|
1207
|
+
];
|
|
1208
|
+
for (const n of t) {
|
|
1209
|
+
const a = this.sanitizeFieldName(n.name), r = this.toJavaType(n.type, n.value), o = this.getDefaultValue(r);
|
|
1210
|
+
s.push(` this.${a} = ${o};`);
|
|
1211
|
+
}
|
|
1212
|
+
return s.push(" }"), s.join(`
|
|
1213
|
+
`);
|
|
1214
|
+
}
|
|
1215
|
+
generateFullConstructor(e, t) {
|
|
1216
|
+
const s = [];
|
|
1217
|
+
for (const a of t) {
|
|
1218
|
+
const r = this.sanitizeFieldName(a.name), o = this.toJavaType(a.type, a.value);
|
|
1219
|
+
s.push(`${o} ${r}`);
|
|
1220
|
+
}
|
|
1221
|
+
const n = [
|
|
1222
|
+
" /**",
|
|
1223
|
+
` * Creates a new ${e} instance.`,
|
|
1224
|
+
" *"
|
|
1225
|
+
];
|
|
1226
|
+
for (const a of t) {
|
|
1227
|
+
const r = this.sanitizeFieldName(a.name);
|
|
1228
|
+
n.push(` * @param ${r} ${a.name} (${a.type})`);
|
|
1229
|
+
}
|
|
1230
|
+
n.push(" */", ` public ${e}(${s.join(", ")}) {`);
|
|
1231
|
+
for (const a of t) {
|
|
1232
|
+
const r = this.sanitizeFieldName(a.name), o = this.toJavaType(a.type, a.value);
|
|
1233
|
+
o.startsWith("List<") ? n.push(` this.${r} = ${r} != null ? Collections.unmodifiableList(${r}) : Collections.emptyList();`) : o.startsWith("Map<") ? n.push(` this.${r} = ${r} != null ? Collections.unmodifiableMap(${r}) : Collections.emptyMap();`) : n.push(` this.${r} = ${r};`);
|
|
1234
|
+
}
|
|
1235
|
+
return n.push(" }"), n.join(`
|
|
1236
|
+
`);
|
|
1237
|
+
}
|
|
1238
|
+
generateGetter(e) {
|
|
1239
|
+
const t = this.sanitizeFieldName(e.name), s = this.toGetterName(t), n = this.toJavaType(e.type, e.value);
|
|
1240
|
+
return [
|
|
1241
|
+
" /**",
|
|
1242
|
+
` * Returns ${e.name}.`,
|
|
1243
|
+
" *",
|
|
1244
|
+
` * @return ${e.name} (${e.type})`,
|
|
1245
|
+
" */",
|
|
1246
|
+
` public ${n} ${s}() {`,
|
|
1247
|
+
` return ${t};`,
|
|
1248
|
+
" }"
|
|
1249
|
+
].join(`
|
|
1250
|
+
`);
|
|
1251
|
+
}
|
|
1252
|
+
generateEqualsMethod(e, t) {
|
|
1253
|
+
const s = [
|
|
1254
|
+
" @Override",
|
|
1255
|
+
" public boolean equals(Object o) {",
|
|
1256
|
+
" if (this == o) return true;",
|
|
1257
|
+
" if (o == null || getClass() != o.getClass()) return false;",
|
|
1258
|
+
` ${e} that = (${e}) o;`,
|
|
1259
|
+
" return "
|
|
1260
|
+
], n = [];
|
|
1261
|
+
for (const a of t) {
|
|
1262
|
+
const r = this.sanitizeFieldName(a.name);
|
|
1263
|
+
n.push(`Objects.equals(${r}, that.${r})`);
|
|
1264
|
+
}
|
|
1265
|
+
return s.push(" " + n.join(`
|
|
1266
|
+
&& `)), s.push(" ;"), s.push(" }"), s.join(`
|
|
1267
|
+
`);
|
|
1268
|
+
}
|
|
1269
|
+
generateHashCodeMethod(e) {
|
|
1270
|
+
return [
|
|
1271
|
+
" @Override",
|
|
1272
|
+
" public int hashCode() {",
|
|
1273
|
+
` return Objects.hash(${e.map((n) => this.sanitizeFieldName(n.name)).join(", ")});`,
|
|
1274
|
+
" }"
|
|
1275
|
+
].join(`
|
|
1276
|
+
`);
|
|
1277
|
+
}
|
|
1278
|
+
generateToStringMethod(e, t) {
|
|
1279
|
+
if (t.length === 0)
|
|
1280
|
+
return ` @Override
|
|
1281
|
+
public String toString() {
|
|
1282
|
+
return "${e}{}";
|
|
1283
|
+
}`;
|
|
1284
|
+
const s = [
|
|
1285
|
+
" @Override",
|
|
1286
|
+
" public String toString() {",
|
|
1287
|
+
` return "${e}{" +`
|
|
1288
|
+
];
|
|
1289
|
+
for (let n = 0; n < t.length; n++) {
|
|
1290
|
+
const a = t[n], r = this.sanitizeFieldName(a.name);
|
|
1291
|
+
n === 0 ? s.push(` "${r}=" + ${r}`) : s.push(` + ", ${r}=" + ${r}`);
|
|
1292
|
+
}
|
|
1293
|
+
return s.push(" + '}';"), s.push(" }"), s.join(`
|
|
1294
|
+
`);
|
|
1295
|
+
}
|
|
1296
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
1297
|
+
// Private: Type Conversion & Utilities
|
|
1298
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
1299
|
+
toJavaType(e, t) {
|
|
1300
|
+
switch (e) {
|
|
1301
|
+
case "boolean":
|
|
1302
|
+
return "Boolean";
|
|
1303
|
+
case "number":
|
|
1304
|
+
return "Double";
|
|
1305
|
+
// Use Double for numbers to handle both int and float
|
|
1306
|
+
case "string":
|
|
1307
|
+
return "String";
|
|
1308
|
+
case "array":
|
|
1309
|
+
return this.inferArrayType(t);
|
|
1310
|
+
case "object":
|
|
1311
|
+
return "Map<String, Object>";
|
|
1312
|
+
default:
|
|
1313
|
+
return "Object";
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
inferArrayType(e) {
|
|
1317
|
+
if (Array.isArray(e) && e.length > 0) {
|
|
1318
|
+
const t = typeof e[0];
|
|
1319
|
+
if (q(t))
|
|
1320
|
+
switch (t) {
|
|
1321
|
+
case "boolean":
|
|
1322
|
+
return "List<Boolean>";
|
|
1323
|
+
case "number":
|
|
1324
|
+
return "List<Double>";
|
|
1325
|
+
case "string":
|
|
1326
|
+
return "List<String>";
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
return "List<Object>";
|
|
1330
|
+
}
|
|
1331
|
+
getDefaultValue(e) {
|
|
1332
|
+
switch (e) {
|
|
1333
|
+
case "Boolean":
|
|
1334
|
+
return "null";
|
|
1335
|
+
case "Double":
|
|
1336
|
+
case "Integer":
|
|
1337
|
+
case "Long":
|
|
1338
|
+
return "null";
|
|
1339
|
+
case "String":
|
|
1340
|
+
return "null";
|
|
1341
|
+
case "List<Boolean>":
|
|
1342
|
+
case "List<Double>":
|
|
1343
|
+
case "List<String>":
|
|
1344
|
+
case "List<Object>":
|
|
1345
|
+
return "Collections.emptyList()";
|
|
1346
|
+
case "Map<String, Object>":
|
|
1347
|
+
return "Collections.emptyMap()";
|
|
1348
|
+
default:
|
|
1349
|
+
return "null";
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
sanitizeClassName(e) {
|
|
1353
|
+
let t = e.replace(/[^a-zA-Z0-9]/g, "");
|
|
1354
|
+
return t.length === 0 && (t = "Config"), /^[0-9]/.test(t) && (t = "Config" + t), t = t.charAt(0).toUpperCase() + t.slice(1), k.has(t.toLowerCase()) && (t += "Config"), t;
|
|
1355
|
+
}
|
|
1356
|
+
sanitizePackageName(e) {
|
|
1357
|
+
return e.toLowerCase().replace(/[^a-z0-9]/g, "").replace(/^([0-9])/, "_$1");
|
|
1358
|
+
}
|
|
1359
|
+
sanitizeFieldName(e) {
|
|
1360
|
+
let t = e.replace(/[^a-zA-Z0-9_$]/g, "_");
|
|
1361
|
+
return t.length === 0 && (t = "value"), /^[0-9]/.test(t) && (t = "_" + t), t = t.replace(/_([a-z])/g, (s, n) => n.toUpperCase()), t.charAt(0).toUpperCase() === t.charAt(0) && /^[a-z]/.test(e) && (t = t.charAt(0).toLowerCase() + t.slice(1)), k.has(t.toLowerCase()) && (t += "_"), t;
|
|
1362
|
+
}
|
|
1363
|
+
toGetterName(e) {
|
|
1364
|
+
return "get" + e.charAt(0).toUpperCase() + e.slice(1);
|
|
1365
|
+
}
|
|
1366
|
+
collectTypesUsed(e) {
|
|
1367
|
+
const t = /* @__PURE__ */ new Set();
|
|
1368
|
+
for (const s of e) {
|
|
1369
|
+
const n = this.toJavaType(s.type, s.value);
|
|
1370
|
+
n.startsWith("List<") && t.add("List"), n.startsWith("Map<") && t.add("Map");
|
|
1371
|
+
}
|
|
1372
|
+
return t;
|
|
1373
|
+
}
|
|
1374
|
+
getFilePath(e, t) {
|
|
1375
|
+
return `${e.replace(/\./g, "/")}/${t}.java`;
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
const w = [
|
|
1379
|
+
{
|
|
1380
|
+
groupId: "com.fasterxml.jackson.core",
|
|
1381
|
+
artifactId: "jackson-databind",
|
|
1382
|
+
version: "2.16.1",
|
|
1383
|
+
scope: "implementation"
|
|
1384
|
+
},
|
|
1385
|
+
{
|
|
1386
|
+
groupId: "com.fasterxml.jackson.core",
|
|
1387
|
+
artifactId: "jackson-annotations",
|
|
1388
|
+
version: "2.16.1",
|
|
1389
|
+
scope: "implementation"
|
|
1390
|
+
}
|
|
1391
|
+
];
|
|
1392
|
+
function V(i) {
|
|
1393
|
+
let e = p.resolve(i);
|
|
1394
|
+
const t = 10;
|
|
1395
|
+
let s = 0;
|
|
1396
|
+
for (; s < t; ) {
|
|
1397
|
+
const n = p.join(e, "build.gradle");
|
|
1398
|
+
if (f.existsSync(n))
|
|
1399
|
+
return { projectRoot: e, buildFile: n, projectType: "gradle" };
|
|
1400
|
+
const a = p.join(e, "build.gradle.kts");
|
|
1401
|
+
if (f.existsSync(a))
|
|
1402
|
+
return { projectRoot: e, buildFile: a, projectType: "gradle" };
|
|
1403
|
+
const r = p.join(e, "pom.xml");
|
|
1404
|
+
if (f.existsSync(r))
|
|
1405
|
+
return { projectRoot: e, buildFile: r, projectType: "maven" };
|
|
1406
|
+
const o = p.dirname(e);
|
|
1407
|
+
if (o === e)
|
|
1408
|
+
break;
|
|
1409
|
+
e = o, s++;
|
|
1410
|
+
}
|
|
1411
|
+
return null;
|
|
1412
|
+
}
|
|
1413
|
+
function W(i, e) {
|
|
1414
|
+
return [
|
|
1415
|
+
// Standard format: implementation 'group:artifact:version'
|
|
1416
|
+
new RegExp(`['"]${g(e.groupId)}:${g(e.artifactId)}:[^'"]+['"]`),
|
|
1417
|
+
// Without version (e.g., using BOM or version catalog)
|
|
1418
|
+
new RegExp(`['"]${g(e.groupId)}:${g(e.artifactId)}['"]`),
|
|
1419
|
+
// Gradle Kotlin DSL format
|
|
1420
|
+
new RegExp(`"${g(e.groupId)}:${g(e.artifactId)}:[^"]+"`)
|
|
1421
|
+
].some((s) => s.test(i));
|
|
1422
|
+
}
|
|
1423
|
+
function Z(i, e) {
|
|
1424
|
+
const t = `<groupId>${g(e.groupId)}</groupId>`, s = `<artifactId>${g(e.artifactId)}</artifactId>`;
|
|
1425
|
+
return i.includes(e.groupId) && i.includes(e.artifactId) && new RegExp(t).test(i) && new RegExp(s).test(i);
|
|
1426
|
+
}
|
|
1427
|
+
function g(i) {
|
|
1428
|
+
return i.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1429
|
+
}
|
|
1430
|
+
function X(i, e, t) {
|
|
1431
|
+
const s = [], n = [];
|
|
1432
|
+
for (const a of e) {
|
|
1433
|
+
const r = `${a.groupId}:${a.artifactId}`;
|
|
1434
|
+
if (W(i, a)) {
|
|
1435
|
+
n.push(r);
|
|
1436
|
+
continue;
|
|
1437
|
+
}
|
|
1438
|
+
const l = /dependencies\s*\{/.exec(i);
|
|
1439
|
+
if (l) {
|
|
1440
|
+
const c = l.index + l[0].length, u = t ? '"' : "'", h = `
|
|
1441
|
+
${a.scope}(${u}${a.groupId}:${a.artifactId}:${a.version}${u})`;
|
|
1442
|
+
i = i.slice(0, c) + h + i.slice(c), s.push(r);
|
|
1443
|
+
}
|
|
1444
|
+
}
|
|
1445
|
+
return { content: i, added: s, existing: n };
|
|
1446
|
+
}
|
|
1447
|
+
function Y(i, e) {
|
|
1448
|
+
const t = [], s = [];
|
|
1449
|
+
for (const n of e) {
|
|
1450
|
+
const a = `${n.groupId}:${n.artifactId}`;
|
|
1451
|
+
if (Z(i, n)) {
|
|
1452
|
+
s.push(a);
|
|
1453
|
+
continue;
|
|
1454
|
+
}
|
|
1455
|
+
const o = /<dependencies>/.exec(i);
|
|
1456
|
+
if (o) {
|
|
1457
|
+
const l = o.index + o[0].length, c = `
|
|
1458
|
+
<dependency>
|
|
1459
|
+
<groupId>${n.groupId}</groupId>
|
|
1460
|
+
<artifactId>${n.artifactId}</artifactId>
|
|
1461
|
+
<version>${n.version}</version>
|
|
1462
|
+
</dependency>`;
|
|
1463
|
+
i = i.slice(0, l) + c + i.slice(l), t.push(a);
|
|
1464
|
+
} else {
|
|
1465
|
+
const c = /<\/project>/.exec(i);
|
|
1466
|
+
if (c) {
|
|
1467
|
+
const u = c.index, h = `
|
|
1468
|
+
<dependencies>
|
|
1469
|
+
<dependency>
|
|
1470
|
+
<groupId>${n.groupId}</groupId>
|
|
1471
|
+
<artifactId>${n.artifactId}</artifactId>
|
|
1472
|
+
<version>${n.version}</version>
|
|
1473
|
+
</dependency>
|
|
1474
|
+
</dependencies>
|
|
1475
|
+
`;
|
|
1476
|
+
i = i.slice(0, u) + h + i.slice(u), t.push(a);
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
return { content: i, added: t, existing: s };
|
|
1481
|
+
}
|
|
1482
|
+
function Q(i, e = !1) {
|
|
1483
|
+
const t = [], s = V(i);
|
|
1484
|
+
if (!s)
|
|
1485
|
+
return {
|
|
1486
|
+
success: !1,
|
|
1487
|
+
projectType: "unknown",
|
|
1488
|
+
error: "Could not find build.gradle, build.gradle.kts, or pom.xml in the project hierarchy. Please manually add the Jackson dependency to your project.",
|
|
1489
|
+
warnings: [
|
|
1490
|
+
"For Gradle: implementation 'com.fasterxml.jackson.core:jackson-databind:2.16.1'",
|
|
1491
|
+
"For Maven: <dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.16.1</version></dependency>"
|
|
1492
|
+
]
|
|
1493
|
+
};
|
|
1494
|
+
const { projectRoot: n, buildFile: a, projectType: r } = s, o = a.endsWith(".kts");
|
|
1495
|
+
try {
|
|
1496
|
+
const l = f.readFileSync(a, "utf-8");
|
|
1497
|
+
let c;
|
|
1498
|
+
return r === "gradle" ? c = X(l, w, o) : c = Y(l, w), c.added.length > 0 && !e && f.writeFileSync(a, c.content, "utf-8"), c.existing.length > 0 && t.push(`Already present: ${c.existing.join(", ")}`), {
|
|
1499
|
+
success: !0,
|
|
1500
|
+
projectType: r,
|
|
1501
|
+
buildFilePath: a,
|
|
1502
|
+
addedDependencies: c.added,
|
|
1503
|
+
existingDependencies: c.existing,
|
|
1504
|
+
warnings: t.length > 0 ? t : void 0
|
|
1505
|
+
};
|
|
1506
|
+
} catch (l) {
|
|
1507
|
+
return {
|
|
1508
|
+
success: !1,
|
|
1509
|
+
projectType: r,
|
|
1510
|
+
buildFilePath: a,
|
|
1511
|
+
error: l instanceof Error ? l.message : "Failed to update build file"
|
|
1512
|
+
};
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
function te() {
|
|
1516
|
+
return [...w];
|
|
1517
|
+
}
|
|
1518
|
+
function se(i, e = w) {
|
|
1519
|
+
return i === "gradle" ? e.map(
|
|
1520
|
+
(t) => `implementation '${t.groupId}:${t.artifactId}:${t.version}'`
|
|
1521
|
+
) : e.map(
|
|
1522
|
+
(t) => `<dependency>
|
|
1523
|
+
<groupId>${t.groupId}</groupId>
|
|
1524
|
+
<artifactId>${t.artifactId}</artifactId>
|
|
1525
|
+
<version>${t.version}</version>
|
|
1526
|
+
</dependency>`
|
|
1527
|
+
);
|
|
1528
|
+
}
|
|
1529
|
+
function E(i) {
|
|
1530
|
+
const e = p.dirname(i);
|
|
1531
|
+
f.existsSync(e) || f.mkdirSync(e, { recursive: !0 });
|
|
1532
|
+
}
|
|
1533
|
+
function D(i) {
|
|
1534
|
+
let e = 0, t = 0;
|
|
1535
|
+
for (const s of i) {
|
|
1536
|
+
e += s.configs.length;
|
|
1537
|
+
for (const n of s.configs)
|
|
1538
|
+
t += n.keys.length;
|
|
1539
|
+
}
|
|
1540
|
+
return { configs: e, keys: t };
|
|
1541
|
+
}
|
|
1542
|
+
async function ne(i) {
|
|
1543
|
+
const {
|
|
1544
|
+
apiKey: e,
|
|
1545
|
+
baseUrl: t = A,
|
|
1546
|
+
output: s = z,
|
|
1547
|
+
namespace: n = T
|
|
1548
|
+
} = i;
|
|
1549
|
+
try {
|
|
1550
|
+
const r = await (await S({ apiKey: e, baseUrl: t })).discovery.introspect();
|
|
1551
|
+
if (!r.success || !r.data)
|
|
1552
|
+
return {
|
|
1553
|
+
success: !1,
|
|
1554
|
+
error: r.message || "Failed to fetch introspection data"
|
|
1555
|
+
};
|
|
1556
|
+
const { brands: o } = r.data, { configs: l, keys: c } = D(o), h = new H(n).generate(r.data), d = p.resolve(process.cwd(), s);
|
|
1557
|
+
return E(d), f.writeFileSync(d, h, "utf-8"), {
|
|
1558
|
+
success: !0,
|
|
1559
|
+
outputPath: d,
|
|
1560
|
+
content: h,
|
|
1561
|
+
stats: {
|
|
1562
|
+
brands: o.length,
|
|
1563
|
+
configs: l,
|
|
1564
|
+
keys: c
|
|
1565
|
+
}
|
|
1566
|
+
};
|
|
1567
|
+
} catch (a) {
|
|
1568
|
+
return {
|
|
1569
|
+
success: !1,
|
|
1570
|
+
error: a instanceof Error ? a.message : "Unknown error"
|
|
1571
|
+
};
|
|
1572
|
+
}
|
|
1573
|
+
}
|
|
1574
|
+
async function ae(i) {
|
|
1575
|
+
const {
|
|
1576
|
+
apiKey: e,
|
|
1577
|
+
baseUrl: t = A,
|
|
1578
|
+
output: s = "./libs/dinoconfig-java-sdk/lib/src/main/java/com/dinoconfig/sdk/generated",
|
|
1579
|
+
skipDependencyUpdate: n = !1
|
|
1580
|
+
} = i;
|
|
1581
|
+
try {
|
|
1582
|
+
const r = await (await S({ apiKey: e, baseUrl: t })).discovery.introspect();
|
|
1583
|
+
if (!r.success || !r.data)
|
|
1584
|
+
return {
|
|
1585
|
+
success: !1,
|
|
1586
|
+
error: r.message || "Failed to fetch introspection data"
|
|
1587
|
+
};
|
|
1588
|
+
const { brands: o } = r.data, { configs: l, keys: c } = D(o), u = p.resolve(process.cwd(), s), h = i.package ?? K(u), d = new G({ basePackage: h }), m = d.generate(r.data), y = [];
|
|
1589
|
+
for (const [P, F] of m.entries()) {
|
|
1590
|
+
const C = p.join(u, P);
|
|
1591
|
+
E(C), f.writeFileSync(C, F, "utf-8"), y.push(C);
|
|
1592
|
+
}
|
|
1593
|
+
let b;
|
|
1594
|
+
return n || (b = Q(u)), {
|
|
1595
|
+
success: !0,
|
|
1596
|
+
outputDir: u,
|
|
1597
|
+
generatedFiles: y,
|
|
1598
|
+
stats: {
|
|
1599
|
+
brands: o.length,
|
|
1600
|
+
configs: l,
|
|
1601
|
+
keys: c
|
|
1602
|
+
},
|
|
1603
|
+
dependencyUpdate: b,
|
|
1604
|
+
basePackage: d.getBasePackage()
|
|
1605
|
+
};
|
|
1606
|
+
} catch (a) {
|
|
1607
|
+
return {
|
|
1608
|
+
success: !1,
|
|
1609
|
+
error: a instanceof Error ? a.message : "Unknown error"
|
|
1610
|
+
};
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
export {
|
|
1614
|
+
G as J,
|
|
1615
|
+
H as T,
|
|
1616
|
+
ne as a,
|
|
1617
|
+
te as b,
|
|
1618
|
+
K as d,
|
|
1619
|
+
se as f,
|
|
1620
|
+
ae as g,
|
|
1621
|
+
Q as u
|
|
1622
|
+
};
|