@weclapp/sdk 2.0.0-dev.54 → 2.0.0-dev.55

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.js +1371 -1264
  2. package/package.json +6 -4
package/dist/cli.js CHANGED
@@ -1,1390 +1,1497 @@
1
- import { fileURLToPath } from "url";
2
- import { dirname, resolve } from "path";
3
- import { rolldown } from "rolldown";
4
- import indentString from "indent-string";
5
- import { camelCase, pascalCase, snakeCase } from "change-case";
6
- import chalk from "chalk";
7
- import { OpenAPIV3 } from "openapi-types";
8
- import { createHash } from "crypto";
9
- import { cp, mkdir, readFile, rm, stat, writeFile } from "fs/promises";
10
- import { config } from "dotenv";
11
- import yargs from "yargs";
12
- import { hideBin } from "yargs/helpers";
13
- import pkg from "../package.json" with { type: "json" };
14
- import prettyMs from "pretty-ms";
15
- //#region src/utils/currentDirname.ts
1
+ import { fileURLToPath } from 'url';
2
+ import { resolve, dirname } from 'path';
3
+ import { rollup } from 'rollup';
4
+ import terser from '@rollup/plugin-terser';
5
+ import ts from '@rollup/plugin-typescript';
6
+ import indentString from 'indent-string';
7
+ import { snakeCase, pascalCase, camelCase } from 'change-case';
8
+ import chalk from 'chalk';
9
+ import { OpenAPIV3 } from 'openapi-types';
10
+ import { createHash } from 'crypto';
11
+ import { stat, readFile, rm, cp, writeFile, mkdir } from 'fs/promises';
12
+ import { config } from 'dotenv';
13
+ import yargs from 'yargs';
14
+ import { hideBin } from 'yargs/helpers';
15
+ import pkg from '../package.json' with { type: 'json' };
16
+ import prettyMs from 'pretty-ms';
17
+
16
18
  const currentDirname = () => {
17
- return fileURLToPath(new URL("..", import.meta.url));
18
- };
19
- //#endregion
20
- //#region src/target.ts
21
- let Target = /* @__PURE__ */ function(Target) {
22
- Target["BROWSER_PROMISES"] = "browser";
23
- Target["BROWSER_RX"] = "browser.rx";
24
- Target["NODE_PROMISES"] = "node";
25
- Target["NODE_RX"] = "node.rx";
26
- return Target;
27
- }({});
19
+ // Go one level up as the CLI is inside a folder
20
+ return fileURLToPath(new URL('..', import.meta.url));
21
+ };
22
+
23
+ var Target;
24
+ (function (Target) {
25
+ Target["BROWSER_PROMISES"] = "browser";
26
+ Target["BROWSER_RX"] = "browser.rx";
27
+ Target["NODE_PROMISES"] = "node";
28
+ Target["NODE_RX"] = "node.rx";
29
+ })(Target || (Target = {}));
28
30
  const isNodeTarget = (target) => {
29
- return target === Target.NODE_PROMISES || target === Target.NODE_RX;
31
+ return target === Target.NODE_PROMISES || target === Target.NODE_RX;
30
32
  };
31
33
  const isRXTarget = (target) => {
32
- return target === Target.BROWSER_RX || target === Target.NODE_RX;
34
+ return target === Target.BROWSER_RX || target === Target.NODE_RX;
33
35
  };
34
36
  const resolveResponseType = (target) => {
35
- return isRXTarget(target) ? "Observable" : "Promise";
37
+ return isRXTarget(target) ? 'Observable' : 'Promise';
36
38
  };
37
39
  const resolveBinaryType = (target) => {
38
- return isNodeTarget(target) ? "Buffer" : "Blob";
40
+ return isNodeTarget(target) ? 'Buffer' : 'Blob';
39
41
  };
40
- //#endregion
41
- //#region src/bundle.ts
42
- const tsconfig = resolve(currentDirname(), "./tsconfig.sdk.json");
43
- const resolveGlobals = (...globals) => Object.fromEntries(globals.map((v) => [v, "*"]));
42
+
43
+ const tsconfig = resolve(currentDirname(), './tsconfig.sdk.json');
44
+ const resolveGlobals = (...globals) => Object.fromEntries(globals.map((v) => [v, '*']));
44
45
  const generateOutput = (config) => ({
45
- sourcemap: false,
46
- banner: `/* weclapp sdk */`,
47
- ...config
46
+ sourcemap: false,
47
+ banner: `/* weclapp sdk */`,
48
+ ...config
48
49
  });
49
50
  const bundle = async (workingDirectory, target) => {
50
- const dist = (...paths) => resolve(workingDirectory, "dist", ...paths);
51
- const src = (...paths) => resolve(workingDirectory, "src", ...paths);
52
- const generateNodeOutput = () => [generateOutput({
53
- file: dist("index.cjs"),
54
- format: "cjs",
55
- globals: resolveGlobals("node-fetch", "url")
56
- }), generateOutput({
57
- file: dist("index.js"),
58
- format: "es",
59
- globals: resolveGlobals("node-fetch", "url")
60
- })];
61
- const config = {
62
- [Target.BROWSER_PROMISES]: () => ({
63
- input: src("index.ts"),
64
- resolve: { tsconfigFilename: tsconfig },
65
- output: [generateOutput({
66
- file: dist("index.js"),
67
- format: "es",
68
- minify: true
69
- })]
70
- }),
71
- [Target.BROWSER_RX]: () => ({
72
- input: src("index.ts"),
73
- resolve: { tsconfigFilename: tsconfig },
74
- external: ["rxjs"],
75
- output: [generateOutput({
76
- file: dist("index.js"),
77
- format: "es",
78
- minify: true,
79
- globals: resolveGlobals("rxjs")
80
- })]
81
- }),
82
- [Target.NODE_PROMISES]: () => ({
83
- input: src("index.ts"),
84
- resolve: { tsconfigFilename: tsconfig },
85
- external: ["node-fetch", "url"],
86
- output: generateNodeOutput().map((o) => ({
87
- ...o,
88
- minify: true
89
- }))
90
- }),
91
- [Target.NODE_RX]: () => ({
92
- input: src("index.ts"),
93
- resolve: { tsconfigFilename: tsconfig },
94
- external: [
95
- "node-fetch",
96
- "url",
97
- "rxjs"
98
- ],
99
- output: generateNodeOutput().map((o) => ({
100
- ...o,
101
- minify: true
102
- }))
103
- })
104
- }[target]();
105
- const result = await rolldown(config);
106
- if (Array.isArray(config.output)) await Promise.all(config.output.map((o) => result.write(o)));
107
- else if (config.output) await result.write(config.output);
108
- await result.close();
109
- };
110
- //#endregion
111
- //#region src/ts/generateString.ts
51
+ const dist = (...paths) => resolve(workingDirectory, 'dist', ...paths);
52
+ const src = (...paths) => resolve(workingDirectory, 'src', ...paths);
53
+ const generateNodeOutput = () => [
54
+ generateOutput({
55
+ file: dist('index.cjs'),
56
+ format: 'cjs',
57
+ globals: resolveGlobals('node-fetch', 'url')
58
+ }),
59
+ generateOutput({
60
+ file: dist('index.js'),
61
+ format: 'es',
62
+ globals: resolveGlobals('node-fetch', 'url')
63
+ })
64
+ ];
65
+ const bundles = {
66
+ [Target.BROWSER_PROMISES]: () => ({
67
+ input: src('index.ts'),
68
+ plugins: [ts({ tsconfig, declarationDir: dist(), filterRoot: src() }), terser()],
69
+ output: [
70
+ generateOutput({
71
+ file: dist('index.js'),
72
+ format: 'es'
73
+ })
74
+ ]
75
+ }),
76
+ [Target.BROWSER_RX]: () => ({
77
+ input: src('index.ts'),
78
+ plugins: [ts({ tsconfig, declarationDir: dist(), filterRoot: src() }), terser()],
79
+ external: ['rxjs'],
80
+ output: [
81
+ generateOutput({
82
+ file: dist('index.js'),
83
+ format: 'es',
84
+ globals: resolveGlobals('rxjs')
85
+ })
86
+ ]
87
+ }),
88
+ [Target.NODE_PROMISES]: () => ({
89
+ input: src('index.ts'),
90
+ plugins: [ts({ tsconfig, declarationDir: dist(), filterRoot: src() }), terser()],
91
+ external: ['node-fetch', 'url'],
92
+ output: generateNodeOutput()
93
+ }),
94
+ [Target.NODE_RX]: () => ({
95
+ input: src('index.ts'),
96
+ plugins: [ts({ tsconfig, declarationDir: dist(), filterRoot: src() }), terser()],
97
+ external: ['node-fetch', 'url', 'rxjs'],
98
+ output: generateNodeOutput()
99
+ })
100
+ };
101
+ const config = bundles[target]();
102
+ const bundle = await rollup(config);
103
+ if (Array.isArray(config.output)) {
104
+ await Promise.all(config.output.map(bundle.write));
105
+ }
106
+ else if (config.output) {
107
+ await bundle.write(config.output);
108
+ }
109
+ await bundle.close();
110
+ };
111
+
112
112
  const generateString = (str) => `'${str}'`;
113
113
  const generateStrings = (str) => str.map(generateString);
114
- //#endregion
115
- //#region src/ts/generateImport.ts
114
+
116
115
  const generateImport = (opt) => {
117
- return `import ${[opt.default, opt.imports?.length ? `{${opt.imports.join(", ")}}` : ""].filter(Boolean).join(", ")} from ${generateString(opt.src)};`;
116
+ const imports = [opt.default, opt.imports?.length ? `{${opt.imports.join(', ')}}` : ''];
117
+ return `import ${imports.filter(Boolean).join(', ')} from ${generateString(opt.src)};`;
118
118
  };
119
- //#endregion
120
- //#region src/utils/indent.ts
119
+
121
120
  /**
122
- * Indents each line of the given string
123
- * @param s String to indent
124
- * @param level Indentation level
125
- */
121
+ * Indents each line of the given string
122
+ * @param s String to indent
123
+ * @param level Indentation level
124
+ */
126
125
  const indent = (s, level = 1) => {
127
- return indentString(s, 4 * level);
126
+ return indentString(s, 4 * level);
128
127
  };
129
- //#endregion
130
- //#region src/ts/generateStatements.ts
131
- const generateStatements = (...statements) => statements.map((v) => v.trim()).filter((v) => v.length).join("\n\n");
128
+
129
+ const generateStatements = (...statements) => statements
130
+ .map((v) => v.trim())
131
+ .filter((v) => v.length)
132
+ .join('\n\n');
132
133
  const generateBlockStatements = (...statements) => `{\n${indent(generateStatements(...statements))}\n}`;
133
- //#endregion
134
- //#region src/generator/01-base/static/globalConfig.ts.txt
135
- var globalConfig_ts_default = "export default \"export type RequestPayloadMethod =\\n | 'GET'\\n | 'HEAD'\\n | 'POST'\\n | 'PUT'\\n | 'DELETE'\\n | 'CONNECT'\\n | 'OPTIONS'\\n | 'TRACE'\\n | 'PATCH';\\n\\nexport interface RequestPayload {\\n method?: RequestPayloadMethod;\\n query?: Record<string, any>;\\n body?: any;\\n unwrap?: boolean;\\n forceBlob?: boolean;\\n}\\n\\nexport interface ServiceConfig {\\n // Your API-Key, this is optional in the sense of if you omit this, and you're in a browser, the\\n // cookie-authentication (include-credentials) will be used.\\n key?: string;\\n\\n // Your domain, if omitted location.host will be used (browser env).\\n host?: string;\\n\\n // If you want to use https, defaults to location.protocol (browser env).\\n secure?: boolean;\\n\\n // If you want that some and count requests are bundled into multi requests.\\n multiRequest?: boolean;\\n\\n // If you want that the ignoreMissingProperties parameter to be set to true for every post request.\\n ignoreMissingProperties?: boolean;\\n\\n // Optional request/response interceptors.\\n interceptors?: {\\n // Takes the generated request, you can either return a new request,\\n // a response (which will be taken as \\\"the\\\" response) or nothing.\\n // The payload contains the raw input generated by the SDK.\\n request?: (\\n request: Request,\\n payload: RequestPayload\\n ) => Request | Response | void | Promise<Request | Response | void>;\\n\\n // Takes the response. This can either be the one from the server or an\\n // artificially-crafted one by the request interceptor.\\n response?: (response: Response) => Response | void | Promise<Response | void>;\\n };\\n\\n // Whether POST should be used instead of GET for some() and count() operations\\n usePost?: boolean;\\n}\\n\\nexport interface RequestOptions {\\n signal?: AbortSignal;\\n}\\n\\ntype ServiceConfigWithoutMultiRequest = Omit<ServiceConfig, 'multiRequest'>;\\n\\nlet globalConfig: ServiceConfig | undefined;\\nexport const getGlobalConfig = (): ServiceConfig | undefined => globalConfig;\\nexport const setGlobalConfig = (cfg?: ServiceConfig) => (globalConfig = cfg);\\n\\nexport const getHost = (cfg: ServiceConfig) => {\\n let host = cfg.host?.replace(/^https?:\\\\/\\\\//, '');\\n if (!host && typeof location !== 'undefined') {\\n host = location.host;\\n }\\n\\n if (!host) {\\n throw new Error('Please specify a host');\\n }\\n\\n return host;\\n};\\n\\nexport const getProtocol = (cfg: ServiceConfig) => {\\n const protocol =\\n cfg.secure !== undefined\\n ? cfg.secure\\n ? 'https:'\\n : 'http:'\\n : typeof location !== 'undefined'\\n ? location.protocol\\n : undefined;\\n\\n if (!protocol) {\\n throw new Error('Please specify a protocol (secure)');\\n }\\n\\n return protocol;\\n};\\n\";";
136
- //#endregion
137
- //#region src/generator/01-base/static/multiRequest.ts.txt
138
- var multiRequest_ts_default = "export default \"type RequestTask = {\\n uri: string;\\n resolve: (result: unknown) => void;\\n reject: (error: unknown) => void;\\n};\\n\\ntype BatchRequestTask = RequestTask & {\\n settled: boolean;\\n};\\n\\ntype MultiRequestResponse = {\\n status: number;\\n body: object;\\n};\\n\\nlet microtaskQueued: boolean = false;\\nconst tasksSet: Set<RequestTask> = new Set<RequestTask>();\\n\\nconst SQUARE_BRACKET_OPEN = '['.charCodeAt(0);\\nconst COMMA = ','.charCodeAt(0);\\nconst DECODER = new TextDecoder();\\n\\nconst readNextResponse = (bytes: Uint8Array<ArrayBuffer>) => {\\n let headerStart: number | undefined = undefined;\\n let commasSeen = 0;\\n\\n for (let i = 0; i < bytes.length; i++) {\\n const byte = bytes[i];\\n if (headerStart === undefined) {\\n if (byte === SQUARE_BRACKET_OPEN || byte === COMMA) {\\n headerStart = i + 1;\\n }\\n } else {\\n if (byte === COMMA) {\\n commasSeen++;\\n }\\n if (commasSeen === 2) {\\n const headerArrayString = `[${DECODER.decode(bytes.subarray(headerStart, i))}]`;\\n const [index, jsonLength] = JSON.parse(headerArrayString);\\n if (!(typeof index === 'number') || !(typeof jsonLength === 'number')) {\\n throw new Error(`unexpected header: ${headerArrayString}`);\\n }\\n\\n const endIndex = i + 1 + jsonLength;\\n if (endIndex > bytes.length) {\\n // not all bytes available yet\\n return undefined;\\n }\\n const jsonString = DECODER.decode(bytes.subarray(i + 1, endIndex));\\n const data = JSON.parse(jsonString) as MultiRequestResponse;\\n return {\\n index,\\n data,\\n remainingBytes: bytes.subarray(endIndex)\\n };\\n }\\n }\\n }\\n return undefined;\\n};\\n\\nconst fetchMultiRequest = async (requests: string[]) => {\\n const cfg = getGlobalConfig();\\n\\n if (!cfg) {\\n throw new Error(`ServiceConfig missing.`);\\n }\\n\\n const host = getHost(cfg);\\n const protocol = getProtocol(cfg);\\n\\n return await fetch(`${protocol}//${host}/webapp/api/v2/batch/query`, {\\n method: 'POST',\\n headers: {\\n 'Content-Type': 'application/json',\\n ...(cfg.key && { AuthenticationToken: cfg.key })\\n },\\n body: JSON.stringify({ requests })\\n });\\n};\\n\\nconst rejectTasks = (tasks: BatchRequestTask[], error: unknown) => {\\n for (const task of tasks) {\\n if (!task.settled) {\\n task.reject(error);\\n }\\n }\\n};\\n\\nconst processStream = (\\n { value: chunk, done }: ReadableStreamReadResult<Uint8Array>,\\n remainingBytes: Uint8Array,\\n reader: ReadableStreamDefaultReader<Uint8Array>,\\n tasks: BatchRequestTask[]\\n) => {\\n if (done) {\\n return;\\n }\\n if (chunk) {\\n let bytes = new Uint8Array(remainingBytes.length + chunk.length);\\n bytes.set(remainingBytes);\\n bytes.set(chunk, remainingBytes.length);\\n\\n while (bytes.length) {\\n const result = readNextResponse(bytes);\\n if (!result) {\\n break;\\n }\\n const task = tasks[result.index];\\n if (result.data.status >= 100 && result.data.status < 400) {\\n task.resolve({\\n ...result.data.body\\n });\\n } else {\\n task.reject({\\n ...result.data.body\\n });\\n }\\n task.settled = true;\\n bytes = result.remainingBytes;\\n }\\n reader\\n .read()\\n .then((readResult) => processStream(readResult, bytes, reader, tasks))\\n .catch((error) => rejectTasks(tasks, error));\\n }\\n};\\n\\nconst batch = async (tasks: BatchRequestTask[]) => {\\n try {\\n const requests = tasks.map(({ uri }) => uri);\\n const resp = await fetchMultiRequest(requests);\\n const reader = resp.body?.getReader();\\n\\n if (!reader) {\\n throw new Error('Stream reader is undefined');\\n }\\n reader\\n .read()\\n .then((readResult) => processStream(readResult, new Uint8Array(0), reader, tasks))\\n .catch((error) => rejectTasks(tasks, error));\\n } catch (e) {\\n rejectTasks(tasks, e);\\n throw e;\\n }\\n};\\n\\nconst addTask = (task: RequestTask) => {\\n tasksSet.add(task);\\n\\n if (!microtaskQueued) {\\n queueMicrotask(() => {\\n microtaskQueued = false;\\n if (tasksSet.size > 0) {\\n const batchTasks = Array.from(tasksSet).map((task) => ({ ...task, settled: false }));\\n void batch(batchTasks);\\n tasksSet.clear();\\n }\\n });\\n microtaskQueued = true;\\n }\\n};\\n\\nconst addRequest = (uri: string) => new Promise((resolve, reject) => addTask({ uri, resolve, reject }));\\n\";";
139
- //#endregion
140
- //#region src/generator/01-base/static/queriesWithFilter.ts.txt
141
- var queriesWithFilter_ts_default = "export default \"export type EqualityOperator = 'EQ' | 'NE';\\n\\nexport type ComparisonOperator =\\n | 'LT'\\n | 'GT'\\n | 'LE'\\n | 'GE'\\n | 'LIKE'\\n | 'ILIKE'\\n | 'NOT_LIKE'\\n | 'NOT_ILIKE'\\n | 'IEQ'\\n | 'NOT_IEQ';\\n\\nexport type ArrayOperator = 'IN' | 'NOT_IN';\\n\\nexport type Operator = EqualityOperator | ComparisonOperator | ArrayOperator;\\n\\nexport type MapOperators<T> = { [K in EqualityOperator]?: T | null } & { [K in ComparisonOperator]?: T } & {\\n [K in ArrayOperator]?: T[];\\n};\\n\\nexport type QueryFilter<T> = {\\n [P in keyof T]?: T[P] extends Array<infer U> | undefined\\n ? U extends Record<any, any>\\n ? QueryFilter<U>\\n : MapOperators<U>\\n : T[P] extends Record<any, any> | undefined\\n ? QueryFilter<T[P]>\\n : MapOperators<T[P]>;\\n};\\n\\nexport type CountQuery<F> = {\\n filter?: QueryFilter<F>;\\n or?: (QueryFilter<F> & CustomAttributeFilter)[];\\n};\\n\\nexport type SomeQuery<E, F, I, P> = {\\n serializeNulls?: boolean;\\n include?: QuerySelect<I>;\\n properties?: P;\\n filter?: QueryFilter<F> & CustomAttributeFilter;\\n select?: QuerySelect<E>;\\n or?: (QueryFilter<F> & CustomAttributeFilter)[];\\n sort?: Sort<E>[];\\n pagination?: Pagination;\\n};\\n\\nconst equality: string[] = ['EQ', 'NE', 'IEQ', 'NOT_IEQ'];\\n\\nconst simple: string[] = [...equality, 'LT', 'GT', 'LE', 'GE', 'LIKE', 'NOT_LIKE', 'ILIKE', 'NOT_ILIKE'];\\n\\nconst array: string[] = ['IN', 'NOT_IN'];\\n\\nconst filterMap: Record<Operator, string> = {\\n EQ: 'eq',\\n NE: 'ne',\\n LT: 'lt',\\n GT: 'gt',\\n LE: 'le',\\n GE: 'ge',\\n LIKE: 'like',\\n NOT_LIKE: 'notlike',\\n ILIKE: 'ilike',\\n NOT_ILIKE: 'notilike',\\n IN: 'in',\\n NOT_IN: 'notin',\\n IEQ: 'ieq',\\n NOT_IEQ: 'notieq'\\n};\\n\\nconst flattenCustomAttributes = (obj: CustomAttributeFilter = {}): [string, string][] => {\\n const entries: [string, string][] = [];\\n\\n for (const [id, filter] of Object.entries(obj)) {\\n const key = `customAttribute${id}`;\\n\\n if (typeof filter === 'object') {\\n for (const [prop, value] of Object.entries(filter)) {\\n entries.push([`${key}.${prop}-eq`, String(value)]);\\n }\\n } else if (filter !== undefined) {\\n entries.push([`${key}-eq`, String(filter)]);\\n }\\n }\\n\\n return entries;\\n};\\n\\nconst flatten = (obj: QueryFilter<any> = {}): [string, string][] => {\\n const entries: [string, string][] = [];\\n\\n for (const [prop, propValue] of Object.entries(obj)) {\\n for (const [filter, value] of Object.entries(propValue as object)) {\\n if (value === undefined) continue;\\n\\n if (simple.includes(filter) || array.includes(filter)) {\\n if (value === null && equality.includes(filter)) {\\n entries.push([`${prop}-${filter === 'EQ' ? 'null' : 'notnull'}`, '']);\\n } else {\\n entries.push([`${prop}-${filterMap[filter as Operator]}`, value]);\\n }\\n } else {\\n entries.push(\\n ...(flatten(propValue as QueryFilter<any>).map((v) => [`${prop}.${v[0]}`, v[1]]) as [string, string][])\\n );\\n break;\\n }\\n }\\n }\\n\\n return entries;\\n};\\n\\nconst flattenFilter = (obj: QueryFilter<any> = {}): Record<string, string> => {\\n const filter: [string, any][] = [],\\n customAttributes: [string, any][] = [];\\n\\n Object.entries(obj).forEach((value) => {\\n (value[0].match(/^\\\\d+$/) ? customAttributes : filter).push(value);\\n });\\n\\n return Object.fromEntries([\\n ...flatten(Object.fromEntries(filter)),\\n ...flattenCustomAttributes(Object.fromEntries(customAttributes) as CustomAttributeFilter)\\n ]);\\n};\\n\\nconst flattenOrFilter = (obj: QueryFilter<any>[] = []): Record<string, string> => {\\n const entries: [string, any][] = [];\\n\\n for (let i = 0; i < obj.length; i++) {\\n entries.push(...(flatten(obj[i]).map((v) => [`or${i || ''}-${v[0]}`, v[1]]) as [string, string][]));\\n }\\n\\n return Object.fromEntries(entries);\\n};\\n\\nconst _count = (\\n cfg: ServiceConfig | undefined,\\n endpoint: string,\\n query?: CountQuery<any> & { params?: Record<any, any> },\\n requestOptions?: RequestOptions\\n) =>\\n{\\n const usePost = cfg?.usePost ?? globalConfig?.usePost\\n const payload = {\\n ...flattenFilter(query?.filter),\\n ...flattenOrFilter(query?.or),\\n ...query?.params\\n }\\n\\n return wrapResponse(() =>\\n raw(cfg, endpoint, {\\n method: usePost ? 'POST' : 'GET',\\n unwrap: true,\\n ...(usePost ? { body: payload } : { query: payload })\\n }, requestOptions)\\n )\\n };\\n\\nconst _some = (\\n cfg: ServiceConfig | undefined,\\n endpoint: string,\\n query?: SomeQuery<any, any, any, any> & { params?: Record<any, any> },\\n requestOptions?: RequestOptions\\n) =>\\n{\\n const usePost = cfg?.usePost ?? globalConfig?.usePost\\n const payload = {\\n serializeNulls: query?.serializeNulls,\\n additionalProperties: query?.properties?.join(','),\\n properties: query?.select ? flattenSelect(query.select).join(',') : undefined,\\n includeReferencedEntities: query?.include ? Object.keys(query.include).join(',') : undefined,\\n ...flattenOrFilter(query?.or),\\n ...flattenFilter(query?.filter),\\n ...flattenSort(query?.sort),\\n ...query?.params,\\n ...query?.pagination\\n }\\n\\n return wrapResponse(() =>\\n raw(cfg, usePost ? `${endpoint}/query` : endpoint, {\\n method: usePost ? 'POST' : 'GET',\\n ...(usePost ? { body: payload } : { query: payload })\\n }, requestOptions).then((data) => ({\\n entities: data.result,\\n references: data.referencedEntities ?? {},\\n properties: data.additionalProperties ?? {}\\n }))\\n )\\n };\\n\";";
142
- //#endregion
143
- //#region src/generator/01-base/static/queriesWithQueryLanguage.ts.txt
144
- var queriesWithQueryLanguage_ts_default = "export default \"export type ComparisonOperator =\\n | 'EQ'\\n | 'NE'\\n | 'LT'\\n | 'GT'\\n | 'LE'\\n | 'GE'\\n | 'LIKE';\\n\\nexport type LengthOperator = 'LENGTH';\\n\\nexport type ArrayOperator = 'IN';\\n\\nexport type NullOperator = 'NULL';\\n\\nexport type Operator = ComparisonOperator | ArrayOperator | NullOperator;\\n\\nexport type ModifierFunction = 'LOWER' | 'TRIM';\\n\\n// use globalThis to use typescript's 'Pick', since the SDK contains an interface which is also called 'Pick'\\nexport type RequireAtLeastOne<T> = {\\n [K in keyof T]-?: Required<globalThis.Pick<T, K>> & Partial<Omit<T, K>>;\\n}[keyof T];\\n\\nexport type LengthExpr = {\\n [K in LengthOperator]: {\\n [K in Exclude<ComparisonOperator, 'LIKE'>]?: number\\n }\\n};\\n\\nexport type LengthExprWithModifier =\\n LengthExpr &\\n { [K in ComparisonOperator]?: never } &\\n { [K in ArrayOperator]?: never } &\\n { [K in NullOperator]?: never } &\\n { [K in ModifierFunction]?: boolean };\\n\\nexport type FilterExpr<T> =\\n { [K in ComparisonOperator]?: T } &\\n { [K in ArrayOperator]?: T[] } &\\n { [K in keyof LengthExpr]?: never };\\n\\nexport type FilterExprWithoutNull<T> =\\n RequireAtLeastOne<FilterExpr<T>> &\\n { [K in NullOperator]?: never } &\\n { [K in ModifierFunction]?: boolean };\\n\\nexport type FilterExprWithNull<T> =\\n FilterExpr<T> &\\n { [K in NullOperator]?: boolean} &\\n { [K in ModifierFunction]?: never };\\n\\nexport type MapOperators<T> = LengthExprWithModifier | FilterExprWithoutNull<T> | FilterExprWithNull<T>;\\n\\nexport type SingleFilterExpr<T> = {\\n [P in keyof T]?: T[P] extends Array<infer U> | undefined\\n ? U extends Record<any, any>\\n ? SingleFilterExpr<U> | { NOT?: SingleFilterExpr<U> }\\n : MapOperators<U>\\n : T[P] extends Record<any, any> | undefined\\n ? SingleFilterExpr<T[P]> | { NOT?: SingleFilterExpr<T[P]> }\\n : MapOperators<T[P]>;\\n};\\n\\nexport type QueryFilter<T> = SingleFilterExpr<T> & {\\n OR?: QueryFilter<T>[];\\n AND?: QueryFilter<T>[];\\n NOT?: QueryFilter<T>;\\n};\\n\\nexport type CountQuery<F> = {\\n where?: QueryFilter<F>;\\n};\\n\\nexport type SomeQuery<E, F, I, P> = {\\n serializeNulls?: boolean;\\n include?: QuerySelect<I>;\\n properties?: P;\\n where?: QueryFilter<F>;\\n select?: QuerySelect<E>;\\n sort?: Sort<E>[];\\n pagination?: Pagination;\\n};\\n\\nconst comparisonOperatorList: ComparisonOperator[] = [\\n 'EQ',\\n 'NE',\\n 'LT',\\n 'GT',\\n 'LE',\\n 'GE',\\n 'LIKE'\\n];\\n\\nconst comparisonOperatorMap: Record<Operator, string> = {\\n EQ: '=',\\n NE: '!=',\\n LT: '<',\\n GT: '>',\\n LE: '<=',\\n GE: '>=',\\n LIKE: '~',\\n IN: 'in',\\n NULL: 'null'\\n};\\n\\nconst modifierFunctionList: ModifierFunction[] = ['LOWER', 'TRIM'];\\n\\nconst flattenWhere = (\\n obj: QueryFilter<any> = {},\\n nestedPaths: string[]\\n): string[] => {\\n const entries: string[] = [];\\n for (const [prop, propValue] of Object.entries(obj)) {\\n const setModifiers = findAllModifierFunctions(propValue ?? {}, modifierFunctionList).filter(\\n (modifier) => modifier[1]\\n );\\n if (prop === 'OR') {\\n const flattedOr: string[][] = [];\\n for (let i = 0; i < (obj.OR?.length ?? 0); i++) {\\n flattedOr.push(flattenWhere(obj.OR?.[i], nestedPaths));\\n }\\n entries.push(\\n `(${flattedOr\\n .map((x) => {\\n const joined = x.join(' and ');\\n\\n if (x.length > 1) {\\n return `(${joined})`;\\n } else {\\n return joined;\\n }\\n })\\n .join(' or ')})`\\n );\\n } else if (prop === 'AND') {\\n const flattedAnd: string[][] = [];\\n for (let i = 0; i < (obj.AND?.length ?? 0); i++) {\\n flattedAnd.push(flattenWhere(obj.AND?.[i], nestedPaths));\\n }\\n entries.push(\\n `(${flattedAnd\\n .map((x) => {\\n const joined = x.join(' and ');\\n\\n if (x.length > 1) {\\n return `(${joined})`;\\n } else {\\n return joined;\\n }\\n })\\n .join(' and ')})`\\n );\\n } else if (prop === 'NOT') {\\n const flattedNot = flattenWhere(obj.NOT, nestedPaths);\\n entries.push(\\n `not ${flattedNot.length > 1 ? '(' : ''}${flattedNot.join(' and ')}${flattedNot.length > 1 ? ')' : ''}`\\n );\\n } else if (propValue) {\\n for (const [operator, value] of Object.entries(propValue)) {\\n if (value === undefined) continue;\\n if (comparisonOperatorList.includes(operator as ComparisonOperator)) {\\n entries.push(\\n `${setModifiers.reduce(\\n (acc, [first]) => `${first.toLowerCase()}(${acc})`,\\n nestedPaths.some((path) => path === prop) ? nestedPaths.join('.') : [...nestedPaths, prop].join('.')\\n )} ${comparisonOperatorMap[operator as Operator]} ${\\n typeof value === 'string' ? JSON.stringify(value) : value\\n }`\\n );\\n } else if ((operator as Operator) === 'NULL') {\\n entries.push(\\n `${!value ? 'not ' : ''}${nestedPaths.some((path) => path === prop) ? nestedPaths.join('.') : [...nestedPaths, prop].join('.')} ${comparisonOperatorMap[operator as Operator]}`\\n );\\n } else if ((operator as Operator) === 'IN') {\\n if(value.length === 0) {\\n entries.push('1 = 0')\\n } else {\\n entries.push(\\n `${setModifiers.reduce(\\n (acc, [first]) => `${first.toLowerCase()}(${acc})`,\\n nestedPaths.some((path) => path === prop) ? nestedPaths.join('.') : [...nestedPaths, prop].join('.')\\n )} ${comparisonOperatorMap[operator as Operator]} [${value.map((v: string | number) =>\\n typeof v === 'string' ? JSON.stringify(v) : v\\n )}]`\\n );\\n }\\n } else if ((operator as LengthOperator) === 'LENGTH') {\\n const lengthProp = `length(${setModifiers.reduce(\\n (acc, [first]) => `${first.toLowerCase()}(${acc})`,\\n nestedPaths.some((path) => path === prop) ? nestedPaths.join('.') : [...nestedPaths, prop].join('.')\\n )})`;\\n entries.push(...flattenWhere({ [lengthProp]: value } as QueryFilter<any>, []));\\n } else if (\\n !modifierFunctionList.includes(operator as ModifierFunction)\\n && typeof value === 'object'\\n ) {\\n entries.push(\\n ...flattenWhere(propValue as QueryFilter<any>, [\\n ...nestedPaths,\\n prop\\n ])\\n );\\n break;\\n }\\n }\\n }\\n }\\n return entries;\\n};\\n\\nconst assembleFilterParam = (\\n obj: QueryFilter<any> = {}\\n): Record<string, string> => {\\n const flattedFilter = flattenWhere(obj, []);\\n return flattedFilter.length ? { filter: flattedFilter.join(' and ') } : {};\\n};\\n\\nconst findAllModifierFunctions = (\\n obj: Record<string, any>,\\n types: ModifierFunction[]\\n) => {\\n const result: [string, any][] = [];\\n for (const key in obj) {\\n if (types.includes(key as ModifierFunction)) {\\n result[types.indexOf(key as ModifierFunction)] = [key, obj[key]];\\n }\\n }\\n return result.filter((modifierTuple) => modifierTuple);\\n};\\n\\nconst _count = (\\n cfg: ServiceConfig | undefined,\\n endpoint: string,\\n query?: CountQuery<any> & { params?: Record<any, any> },\\n requestOptions?: RequestOptions\\n) =>\\n {\\n const usePost = cfg?.usePost ?? globalConfig?.usePost\\n const payload = {\\n ...assembleFilterParam(query?.where),\\n ...query?.params\\n }\\n\\n return wrapResponse(() =>\\n raw(cfg, endpoint, {\\n unwrap: true,\\n method: usePost ? 'POST' : 'GET',\\n ...(usePost ? { body: payload } : { query: payload })\\n }, requestOptions)\\n )\\n };\\n\\nconst _some = (\\n cfg: ServiceConfig | undefined,\\n endpoint: string,\\n query?: SomeQuery<any, any, any, any> & { params?: Record<any, any> },\\n requestOptions?: RequestOptions\\n) =>\\n {\\n const usePost = cfg?.usePost ?? globalConfig?.usePost\\n const payload = {\\n serializeNulls: query?.serializeNulls,\\n additionalProperties: query?.properties?.join(','),\\n properties: query?.select\\n ? flattenSelect(query.select).join(',')\\n : undefined,\\n includeReferencedEntities: query?.include\\n ? Object.keys(query.include).join(',')\\n : undefined,\\n ...assembleFilterParam(query?.where),\\n ...flattenSort(query?.sort),\\n ...query?.params,\\n ...query?.pagination\\n }\\n\\n return wrapResponse(() =>\\n raw(cfg, usePost ? `${endpoint}/query` : endpoint, {\\n method: usePost ? 'POST' : 'GET',\\n ...(usePost ? { body: payload } : { query: payload })\\n }, requestOptions).then((data) => ({\\n entities: data.result,\\n references: data.referencedEntities ?? {},\\n properties: data.additionalProperties ?? {}\\n }))\\n )\\n };\\n\";";
145
- //#endregion
146
- //#region src/generator/01-base/static/root.ts.txt
147
- var root_ts_default = "export default \"export const raw = async (\\n cfg: ServiceConfig | undefined,\\n endpoint: string,\\n payload: RequestPayload = {},\\n requestOptions?: RequestOptions\\n): Promise<any> => {\\n if (!cfg && !globalConfig) {\\n throw new Error(`ServiceConfig missing.`);\\n }\\n\\n const localCfg = {\\n ...globalConfig,\\n ...cfg,\\n interceptors: { ...globalConfig?.interceptors, ...cfg?.interceptors }\\n };\\n\\n const isBinaryData = payload.body instanceof resolveBinaryObject();\\n const params = new URLSearchParams(Object.entries(payload.query ?? {}).filter((v) => v[1] !== undefined)\\n .map(([key, value]) => [key, typeof value === 'string' ? value : JSON.stringify(value)])\\n );\\n\\n const protocol = getProtocol(localCfg);\\n\\n const interceptRequest = localCfg.interceptors?.request ?? ((v) => v);\\n const interceptResponse = localCfg.interceptors?.response ?? ((v) => v);\\n\\n const host = getHost(localCfg);\\n\\n let data;\\n if (!cfg && localCfg.multiRequest) {\\n let ep = endpoint;\\n if (endpoint.startsWith('/')) {\\n ep = endpoint.replace('/', '');\\n }\\n data = await addRequest(`${ep}?${params}`);\\n } else {\\n const request = new Request(`${protocol}//${host}/webapp/api/v${apiVersion}${endpoint}?${params}`, {\\n ...(payload.body && {\\n body: isBinaryData\\n ? payload.body\\n : JSON.stringify(payload.body, (_key, value) => (value === undefined ? null : value))\\n }),\\n ...(!localCfg.key && { credentials: 'same-origin' }),\\n method: payload.method ?? 'get',\\n headers: {\\n Accept: 'application/json',\\n ...(localCfg.key && { AuthenticationToken: localCfg.key }),\\n ...(!isBinaryData && { 'Content-Type': 'application/json' })\\n }\\n });\\n let res = (await interceptRequest(request, payload)) ?? request;\\n if (!(res instanceof Response)) {\\n res = requestOptions?.signal ? await fetch(res, { signal: requestOptions.signal } ) : await fetch(res);\\n }\\n res = (await interceptResponse(res)) ?? res;\\n\\n if (res.ok) {\\n data =\\n payload.forceBlob || !res.headers?.get('content-type')?.includes('application/json')\\n ? await res.blob()\\n : await res.json();\\n } else {\\n data = res.headers?.get('content-type')?.includes('application/json')\\n ? await res.json()\\n : res;\\n }\\n\\n // Check if response was successful\\n if (!res.ok) {\\n return Promise.reject(data);\\n }\\n }\\n\\n return payload.unwrap ? data.result : data;\\n};\\n\\nconst _remove = (\\n cfg: ServiceConfigWithoutMultiRequest | undefined,\\n endpoint: string,\\n { dryRun = false }: RemoveQuery = {},\\n requestOptions?: RequestOptions\\n) =>\\n wrapResponse(() =>\\n raw({ ...cfg, multiRequest: false }, endpoint, {\\n method: 'DELETE',\\n query: { dryRun }\\n }, requestOptions).then(() => undefined)\\n );\\n\\nconst _create = (cfg: ServiceConfigWithoutMultiRequest | undefined, endpoint: string, data: any, requestOptions?: RequestOptions) =>\\n wrapResponse(() =>\\n raw({ ...cfg, multiRequest: false }, endpoint, {\\n method: 'POST',\\n body: data\\n }, requestOptions)\\n );\\n\\nconst _update = (\\n cfg: ServiceConfigWithoutMultiRequest | undefined,\\n endpoint: string,\\n data: any,\\n { ignoreMissingProperties, dryRun = false }: UpdateQuery = {},\\n requestOptions?: RequestOptions\\n) =>\\n wrapResponse(() =>\\n raw({ ...cfg, multiRequest: false }, endpoint, {\\n method: 'PUT',\\n body: data,\\n query: {\\n ignoreMissingProperties:\\n ignoreMissingProperties ?? cfg?.ignoreMissingProperties ?? globalConfig?.ignoreMissingProperties,\\n dryRun\\n }\\n }, requestOptions)\\n );\\n\\nconst _generic = (\\n cfg: ServiceConfigWithoutMultiRequest | undefined,\\n method: RequestPayloadMethod,\\n endpoint: string,\\n payload?: GenericQuery<any, any>,\\n forceBlob?: boolean,\\n requestOptions?: RequestOptions\\n) =>\\n{\\n const usePost = cfg?.usePost ?? globalConfig?.usePost\\n return wrapResponse(() =>\\n raw({ ...cfg, multiRequest: false }, endpoint, {\\n method: usePost ? 'POST' : method,\\n forceBlob,\\n ...(usePost && method === 'GET' ?\\n { body: { ...payload?.params } }\\n :\\n { body: payload?.body, query: payload?.params } )\\n }, requestOptions))\\n};\\n\";";
148
- //#endregion
149
- //#region src/generator/01-base/static/unique.ts.txt
150
- var unique_ts_default = "export default \"const _unique = (cfg: ServiceConfigWithoutMultiRequest | undefined, endpoint: string, query?: UniqueQuery, requestOptions?: RequestOptions) =>\\n wrapResponse(() => raw({ ...cfg, multiRequest: false }, endpoint, { query }, requestOptions));\\n\";";
151
- //#endregion
152
- //#region src/generator/01-base/static/types.ts.txt
153
- var types_ts_default = "export default \"export type DeepPartial<T> = T extends object\\n ? {\\n [P in keyof T]?: DeepPartial<T[P]>;\\n }\\n : T;\\n\\nexport type Sort<T> = {\\n [K in keyof T]?: {\\n [V in keyof T]?: V extends K\\n ? T[V] extends Array<infer U> | undefined\\n ? U extends object\\n ? Sort<U>\\n : never\\n : T[V] extends object | undefined\\n ? Sort<T[V]>\\n : 'asc' | 'desc'\\n : never;\\n };\\n}[keyof T];\\n\\nexport type CustomAttributeFilter = {\\n [K in number]:| string | number | boolean | { id: string } | { entityName: string; entityId: string };\\n};\\n\\nexport type QuerySelect<T> = {\\n [P in keyof T]?: T[P] extends Array<infer U> | undefined\\n ? QuerySelect<U> | boolean\\n : T[P] extends Record<any, any> | undefined\\n ? QuerySelect<T[P]> | boolean\\n : boolean;\\n};\\n\\nexport type Select<T, Q extends QuerySelect<T> | undefined> =\\n Q extends QuerySelect<T>\\n ? {\\n // Filter out excluded properties beforehand\\n [P in keyof T as Q[P] extends boolean ? P : Q[P] extends object ? P : never]: // Property\\n Q[P] extends true\\n ? T[P]\\n : // Array\\n T[P] extends Array<infer U>\\n ? Select<U, Q[P] & QuerySelect<any>>[]\\n : // Object\\n T[P] extends Record<any, any>\\n ? Select<T[P], Q[P] & QuerySelect<any>>\\n : never;\\n }\\n : undefined;\\n\\nexport type MapKeys<T, S extends Record<keyof T, string>> = {\\n [K in keyof T as S[K]]: T[K];\\n};\\n\\nexport type ValueOf<T> = T[keyof T];\\n\\nexport type Pagination = {\\n page: number;\\n pageSize: number;\\n};\\n\\nexport type UniqueQuery = {\\n serializeNulls?: boolean;\\n};\\n\\nexport type SomeQueryReturn<E, R, P> = {\\n entities: E[];\\n references?: R;\\n properties?: P[];\\n};\\n\\nexport type GenericQuery<P, B> = {\\n params?: P;\\n body?: B;\\n};\\n\\nexport type UpdateQuery = {\\n ignoreMissingProperties?: boolean;\\n dryRun?: boolean;\\n};\\n\\nexport type RemoveQuery = {\\n dryRun?: boolean;\\n};\\n\\nexport type WEntityPropertyMeta =\\n | {\\n type: 'string';\\n format?: 'decimal' | 'html' | 'email' | 'password';\\n maxLength?: number;\\n pattern?: string;\\n entity?: WEntity;\\n service?: WService;\\n }\\n | {\\n type: 'integer';\\n format: 'int32' | 'int64' | 'duration' | 'date' | 'timestamp';\\n }\\n | { type: 'array'; format: 'reference'; entity: WEntity; service?: WService }\\n | { type: 'array'; format: 'reference'; enum: WEnum }\\n | { type: 'array'; format: 'string' }\\n | { type: 'number'; format: 'double' }\\n | { type: 'reference'; entity: WEntity }\\n | { type: 'reference'; enum: WEnum }\\n | { type: 'boolean' }\\n | { type: 'object' };\\n\";";
154
- //#endregion
155
- //#region src/generator/01-base/static/utils.ts.txt
156
- var utils_ts_default = "export default \"const flattenSelect = (obj: Select<any, any> = {}): string[] => {\\n const entries: string[] = [];\\n\\n for (const [prop, value] of Object.entries(obj)) {\\n if (typeof value === 'object' && value) {\\n entries.push(...flattenSelect(value).map((v) => `${prop}.${v}`));\\n } else if (value) {\\n entries.push(prop);\\n }\\n }\\n\\n return entries;\\n};\\n\\nexport const flattenSort = (obj: Sort<any>[] = []): { sort?: string } => {\\n const flatten = (obj: Sort<any>, base = ''): string | undefined => {\\n const [key, value] = Object.entries(obj ?? {})[0] ?? [];\\n\\n if (key && value) {\\n const path = base + key;\\n\\n if (typeof value === 'object') {\\n return flatten(value, path ? `${path}.` : '');\\n } else if (['asc', 'desc'].includes(value)) {\\n return `${value === 'desc' ? '-' : ''}${path}`;\\n }\\n }\\n\\n return undefined;\\n };\\n\\n const sorts = obj.map((v) => flatten(v)).filter(Boolean);\\n return sorts.length ? { sort: sorts.join(',') } : {};\\n};\\n\";";
157
- //#endregion
158
- //#region src/generator/01-base/index.ts
134
+
135
+ var globalConfig = "export type RequestPayloadMethod =\n | 'GET'\n | 'HEAD'\n | 'POST'\n | 'PUT'\n | 'DELETE'\n | 'CONNECT'\n | 'OPTIONS'\n | 'TRACE'\n | 'PATCH';\n\nexport interface RequestPayload {\n method?: RequestPayloadMethod;\n query?: Record<string, any>;\n body?: any;\n unwrap?: boolean;\n forceBlob?: boolean;\n}\n\nexport interface ServiceConfig {\n // Your API-Key, this is optional in the sense of if you omit this, and you're in a browser, the\n // cookie-authentication (include-credentials) will be used.\n key?: string;\n\n // Your domain, if omitted location.host will be used (browser env).\n host?: string;\n\n // If you want to use https, defaults to location.protocol (browser env).\n secure?: boolean;\n\n // If you want that some and count requests are bundled into multi requests.\n multiRequest?: boolean;\n\n // If you want that the ignoreMissingProperties parameter to be set to true for every post request.\n ignoreMissingProperties?: boolean;\n\n // Optional request/response interceptors.\n interceptors?: {\n // Takes the generated request, you can either return a new request,\n // a response (which will be taken as \"the\" response) or nothing.\n // The payload contains the raw input generated by the SDK.\n request?: (\n request: Request,\n payload: RequestPayload\n ) => Request | Response | void | Promise<Request | Response | void>;\n\n // Takes the response. This can either be the one from the server or an\n // artificially-crafted one by the request interceptor.\n response?: (response: Response) => Response | void | Promise<Response | void>;\n };\n\n // Whether POST should be used instead of GET for some() and count() operations\n usePost?: boolean;\n}\n\nexport interface RequestOptions {\n signal?: AbortSignal;\n}\n\ntype ServiceConfigWithoutMultiRequest = Omit<ServiceConfig, 'multiRequest'>;\n\nlet globalConfig: ServiceConfig | undefined;\nexport const getGlobalConfig = (): ServiceConfig | undefined => globalConfig;\nexport const setGlobalConfig = (cfg?: ServiceConfig) => (globalConfig = cfg);\n\nexport const getHost = (cfg: ServiceConfig) => {\n let host = cfg.host?.replace(/^https?:\\/\\//, '');\n if (!host && typeof location !== 'undefined') {\n host = location.host;\n }\n\n if (!host) {\n throw new Error('Please specify a host');\n }\n\n return host;\n};\n\nexport const getProtocol = (cfg: ServiceConfig) => {\n const protocol =\n cfg.secure !== undefined\n ? cfg.secure\n ? 'https:'\n : 'http:'\n : typeof location !== 'undefined'\n ? location.protocol\n : undefined;\n\n if (!protocol) {\n throw new Error('Please specify a protocol (secure)');\n }\n\n return protocol;\n};\n";
136
+
137
+ var multiRequest = "type RequestTask = {\n uri: string;\n resolve: (result: unknown) => void;\n reject: (error: unknown) => void;\n};\n\ntype BatchRequestTask = RequestTask & {\n settled: boolean;\n};\n\ntype MultiRequestResponse = {\n status: number;\n body: object;\n};\n\nlet microtaskQueued: boolean = false;\nconst tasksSet: Set<RequestTask> = new Set<RequestTask>();\n\nconst SQUARE_BRACKET_OPEN = '['.charCodeAt(0);\nconst COMMA = ','.charCodeAt(0);\nconst DECODER = new TextDecoder();\n\nconst readNextResponse = (bytes: Uint8Array<ArrayBuffer>) => {\n let headerStart: number | undefined = undefined;\n let commasSeen = 0;\n\n for (let i = 0; i < bytes.length; i++) {\n const byte = bytes[i];\n if (headerStart === undefined) {\n if (byte === SQUARE_BRACKET_OPEN || byte === COMMA) {\n headerStart = i + 1;\n }\n } else {\n if (byte === COMMA) {\n commasSeen++;\n }\n if (commasSeen === 2) {\n const headerArrayString = `[${DECODER.decode(bytes.subarray(headerStart, i))}]`;\n const [index, jsonLength] = JSON.parse(headerArrayString);\n if (!(typeof index === 'number') || !(typeof jsonLength === 'number')) {\n throw new Error(`unexpected header: ${headerArrayString}`);\n }\n\n const endIndex = i + 1 + jsonLength;\n if (endIndex > bytes.length) {\n // not all bytes available yet\n return undefined;\n }\n const jsonString = DECODER.decode(bytes.subarray(i + 1, endIndex));\n const data = JSON.parse(jsonString) as MultiRequestResponse;\n return {\n index,\n data,\n remainingBytes: bytes.subarray(endIndex)\n };\n }\n }\n }\n return undefined;\n};\n\nconst fetchMultiRequest = async (requests: string[]) => {\n const cfg = getGlobalConfig();\n\n if (!cfg) {\n throw new Error(`ServiceConfig missing.`);\n }\n\n const host = getHost(cfg);\n const protocol = getProtocol(cfg);\n\n return await fetch(`${protocol}//${host}/webapp/api/v2/batch/query`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(cfg.key && { AuthenticationToken: cfg.key })\n },\n body: JSON.stringify({ requests })\n });\n};\n\nconst rejectTasks = (tasks: BatchRequestTask[], error: unknown) => {\n for (const task of tasks) {\n if (!task.settled) {\n task.reject(error);\n }\n }\n};\n\nconst processStream = (\n { value: chunk, done }: ReadableStreamReadResult<Uint8Array>,\n remainingBytes: Uint8Array,\n reader: ReadableStreamDefaultReader<Uint8Array>,\n tasks: BatchRequestTask[]\n) => {\n if (done) {\n return;\n }\n if (chunk) {\n let bytes = new Uint8Array(remainingBytes.length + chunk.length);\n bytes.set(remainingBytes);\n bytes.set(chunk, remainingBytes.length);\n\n while (bytes.length) {\n const result = readNextResponse(bytes);\n if (!result) {\n break;\n }\n const task = tasks[result.index];\n if (result.data.status >= 100 && result.data.status < 400) {\n task.resolve({\n ...result.data.body\n });\n } else {\n task.reject({\n ...result.data.body\n });\n }\n task.settled = true;\n bytes = result.remainingBytes;\n }\n reader\n .read()\n .then((readResult) => processStream(readResult, bytes, reader, tasks))\n .catch((error) => rejectTasks(tasks, error));\n }\n};\n\nconst batch = async (tasks: BatchRequestTask[]) => {\n try {\n const requests = tasks.map(({ uri }) => uri);\n const resp = await fetchMultiRequest(requests);\n const reader = resp.body?.getReader();\n\n if (!reader) {\n throw new Error('Stream reader is undefined');\n }\n reader\n .read()\n .then((readResult) => processStream(readResult, new Uint8Array(0), reader, tasks))\n .catch((error) => rejectTasks(tasks, error));\n } catch (e) {\n rejectTasks(tasks, e);\n throw e;\n }\n};\n\nconst addTask = (task: RequestTask) => {\n tasksSet.add(task);\n\n if (!microtaskQueued) {\n queueMicrotask(() => {\n microtaskQueued = false;\n if (tasksSet.size > 0) {\n const batchTasks = Array.from(tasksSet).map((task) => ({ ...task, settled: false }));\n void batch(batchTasks);\n tasksSet.clear();\n }\n });\n microtaskQueued = true;\n }\n};\n\nconst addRequest = (uri: string) => new Promise((resolve, reject) => addTask({ uri, resolve, reject }));\n";
138
+
139
+ var queriesWithFilter = "export type EqualityOperator = 'EQ' | 'NE';\n\nexport type ComparisonOperator =\n | 'LT'\n | 'GT'\n | 'LE'\n | 'GE'\n | 'LIKE'\n | 'ILIKE'\n | 'NOT_LIKE'\n | 'NOT_ILIKE'\n | 'IEQ'\n | 'NOT_IEQ';\n\nexport type ArrayOperator = 'IN' | 'NOT_IN';\n\nexport type Operator = EqualityOperator | ComparisonOperator | ArrayOperator;\n\nexport type MapOperators<T> = { [K in EqualityOperator]?: T | null } & { [K in ComparisonOperator]?: T } & {\n [K in ArrayOperator]?: T[];\n};\n\nexport type QueryFilter<T> = {\n [P in keyof T]?: T[P] extends Array<infer U> | undefined\n ? U extends Record<any, any>\n ? QueryFilter<U>\n : MapOperators<U>\n : T[P] extends Record<any, any> | undefined\n ? QueryFilter<T[P]>\n : MapOperators<T[P]>;\n};\n\nexport type CountQuery<F> = {\n filter?: QueryFilter<F>;\n or?: (QueryFilter<F> & CustomAttributeFilter)[];\n};\n\nexport type SomeQuery<E, F, I, P> = {\n serializeNulls?: boolean;\n include?: QuerySelect<I>;\n properties?: P;\n filter?: QueryFilter<F> & CustomAttributeFilter;\n select?: QuerySelect<E>;\n or?: (QueryFilter<F> & CustomAttributeFilter)[];\n sort?: Sort<E>[];\n pagination?: Pagination;\n};\n\nconst equality: string[] = ['EQ', 'NE', 'IEQ', 'NOT_IEQ'];\n\nconst simple: string[] = [...equality, 'LT', 'GT', 'LE', 'GE', 'LIKE', 'NOT_LIKE', 'ILIKE', 'NOT_ILIKE'];\n\nconst array: string[] = ['IN', 'NOT_IN'];\n\nconst filterMap: Record<Operator, string> = {\n EQ: 'eq',\n NE: 'ne',\n LT: 'lt',\n GT: 'gt',\n LE: 'le',\n GE: 'ge',\n LIKE: 'like',\n NOT_LIKE: 'notlike',\n ILIKE: 'ilike',\n NOT_ILIKE: 'notilike',\n IN: 'in',\n NOT_IN: 'notin',\n IEQ: 'ieq',\n NOT_IEQ: 'notieq'\n};\n\nconst flattenCustomAttributes = (obj: CustomAttributeFilter = {}): [string, string][] => {\n const entries: [string, string][] = [];\n\n for (const [id, filter] of Object.entries(obj)) {\n const key = `customAttribute${id}`;\n\n if (typeof filter === 'object') {\n for (const [prop, value] of Object.entries(filter)) {\n entries.push([`${key}.${prop}-eq`, String(value)]);\n }\n } else if (filter !== undefined) {\n entries.push([`${key}-eq`, String(filter)]);\n }\n }\n\n return entries;\n};\n\nconst flatten = (obj: QueryFilter<any> = {}): [string, string][] => {\n const entries: [string, string][] = [];\n\n for (const [prop, propValue] of Object.entries(obj)) {\n for (const [filter, value] of Object.entries(propValue as object)) {\n if (value === undefined) continue;\n\n if (simple.includes(filter) || array.includes(filter)) {\n if (value === null && equality.includes(filter)) {\n entries.push([`${prop}-${filter === 'EQ' ? 'null' : 'notnull'}`, '']);\n } else {\n entries.push([`${prop}-${filterMap[filter as Operator]}`, value]);\n }\n } else {\n entries.push(\n ...(flatten(propValue as QueryFilter<any>).map((v) => [`${prop}.${v[0]}`, v[1]]) as [string, string][])\n );\n break;\n }\n }\n }\n\n return entries;\n};\n\nconst flattenFilter = (obj: QueryFilter<any> = {}): Record<string, string> => {\n const filter: [string, any][] = [],\n customAttributes: [string, any][] = [];\n\n Object.entries(obj).forEach((value) => {\n (value[0].match(/^\\d+$/) ? customAttributes : filter).push(value);\n });\n\n return Object.fromEntries([\n ...flatten(Object.fromEntries(filter)),\n ...flattenCustomAttributes(Object.fromEntries(customAttributes) as CustomAttributeFilter)\n ]);\n};\n\nconst flattenOrFilter = (obj: QueryFilter<any>[] = []): Record<string, string> => {\n const entries: [string, any][] = [];\n\n for (let i = 0; i < obj.length; i++) {\n entries.push(...(flatten(obj[i]).map((v) => [`or${i || ''}-${v[0]}`, v[1]]) as [string, string][]));\n }\n\n return Object.fromEntries(entries);\n};\n\nconst _count = (\n cfg: ServiceConfig | undefined,\n endpoint: string,\n query?: CountQuery<any> & { params?: Record<any, any> },\n requestOptions?: RequestOptions\n) =>\n{\n const usePost = cfg?.usePost ?? globalConfig?.usePost\n const payload = {\n ...flattenFilter(query?.filter),\n ...flattenOrFilter(query?.or),\n ...query?.params\n }\n\n return wrapResponse(() =>\n raw(cfg, endpoint, {\n method: usePost ? 'POST' : 'GET',\n unwrap: true,\n ...(usePost ? { body: payload } : { query: payload })\n }, requestOptions)\n )\n };\n\nconst _some = (\n cfg: ServiceConfig | undefined,\n endpoint: string,\n query?: SomeQuery<any, any, any, any> & { params?: Record<any, any> },\n requestOptions?: RequestOptions\n) =>\n{\n const usePost = cfg?.usePost ?? globalConfig?.usePost\n const payload = {\n serializeNulls: query?.serializeNulls,\n additionalProperties: query?.properties?.join(','),\n properties: query?.select ? flattenSelect(query.select).join(',') : undefined,\n includeReferencedEntities: query?.include ? Object.keys(query.include).join(',') : undefined,\n ...flattenOrFilter(query?.or),\n ...flattenFilter(query?.filter),\n ...flattenSort(query?.sort),\n ...query?.params,\n ...query?.pagination\n }\n\n return wrapResponse(() =>\n raw(cfg, usePost ? `${endpoint}/query` : endpoint, {\n method: usePost ? 'POST' : 'GET',\n ...(usePost ? { body: payload } : { query: payload })\n }, requestOptions).then((data) => ({\n entities: data.result,\n references: data.referencedEntities ?? {},\n properties: data.additionalProperties ?? {}\n }))\n )\n };\n";
140
+
141
+ var queriesWithQueryLanguage = "export type ComparisonOperator =\n | 'EQ'\n | 'NE'\n | 'LT'\n | 'GT'\n | 'LE'\n | 'GE'\n | 'LIKE';\n\nexport type LengthOperator = 'LENGTH';\n\nexport type ArrayOperator = 'IN';\n\nexport type NullOperator = 'NULL';\n\nexport type Operator = ComparisonOperator | ArrayOperator | NullOperator;\n\nexport type ModifierFunction = 'LOWER' | 'TRIM';\n\n// use globalThis to use typescript's 'Pick', since the SDK contains an interface which is also called 'Pick'\nexport type RequireAtLeastOne<T> = {\n [K in keyof T]-?: Required<globalThis.Pick<T, K>> & Partial<Omit<T, K>>;\n}[keyof T];\n\nexport type LengthExpr = {\n [K in LengthOperator]: {\n [K in Exclude<ComparisonOperator, 'LIKE'>]?: number\n }\n};\n\nexport type LengthExprWithModifier =\n LengthExpr &\n { [K in ComparisonOperator]?: never } &\n { [K in ArrayOperator]?: never } &\n { [K in NullOperator]?: never } &\n { [K in ModifierFunction]?: boolean };\n\nexport type FilterExpr<T> =\n { [K in ComparisonOperator]?: T } &\n { [K in ArrayOperator]?: T[] } &\n { [K in keyof LengthExpr]?: never };\n\nexport type FilterExprWithoutNull<T> =\n RequireAtLeastOne<FilterExpr<T>> &\n { [K in NullOperator]?: never } &\n { [K in ModifierFunction]?: boolean };\n\nexport type FilterExprWithNull<T> =\n FilterExpr<T> &\n { [K in NullOperator]?: boolean} &\n { [K in ModifierFunction]?: never };\n\nexport type MapOperators<T> = LengthExprWithModifier | FilterExprWithoutNull<T> | FilterExprWithNull<T>;\n\nexport type SingleFilterExpr<T> = {\n [P in keyof T]?: T[P] extends Array<infer U> | undefined\n ? U extends Record<any, any>\n ? SingleFilterExpr<U> | { NOT?: SingleFilterExpr<U> }\n : MapOperators<U>\n : T[P] extends Record<any, any> | undefined\n ? SingleFilterExpr<T[P]> | { NOT?: SingleFilterExpr<T[P]> }\n : MapOperators<T[P]>;\n};\n\nexport type QueryFilter<T> = SingleFilterExpr<T> & {\n OR?: QueryFilter<T>[];\n AND?: QueryFilter<T>[];\n NOT?: QueryFilter<T>;\n};\n\nexport type CountQuery<F> = {\n where?: QueryFilter<F>;\n};\n\nexport type SomeQuery<E, F, I, P> = {\n serializeNulls?: boolean;\n include?: QuerySelect<I>;\n properties?: P;\n where?: QueryFilter<F>;\n select?: QuerySelect<E>;\n sort?: Sort<E>[];\n pagination?: Pagination;\n};\n\nconst comparisonOperatorList: ComparisonOperator[] = [\n 'EQ',\n 'NE',\n 'LT',\n 'GT',\n 'LE',\n 'GE',\n 'LIKE'\n];\n\nconst comparisonOperatorMap: Record<Operator, string> = {\n EQ: '=',\n NE: '!=',\n LT: '<',\n GT: '>',\n LE: '<=',\n GE: '>=',\n LIKE: '~',\n IN: 'in',\n NULL: 'null'\n};\n\nconst modifierFunctionList: ModifierFunction[] = ['LOWER', 'TRIM'];\n\nconst flattenWhere = (\n obj: QueryFilter<any> = {},\n nestedPaths: string[]\n): string[] => {\n const entries: string[] = [];\n for (const [prop, propValue] of Object.entries(obj)) {\n const setModifiers = findAllModifierFunctions(propValue ?? {}, modifierFunctionList).filter(\n (modifier) => modifier[1]\n );\n if (prop === 'OR') {\n const flattedOr: string[][] = [];\n for (let i = 0; i < (obj.OR?.length ?? 0); i++) {\n flattedOr.push(flattenWhere(obj.OR?.[i], nestedPaths));\n }\n entries.push(\n `(${flattedOr\n .map((x) => {\n const joined = x.join(' and ');\n\n if (x.length > 1) {\n return `(${joined})`;\n } else {\n return joined;\n }\n })\n .join(' or ')})`\n );\n } else if (prop === 'AND') {\n const flattedAnd: string[][] = [];\n for (let i = 0; i < (obj.AND?.length ?? 0); i++) {\n flattedAnd.push(flattenWhere(obj.AND?.[i], nestedPaths));\n }\n entries.push(\n `(${flattedAnd\n .map((x) => {\n const joined = x.join(' and ');\n\n if (x.length > 1) {\n return `(${joined})`;\n } else {\n return joined;\n }\n })\n .join(' and ')})`\n );\n } else if (prop === 'NOT') {\n const flattedNot = flattenWhere(obj.NOT, nestedPaths);\n entries.push(\n `not ${flattedNot.length > 1 ? '(' : ''}${flattedNot.join(' and ')}${flattedNot.length > 1 ? ')' : ''}`\n );\n } else if (propValue) {\n for (const [operator, value] of Object.entries(propValue)) {\n if (value === undefined) continue;\n if (comparisonOperatorList.includes(operator as ComparisonOperator)) {\n entries.push(\n `${setModifiers.reduce(\n (acc, [first]) => `${first.toLowerCase()}(${acc})`,\n nestedPaths.some((path) => path === prop) ? nestedPaths.join('.') : [...nestedPaths, prop].join('.')\n )} ${comparisonOperatorMap[operator as Operator]} ${\n typeof value === 'string' ? JSON.stringify(value) : value\n }`\n );\n } else if ((operator as Operator) === 'NULL') {\n entries.push(\n `${!value ? 'not ' : ''}${nestedPaths.some((path) => path === prop) ? nestedPaths.join('.') : [...nestedPaths, prop].join('.')} ${comparisonOperatorMap[operator as Operator]}`\n );\n } else if ((operator as Operator) === 'IN') {\n if(value.length === 0) {\n entries.push('1 = 0')\n } else {\n entries.push(\n `${setModifiers.reduce(\n (acc, [first]) => `${first.toLowerCase()}(${acc})`,\n nestedPaths.some((path) => path === prop) ? nestedPaths.join('.') : [...nestedPaths, prop].join('.')\n )} ${comparisonOperatorMap[operator as Operator]} [${value.map((v: string | number) =>\n typeof v === 'string' ? JSON.stringify(v) : v\n )}]`\n );\n }\n } else if ((operator as LengthOperator) === 'LENGTH') {\n const lengthProp = `length(${setModifiers.reduce(\n (acc, [first]) => `${first.toLowerCase()}(${acc})`,\n nestedPaths.some((path) => path === prop) ? nestedPaths.join('.') : [...nestedPaths, prop].join('.')\n )})`;\n entries.push(...flattenWhere({ [lengthProp]: value } as QueryFilter<any>, []));\n } else if (\n !modifierFunctionList.includes(operator as ModifierFunction)\n && typeof value === 'object'\n ) {\n entries.push(\n ...flattenWhere(propValue as QueryFilter<any>, [\n ...nestedPaths,\n prop\n ])\n );\n break;\n }\n }\n }\n }\n return entries;\n};\n\nconst assembleFilterParam = (\n obj: QueryFilter<any> = {}\n): Record<string, string> => {\n const flattedFilter = flattenWhere(obj, []);\n return flattedFilter.length ? { filter: flattedFilter.join(' and ') } : {};\n};\n\nconst findAllModifierFunctions = (\n obj: Record<string, any>,\n types: ModifierFunction[]\n) => {\n const result: [string, any][] = [];\n for (const key in obj) {\n if (types.includes(key as ModifierFunction)) {\n result[types.indexOf(key as ModifierFunction)] = [key, obj[key]];\n }\n }\n return result.filter((modifierTuple) => modifierTuple);\n};\n\nconst _count = (\n cfg: ServiceConfig | undefined,\n endpoint: string,\n query?: CountQuery<any> & { params?: Record<any, any> },\n requestOptions?: RequestOptions\n) =>\n {\n const usePost = cfg?.usePost ?? globalConfig?.usePost\n const payload = {\n ...assembleFilterParam(query?.where),\n ...query?.params\n }\n\n return wrapResponse(() =>\n raw(cfg, endpoint, {\n unwrap: true,\n method: usePost ? 'POST' : 'GET',\n ...(usePost ? { body: payload } : { query: payload })\n }, requestOptions)\n )\n };\n\nconst _some = (\n cfg: ServiceConfig | undefined,\n endpoint: string,\n query?: SomeQuery<any, any, any, any> & { params?: Record<any, any> },\n requestOptions?: RequestOptions\n) =>\n {\n const usePost = cfg?.usePost ?? globalConfig?.usePost\n const payload = {\n serializeNulls: query?.serializeNulls,\n additionalProperties: query?.properties?.join(','),\n properties: query?.select\n ? flattenSelect(query.select).join(',')\n : undefined,\n includeReferencedEntities: query?.include\n ? Object.keys(query.include).join(',')\n : undefined,\n ...assembleFilterParam(query?.where),\n ...flattenSort(query?.sort),\n ...query?.params,\n ...query?.pagination\n }\n\n return wrapResponse(() =>\n raw(cfg, usePost ? `${endpoint}/query` : endpoint, {\n method: usePost ? 'POST' : 'GET',\n ...(usePost ? { body: payload } : { query: payload })\n }, requestOptions).then((data) => ({\n entities: data.result,\n references: data.referencedEntities ?? {},\n properties: data.additionalProperties ?? {}\n }))\n )\n };\n";
142
+
143
+ var root = "export const raw = async (\n cfg: ServiceConfig | undefined,\n endpoint: string,\n payload: RequestPayload = {},\n requestOptions?: RequestOptions\n): Promise<any> => {\n if (!cfg && !globalConfig) {\n throw new Error(`ServiceConfig missing.`);\n }\n\n const localCfg = {\n ...globalConfig,\n ...cfg,\n interceptors: { ...globalConfig?.interceptors, ...cfg?.interceptors }\n };\n\n const isBinaryData = payload.body instanceof resolveBinaryObject();\n const params = new URLSearchParams(Object.entries(payload.query ?? {}).filter((v) => v[1] !== undefined)\n .map(([key, value]) => [key, typeof value === 'string' ? value : JSON.stringify(value)])\n );\n\n const protocol = getProtocol(localCfg);\n\n const interceptRequest = localCfg.interceptors?.request ?? ((v) => v);\n const interceptResponse = localCfg.interceptors?.response ?? ((v) => v);\n\n const host = getHost(localCfg);\n\n let data;\n if (!cfg && localCfg.multiRequest) {\n let ep = endpoint;\n if (endpoint.startsWith('/')) {\n ep = endpoint.replace('/', '');\n }\n data = await addRequest(`${ep}?${params}`);\n } else {\n const request = new Request(`${protocol}//${host}/webapp/api/v${apiVersion}${endpoint}?${params}`, {\n ...(payload.body && {\n body: isBinaryData\n ? payload.body\n : JSON.stringify(payload.body, (_key, value) => (value === undefined ? null : value))\n }),\n ...(!localCfg.key && { credentials: 'same-origin' }),\n method: payload.method ?? 'get',\n headers: {\n Accept: 'application/json',\n ...(localCfg.key && { AuthenticationToken: localCfg.key }),\n ...(!isBinaryData && { 'Content-Type': 'application/json' })\n }\n });\n let res = (await interceptRequest(request, payload)) ?? request;\n if (!(res instanceof Response)) {\n res = requestOptions?.signal ? await fetch(res, { signal: requestOptions.signal } ) : await fetch(res);\n }\n res = (await interceptResponse(res)) ?? res;\n\n if (res.ok) {\n data =\n payload.forceBlob || !res.headers?.get('content-type')?.includes('application/json')\n ? await res.blob()\n : await res.json();\n } else {\n data = res.headers?.get('content-type')?.includes('application/json')\n ? await res.json()\n : res;\n }\n\n // Check if response was successful\n if (!res.ok) {\n return Promise.reject(data);\n }\n }\n\n return payload.unwrap ? data.result : data;\n};\n\nconst _remove = (\n cfg: ServiceConfigWithoutMultiRequest | undefined,\n endpoint: string,\n { dryRun = false }: RemoveQuery = {},\n requestOptions?: RequestOptions\n) =>\n wrapResponse(() =>\n raw({ ...cfg, multiRequest: false }, endpoint, {\n method: 'DELETE',\n query: { dryRun }\n }, requestOptions).then(() => undefined)\n );\n\nconst _create = (cfg: ServiceConfigWithoutMultiRequest | undefined, endpoint: string, data: any, requestOptions?: RequestOptions) =>\n wrapResponse(() =>\n raw({ ...cfg, multiRequest: false }, endpoint, {\n method: 'POST',\n body: data\n }, requestOptions)\n );\n\nconst _update = (\n cfg: ServiceConfigWithoutMultiRequest | undefined,\n endpoint: string,\n data: any,\n { ignoreMissingProperties, dryRun = false }: UpdateQuery = {},\n requestOptions?: RequestOptions\n) =>\n wrapResponse(() =>\n raw({ ...cfg, multiRequest: false }, endpoint, {\n method: 'PUT',\n body: data,\n query: {\n ignoreMissingProperties:\n ignoreMissingProperties ?? cfg?.ignoreMissingProperties ?? globalConfig?.ignoreMissingProperties,\n dryRun\n }\n }, requestOptions)\n );\n\nconst _generic = (\n cfg: ServiceConfigWithoutMultiRequest | undefined,\n method: RequestPayloadMethod,\n endpoint: string,\n payload?: GenericQuery<any, any>,\n forceBlob?: boolean,\n requestOptions?: RequestOptions\n) =>\n{\n const usePost = cfg?.usePost ?? globalConfig?.usePost\n return wrapResponse(() =>\n raw({ ...cfg, multiRequest: false }, endpoint, {\n method: usePost ? 'POST' : method,\n forceBlob,\n ...(usePost && method === 'GET' ?\n { body: { ...payload?.params } }\n :\n { body: payload?.body, query: payload?.params } )\n }, requestOptions))\n};\n";
144
+
145
+ var unique = "const _unique = (cfg: ServiceConfigWithoutMultiRequest | undefined, endpoint: string, query?: UniqueQuery, requestOptions?: RequestOptions) =>\n wrapResponse(() => raw({ ...cfg, multiRequest: false }, endpoint, { query }, requestOptions));\n";
146
+
147
+ var types = "export type DeepPartial<T> = T extends object\n ? {\n [P in keyof T]?: DeepPartial<T[P]>;\n }\n : T;\n\nexport type Sort<T> = {\n [K in keyof T]?: {\n [V in keyof T]?: V extends K\n ? T[V] extends Array<infer U> | undefined\n ? U extends object\n ? Sort<U>\n : never\n : T[V] extends object | undefined\n ? Sort<T[V]>\n : 'asc' | 'desc'\n : never;\n };\n}[keyof T];\n\nexport type CustomAttributeFilter = {\n [K in number]:| string | number | boolean | { id: string } | { entityName: string; entityId: string };\n};\n\nexport type QuerySelect<T> = {\n [P in keyof T]?: T[P] extends Array<infer U> | undefined\n ? QuerySelect<U> | boolean\n : T[P] extends Record<any, any> | undefined\n ? QuerySelect<T[P]> | boolean\n : boolean;\n};\n\nexport type Select<T, Q extends QuerySelect<T> | undefined> =\n Q extends QuerySelect<T>\n ? {\n // Filter out excluded properties beforehand\n [P in keyof T as Q[P] extends boolean ? P : Q[P] extends object ? P : never]: // Property\n Q[P] extends true\n ? T[P]\n : // Array\n T[P] extends Array<infer U>\n ? Select<U, Q[P] & QuerySelect<any>>[]\n : // Object\n T[P] extends Record<any, any>\n ? Select<T[P], Q[P] & QuerySelect<any>>\n : never;\n }\n : undefined;\n\nexport type MapKeys<T, S extends Record<keyof T, string>> = {\n [K in keyof T as S[K]]: T[K];\n};\n\nexport type ValueOf<T> = T[keyof T];\n\nexport type Pagination = {\n page: number;\n pageSize: number;\n};\n\nexport type UniqueQuery = {\n serializeNulls?: boolean;\n};\n\nexport type SomeQueryReturn<E, R, P> = {\n entities: E[];\n references?: R;\n properties?: P[];\n};\n\nexport type GenericQuery<P, B> = {\n params?: P;\n body?: B;\n};\n\nexport type UpdateQuery = {\n ignoreMissingProperties?: boolean;\n dryRun?: boolean;\n};\n\nexport type RemoveQuery = {\n dryRun?: boolean;\n};\n\nexport type WEntityPropertyMeta =\n | {\n type: 'string';\n format?: 'decimal' | 'html' | 'email' | 'password';\n maxLength?: number;\n pattern?: string;\n entity?: WEntity;\n service?: WService;\n }\n | {\n type: 'integer';\n format: 'int32' | 'int64' | 'duration' | 'date' | 'timestamp';\n }\n | { type: 'array'; format: 'reference'; entity: WEntity; service?: WService }\n | { type: 'array'; format: 'reference'; enum: WEnum }\n | { type: 'array'; format: 'string' }\n | { type: 'number'; format: 'double' }\n | { type: 'reference'; entity: WEntity }\n | { type: 'reference'; enum: WEnum }\n | { type: 'boolean' }\n | { type: 'object' };\n";
148
+
149
+ var utils = "const flattenSelect = (obj: Select<any, any> = {}): string[] => {\n const entries: string[] = [];\n\n for (const [prop, value] of Object.entries(obj)) {\n if (typeof value === 'object' && value) {\n entries.push(...flattenSelect(value).map((v) => `${prop}.${v}`));\n } else if (value) {\n entries.push(prop);\n }\n }\n\n return entries;\n};\n\nexport const flattenSort = (obj: Sort<any>[] = []): { sort?: string } => {\n const flatten = (obj: Sort<any>, base = ''): string | undefined => {\n const [key, value] = Object.entries(obj ?? {})[0] ?? [];\n\n if (key && value) {\n const path = base + key;\n\n if (typeof value === 'object') {\n return flatten(value, path ? `${path}.` : '');\n } else if (['asc', 'desc'].includes(value)) {\n return `${value === 'desc' ? '-' : ''}${path}`;\n }\n }\n\n return undefined;\n };\n\n const sorts = obj.map((v) => flatten(v)).filter(Boolean);\n return sorts.length ? { sort: sorts.join(',') } : {};\n};\n";
150
+
159
151
  const resolveImports = (target) => {
160
- const imports = [];
161
- if (isRXTarget(target)) imports.push(generateImport({
162
- src: "rxjs",
163
- imports: ["defer", "Observable"]
164
- }));
165
- return imports.join("\n");
166
- };
167
- const resolveMappings = (target) => `const wrapResponse = ${isRXTarget(target) ? "defer" : "(v: (...args: any[]) => any) => v()"};`;
152
+ const imports = [];
153
+ if (isRXTarget(target)) {
154
+ imports.push(generateImport({ src: 'rxjs', imports: ['defer', 'Observable'] }));
155
+ }
156
+ return imports.join('\n');
157
+ };
158
+ const resolveMappings = (target) => `const wrapResponse = ${isRXTarget(target) ? 'defer' : '(v: (...args: any[]) => any) => v()'};`;
168
159
  const resolveBinaryClass = (target) => `const resolveBinaryObject = () => ${resolveBinaryType(target)};`;
169
160
  const generateBase = (apiVersion, { target, useQueryLanguage, generateUnique }) => {
170
- return generateStatements(resolveImports(target), `const apiVersion = ${apiVersion}`, resolveMappings(target), resolveBinaryClass(target), globalConfig_ts_default, types_ts_default, utils_ts_default, root_ts_default, useQueryLanguage ? queriesWithQueryLanguage_ts_default : queriesWithFilter_ts_default, generateUnique ? unique_ts_default : "", multiRequest_ts_default);
161
+ return generateStatements(resolveImports(target), `const apiVersion = ${apiVersion}`, resolveMappings(target), resolveBinaryClass(target), globalConfig, types, utils, root, useQueryLanguage ? queriesWithQueryLanguage : queriesWithFilter, generateUnique ? unique : '', multiRequest);
171
162
  };
172
- //#endregion
173
- //#region src/ts/generateEnum.ts
163
+
174
164
  const transformKey = (s) => snakeCase(s).toUpperCase();
175
165
  const generateEnum = (name, values) => {
176
- return `export enum ${name} {\n${indent(values.map((v) => `${transformKey(v)} = ${generateString(v)}`).join(",\n"))}\n}`;
166
+ const props = indent(values.map((v) => `${transformKey(v)} = ${generateString(v)}`).join(',\n'));
167
+ return `export enum ${name} {\n${props}\n}`;
177
168
  };
178
- //#endregion
179
- //#region src/utils/case.ts
169
+
170
+ // We can't use the pascalCase utility as it converts "cDBReminderType" to "CDbReminderType" which is incorrect.
180
171
  const loosePascalCase = (str) => str[0].toUpperCase() + str.slice(1);
181
- //#endregion
182
- //#region src/utils/openapi/guards.ts
172
+
183
173
  const isObject = (v) => {
184
- return v !== null && typeof v === "object" && !Array.isArray(v);
174
+ return v !== null && typeof v === 'object' && !Array.isArray(v);
185
175
  };
186
176
  const isParameterObject = (v) => {
187
- return isObject(v) && typeof v.name === "string" && typeof v.in === "string";
177
+ return isObject(v) && typeof v.name === 'string' && typeof v.in === 'string';
188
178
  };
189
179
  const isReferenceObject = (v) => {
190
- return isObject(v) && typeof v.$ref === "string";
180
+ return isObject(v) && typeof v.$ref === 'string';
191
181
  };
192
182
  const isObjectSchemaObject = (v) => {
193
- return isObject(v) && v.type === "object" && isObject(v.properties);
183
+ return isObject(v) && v.type === 'object' && isObject(v.properties);
194
184
  };
195
185
  const isEnumSchemaObject = (v) => {
196
- return isObject(v) && v.type === "string" && Array.isArray(v.enum);
186
+ return isObject(v) && v.type === 'string' && Array.isArray(v.enum);
197
187
  };
198
188
  const isArraySchemaObject = (v) => {
199
- return isObject(v) && v.type === "array" && typeof v.items === "object";
189
+ return isObject(v) && v.type === 'array' && typeof v.items === 'object';
200
190
  };
201
191
  const isResponseObject = (v) => {
202
- return isObject(v) && typeof v.description === "string";
192
+ return isObject(v) && typeof v.description === 'string';
203
193
  };
204
- //#endregion
205
- //#region src/generator/02-enums/index.ts
194
+
206
195
  const generateEnums = (context) => {
207
- const enums = /* @__PURE__ */ new Map();
208
- for (const [schemaName, schema] of context.schemas) if (isEnumSchemaObject(schema)) {
209
- const enumName = loosePascalCase(schemaName);
210
- if (!enums.has(enumName)) enums.set(enumName, {
211
- name: enumName,
212
- properties: schema.enum,
213
- source: generateEnum(enumName, schema.enum)
214
- });
215
- }
216
- return enums;
217
- };
218
- //#endregion
219
- //#region src/utils/concat.ts
220
- const concat = (strings, separator = ", ", maxLength = 80) => {
221
- const joined = strings.join(separator);
222
- if (joined.length > maxLength) {
223
- const length = strings.length - 1;
224
- return `\n${indent(strings.map((value, index) => index === length ? value : `${(value + separator).trim()}\n`).join(""))}\n`;
225
- } else return joined;
226
- };
227
- //#endregion
228
- //#region src/utils/openapi/convertParametersToSchemaObject.ts
196
+ const enums = new Map();
197
+ for (const [schemaName, schema] of context.schemas) {
198
+ if (isEnumSchemaObject(schema)) {
199
+ const enumName = loosePascalCase(schemaName);
200
+ if (!enums.has(enumName)) {
201
+ enums.set(enumName, {
202
+ name: enumName,
203
+ properties: schema.enum,
204
+ source: generateEnum(enumName, schema.enum)
205
+ });
206
+ }
207
+ }
208
+ }
209
+ return enums;
210
+ };
211
+
212
+ const concat = (strings, separator = ', ', maxLength = 80) => {
213
+ const joined = strings.join(separator);
214
+ if (joined.length > maxLength) {
215
+ const length = strings.length - 1;
216
+ return `\n${indent(strings.map((value, index) => (index === length ? value : `${(value + separator).trim()}\n`)).join(''))}\n`;
217
+ }
218
+ else {
219
+ return joined;
220
+ }
221
+ };
222
+
229
223
  const convertParametersToSchemaObject = (parameters) => {
230
- const properties = [];
231
- const required = [];
232
- for (const param of parameters) if (param.in === "query" && param.schema) {
233
- properties.push([param.name, param.schema]);
234
- if (param.required) required.push(param.name);
235
- }
236
- return {
237
- type: "object",
238
- properties: Object.fromEntries(properties),
239
- required
240
- };
241
- };
242
- //#endregion
243
- //#region src/utils/openapi/convertToTypeScriptType.ts
224
+ const properties = [];
225
+ const required = [];
226
+ for (const param of parameters) {
227
+ if (param.in === 'query' && param.schema) {
228
+ properties.push([param.name, param.schema]);
229
+ if (param.required)
230
+ required.push(param.name);
231
+ }
232
+ }
233
+ return {
234
+ type: 'object',
235
+ properties: Object.fromEntries(properties),
236
+ required
237
+ };
238
+ };
239
+
244
240
  const createReferenceType = (value) => ({
245
- type: "reference",
246
- toString: () => loosePascalCase(value)
241
+ type: 'reference',
242
+ toString: () => loosePascalCase(value)
247
243
  });
248
244
  const createRawType = (value) => ({
249
- type: "raw",
250
- toString: () => value
245
+ type: 'raw',
246
+ toString: () => value
251
247
  });
252
248
  const createArrayType = (value) => ({
253
- type: "array",
254
- toString: () => `(${value.toString()})[]`
249
+ type: 'array',
250
+ toString: () => `(${value.toString()})[]`
255
251
  });
256
252
  const createTupleType = (value) => ({
257
- type: "tuple",
258
- toString: () => concat([...new Set(value.map((v) => typeof v === "string" ? `'${v}'` : v.toString()))], " | ")
253
+ type: 'tuple',
254
+ toString: () => concat([...new Set(value.map((v) => (typeof v === 'string' ? `'${v}'` : v.toString())))], ' | ')
259
255
  });
260
256
  const createObjectType = (value, required = []) => ({
261
- type: "object",
262
- isFullyOptional: () => {
263
- return !required.length && Object.values(value).filter((v) => v?.type === "object").every((v) => v.isFullyOptional());
264
- },
265
- toString: (propertyPropagationOption = "ignore") => {
266
- const properties = Object.entries(value).filter((v) => v[1]).map((v) => {
267
- const name = v[0];
268
- const value = v[1];
269
- return `${name + (required.includes(name) || propertyPropagationOption === "force" || value.type === "object" && !value.isFullyOptional() && propertyPropagationOption === "propagate" ? "" : "?")}: ${value.toString()};`;
270
- });
271
- return properties.length ? `{\n${indent(properties.join("\n"))}\n}` : "{}";
272
- }
257
+ type: 'object',
258
+ isFullyOptional: () => {
259
+ return (!required.length &&
260
+ Object.values(value)
261
+ .filter((v) => v?.type === 'object')
262
+ .every((v) => v.isFullyOptional()));
263
+ },
264
+ toString: (propertyPropagationOption = 'ignore') => {
265
+ const properties = Object.entries(value)
266
+ .filter((v) => v[1])
267
+ .map((v) => {
268
+ const name = v[0];
269
+ const value = v[1];
270
+ const isRequired = required.includes(name) ||
271
+ propertyPropagationOption === 'force' ||
272
+ (value.type === 'object' && !value.isFullyOptional() && propertyPropagationOption === 'propagate');
273
+ return `${name + (isRequired ? '' : '?')}: ${value.toString()};`;
274
+ });
275
+ return properties.length ? `{\n${indent(properties.join('\n'))}\n}` : '{}';
276
+ }
273
277
  });
274
278
  const getRefName = (obj) => {
275
- return obj.$ref.replace(/.*\//, "");
279
+ return obj.$ref.replace(/.*\//, '');
276
280
  };
277
281
  const convertToTypeScriptType = (schema) => {
278
- if (Array.isArray(schema)) return convertToTypeScriptType(convertParametersToSchemaObject(schema));
279
- else if (isReferenceObject(schema)) return createReferenceType(getRefName(schema));
280
- else switch (schema.type) {
281
- case "integer":
282
- case "number": return createRawType("number");
283
- case "string": if (schema.enum) return createTupleType(schema.enum);
284
- else return schema.format === "binary" ? createRawType("binary") : createRawType("string");
285
- case "boolean": return createRawType("boolean");
286
- case "object": {
287
- const { properties = {}, required = [] } = schema;
288
- return createObjectType(Object.fromEntries(Object.entries(properties).map(([prop, propSchema]) => [prop, convertToTypeScriptType(propSchema)])), required);
289
- }
290
- case "array": return createArrayType(convertToTypeScriptType(schema.items));
291
- default: return createRawType("unknown");
292
- }
293
- };
294
- //#endregion
295
- //#region src/generator/03-entities/utils/extractPropertyMetaData.ts
282
+ if (Array.isArray(schema)) {
283
+ return convertToTypeScriptType(convertParametersToSchemaObject(schema));
284
+ }
285
+ else if (isReferenceObject(schema)) {
286
+ return createReferenceType(getRefName(schema));
287
+ }
288
+ else {
289
+ switch (schema.type) {
290
+ case 'integer':
291
+ case 'number':
292
+ return createRawType('number');
293
+ case 'string':
294
+ if (schema.enum) {
295
+ return createTupleType(schema.enum);
296
+ }
297
+ else {
298
+ return schema.format === 'binary' ? createRawType('binary') : createRawType('string');
299
+ }
300
+ case 'boolean':
301
+ return createRawType('boolean');
302
+ case 'object': {
303
+ const { properties = {}, required = [] } = schema;
304
+ return createObjectType(Object.fromEntries(Object.entries(properties).map(([prop, propSchema]) => [prop, convertToTypeScriptType(propSchema)])), required);
305
+ }
306
+ case 'array':
307
+ return createArrayType(convertToTypeScriptType(schema.items));
308
+ default:
309
+ return createRawType('unknown');
310
+ }
311
+ }
312
+ };
313
+
296
314
  const setReferenceMeta = (prop, metaData, context) => {
297
- const referenceName = getRefName(prop);
298
- if (isEnumSchemaObject(context.schemas.get(referenceName))) metaData.enum = loosePascalCase(referenceName);
299
- else metaData.entity = referenceName;
315
+ const referenceName = getRefName(prop);
316
+ const referenceSchema = context.schemas.get(referenceName);
317
+ if (isEnumSchemaObject(referenceSchema)) {
318
+ metaData.enum = loosePascalCase(referenceName);
319
+ }
320
+ else {
321
+ metaData.entity = referenceName;
322
+ }
300
323
  };
301
324
  const extractPropertyMetaData = (prop, context) => {
302
- const metaData = {};
303
- const weclappExtension = prop["x-weclapp"];
304
- if (weclappExtension) {
305
- metaData.service = weclappExtension.service;
306
- metaData.entity = weclappExtension.entity;
307
- }
308
- if (isReferenceObject(prop)) {
309
- metaData.type = "reference";
310
- setReferenceMeta(prop, metaData, context);
311
- } else {
312
- metaData.type = prop.type;
313
- metaData.format = prop.format;
314
- metaData.maxLength = prop.maxLength;
315
- metaData.pattern = prop.pattern;
316
- if (isArraySchemaObject(prop)) if (isReferenceObject(prop.items)) {
317
- metaData.format = "reference";
318
- setReferenceMeta(prop.items, metaData, context);
319
- } else metaData.format = "string";
320
- }
321
- return metaData;
322
- };
323
- //#endregion
324
- //#region src/ts/generateComment.ts
325
+ const metaData = {};
326
+ const weclappExtension = prop['x-weclapp'];
327
+ if (weclappExtension) {
328
+ metaData.service = weclappExtension.service;
329
+ metaData.entity = weclappExtension.entity;
330
+ }
331
+ if (isReferenceObject(prop)) {
332
+ metaData.type = 'reference';
333
+ setReferenceMeta(prop, metaData, context);
334
+ }
335
+ else {
336
+ metaData.type = prop.type;
337
+ metaData.format = prop.format;
338
+ metaData.maxLength = prop.maxLength;
339
+ metaData.pattern = prop.pattern;
340
+ if (isArraySchemaObject(prop)) {
341
+ if (isReferenceObject(prop.items)) {
342
+ metaData.format = 'reference';
343
+ setReferenceMeta(prop.items, metaData, context);
344
+ }
345
+ else {
346
+ metaData.format = 'string';
347
+ }
348
+ }
349
+ }
350
+ return metaData;
351
+ };
352
+
325
353
  const generateInlineComment = (comment) => `/** ${comment} */`;
326
- const generateBlockComment = (comment, body) => `/**\n${comment.trim().replace(/^ */gm, " * ")}\n */${body ? `\n${body}` : ""}`;
327
- //#endregion
328
- //#region src/ts/generateType.ts
354
+ const generateBlockComment = (comment, body) => `/**\n${comment.trim().replace(/^ */gm, ' * ')}\n */${body ? `\n${body}` : ''}`;
355
+
329
356
  const generateType = (name, value) => {
330
- return `export type ${name} = ${value.trim()};`;
357
+ return `export type ${name} = ${value.trim()};`;
331
358
  };
332
- //#endregion
333
- //#region src/utils/arrayify.ts
334
- const arrayify = (v) => Array.isArray(v) ? v : [v];
335
- //#endregion
336
- //#region src/ts/generateInterface.ts
359
+
360
+ const arrayify = (v) => (Array.isArray(v) ? v : [v]);
361
+
337
362
  const generateInterfaceProperties = (entries) => {
338
- const properties = entries.filter((v) => v.type !== void 0).filter((value, index, array) => array.findIndex((v) => v.name === value.name) === index).map(({ name, type, required, readonly, comment }) => {
339
- const cmd = comment ? `${generateInlineComment(comment)}\n` : "";
340
- const req = required ? "" : "?";
341
- return `${cmd + (readonly ? "readonly " : "") + name + req}: ${type};`;
342
- }).join("\n");
343
- return properties.length ? `{\n${indent(properties)}\n}` : `{}`;
363
+ const properties = entries
364
+ .filter((v) => v.type !== undefined)
365
+ .filter((value, index, array) => array.findIndex((v) => v.name === value.name) === index)
366
+ .map(({ name, type, required, readonly, comment }) => {
367
+ const cmd = comment ? `${generateInlineComment(comment)}\n` : '';
368
+ const req = required ? '' : '?';
369
+ const rol = readonly ? 'readonly ' : '';
370
+ return `${cmd + rol + name + req}: ${type};`;
371
+ })
372
+ .join('\n');
373
+ return properties.length ? `{\n${indent(properties)}\n}` : `{}`;
344
374
  };
345
375
  const generateInterfaceFromObject = (name, obj, propertyPropagationOption) => `export interface ${name} ${obj.toString(propertyPropagationOption)}`;
346
376
  const generateInterface = (name, entries, extend) => {
347
- return `export interface ${`${name} ${extend ? `extends ${arrayify(extend).join(", ")}` : ""}`.trim()} ${generateInterfaceProperties(entries)}`;
377
+ const signature = `${name} ${extend ? `extends ${arrayify(extend).join(', ')}` : ''}`.trim();
378
+ const body = generateInterfaceProperties(entries);
379
+ return `export interface ${signature} ${body}`;
348
380
  };
349
381
  const generateInterfaceType = (name, entries, extend) => {
350
- const body = generateInterfaceProperties(entries);
351
- const bases = extend ? arrayify(extend).join(" & ") : void 0;
352
- let typeDefinition = "";
353
- if (bases) typeDefinition = bases;
354
- else typeDefinition = body;
355
- if (bases && body !== "{}") typeDefinition += ` & ${body}`;
356
- return generateType(name, typeDefinition);
357
- };
358
- //#endregion
359
- //#region src/utils/pluralize.ts
382
+ const body = generateInterfaceProperties(entries);
383
+ const bases = extend ? arrayify(extend).join(' & ') : undefined;
384
+ let typeDefinition = '';
385
+ if (bases) {
386
+ typeDefinition = bases;
387
+ }
388
+ else {
389
+ typeDefinition = body;
390
+ }
391
+ if (bases && body !== '{}') {
392
+ typeDefinition += ` & ${body}`;
393
+ }
394
+ return generateType(name, typeDefinition);
395
+ };
396
+
360
397
  /**
361
- * Pluralizes a word, most of the time correct.
362
- * @param s String to pluralize.
363
- */
398
+ * Pluralizes a word, most of the time correct.
399
+ * @param s String to pluralize.
400
+ */
364
401
  const pluralize = (s) => {
365
- return s.endsWith("s") ? s : s.endsWith("y") ? `${s.slice(0, -1)}ies` : `${s}s`;
366
- };
367
- //#endregion
368
- //#region src/utils/logger.ts
369
- const logger = new class {
370
- active = true;
371
- warnings = 0;
372
- errors = 0;
373
- write(str = "") {
374
- process.stdout.write(str);
375
- }
376
- blankLn(str = "") {
377
- this.blank(`${str}\n`);
378
- }
379
- warnLn(str) {
380
- this.warn(`${str}\n`);
381
- }
382
- errorLn(str) {
383
- this.error(`${str}\n`);
384
- }
385
- successLn(str) {
386
- this.success(`${str}\n`);
387
- }
388
- infoLn(str) {
389
- this.info(`${str}\n`);
390
- }
391
- debugLn(str) {
392
- this.debug(`${str}\n`);
393
- }
394
- blank(str) {
395
- this.write(str);
396
- }
397
- warn(str) {
398
- this.write(`${chalk.yellowBright("[!]")} ${str}`);
399
- this.warnings++;
400
- }
401
- error(str) {
402
- this.write(`${chalk.redBright("[X]")} ${str}`);
403
- this.errors++;
404
- }
405
- success(str) {
406
- this.write(`${chalk.greenBright("[✓]")} ${str}`);
407
- }
408
- info(str) {
409
- this.write(`${chalk.blueBright("[i]")} ${str}`);
410
- }
411
- debug(str) {
412
- this.write(`[-] ${str}`);
413
- }
414
- printSummary() {
415
- const format = (v, name, fail, ok) => {
416
- const color = v ? fail : ok;
417
- return v === 0 ? `${color("zero")} ${pluralize(name)}` : v === 1 ? `${color("one")} ${name}` : `${color(v)} ${pluralize(name)}`;
418
- };
419
- const info = `Finished with ${format(this.warnings, "warning", chalk.yellowBright, chalk.greenBright)} and ${format(this.errors, "error", chalk.redBright, chalk.greenBright)}.`;
420
- this[this.errors ? "errorLn" : this.warnings ? "warnLn" : "successLn"](info);
421
- }
422
- }();
423
- //#endregion
424
- //#region src/generator/03-entities/index.ts
425
- const FILTER_PROPS_SUFFIX = "Filter_Props";
402
+ return s.endsWith('s') ? s : s.endsWith('y') ? `${s.slice(0, -1)}ies` : `${s}s`;
403
+ };
404
+
405
+ const logger = new (class {
406
+ active = true;
407
+ warnings = 0;
408
+ errors = 0;
409
+ write(str = '') {
410
+ process.stdout.write(str);
411
+ }
412
+ blankLn(str = '') {
413
+ this.blank(`${str}\n`);
414
+ }
415
+ warnLn(str) {
416
+ this.warn(`${str}\n`);
417
+ }
418
+ errorLn(str) {
419
+ this.error(`${str}\n`);
420
+ }
421
+ successLn(str) {
422
+ this.success(`${str}\n`);
423
+ }
424
+ infoLn(str) {
425
+ this.info(`${str}\n`);
426
+ }
427
+ debugLn(str) {
428
+ this.debug(`${str}\n`);
429
+ }
430
+ blank(str) {
431
+ this.write(str);
432
+ }
433
+ warn(str) {
434
+ this.write(`${chalk.yellowBright('[!]')} ${str}`);
435
+ this.warnings++;
436
+ }
437
+ error(str) {
438
+ this.write(`${chalk.redBright('[X]')} ${str}`);
439
+ this.errors++;
440
+ }
441
+ success(str) {
442
+ this.write(`${chalk.greenBright('[✓]')} ${str}`);
443
+ }
444
+ info(str) {
445
+ this.write(`${chalk.blueBright('[i]')} ${str}`);
446
+ }
447
+ debug(str) {
448
+ this.write(`[-] ${str}`);
449
+ }
450
+ printSummary() {
451
+ const format = (v, name, fail, ok) => {
452
+ const color = v ? fail : ok;
453
+ return v === 0
454
+ ? `${color('zero')} ${pluralize(name)}`
455
+ : v === 1
456
+ ? `${color('one')} ${name}`
457
+ : `${color(v)} ${pluralize(name)}`;
458
+ };
459
+ const warnings = format(this.warnings, 'warning', chalk.yellowBright, chalk.greenBright);
460
+ const errors = format(this.errors, 'error', chalk.redBright, chalk.greenBright);
461
+ const info = `Finished with ${warnings} and ${errors}.`;
462
+ this[this.errors ? 'errorLn' : this.warnings ? 'warnLn' : 'successLn'](info);
463
+ }
464
+ })();
465
+
466
+ const FILTER_PROPS_SUFFIX = 'Filter_Props';
426
467
  const generateEntities = (context) => {
427
- const entities = /* @__PURE__ */ new Map();
428
- for (const [schemaName, schema] of context.schemas) {
429
- if (isEnumSchemaObject(schema)) continue;
430
- const entityName = schemaName;
431
- const entityInterfaceName = loosePascalCase(entityName);
432
- const entityInterfaceProperties = [];
433
- const properties = /* @__PURE__ */ new Map();
434
- let parentEntityName = void 0;
435
- let parentEntityInterfaceName = void 0;
436
- const entityFilterInterfaceName = `${entityInterfaceName}_${FILTER_PROPS_SUFFIX}`;
437
- const entityFilterInterfaceProperties = [];
438
- let parentEntityFilterInterfaceName = void 0;
439
- const processProperties = (props = {}) => {
440
- for (const [propertyName, propertySchema] of Object.entries(props)) {
441
- const weclappExtension = propertySchema["x-weclapp"];
442
- properties.set(propertyName, extractPropertyMetaData(propertySchema, context));
443
- const type = convertToTypeScriptType(propertySchema).toString();
444
- const castedSchema = propertySchema;
445
- const comment = castedSchema.deprecated ? "@deprecated will be removed." : castedSchema.format ? `format: ${castedSchema.format}` : void 0;
446
- if (weclappExtension?.filterable !== false) entityFilterInterfaceProperties.push({
447
- name: propertyName,
448
- type,
449
- comment
450
- });
451
- entityInterfaceProperties.push({
452
- name: propertyName,
453
- type,
454
- required: weclappExtension?.required,
455
- readonly: castedSchema.readOnly,
456
- comment
457
- });
458
- }
459
- };
460
- const processExtraFilterProperties = (props = {}) => {
461
- for (const [propertyName, propertySchema] of Object.entries(props)) {
462
- if (isReferenceObject(propertySchema)) continue;
463
- const type = convertToTypeScriptType(propertySchema).toString();
464
- const comment = propertySchema.deprecated ? "@deprecated will be removed." : propertySchema.format ? `format: ${propertySchema.format}` : void 0;
465
- entityFilterInterfaceProperties.push({
466
- name: propertyName,
467
- type,
468
- comment
469
- });
470
- }
471
- };
472
- const processFilterPaths = (filterPaths = {}) => {
473
- for (const [filterProp, entityName] of Object.entries(filterPaths)) if (!filterProp.includes(".") && context.schemas.get(entityName)) entityFilterInterfaceProperties.push({
474
- name: filterProp,
475
- type: `${loosePascalCase(entityName)}_${FILTER_PROPS_SUFFIX}`
476
- });
477
- };
478
- if (schema.allOf?.length) {
479
- if (schema.allOf.length > 2) {
480
- logger.errorLn(`Failed to process schema for ${schemaName}: invalid allOf length`);
481
- continue;
482
- }
483
- for (const item of schema.allOf) if (isReferenceObject(item)) {
484
- parentEntityName = getRefName(item);
485
- parentEntityInterfaceName = createReferenceType(parentEntityName).toString();
486
- parentEntityFilterInterfaceName = `${parentEntityInterfaceName}_${FILTER_PROPS_SUFFIX}`;
487
- } else if (item.type === "object") {
488
- processProperties(item.properties);
489
- processExtraFilterProperties(item["x-weclapp-filterProperties"]);
490
- processFilterPaths(item["x-weclapp-filterPaths"]);
491
- } else logger.errorLn(`Failed to process schema for ${schemaName}: invalid schema type in allOf`);
492
- } else processProperties(schema.properties);
493
- entities.set(entityName, {
494
- name: entityName,
495
- interfaceName: entityInterfaceName,
496
- properties,
497
- source: generateStatements(generateInterface(entityInterfaceName, entityInterfaceProperties, parentEntityInterfaceName)),
498
- filterInterfaceName: entityFilterInterfaceName,
499
- filterSource: generateStatements(generateInterface(entityFilterInterfaceName, entityFilterInterfaceProperties, parentEntityFilterInterfaceName)),
500
- parentName: parentEntityName,
501
- parentInterfaceName: parentEntityInterfaceName
502
- });
503
- }
504
- return entities;
505
- };
506
- //#endregion
507
- //#region src/utils/weclapp/parseEndpointPath.ts
468
+ const entities = new Map();
469
+ for (const [schemaName, schema] of context.schemas) {
470
+ // Enums are generated separately
471
+ if (isEnumSchemaObject(schema)) {
472
+ continue;
473
+ }
474
+ const entityName = schemaName;
475
+ const entityInterfaceName = loosePascalCase(entityName);
476
+ const entityInterfaceProperties = [];
477
+ const properties = new Map();
478
+ let parentEntityName = undefined;
479
+ let parentEntityInterfaceName = undefined;
480
+ const entityFilterInterfaceName = `${entityInterfaceName}_${FILTER_PROPS_SUFFIX}`;
481
+ const entityFilterInterfaceProperties = [];
482
+ let parentEntityFilterInterfaceName = undefined;
483
+ const processProperties = (props = {}) => {
484
+ for (const [propertyName, propertySchema] of Object.entries(props)) {
485
+ const weclappExtension = propertySchema['x-weclapp'];
486
+ properties.set(propertyName, extractPropertyMetaData(propertySchema, context));
487
+ const type = convertToTypeScriptType(propertySchema).toString();
488
+ // cast to SchemaObject to access deprecated and readOnly properties (ReferenceObject can also include these props in OpenAPI 3.1)
489
+ const castedSchema = propertySchema;
490
+ const comment = castedSchema.deprecated
491
+ ? '@deprecated will be removed.'
492
+ : castedSchema.format
493
+ ? `format: ${castedSchema.format}`
494
+ : undefined;
495
+ if (weclappExtension?.filterable !== false) {
496
+ entityFilterInterfaceProperties.push({ name: propertyName, type, comment });
497
+ }
498
+ entityInterfaceProperties.push({
499
+ name: propertyName,
500
+ type,
501
+ required: weclappExtension?.required,
502
+ readonly: castedSchema.readOnly,
503
+ comment
504
+ });
505
+ }
506
+ };
507
+ const processExtraFilterProperties = (props = {}) => {
508
+ for (const [propertyName, propertySchema] of Object.entries(props)) {
509
+ if (isReferenceObject(propertySchema))
510
+ continue;
511
+ const type = convertToTypeScriptType(propertySchema).toString();
512
+ const comment = propertySchema.deprecated
513
+ ? '@deprecated will be removed.'
514
+ : propertySchema.format
515
+ ? `format: ${propertySchema.format}`
516
+ : undefined;
517
+ entityFilterInterfaceProperties.push({ name: propertyName, type, comment });
518
+ }
519
+ };
520
+ const processFilterPaths = (filterPaths = {}) => {
521
+ for (const [filterProp, entityName] of Object.entries(filterPaths)) {
522
+ if (!filterProp.includes('.') && context.schemas.get(entityName)) {
523
+ entityFilterInterfaceProperties.push({
524
+ name: filterProp,
525
+ type: `${loosePascalCase(entityName)}_${FILTER_PROPS_SUFFIX}`
526
+ });
527
+ }
528
+ }
529
+ };
530
+ if (schema.allOf?.length) {
531
+ if (schema.allOf.length > 2) {
532
+ logger.errorLn(`Failed to process schema for ${schemaName}: invalid allOf length`);
533
+ continue;
534
+ }
535
+ for (const item of schema.allOf) {
536
+ if (isReferenceObject(item)) {
537
+ parentEntityName = getRefName(item);
538
+ parentEntityInterfaceName = createReferenceType(parentEntityName).toString();
539
+ parentEntityFilterInterfaceName = `${parentEntityInterfaceName}_${FILTER_PROPS_SUFFIX}`;
540
+ }
541
+ else if (item.type === 'object') {
542
+ processProperties(item.properties);
543
+ processExtraFilterProperties(item['x-weclapp-filterProperties']);
544
+ processFilterPaths(item['x-weclapp-filterPaths']);
545
+ }
546
+ else {
547
+ logger.errorLn(`Failed to process schema for ${schemaName}: invalid schema type in allOf`);
548
+ }
549
+ }
550
+ }
551
+ else {
552
+ processProperties(schema.properties);
553
+ }
554
+ entities.set(entityName, {
555
+ name: entityName,
556
+ interfaceName: entityInterfaceName,
557
+ properties,
558
+ source: generateStatements(generateInterface(entityInterfaceName, entityInterfaceProperties, parentEntityInterfaceName)),
559
+ filterInterfaceName: entityFilterInterfaceName,
560
+ filterSource: generateStatements(generateInterface(entityFilterInterfaceName, entityFilterInterfaceProperties, parentEntityFilterInterfaceName)),
561
+ parentName: parentEntityName,
562
+ parentInterfaceName: parentEntityInterfaceName
563
+ });
564
+ }
565
+ return entities;
566
+ };
567
+
508
568
  /**
509
- * ROOT => /article
510
- * COUNT => /article/count
511
- * ENTITY => /article/{id}
512
- * SPECIAL_ROOT => /article/generateImage
513
- * SPECIAL_ENTITY => /article/id/{id}/generateImag
514
- */
515
- let WeclappEndpointType = /* @__PURE__ */ function(WeclappEndpointType) {
516
- WeclappEndpointType["ROOT"] = "ROOT";
517
- WeclappEndpointType["COUNT"] = "COUNT";
518
- WeclappEndpointType["ENTITY"] = "ENTITY";
519
- WeclappEndpointType["GENERIC_ROOT"] = "GENERIC_ROOT";
520
- WeclappEndpointType["GENERIC_ENTITY"] = "GENERIC_ENTITY";
521
- return WeclappEndpointType;
522
- }({});
569
+ * ROOT => /article
570
+ * COUNT => /article/count
571
+ * ENTITY => /article/{id}
572
+ * SPECIAL_ROOT => /article/generateImage
573
+ * SPECIAL_ENTITY => /article/id/{id}/generateImag
574
+ */
575
+ var WeclappEndpointType;
576
+ (function (WeclappEndpointType) {
577
+ WeclappEndpointType["ROOT"] = "ROOT";
578
+ WeclappEndpointType["COUNT"] = "COUNT";
579
+ WeclappEndpointType["ENTITY"] = "ENTITY";
580
+ WeclappEndpointType["GENERIC_ROOT"] = "GENERIC_ROOT";
581
+ WeclappEndpointType["GENERIC_ENTITY"] = "GENERIC_ENTITY";
582
+ })(WeclappEndpointType || (WeclappEndpointType = {}));
523
583
  const parseEndpointPath = (path) => {
524
- const [, service, ...rest] = path.split("/");
525
- if (!service) return;
526
- if (!rest.length) return {
527
- path,
528
- service,
529
- type: WeclappEndpointType.ROOT
530
- };
531
- else if (rest[0] === "count") return {
532
- path,
533
- service,
534
- type: WeclappEndpointType.COUNT
535
- };
536
- else if (rest[0] === "id") return rest.length === 2 ? {
537
- path,
538
- service,
539
- type: WeclappEndpointType.ENTITY
540
- } : {
541
- path,
542
- service,
543
- method: rest[2],
544
- type: WeclappEndpointType.GENERIC_ENTITY
545
- };
546
- else if (rest.length === 1) return {
547
- path,
548
- service,
549
- method: rest[1],
550
- type: WeclappEndpointType.GENERIC_ROOT
551
- };
584
+ const [, service, ...rest] = path.split('/');
585
+ if (!service) {
586
+ return undefined;
587
+ }
588
+ if (!rest.length) {
589
+ return { path, service, type: WeclappEndpointType.ROOT };
590
+ }
591
+ else if (rest[0] === 'count') {
592
+ return { path, service, type: WeclappEndpointType.COUNT };
593
+ }
594
+ else if (rest[0] === 'id') {
595
+ return rest.length === 2
596
+ ? { path, service, type: WeclappEndpointType.ENTITY }
597
+ : {
598
+ path,
599
+ service,
600
+ method: rest[2],
601
+ type: WeclappEndpointType.GENERIC_ENTITY
602
+ };
603
+ }
604
+ else if (rest.length === 1) {
605
+ return {
606
+ path,
607
+ service,
608
+ method: rest[1],
609
+ type: WeclappEndpointType.GENERIC_ROOT
610
+ };
611
+ }
612
+ return undefined;
552
613
  };
553
614
  const isMultiPartUploadPath = (path) => {
554
- const [, entity, ...rest] = path.split("/");
555
- return entity && rest.length === 2 && rest[1] === "multipartUpload";
615
+ const [, entity, ...rest] = path.split('/');
616
+ return entity && rest.length === 2 && rest[1] === 'multipartUpload';
556
617
  };
557
618
  const parseEndpointsPaths = (paths) => {
558
- const endpoints = /* @__PURE__ */ new Map();
559
- for (const [rawPath, path] of Object.entries(paths)) {
560
- const endpoint = parseEndpointPath(rawPath);
561
- if (!endpoint || !path) {
562
- if (isMultiPartUploadPath(rawPath)) continue;
563
- logger.errorLn(`Failed to parse ${rawPath}`);
564
- continue;
565
- }
566
- if (endpoints.has(endpoint.service)) endpoints.get(endpoint.service)?.push({
567
- endpoint,
568
- path
569
- });
570
- else endpoints.set(endpoint.service, [{
571
- endpoint,
572
- path
573
- }]);
574
- }
575
- return endpoints;
576
- };
577
- //#endregion
578
- //#region src/ts/generateArrowFunction.ts
619
+ const endpoints = new Map();
620
+ for (const [rawPath, path] of Object.entries(paths)) {
621
+ const endpoint = parseEndpointPath(rawPath);
622
+ if (!endpoint || !path) {
623
+ // Todo: Should be removed if sdk supports multi part upload.
624
+ if (isMultiPartUploadPath(rawPath)) {
625
+ continue;
626
+ }
627
+ logger.errorLn(`Failed to parse ${rawPath}`);
628
+ continue;
629
+ }
630
+ if (endpoints.has(endpoint.service)) {
631
+ endpoints.get(endpoint.service)?.push({ endpoint, path });
632
+ }
633
+ else {
634
+ endpoints.set(endpoint.service, [{ endpoint, path }]);
635
+ }
636
+ }
637
+ return endpoints;
638
+ };
639
+
579
640
  const generateArrowFunction = ({ name, signature, returns, params }) => {
580
- return `const ${name}: ${signature} = (${params?.join(", ") ?? ""}) =>\n${indent(returns)};`;
641
+ return `const ${name}: ${signature} = (${params?.join(', ') ?? ''}) =>\n${indent(returns)};`;
581
642
  };
582
- //#endregion
583
- //#region src/ts/generateArrowFunctionType.ts
584
- const generateArrowFunctionType = ({ type, returns = "void", generics, params }) => {
585
- return generateType(type, `${(generics?.length ? `<\n${indent(generics.join(",\n"))}\n>` : "") + (params?.length ? `(${params.join(", ")})` : `()`)} =>\n${indent(returns)}`);
643
+
644
+ const generateArrowFunctionType = ({ type, returns = 'void', generics, params }) => {
645
+ const genericsString = generics?.length ? `<\n${indent(generics.join(',\n'))}\n>` : '';
646
+ const paramsString = params?.length ? `(${params.join(', ')})` : `()`;
647
+ return generateType(type, `${genericsString + paramsString} =>\n${indent(returns)}`);
586
648
  };
587
- //#endregion
588
- //#region src/generator/04-services/utils/resolveParameters.ts
649
+
589
650
  const resolveParameters = (resolvableParameters = [], parameters) => {
590
- if (!resolvableParameters) return [];
591
- return resolvableParameters.flatMap((param) => {
592
- if (isReferenceObject(param)) {
593
- const resolved = parameters.get(getRefName(param));
594
- return resolved ? [resolved] : [];
595
- }
596
- return [param];
597
- });
598
- };
599
- //#endregion
600
- //#region src/generator/04-services/endpoints/count.ts
651
+ if (!resolvableParameters)
652
+ return [];
653
+ return resolvableParameters.flatMap((param) => {
654
+ if (isReferenceObject(param)) {
655
+ const resolved = parameters.get(getRefName(param));
656
+ return resolved ? [resolved] : [];
657
+ }
658
+ return [param];
659
+ });
660
+ };
661
+
601
662
  const generateCountEndpoint = ({ endpoint, operationObject, entities, context, options }) => {
602
- const functionName = "count";
603
- const functionTypeName = `${pascalCase(endpoint.service)}Service_${pascalCase(functionName)}`;
604
- const relatedEntityName = context.aliases.get(endpoint.service);
605
- const relatedEntity = !!relatedEntityName && entities.get(relatedEntityName);
606
- if (!relatedEntity) throw Error(`Related entity schema for service ${endpoint.service} not found`);
607
- const parametersTypeName = `${functionTypeName}_Parameters`;
608
- const parametersType = createObjectType({ params: convertToTypeScriptType(resolveParameters(operationObject.parameters, context.parameters)) });
609
- const parametersTypeSource = generateInterfaceFromObject(parametersTypeName, parametersType, "propagate");
610
- const filterTypeName = `${functionTypeName}_Filter`;
611
- const filterTypeSource = generateInterfaceType(filterTypeName, [], [`${relatedEntity.filterInterfaceName}`]);
612
- const functionTypeSource = generateArrowFunctionType({
613
- type: functionTypeName,
614
- params: [`query${parametersType.isFullyOptional() ? "?" : ""}: CountQuery<${filterTypeName}>${operationObject.parameters?.length ? " & " + parametersTypeName : ""}`, "requestOptions?: RequestOptions"],
615
- returns: `${resolveResponseType(options.target)}<number>`
616
- });
617
- const functionSource = generateArrowFunction({
618
- name: functionName,
619
- signature: functionTypeName,
620
- returns: `_${functionName}(cfg, ${generateString(endpoint.path)}, query, requestOptions)`,
621
- params: ["query", "requestOptions?: RequestOptions"]
622
- });
623
- return {
624
- name: functionName,
625
- type: {
626
- name: functionTypeName,
627
- source: functionTypeSource
628
- },
629
- func: {
630
- name: functionName,
631
- source: functionSource
632
- },
633
- interfaces: [...operationObject.parameters?.length ? [{
634
- name: parametersTypeName,
635
- source: parametersTypeSource
636
- }] : [], {
637
- name: filterTypeName,
638
- source: filterTypeSource
639
- }]
640
- };
641
- };
642
- //#endregion
643
- //#region src/generator/04-services/utils/generateContentType.ts
644
- const generateContentType = (body, fallback = "unknown") => {
645
- if (!body?.content) return createRawType(fallback);
646
- const types = [];
647
- for (const { schema } of Object.values(body.content)) if (schema) types.push(convertToTypeScriptType(schema));
648
- return (types.length > 1 ? createTupleType(types) : types[0]) ?? createRawType(fallback);
649
- };
650
- //#endregion
651
- //#region src/generator/04-services/utils/generateRequestBodyType.ts
663
+ const functionName = 'count';
664
+ const functionTypeName = `${pascalCase(endpoint.service)}Service_${pascalCase(functionName)}`;
665
+ const relatedEntityName = context.aliases.get(endpoint.service);
666
+ const relatedEntity = !!relatedEntityName && entities.get(relatedEntityName);
667
+ if (!relatedEntity) {
668
+ throw Error(`Related entity schema for service ${endpoint.service} not found`);
669
+ }
670
+ const parametersTypeName = `${functionTypeName}_Parameters`;
671
+ const parametersType = createObjectType({
672
+ params: convertToTypeScriptType(resolveParameters(operationObject.parameters, context.parameters))
673
+ });
674
+ const parametersTypeSource = generateInterfaceFromObject(parametersTypeName, parametersType, 'propagate');
675
+ const filterTypeName = `${functionTypeName}_Filter`;
676
+ const filterTypeSource = generateInterfaceType(filterTypeName, [], [`${relatedEntity.filterInterfaceName}`]);
677
+ const functionTypeSource = generateArrowFunctionType({
678
+ type: functionTypeName,
679
+ params: [
680
+ `query${parametersType.isFullyOptional() ? '?' : ''}: CountQuery<${filterTypeName}>${operationObject.parameters?.length ? ' & ' + parametersTypeName : ''}`,
681
+ 'requestOptions?: RequestOptions'
682
+ ],
683
+ returns: `${resolveResponseType(options.target)}<number>`
684
+ });
685
+ const functionSource = generateArrowFunction({
686
+ name: functionName,
687
+ signature: functionTypeName,
688
+ returns: `_${functionName}(cfg, ${generateString(endpoint.path)}, query, requestOptions)`,
689
+ params: ['query', 'requestOptions?: RequestOptions']
690
+ });
691
+ return {
692
+ name: functionName,
693
+ type: { name: functionTypeName, source: functionTypeSource },
694
+ func: { name: functionName, source: functionSource },
695
+ interfaces: [
696
+ ...(operationObject.parameters?.length ? [{ name: parametersTypeName, source: parametersTypeSource }] : []),
697
+ { name: filterTypeName, source: filterTypeSource }
698
+ ]
699
+ };
700
+ };
701
+
702
+ const generateContentType = (body, fallback = 'unknown') => {
703
+ if (!body?.content)
704
+ return createRawType(fallback);
705
+ const types = [];
706
+ for (const { schema } of Object.values(body.content)) {
707
+ if (schema) {
708
+ types.push(convertToTypeScriptType(schema));
709
+ }
710
+ }
711
+ return (types.length > 1 ? createTupleType(types) : types[0]) ?? createRawType(fallback);
712
+ };
713
+
652
714
  const generateRequestBodyType = ({ requestBody }, requestBodies) => {
653
- return generateContentType(requestBody && isReferenceObject(requestBody) ? requestBodies.get(getRefName(requestBody)) : requestBody);
715
+ const requestBodyObject = requestBody && isReferenceObject(requestBody) ? requestBodies.get(getRefName(requestBody)) : requestBody;
716
+ return generateContentType(requestBodyObject);
654
717
  };
655
- //#endregion
656
- //#region src/generator/04-services/utils/resolveResponsesObject.ts
657
- const resolveResponsesObject = (responses) => Object.entries(responses).find(([statusCode]) => statusCode.startsWith("2"))?.[1];
658
- //#endregion
659
- //#region src/generator/04-services/utils/generateResponseType.ts
718
+
719
+ const resolveResponsesObject = (responses) => Object.entries(responses).find(([statusCode]) => statusCode.startsWith('2'))?.[1];
720
+
660
721
  const generateResponseType = (operationObject, responses) => {
661
- const response = resolveResponsesObject(operationObject.responses);
662
- return generateContentType(response && isReferenceObject(response) ? responses.get(getRefName(response)) : response, "void");
722
+ const response = resolveResponsesObject(operationObject.responses);
723
+ const responseObject = response && isReferenceObject(response) ? responses.get(getRefName(response)) : response;
724
+ return generateContentType(responseObject, 'void');
663
725
  };
664
- //#endregion
665
- //#region src/generator/04-services/endpoints/create.ts
726
+
666
727
  const generateCreateEndpoint = ({ endpoint, operationObject, context, options }) => {
667
- const functionName = "create";
668
- const functionTypeName = `${pascalCase(endpoint.service)}Service_${pascalCase(functionName)}`;
669
- const functionTypeSource = generateArrowFunctionType({
670
- type: functionTypeName,
671
- params: [`data: DeepPartial<${generateRequestBodyType(operationObject, context.requestBodies).toString()}>`, "requestOptions?: RequestOptions"],
672
- returns: `${resolveResponseType(options.target)}<${generateResponseType(operationObject, context.responses).toString()}>`
673
- });
674
- const functionSource = generateArrowFunction({
675
- name: functionName,
676
- signature: functionTypeName,
677
- returns: `_${functionName}(cfg, ${generateString(endpoint.path)}, data, requestOptions)`,
678
- params: ["data", "requestOptions?: RequestOptions"]
679
- });
680
- return {
681
- name: functionName,
682
- type: {
683
- name: functionTypeName,
684
- source: functionTypeSource
685
- },
686
- func: {
687
- name: functionName,
688
- source: functionSource
689
- }
690
- };
691
- };
692
- //#endregion
693
- //#region src/generator/04-services/utils/generateGenericFunctionName.ts
694
- const generateGenericFunctionName = (path, suffix = "", prefix = "") => {
695
- return camelCase(`${prefix}_` + path.replace(/.*\//, "").replace(/\W+/, "_").replace(/[_]+/, "_") + `_${suffix}`);
696
- };
697
- //#endregion
698
- //#region src/generator/04-services/utils/insertPathPlaceholder.ts
728
+ const functionName = 'create';
729
+ const functionTypeName = `${pascalCase(endpoint.service)}Service_${pascalCase(functionName)}`;
730
+ const functionTypeSource = generateArrowFunctionType({
731
+ type: functionTypeName,
732
+ params: [
733
+ `data: DeepPartial<${generateRequestBodyType(operationObject, context.requestBodies).toString()}>`,
734
+ 'requestOptions?: RequestOptions'
735
+ ],
736
+ returns: `${resolveResponseType(options.target)}<${generateResponseType(operationObject, context.responses).toString()}>`
737
+ });
738
+ const functionSource = generateArrowFunction({
739
+ name: functionName,
740
+ signature: functionTypeName,
741
+ returns: `_${functionName}(cfg, ${generateString(endpoint.path)}, data, requestOptions)`,
742
+ params: ['data', 'requestOptions?: RequestOptions']
743
+ });
744
+ return {
745
+ name: functionName,
746
+ type: { name: functionTypeName, source: functionTypeSource },
747
+ func: { name: functionName, source: functionSource }
748
+ };
749
+ };
750
+
751
+ const generateGenericFunctionName = (path, suffix = '', prefix = '') => {
752
+ return camelCase(`${prefix}_` + path.replace(/.*\//, '').replace(/\W+/, '_').replace(/[_]+/, '_') + `_${suffix}`);
753
+ };
754
+
699
755
  const insertPathPlaceholder = (path, record) => {
700
- return path.replace(/{(\w+)}/g, (_, name) => record[name]);
756
+ return path.replace(/{(\w+)}/g, (_, name) => record[name]);
701
757
  };
702
- //#endregion
703
- //#region src/generator/04-services/endpoints/generic.ts
758
+
704
759
  const wrapBody = (type, target) => {
705
- return type.toString() === "binary" ? createRawType(isNodeTarget(target) ? "BodyInit" : "Blob") : type;
760
+ return type.toString() === 'binary' ? createRawType(isNodeTarget(target) ? 'BodyInit' : 'Blob') : type; // node-fetch returns a Blob as well
706
761
  };
707
762
  const generateGenericEndpoint = (suffix) => ({ method, endpoint, operationObject, context, options }) => {
708
- const functionName = generateGenericFunctionName(endpoint.path, suffix, method);
709
- const functionTypeName = `${pascalCase(endpoint.service)}Service_${pascalCase(functionName)}`;
710
- const entityQuery = `${functionTypeName}_Query`;
711
- const hasId = endpoint.path.includes("{id}");
712
- const params = createObjectType({
713
- params: operationObject.parameters && convertToTypeScriptType(resolveParameters(operationObject.parameters, context.parameters)),
714
- body: method === "get" ? void 0 : wrapBody(generateRequestBodyType(operationObject, context.requestBodies), options.target)
715
- });
716
- const responseBody = generateResponseType(operationObject, context.responses);
717
- const functionTypeSource = generateArrowFunctionType({
718
- type: functionTypeName,
719
- params: [
720
- ...hasId ? ["id: string"] : [],
721
- `query${params.isFullyOptional() ? "?" : ""}: ${entityQuery}`,
722
- "requestOptions?: RequestOptions"
723
- ],
724
- returns: `${resolveResponseType(options.target)}<${wrapBody(responseBody, options.target).toString("force")}>`
725
- });
726
- const functionSource = generateArrowFunction({
727
- name: functionName,
728
- signature: functionTypeName,
729
- params: hasId ? [
730
- "id",
731
- "query",
732
- "requestOptions?: RequestOptions"
733
- ] : ["query", "requestOptions?: RequestOptions"],
734
- returns: `_generic(cfg, ${generateString(method.toUpperCase())}, \`${insertPathPlaceholder(endpoint.path, { id: "${id}" })}\`, query, ${String(responseBody.toString() === "binary")}, requestOptions)`
735
- });
736
- return {
737
- name: functionName,
738
- type: {
739
- name: functionTypeName,
740
- source: functionTypeSource
741
- },
742
- func: {
743
- name: functionName,
744
- source: functionSource
745
- },
746
- interfaces: [{
747
- name: entityQuery,
748
- source: generateInterfaceFromObject(entityQuery, params, "propagate")
749
- }]
750
- };
751
- };
752
- //#endregion
753
- //#region src/generator/04-services/endpoints/remove.ts
763
+ const functionName = generateGenericFunctionName(endpoint.path, suffix, method);
764
+ const functionTypeName = `${pascalCase(endpoint.service)}Service_${pascalCase(functionName)}`;
765
+ const entityQuery = `${functionTypeName}_Query`;
766
+ const hasId = endpoint.path.includes('{id}');
767
+ const params = createObjectType({
768
+ params: operationObject.parameters &&
769
+ convertToTypeScriptType(resolveParameters(operationObject.parameters, context.parameters)),
770
+ body: method === 'get'
771
+ ? undefined
772
+ : wrapBody(generateRequestBodyType(operationObject, context.requestBodies), options.target)
773
+ });
774
+ const responseBody = generateResponseType(operationObject, context.responses);
775
+ const functionTypeSource = generateArrowFunctionType({
776
+ type: functionTypeName,
777
+ params: [
778
+ ...(hasId ? ['id: string'] : []),
779
+ `query${params.isFullyOptional() ? '?' : ''}: ${entityQuery}`,
780
+ 'requestOptions?: RequestOptions'
781
+ ],
782
+ returns: `${resolveResponseType(options.target)}<${wrapBody(responseBody, options.target).toString('force')}>`
783
+ });
784
+ const functionSource = generateArrowFunction({
785
+ name: functionName,
786
+ signature: functionTypeName,
787
+ params: hasId ? ['id', 'query', 'requestOptions?: RequestOptions'] : ['query', 'requestOptions?: RequestOptions'],
788
+ returns: `_generic(cfg, ${generateString(method.toUpperCase())}, \`${insertPathPlaceholder(endpoint.path, { id: '${id}' })}\`, query, ${String(responseBody.toString() === 'binary')}, requestOptions)`
789
+ });
790
+ return {
791
+ name: functionName,
792
+ type: { name: functionTypeName, source: functionTypeSource },
793
+ func: { name: functionName, source: functionSource },
794
+ interfaces: [
795
+ {
796
+ name: entityQuery,
797
+ source: generateInterfaceFromObject(entityQuery, params, 'propagate')
798
+ }
799
+ ]
800
+ };
801
+ };
802
+
754
803
  const generateRemoveEndpoint = ({ endpoint, options }) => {
755
- const functionName = "remove";
756
- const functionTypeName = `${pascalCase(endpoint.service)}Service_${pascalCase(functionName)}`;
757
- const functionTypeSource = generateArrowFunctionType({
758
- type: functionTypeName,
759
- params: [
760
- "id: string",
761
- "options?: RemoveQuery",
762
- "requestOptions?: RequestOptions"
763
- ],
764
- returns: `${resolveResponseType(options.target)}<void>`
765
- });
766
- const functionSource = generateArrowFunction({
767
- name: functionName,
768
- signature: functionTypeName,
769
- returns: `_${functionName}(cfg, \`${insertPathPlaceholder(endpoint.path, { id: "${id}" })}\`, options, requestOptions)`,
770
- params: [
771
- "id",
772
- "options?: RemoveQuery",
773
- "requestOptions?: RequestOptions"
774
- ]
775
- });
776
- return {
777
- name: functionName,
778
- type: {
779
- name: functionTypeName,
780
- source: functionTypeSource
781
- },
782
- func: {
783
- name: functionName,
784
- source: functionSource
785
- }
786
- };
787
- };
788
- //#endregion
789
- //#region src/generator/04-services/endpoints/some.ts
804
+ const functionName = 'remove';
805
+ const functionTypeName = `${pascalCase(endpoint.service)}Service_${pascalCase(functionName)}`;
806
+ const functionTypeSource = generateArrowFunctionType({
807
+ type: functionTypeName,
808
+ params: ['id: string', 'options?: RemoveQuery', 'requestOptions?: RequestOptions'],
809
+ returns: `${resolveResponseType(options.target)}<void>`
810
+ });
811
+ const functionSource = generateArrowFunction({
812
+ name: functionName,
813
+ signature: functionTypeName,
814
+ returns: `_${functionName}(cfg, \`${insertPathPlaceholder(endpoint.path, { id: '${id}' })}\`, options, requestOptions)`,
815
+ params: ['id', 'options?: RemoveQuery', 'requestOptions?: RequestOptions']
816
+ });
817
+ return {
818
+ name: functionName,
819
+ type: { name: functionTypeName, source: functionTypeSource },
820
+ func: { name: functionName, source: functionSource }
821
+ };
822
+ };
823
+
824
+ const generateTupleArray = (values) => `(${concat(values.map(generateString), ' | ')})[]`;
825
+
790
826
  const excludedParameters = [
791
- "page",
792
- "pageSize",
793
- "sort",
794
- "serializeNulls",
795
- "properties",
796
- "includeReferencedEntities",
797
- "additionalProperties"
827
+ 'page',
828
+ 'pageSize',
829
+ 'sort',
830
+ 'serializeNulls',
831
+ 'properties',
832
+ 'includeReferencedEntities',
833
+ 'additionalProperties'
798
834
  ];
799
- const resolveAdditionalPropertiesSchema = ({ responses }) => {
800
- const body = resolveResponsesObject(responses);
801
- if (isResponseObject(body)) {
802
- const schema = body?.content?.["application/json"]?.schema;
803
- if (isObjectSchemaObject(schema)) {
804
- const obj = schema?.properties?.additionalProperties;
805
- if (isObjectSchemaObject(obj)) return obj;
806
- }
807
- }
835
+ const resolveAdditionalPropertiesSchema = ({ responses }, contextResponses) => {
836
+ const response = resolveResponsesObject(responses);
837
+ const body = response && isReferenceObject(response) ? contextResponses.get(getRefName(response)) : response;
838
+ if (isResponseObject(body)) {
839
+ const schema = body?.content?.['application/json']?.schema;
840
+ if (isObjectSchemaObject(schema)) {
841
+ const obj = schema?.properties?.additionalProperties;
842
+ if (isObjectSchemaObject(obj)) {
843
+ return obj;
844
+ }
845
+ }
846
+ }
847
+ return undefined;
808
848
  };
809
849
  const resolveReferences = (entity, entities) => {
810
- const references = [];
811
- const generatedEntity = entities.get(entity);
812
- if (generatedEntity) {
813
- for (const [property, propertyMetaData] of generatedEntity.properties) if (propertyMetaData.service) references.push({
814
- name: property,
815
- type: generateString(propertyMetaData.service),
816
- required: true
817
- });
818
- if (generatedEntity.parentName) references.push(...resolveReferences(generatedEntity.parentName, entities));
819
- }
820
- return references;
850
+ const references = [];
851
+ const generatedEntity = entities.get(entity);
852
+ if (generatedEntity) {
853
+ for (const [property, propertyMetaData] of generatedEntity.properties) {
854
+ if (propertyMetaData.service) {
855
+ references.push({
856
+ name: property,
857
+ type: generateString(propertyMetaData.service),
858
+ required: true
859
+ });
860
+ }
861
+ }
862
+ if (generatedEntity.parentName) {
863
+ references.push(...resolveReferences(generatedEntity.parentName, entities));
864
+ }
865
+ }
866
+ return references;
821
867
  };
822
868
  const resolveReferencedEntities = (entity, entities) => {
823
- const referencedEntities = [];
824
- const generatedEntity = entities.get(entity);
825
- if (generatedEntity) {
826
- for (const [, propertyMetaData] of generatedEntity.properties) if (propertyMetaData.service && propertyMetaData.entity) {
827
- const referencedEntity = entities.get(propertyMetaData.entity);
828
- if (referencedEntity) referencedEntities.push({
829
- name: propertyMetaData.service,
830
- type: `${referencedEntity.interfaceName}[]`,
831
- required: true
832
- });
833
- }
834
- if (generatedEntity.parentName) referencedEntities.push(...resolveReferencedEntities(generatedEntity.parentName, entities));
835
- }
836
- return referencedEntities;
869
+ const referencedEntities = [];
870
+ const generatedEntity = entities.get(entity);
871
+ if (generatedEntity) {
872
+ for (const [, propertyMetaData] of generatedEntity.properties) {
873
+ if (propertyMetaData.service && propertyMetaData.entity) {
874
+ const referencedEntity = entities.get(propertyMetaData.entity);
875
+ if (referencedEntity)
876
+ referencedEntities.push({
877
+ name: propertyMetaData.service,
878
+ type: `${referencedEntity.interfaceName}[]`,
879
+ required: true
880
+ });
881
+ }
882
+ }
883
+ if (generatedEntity.parentName) {
884
+ referencedEntities.push(...resolveReferencedEntities(generatedEntity.parentName, entities));
885
+ }
886
+ }
887
+ return referencedEntities;
837
888
  };
838
889
  const generateSomeEndpoint = ({ endpoint, operationObject, entities, context, options }) => {
839
- const functionName = "some";
840
- const functionTypeName = `${pascalCase(endpoint.service)}Service_${pascalCase(functionName)}`;
841
- const relatedEntityName = context.aliases.get(endpoint.service);
842
- const relatedEntity = !!relatedEntityName && entities.get(relatedEntityName);
843
- if (!relatedEntity) throw Error(`Related entity schema for service ${endpoint.service} not found`);
844
- const parametersTypeName = `${functionTypeName}_Parameters`;
845
- const parameters = operationObject.parameters?.filter((v) => isParameterObject(v) ? !excludedParameters.includes(v.name) : false);
846
- const parametersType = createObjectType({ params: parameters && convertToTypeScriptType(resolveParameters(parameters, context.parameters)) });
847
- const parametersTypeSource = generateInterfaceFromObject(parametersTypeName, parametersType, "propagate");
848
- const filterTypeName = `${functionTypeName}_Filter`;
849
- const filterTypeSource = generateInterfaceType(filterTypeName, [], [`${relatedEntity.filterInterfaceName}`]);
850
- const referencesTypeName = `${functionTypeName}_References`;
851
- const referencesTypeSource = generateInterfaceType(referencesTypeName, resolveReferences(endpoint.service, entities));
852
- const additionalPropertyTypeName = `${functionTypeName}_AdditionalProperty`;
853
- const additionalPropertyTypeSource = generateType(additionalPropertyTypeName, "string");
854
- const queryTypeName = `${functionTypeName}_Query`;
855
- const queryTypeSource = generateType(queryTypeName, `SomeQuery<${relatedEntity.interfaceName}, ${filterTypeName}, ${referencesTypeName}, ${additionalPropertyTypeName}> & ${parametersTypeName}`);
856
- const referencedEntitiesTypeName = `${functionTypeName}_ReferencedEntities`;
857
- const referencedEntitiesTypeSource = generateInterfaceType(referencedEntitiesTypeName, resolveReferencedEntities(endpoint.service, entities));
858
- const additionalPropertiesTypeName = `${functionTypeName}_AdditionalProperties`;
859
- const additionalPropertiesSchema = resolveAdditionalPropertiesSchema(operationObject);
860
- const additionalPropertiesTypeSource = generateType(additionalPropertiesTypeName, additionalPropertiesSchema ? convertToTypeScriptType(additionalPropertiesSchema).toString() : "{}");
861
- const functionTypeSource = generateArrowFunctionType({
862
- type: functionTypeName,
863
- params: [`query${parametersType.isFullyOptional() ? "?" : ""}: ${queryTypeName}, requestOptions?: RequestOptions`],
864
- returns: `${resolveResponseType(options.target)}<SomeQueryReturn<${relatedEntity.interfaceName}, ${referencedEntitiesTypeName}, ${additionalPropertiesTypeName}>>`
865
- });
866
- const functionSource = generateArrowFunction({
867
- name: functionName,
868
- signature: functionTypeName,
869
- returns: `_${functionName}(cfg, ${generateString(endpoint.path)}, query, requestOptions)`,
870
- params: ["query", "requestOptions?: RequestOptions"]
871
- });
872
- return {
873
- name: functionName,
874
- type: {
875
- name: functionTypeName,
876
- source: functionTypeSource
877
- },
878
- func: {
879
- name: functionName,
880
- source: functionSource
881
- },
882
- interfaces: [
883
- {
884
- name: parametersTypeName,
885
- source: parametersTypeSource
886
- },
887
- {
888
- name: filterTypeName,
889
- source: filterTypeSource
890
- },
891
- {
892
- name: referencesTypeName,
893
- source: referencesTypeSource
894
- },
895
- {
896
- name: additionalPropertyTypeName,
897
- source: additionalPropertyTypeSource
898
- },
899
- {
900
- name: queryTypeName,
901
- source: queryTypeSource
902
- },
903
- {
904
- name: referencedEntitiesTypeName,
905
- source: referencedEntitiesTypeSource
906
- },
907
- {
908
- name: additionalPropertiesTypeName,
909
- source: additionalPropertiesTypeSource
910
- }
911
- ]
912
- };
913
- };
914
- //#endregion
915
- //#region src/generator/04-services/endpoints/unique.ts
890
+ const functionName = 'some';
891
+ const functionTypeName = `${pascalCase(endpoint.service)}Service_${pascalCase(functionName)}`;
892
+ const relatedEntityName = context.aliases.get(endpoint.service);
893
+ const relatedEntity = !!relatedEntityName && entities.get(relatedEntityName);
894
+ if (!relatedEntity) {
895
+ throw Error(`Related entity schema for service ${endpoint.service} not found`);
896
+ }
897
+ const parametersTypeName = `${functionTypeName}_Parameters`;
898
+ const parameters = operationObject.parameters?.filter((v) => isParameterObject(v) ? !excludedParameters.includes(v.name) : false);
899
+ const parametersType = createObjectType({
900
+ params: parameters && convertToTypeScriptType(resolveParameters(parameters, context.parameters))
901
+ });
902
+ const parametersTypeSource = generateInterfaceFromObject(parametersTypeName, parametersType, 'propagate');
903
+ const filterTypeName = `${functionTypeName}_Filter`;
904
+ const filterTypeSource = generateInterfaceType(filterTypeName, [], [`${relatedEntity.filterInterfaceName}`]);
905
+ const referencesTypeName = `${functionTypeName}_References`;
906
+ const referencesTypeSource = generateInterfaceType(referencesTypeName, resolveReferences(endpoint.service, entities));
907
+ const additionalPropertiesSchema = resolveAdditionalPropertiesSchema(operationObject, context.responses);
908
+ const additionalPropertyTypeName = `${functionTypeName}_AdditionalPropertyNames`;
909
+ const additionalPropertyTypeSource = generateType(additionalPropertyTypeName, additionalPropertiesSchema ? generateTupleArray(Object.keys(additionalPropertiesSchema?.properties)) : '[]');
910
+ const queryTypeName = `${functionTypeName}_Query`;
911
+ const queryTypeSource = generateType(queryTypeName, `SomeQuery<${relatedEntity.interfaceName}, ${filterTypeName}, ${referencesTypeName}, ${additionalPropertyTypeName}> & ${parametersTypeName}`);
912
+ const referencedEntitiesTypeName = `${functionTypeName}_ReferencedEntities`;
913
+ const referencedEntitiesTypeSource = generateInterfaceType(referencedEntitiesTypeName, resolveReferencedEntities(endpoint.service, entities));
914
+ const additionalPropertiesTypeName = `${functionTypeName}_AdditionalProperties`;
915
+ const additionalPropertiesTypeSource = generateType(additionalPropertiesTypeName, additionalPropertiesSchema ? convertToTypeScriptType(additionalPropertiesSchema).toString() : '{}');
916
+ const functionTypeSource = generateArrowFunctionType({
917
+ type: functionTypeName,
918
+ params: [`query${parametersType.isFullyOptional() ? '?' : ''}: ${queryTypeName}, requestOptions?: RequestOptions`],
919
+ returns: `${resolveResponseType(options.target)}<SomeQueryReturn<${relatedEntity.interfaceName}, ${referencedEntitiesTypeName}, ${additionalPropertiesTypeName}>>`
920
+ });
921
+ const functionSource = generateArrowFunction({
922
+ name: functionName,
923
+ signature: functionTypeName,
924
+ returns: `_${functionName}(cfg, ${generateString(endpoint.path)}, query, requestOptions)`,
925
+ params: ['query', 'requestOptions?: RequestOptions']
926
+ });
927
+ return {
928
+ name: functionName,
929
+ type: { name: functionTypeName, source: functionTypeSource },
930
+ func: { name: functionName, source: functionSource },
931
+ interfaces: [
932
+ { name: parametersTypeName, source: parametersTypeSource },
933
+ { name: filterTypeName, source: filterTypeSource },
934
+ { name: referencesTypeName, source: referencesTypeSource },
935
+ { name: additionalPropertyTypeName, source: additionalPropertyTypeSource },
936
+ { name: queryTypeName, source: queryTypeSource },
937
+ { name: referencedEntitiesTypeName, source: referencedEntitiesTypeSource },
938
+ { name: additionalPropertiesTypeName, source: additionalPropertiesTypeSource }
939
+ ]
940
+ };
941
+ };
942
+
916
943
  const generateUniqueEndpoint = ({ operationObject, endpoint, context, options }) => {
917
- const functionName = "unique";
918
- const functionTypeName = `${pascalCase(endpoint.service)}Service_${pascalCase(functionName)}`;
919
- const functionTypeSource = generateArrowFunctionType({
920
- type: functionTypeName,
921
- params: [
922
- "id: string",
923
- "query?: Q",
924
- "requestOptions?: RequestOptions"
925
- ],
926
- generics: ["Q extends UniqueQuery"],
927
- returns: `${resolveResponseType(options.target)}<${generateResponseType(operationObject, context.responses).toString()}>`
928
- });
929
- const functionSource = generateArrowFunction({
930
- name: functionName,
931
- signature: functionTypeName,
932
- params: [
933
- "id",
934
- "query",
935
- "requestOptions?: RequestOptions"
936
- ],
937
- returns: `_${functionName}(cfg, \`${insertPathPlaceholder(endpoint.path, { id: "${id}" })}\`, query, requestOptions)`
938
- });
939
- return {
940
- name: functionName,
941
- type: {
942
- name: functionTypeName,
943
- source: functionTypeSource
944
- },
945
- func: {
946
- name: functionName,
947
- source: functionSource
948
- }
949
- };
950
- };
951
- //#endregion
952
- //#region src/generator/04-services/endpoints/update.ts
944
+ const functionName = 'unique';
945
+ const functionTypeName = `${pascalCase(endpoint.service)}Service_${pascalCase(functionName)}`;
946
+ const functionTypeSource = generateArrowFunctionType({
947
+ type: functionTypeName,
948
+ params: ['id: string', 'query?: Q', 'requestOptions?: RequestOptions'],
949
+ generics: ['Q extends UniqueQuery'],
950
+ returns: `${resolveResponseType(options.target)}<${generateResponseType(operationObject, context.responses).toString()}>`
951
+ });
952
+ const functionSource = generateArrowFunction({
953
+ name: functionName,
954
+ signature: functionTypeName,
955
+ params: ['id', 'query', 'requestOptions?: RequestOptions'],
956
+ returns: `_${functionName}(cfg, \`${insertPathPlaceholder(endpoint.path, { id: '${id}' })}\`, query, requestOptions)`
957
+ });
958
+ return {
959
+ name: functionName,
960
+ type: { name: functionTypeName, source: functionTypeSource },
961
+ func: { name: functionName, source: functionSource }
962
+ };
963
+ };
964
+
953
965
  const generateUpdateEndpoint = ({ endpoint, operationObject, context, options }) => {
954
- const functionName = "update";
955
- const functionTypeName = `${pascalCase(endpoint.service)}Service_${pascalCase(functionName)}`;
956
- const functionTypeSource = generateArrowFunctionType({
957
- type: functionTypeName,
958
- params: [
959
- "id: string",
960
- `data: DeepPartial<${generateRequestBodyType(operationObject, context.requestBodies).toString()}>`,
961
- "options?: UpdateQuery",
962
- "requestOptions?: RequestOptions"
963
- ],
964
- returns: `${resolveResponseType(options.target)}<${generateResponseType(operationObject, context.responses).toString()}>`
965
- });
966
- const functionSource = generateArrowFunction({
967
- name: functionName,
968
- signature: functionTypeName,
969
- returns: `_${functionName}(cfg, \`${insertPathPlaceholder(endpoint.path, { id: "${id}" })}\`, data, options, requestOptions)`,
970
- params: [
971
- "id",
972
- "data",
973
- "options",
974
- "requestOptions?: RequestOptions"
975
- ]
976
- });
977
- return {
978
- name: functionName,
979
- type: {
980
- name: functionTypeName,
981
- source: functionTypeSource
982
- },
983
- func: {
984
- name: functionName,
985
- source: functionSource
986
- }
987
- };
988
- };
989
- //#endregion
990
- //#region src/generator/04-services/index.ts
966
+ const functionName = 'update';
967
+ const functionTypeName = `${pascalCase(endpoint.service)}Service_${pascalCase(functionName)}`;
968
+ const functionTypeSource = generateArrowFunctionType({
969
+ type: functionTypeName,
970
+ params: [
971
+ 'id: string',
972
+ `data: DeepPartial<${generateRequestBodyType(operationObject, context.requestBodies).toString()}>`,
973
+ 'options?: UpdateQuery',
974
+ 'requestOptions?: RequestOptions'
975
+ ],
976
+ returns: `${resolveResponseType(options.target)}<${generateResponseType(operationObject, context.responses).toString()}>`
977
+ });
978
+ const functionSource = generateArrowFunction({
979
+ name: functionName,
980
+ signature: functionTypeName,
981
+ returns: `_${functionName}(cfg, \`${insertPathPlaceholder(endpoint.path, { id: '${id}' })}\`, data, options, requestOptions)`,
982
+ params: ['id', 'data', 'options', 'requestOptions?: RequestOptions']
983
+ });
984
+ return {
985
+ name: functionName,
986
+ type: { name: functionTypeName, source: functionTypeSource },
987
+ func: { name: functionName, source: functionSource }
988
+ };
989
+ };
990
+
991
991
  const generators = {
992
- [WeclappEndpointType.ROOT]: {
993
- [OpenAPIV3.HttpMethods.GET]: generateSomeEndpoint,
994
- [OpenAPIV3.HttpMethods.POST]: generateCreateEndpoint
995
- },
996
- [WeclappEndpointType.COUNT]: { [OpenAPIV3.HttpMethods.GET]: generateCountEndpoint },
997
- [WeclappEndpointType.ENTITY]: {
998
- [OpenAPIV3.HttpMethods.GET]: generateUniqueEndpoint,
999
- [OpenAPIV3.HttpMethods.PUT]: generateUpdateEndpoint,
1000
- [OpenAPIV3.HttpMethods.DELETE]: generateRemoveEndpoint
1001
- },
1002
- [WeclappEndpointType.GENERIC_ENTITY]: {
1003
- [OpenAPIV3.HttpMethods.GET]: generateGenericEndpoint("ById"),
1004
- [OpenAPIV3.HttpMethods.POST]: generateGenericEndpoint("ById")
1005
- },
1006
- [WeclappEndpointType.GENERIC_ROOT]: {
1007
- [OpenAPIV3.HttpMethods.GET]: generateGenericEndpoint(),
1008
- [OpenAPIV3.HttpMethods.POST]: generateGenericEndpoint()
1009
- }
992
+ /* /article */
993
+ [WeclappEndpointType.ROOT]: {
994
+ [OpenAPIV3.HttpMethods.GET]: generateSomeEndpoint,
995
+ [OpenAPIV3.HttpMethods.POST]: generateCreateEndpoint
996
+ },
997
+ /* /article/count */
998
+ [WeclappEndpointType.COUNT]: {
999
+ [OpenAPIV3.HttpMethods.GET]: generateCountEndpoint
1000
+ },
1001
+ /* /article/:id */
1002
+ [WeclappEndpointType.ENTITY]: {
1003
+ [OpenAPIV3.HttpMethods.GET]: generateUniqueEndpoint,
1004
+ [OpenAPIV3.HttpMethods.PUT]: generateUpdateEndpoint,
1005
+ [OpenAPIV3.HttpMethods.DELETE]: generateRemoveEndpoint
1006
+ },
1007
+ /* /article/:id/method */
1008
+ [WeclappEndpointType.GENERIC_ENTITY]: {
1009
+ [OpenAPIV3.HttpMethods.GET]: generateGenericEndpoint('ById'),
1010
+ [OpenAPIV3.HttpMethods.POST]: generateGenericEndpoint('ById')
1011
+ },
1012
+ /* /article/method */
1013
+ [WeclappEndpointType.GENERIC_ROOT]: {
1014
+ [OpenAPIV3.HttpMethods.GET]: generateGenericEndpoint(),
1015
+ [OpenAPIV3.HttpMethods.POST]: generateGenericEndpoint()
1016
+ }
1010
1017
  };
1011
1018
  const generateServices = (entities, context, options) => {
1012
- const services = /* @__PURE__ */ new Map();
1013
- for (const [serviceName, serviceEndpoints] of context.endpoints) {
1014
- const serviceFnName = camelCase(`${serviceName}Service`);
1015
- const serviceTypeName = pascalCase(`${serviceName}Service`);
1016
- const functions = [];
1017
- for (const { path, endpoint } of serviceEndpoints) for (const method of [
1018
- OpenAPIV3.HttpMethods.GET,
1019
- OpenAPIV3.HttpMethods.POST,
1020
- OpenAPIV3.HttpMethods.PUT,
1021
- OpenAPIV3.HttpMethods.DELETE
1022
- ]) {
1023
- if (method === OpenAPIV3.HttpMethods.GET && endpoint.type === WeclappEndpointType.ENTITY && !options.generateUnique || method === OpenAPIV3.HttpMethods.POST && (endpoint.type === WeclappEndpointType.COUNT || endpoint.path.endsWith("query"))) continue;
1024
- const operationObject = path[method];
1025
- const generatorFn = generators[endpoint.type][method];
1026
- if (operationObject && generatorFn) {
1027
- if (!operationObject.deprecated || options.deprecated) functions.push({
1028
- ...generatorFn({
1029
- method,
1030
- endpoint,
1031
- operationObject,
1032
- entities,
1033
- context,
1034
- options
1035
- }),
1036
- path: operationObject
1037
- });
1038
- }
1039
- }
1040
- if (!functions.length) continue;
1041
- const serviceTypes = generateStatements(...functions.flatMap((v) => generateBlockComment(`${serviceTypeName} - ${pascalCase(v.name)}`, generateStatements(...[...v.interfaces?.map((v) => v.source) ?? [], v.type.source]))), generateBlockComment(`${serviceTypeName}`, generateInterface(serviceTypeName, [...functions.map((v) => ({
1042
- required: true,
1043
- comment: v.path.deprecated ? "@deprecated" : void 0,
1044
- name: v.func.name,
1045
- type: v.type.name
1046
- }))])));
1047
- const serviceFn = `export const ${serviceFnName} = (cfg?: ServiceConfig): ${serviceTypeName} => ${generateBlockStatements(...functions.map((v) => v.func.source), `return {${concat(functions.map((v) => v.func.name))}};`)};`;
1048
- const relatedEntityName = context.aliases.get(serviceName);
1049
- const relatedEntity = relatedEntityName ? entities.get(relatedEntityName) : void 0;
1050
- services.set(serviceName, {
1051
- name: serviceName,
1052
- serviceFnName,
1053
- functions,
1054
- source: generateStatements(serviceTypes, serviceFn),
1055
- deprecated: functions.every((v) => v.path.deprecated),
1056
- relatedEntity
1057
- });
1058
- }
1059
- return services;
1060
- };
1061
- //#endregion
1062
- //#region src/generator/05-maps/utils/generateCustomValueServices.ts
1019
+ const services = new Map();
1020
+ for (const [serviceName, serviceEndpoints] of context.endpoints) {
1021
+ const serviceFnName = camelCase(`${serviceName}Service`);
1022
+ const serviceTypeName = pascalCase(`${serviceName}Service`);
1023
+ const functions = [];
1024
+ for (const { path, endpoint } of serviceEndpoints) {
1025
+ for (const method of [
1026
+ OpenAPIV3.HttpMethods.GET,
1027
+ OpenAPIV3.HttpMethods.POST,
1028
+ OpenAPIV3.HttpMethods.PUT,
1029
+ OpenAPIV3.HttpMethods.DELETE
1030
+ ]) {
1031
+ if ((method === OpenAPIV3.HttpMethods.GET &&
1032
+ endpoint.type === WeclappEndpointType.ENTITY &&
1033
+ !options.generateUnique) ||
1034
+ (method === OpenAPIV3.HttpMethods.POST &&
1035
+ (endpoint.type === WeclappEndpointType.COUNT || endpoint.path.endsWith('query')))) {
1036
+ // Skip unique endpoints if generateUnique option is not set or if POST is used for filter queries
1037
+ continue;
1038
+ }
1039
+ const operationObject = path[method];
1040
+ const generatorFn = generators[endpoint.type][method];
1041
+ if (operationObject && generatorFn) {
1042
+ if (!operationObject.deprecated || options.deprecated) {
1043
+ functions.push({
1044
+ ...generatorFn({
1045
+ method,
1046
+ endpoint,
1047
+ operationObject,
1048
+ entities,
1049
+ context,
1050
+ options
1051
+ }),
1052
+ path: operationObject
1053
+ });
1054
+ }
1055
+ }
1056
+ }
1057
+ }
1058
+ if (!functions.length) {
1059
+ continue;
1060
+ }
1061
+ const serviceTypes = generateStatements(...functions.flatMap((v) => generateBlockComment(`${serviceTypeName} - ${pascalCase(v.name)}`, generateStatements(...[...(v.interfaces?.map((v) => v.source) ?? []), v.type.source]))), generateBlockComment(`${serviceTypeName}`, generateInterface(serviceTypeName, [
1062
+ ...functions.map((v) => ({
1063
+ required: true,
1064
+ comment: v.path.deprecated ? '@deprecated' : undefined,
1065
+ name: v.func.name,
1066
+ type: v.type.name
1067
+ }))
1068
+ ])));
1069
+ const serviceFn = `export const ${serviceFnName} = (cfg?: ServiceConfig): ${serviceTypeName} => ${generateBlockStatements(...functions.map((v) => v.func.source), `return {${concat(functions.map((v) => v.func.name))}};`)};`;
1070
+ const relatedEntityName = context.aliases.get(serviceName);
1071
+ const relatedEntity = relatedEntityName ? entities.get(relatedEntityName) : undefined;
1072
+ services.set(serviceName, {
1073
+ name: serviceName,
1074
+ serviceFnName,
1075
+ functions,
1076
+ source: generateStatements(serviceTypes, serviceFn),
1077
+ deprecated: functions.every((v) => v.path.deprecated),
1078
+ relatedEntity
1079
+ });
1080
+ }
1081
+ return services;
1082
+ };
1083
+
1063
1084
  const generateCustomValueServices = (services) => {
1064
- const customValueEntities = [];
1065
- for (const service of services) if (service.relatedEntity?.name === "customValue") customValueEntities.push(service.name);
1066
- return generateStatements(generateType("WCustomValueService", concat(generateStrings(customValueEntities), " | ")), `export const wCustomValueServiceNames: WCustomValueService[] = [${concat(generateStrings(customValueEntities))}];`, `export const isWCustomValueService = (service: string | undefined): service is WCustomValueService =>\n${indent("wCustomValueServiceNames.includes(service as WCustomValueService);")}`);
1067
- };
1068
- //#endregion
1069
- //#region src/ts/generateObject.ts
1085
+ const customValueEntities = [];
1086
+ for (const service of services) {
1087
+ const relatedEntity = service.relatedEntity;
1088
+ if (relatedEntity?.name === 'customValue') {
1089
+ customValueEntities.push(service.name);
1090
+ }
1091
+ }
1092
+ return generateStatements(generateType('WCustomValueService', concat(generateStrings(customValueEntities), ' | ')), `export const wCustomValueServiceNames: WCustomValueService[] = [${concat(generateStrings(customValueEntities))}];`, `export const isWCustomValueService = (service: string | undefined): service is WCustomValueService =>\n${indent('wCustomValueServiceNames.includes(service as WCustomValueService);')}`);
1093
+ };
1094
+
1070
1095
  const generateObject = (properties) => {
1071
- const body = [];
1072
- for (const { key, value, comment } of properties) {
1073
- if (value === void 0) continue;
1074
- if (Array.isArray(value)) {
1075
- const str = generateObject(value);
1076
- if (str.length > 2) body.push(`${comment ? generateInlineComment(comment) + "\n" : ""}${key}: ${str}`);
1077
- } else body.push(`${comment ? generateInlineComment(comment) + "\n" : ""}${key}: ${String(value)}`);
1078
- }
1079
- return body.length ? `{\n${indent(body.join(",\n"))}\n}` : `{}`;
1080
- };
1081
- //#endregion
1082
- //#region src/generator/05-maps/utils/generateEntityProperties.ts
1096
+ const body = [];
1097
+ for (const { key, value, comment } of properties) {
1098
+ if (value === undefined) {
1099
+ continue;
1100
+ }
1101
+ if (Array.isArray(value)) {
1102
+ const str = generateObject(value);
1103
+ if (str.length > 2) {
1104
+ body.push(`${comment ? generateInlineComment(comment) + '\n' : ''}${key}: ${str}`);
1105
+ }
1106
+ }
1107
+ else {
1108
+ body.push(`${comment ? generateInlineComment(comment) + '\n' : ''}${key}: ${String(value)}`);
1109
+ }
1110
+ }
1111
+ return body.length ? `{\n${indent(body.join(',\n'))}\n}` : `{}`;
1112
+ };
1113
+
1083
1114
  const resolveInheritedEntities = (root, entities) => {
1084
- const parent = root.parentName ? entities.get(root.parentName) : void 0;
1085
- return parent ? [parent, ...resolveInheritedEntities(parent, entities)] : [];
1086
- };
1087
- const generatePropertyDescriptors = (entity, entities, services, options) => [...resolveInheritedEntities(entity, entities).flatMap((v) => [...v.properties]), ...entity.properties].filter(([, meta]) => {
1088
- if (options.deprecated) return true;
1089
- const service = services.find((v) => v.name === meta.service);
1090
- return !meta.service || service && !service.deprecated;
1091
- }).map(([property, meta]) => ({
1092
- key: property,
1093
- value: Object.entries(meta).map(([key, value]) => ({
1094
- key,
1095
- value: value !== void 0 ? typeof value === "number" ? value : generateString(value) : void 0
1096
- }))
1115
+ const parent = root.parentName ? entities.get(root.parentName) : undefined;
1116
+ return parent ? [parent, ...resolveInheritedEntities(parent, entities)] : [];
1117
+ };
1118
+ const generatePropertyDescriptors = (entity, entities, services, options) => [...resolveInheritedEntities(entity, entities).flatMap((v) => [...v.properties]), ...entity.properties]
1119
+ .filter(([, meta]) => {
1120
+ // If we generate deprecated things we can skip the filtering
1121
+ if (options.deprecated) {
1122
+ return true;
1123
+ }
1124
+ // Check if corresponding service is deprecated and can be removed
1125
+ const service = services.find((v) => v.name === meta.service);
1126
+ return !meta.service || (service && !service.deprecated);
1127
+ })
1128
+ .map(([property, meta]) => ({
1129
+ key: property,
1130
+ value: Object.entries(meta).map(([key, value]) => ({
1131
+ key,
1132
+ value: value !== undefined ? (typeof value === 'number' ? value : generateString(value)) : undefined
1133
+ }))
1097
1134
  }));
1098
1135
  const generateEntityProperties = (entities, services, options) => {
1099
- const typeName = "WEntityProperties";
1100
- const propertyMap = [...entities.entries(), ...services.filter(({ relatedEntity }) => !!relatedEntity).filter(({ name }) => !entities.get(name)).map(({ name, relatedEntity }) => {
1101
- return [name, relatedEntity];
1102
- })].map(([entityName, entity]) => ({
1103
- key: entityName,
1104
- value: generatePropertyDescriptors(entity, entities, services, options)
1105
- }));
1106
- return generateStatements(`export type ${typeName} = Partial<Record<WEntity, Partial<Record<string, WEntityPropertyMeta>>>>;`, `export const wEntityProperties: ${typeName} = ${generateObject(propertyMap)};`);
1107
- };
1108
- //#endregion
1109
- //#region src/ts/generateArray.ts
1136
+ const typeName = 'WEntityProperties';
1137
+ const propertyMap = [
1138
+ ...entities.entries(),
1139
+ ...services
1140
+ .filter(({ relatedEntity }) => !!relatedEntity)
1141
+ .filter(({ name }) => !entities.get(name))
1142
+ .map(({ name, relatedEntity }) => {
1143
+ return [name, relatedEntity];
1144
+ })
1145
+ ].map(([entityName, entity]) => ({
1146
+ key: entityName,
1147
+ value: generatePropertyDescriptors(entity, entities, services, options)
1148
+ }));
1149
+ return generateStatements(`export type ${typeName} = Partial<Record<WEntity, Partial<Record<string, WEntityPropertyMeta>>>>;`, `export const wEntityProperties: ${typeName} = ${generateObject(propertyMap)};`);
1150
+ };
1151
+
1110
1152
  const generateArray = (values) => {
1111
- return `[${concat(values.map((v) => generateString(String(v))))}]`;
1153
+ return `[${concat(values.map((v) => generateString(String(v))))}]`;
1112
1154
  };
1113
- //#endregion
1114
- //#region src/generator/05-maps/utils/generateGroupedServices.ts
1155
+
1156
+ // Only functions matching this regex are included in the generation.
1115
1157
  const FILTER_REGEX = /^(some|count|create|remove|unique|update)$/;
1116
1158
  /**
1117
- * Generates for each function a map with the entity-name as key and service type as value.
1118
- * E.g. WServicesWith[Function] where [Function] may be something like "some" or "create".
1119
- *
1120
- * This function also generates an exported array with the names of each service for each name.
1121
- */
1159
+ * Generates for each function a map with the entity-name as key and service type as value.
1160
+ * E.g. WServicesWith[Function] where [Function] may be something like "some" or "create".
1161
+ *
1162
+ * This function also generates an exported array with the names of each service for each name.
1163
+ */
1122
1164
  const generateGroupedServices = (services) => {
1123
- const entityDescriptors = /* @__PURE__ */ new Map();
1124
- for (const service of services) for (const fn of service.functions) {
1125
- if (!FILTER_REGEX.test(fn.name)) continue;
1126
- entityDescriptors.set(fn.name, [...entityDescriptors.get(fn.name) ?? [], {
1127
- name: service.name,
1128
- required: true,
1129
- type: `${pascalCase(service.name)}Service_${pascalCase(fn.name)}`
1130
- }]);
1131
- }
1132
- const descriptors = [...entityDescriptors.entries()];
1133
- const typeGuards = [];
1134
- for (const [name] of descriptors) {
1135
- const constant = camelCase(`wServiceWith_${name}_Names`);
1136
- const service = pascalCase(`WServiceWith_${name}`);
1137
- const guard = `(service: string | undefined): service is ${service} =>\n${indent(`${constant}.includes(service as ${service});`)}`;
1138
- typeGuards.push(`export const is${service} = ${guard}`);
1139
- }
1140
- return generateStatements(...descriptors.map(([name, props]) => generateInterface(pascalCase(`WServicesWith_${name}`), props)), ...descriptors.map(([name]) => generateType(pascalCase(`WServiceWith_${name}`), `keyof ${pascalCase(`WServicesWith_${name}`)}`)), ...descriptors.map(([name, props]) => {
1141
- return `export const ${camelCase(`wServiceWith_${name}_Names`)}: ${pascalCase(`WServiceWith_${name}`)}[] = ${generateArray(props.map((v) => v.name))};`;
1142
- }), ...typeGuards);
1143
- };
1144
- //#endregion
1145
- //#region src/generator/05-maps/index.ts
1165
+ const entityDescriptors = new Map();
1166
+ for (const service of services) {
1167
+ for (const fn of service.functions) {
1168
+ if (!FILTER_REGEX.test(fn.name)) {
1169
+ continue;
1170
+ }
1171
+ entityDescriptors.set(fn.name, [
1172
+ ...(entityDescriptors.get(fn.name) ?? []),
1173
+ {
1174
+ name: service.name,
1175
+ required: true,
1176
+ type: `${pascalCase(service.name)}Service_${pascalCase(fn.name)}`
1177
+ }
1178
+ ]);
1179
+ }
1180
+ }
1181
+ const descriptors = [...entityDescriptors.entries()];
1182
+ const typeGuards = [];
1183
+ for (const [name] of descriptors) {
1184
+ const constant = camelCase(`wServiceWith_${name}_Names`);
1185
+ const service = pascalCase(`WServiceWith_${name}`);
1186
+ const guard = `(service: string | undefined): service is ${service} =>\n${indent(`${constant}.includes(service as ${service});`)}`;
1187
+ typeGuards.push(`export const is${service} = ${guard}`);
1188
+ }
1189
+ return generateStatements(...descriptors.map(([name, props]) => generateInterface(pascalCase(`WServicesWith_${name}`), props)), ...descriptors.map(([name]) => generateType(pascalCase(`WServiceWith_${name}`), `keyof ${pascalCase(`WServicesWith_${name}`)}`)), ...descriptors.map(([name, props]) => {
1190
+ const constant = camelCase(`wServiceWith_${name}_Names`);
1191
+ const type = pascalCase(`WServiceWith_${name}`);
1192
+ const value = generateArray(props.map((v) => v.name));
1193
+ return `export const ${constant}: ${type}[] = ${value};`;
1194
+ }), ...typeGuards);
1195
+ };
1196
+
1146
1197
  const generateMaps = (enums, entities, services, context, options) => {
1147
- const enumInstances = `export const wEnums = ${generateObject([...enums.keys()].map((v) => ({
1148
- key: v,
1149
- value: v
1150
- })))};`;
1151
- const entityNames = `export const wEntityNames: WEntity[] = ${generateArray([...entities.keys()])};`;
1152
- const generatedServices = [...services.values()];
1153
- const serviceInstances = `export const wServices = ${generateObject(generatedServices.map((v) => ({
1154
- key: v.name,
1155
- value: `${v.serviceFnName}()`,
1156
- comment: v.deprecated ? "@deprecated" : void 0
1157
- })))};`;
1158
- const serviceFactories = `export const wServiceFactories = ${generateObject(generatedServices.map((v) => ({
1159
- key: v.name,
1160
- value: v.serviceFnName,
1161
- comment: v.deprecated ? "@deprecated" : void 0
1162
- })))};`;
1163
- return generateStatements(generateInterface("WEnums", [...enums.keys()].map((name) => ({
1164
- name,
1165
- type: name,
1166
- required: true
1167
- }))), generateType("WEnum", "keyof WEnums"), enumInstances, generateInterface("WEntities", [...[...entities.entries()].map(([name, entity]) => ({
1168
- name,
1169
- type: entity.interfaceName,
1170
- required: true
1171
- })), ...generatedServices.filter(({ relatedEntity }) => !!relatedEntity).filter(({ name }) => !entities.get(name)).map(({ name, relatedEntity }) => ({
1172
- name,
1173
- type: relatedEntity.interfaceName,
1174
- required: true
1175
- }))].sort((a, b) => a.name > b.name ? 1 : -1)), generateType("WEntity", "keyof WEntities"), entityNames, serviceInstances, generateType("WServices", "typeof wServices"), generateType("WService", "keyof WServices"), serviceFactories, generateType("WServiceFactories", "typeof wServiceFactories"), generateGroupedServices(generatedServices), generateCustomValueServices(generatedServices), generateEntityProperties(entities, generatedServices, options));
1176
- };
1177
- //#endregion
1178
- //#region src/utils/weclapp/extractRelatedEntityName.ts
1198
+ const enumInstances = `export const wEnums = ${generateObject([...enums.keys()].map((v) => ({ key: v, value: v })))};`;
1199
+ const entityNames = `export const wEntityNames: WEntity[] = ${generateArray([...entities.keys()])};`;
1200
+ const generatedServices = [...services.values()];
1201
+ const serviceInstances = `export const wServices = ${generateObject(generatedServices.map((v) => ({
1202
+ key: v.name,
1203
+ value: `${v.serviceFnName}()`,
1204
+ comment: v.deprecated ? '@deprecated' : undefined
1205
+ })))};`;
1206
+ const serviceFactories = `export const wServiceFactories = ${generateObject(generatedServices.map((v) => ({
1207
+ key: v.name,
1208
+ value: v.serviceFnName,
1209
+ comment: v.deprecated ? '@deprecated' : undefined
1210
+ })))};`;
1211
+ return generateStatements(
1212
+ /* Enums */
1213
+ generateInterface('WEnums', [...enums.keys()].map((name) => ({ name, type: name, required: true }))), generateType('WEnum', 'keyof WEnums'), enumInstances,
1214
+ /* Entities */
1215
+ generateInterface('WEntities', [
1216
+ ...[...entities.entries()].map(([name, entity]) => ({
1217
+ name,
1218
+ type: entity.interfaceName,
1219
+ required: true
1220
+ })),
1221
+ ...generatedServices
1222
+ .filter(({ relatedEntity }) => !!relatedEntity)
1223
+ .filter(({ name }) => !entities.get(name))
1224
+ .map(({ name, relatedEntity }) => ({
1225
+ name,
1226
+ type: relatedEntity.interfaceName,
1227
+ required: true
1228
+ }))
1229
+ ].sort((a, b) => (a.name > b.name ? 1 : -1))), generateType('WEntity', 'keyof WEntities'), entityNames,
1230
+ /* Services */
1231
+ serviceInstances, generateType('WServices', 'typeof wServices'), generateType('WService', 'keyof WServices'), serviceFactories, generateType('WServiceFactories', 'typeof wServiceFactories'),
1232
+ /* Service Utils */
1233
+ generateGroupedServices(generatedServices), generateCustomValueServices(generatedServices),
1234
+ /* Entity Properties (Runtime Meta Infos) */
1235
+ generateEntityProperties(entities, generatedServices, options));
1236
+ };
1237
+
1179
1238
  function extractRelatedEntityName(serviceEndpoints, responses) {
1180
- const rootEndpoint = serviceEndpoints.find((v) => v.endpoint.type === WeclappEndpointType.ROOT);
1181
- if (!rootEndpoint) return;
1182
- const response = rootEndpoint?.path.get?.responses["200"];
1183
- if (!response) return;
1184
- let responseObject;
1185
- if (isReferenceObject(response)) {
1186
- const refName = getRefName(response);
1187
- responseObject = responses.get(refName);
1188
- } else responseObject = response;
1189
- const responseSchema = responseObject?.content?.["application/json"].schema;
1190
- if (responseSchema) {
1191
- if (isReferenceObject(responseSchema)) return;
1192
- const resultSchema = responseSchema.properties?.result;
1193
- if (!resultSchema) return;
1194
- if (isReferenceObject(resultSchema)) return getRefName(resultSchema);
1195
- else if (isArraySchemaObject(resultSchema)) {
1196
- const resultItemSchema = resultSchema.items;
1197
- if (isReferenceObject(resultItemSchema)) return getRefName(resultItemSchema);
1198
- }
1199
- }
1239
+ const rootEndpoint = serviceEndpoints.find((v) => v.endpoint.type === WeclappEndpointType.ROOT);
1240
+ if (!rootEndpoint)
1241
+ return;
1242
+ const response = rootEndpoint?.path.get?.responses['200'];
1243
+ if (!response)
1244
+ return;
1245
+ let responseObject;
1246
+ if (isReferenceObject(response)) {
1247
+ const refName = getRefName(response);
1248
+ responseObject = responses.get(refName);
1249
+ }
1250
+ else {
1251
+ responseObject = response;
1252
+ }
1253
+ const responseSchema = responseObject?.content?.['application/json'].schema;
1254
+ if (responseSchema) {
1255
+ if (isReferenceObject(responseSchema)) {
1256
+ return;
1257
+ }
1258
+ const resultSchema = responseSchema.properties?.result;
1259
+ if (!resultSchema) {
1260
+ return;
1261
+ }
1262
+ if (isReferenceObject(resultSchema)) {
1263
+ return getRefName(resultSchema);
1264
+ }
1265
+ else if (isArraySchemaObject(resultSchema)) {
1266
+ const resultItemSchema = resultSchema.items;
1267
+ if (isReferenceObject(resultItemSchema)) {
1268
+ return getRefName(resultItemSchema);
1269
+ }
1270
+ }
1271
+ }
1200
1272
  }
1201
- //#endregion
1202
- //#region src/utils/weclapp/extractContext.ts
1273
+
1203
1274
  const extractServiceAliases = (endpoints, responses) => {
1204
- const aliases = /* @__PURE__ */ new Map();
1205
- for (const [serviceName, serviceEndpoints] of endpoints) {
1206
- const relatedEntityName = extractRelatedEntityName(serviceEndpoints, responses);
1207
- if (relatedEntityName) aliases.set(serviceName, relatedEntityName);
1208
- }
1209
- return aliases;
1275
+ const aliases = new Map();
1276
+ for (const [serviceName, serviceEndpoints] of endpoints) {
1277
+ const relatedEntityName = extractRelatedEntityName(serviceEndpoints, responses);
1278
+ if (relatedEntityName)
1279
+ aliases.set(serviceName, relatedEntityName);
1280
+ }
1281
+ return aliases;
1210
1282
  };
1211
1283
  const extractContext = (doc) => {
1212
- const endpoints = parseEndpointsPaths(doc.paths);
1213
- const schemas = /* @__PURE__ */ new Map();
1214
- for (const [name, schema] of Object.entries(doc.components?.schemas ?? {})) if (!isReferenceObject(schema)) schemas.set(name, schema);
1215
- const responses = /* @__PURE__ */ new Map();
1216
- for (const [name, response] of Object.entries(doc.components?.responses ?? {})) if (!isReferenceObject(response)) responses.set(name, response);
1217
- const parameters = /* @__PURE__ */ new Map();
1218
- for (const [name, parameter] of Object.entries(doc.components?.parameters ?? {})) if (!isReferenceObject(parameter)) parameters.set(name, parameter);
1219
- const requestBodies = /* @__PURE__ */ new Map();
1220
- for (const [name, requestBody] of Object.entries(doc.components?.requestBodies ?? {})) if (!isReferenceObject(requestBody)) requestBodies.set(name, requestBody);
1221
- return {
1222
- endpoints,
1223
- schemas,
1224
- responses,
1225
- parameters,
1226
- requestBodies,
1227
- aliases: extractServiceAliases(endpoints, responses)
1228
- };
1229
- };
1230
- //#endregion
1231
- //#region src/generator/generate.ts
1284
+ const endpoints = parseEndpointsPaths(doc.paths);
1285
+ const schemas = new Map();
1286
+ for (const [name, schema] of Object.entries(doc.components?.schemas ?? {})) {
1287
+ if (!isReferenceObject(schema)) {
1288
+ schemas.set(name, schema);
1289
+ }
1290
+ }
1291
+ const responses = new Map();
1292
+ for (const [name, response] of Object.entries(doc.components?.responses ?? {})) {
1293
+ if (!isReferenceObject(response)) {
1294
+ responses.set(name, response);
1295
+ }
1296
+ }
1297
+ const parameters = new Map();
1298
+ for (const [name, parameter] of Object.entries(doc.components?.parameters ?? {})) {
1299
+ if (!isReferenceObject(parameter)) {
1300
+ parameters.set(name, parameter);
1301
+ }
1302
+ }
1303
+ const requestBodies = new Map();
1304
+ for (const [name, requestBody] of Object.entries(doc.components?.requestBodies ?? {})) {
1305
+ if (!isReferenceObject(requestBody)) {
1306
+ requestBodies.set(name, requestBody);
1307
+ }
1308
+ }
1309
+ const aliases = extractServiceAliases(endpoints, responses);
1310
+ return { endpoints, schemas, responses, parameters, requestBodies, aliases };
1311
+ };
1312
+
1232
1313
  const generate = (doc, options) => {
1233
- const context = extractContext(doc);
1234
- const base = generateBase(doc.info.version, options);
1235
- const enums = generateEnums(context);
1236
- const entities = generateEntities(context);
1237
- const services = generateServices(entities, context, options);
1238
- const maps = generateMaps(enums, entities, services, context, options);
1239
- return generateStatements(generateBlockComment("BASE", base), generateBlockComment("ENUMS", generateStatements(...[...enums.values()].map((v) => v.source))), generateBlockComment("ENTITIES", generateStatements(...[...entities.values()].map((v) => v.source))), generateBlockComment("FILTERS", generateStatements(...[...entities.values()].map((v) => v.filterSource))), generateBlockComment("SERVICES", generateStatements(...[...services.values()].map((v) => v.source))), generateBlockComment("MAPS", maps));
1240
- };
1241
- //#endregion
1242
- //#region src/utils/hash.ts
1243
- const hash = (content, algorithm = "sha256") => {
1244
- const hash = createHash(algorithm);
1245
- if (Array.isArray(content)) content.map(hash.update.bind(hash));
1246
- else hash.update(content);
1247
- return hash.digest("hex");
1248
- };
1249
- //#endregion
1250
- //#region src/cli.ts
1314
+ const context = extractContext(doc);
1315
+ const base = generateBase(doc.info.version, options);
1316
+ const enums = generateEnums(context);
1317
+ const entities = generateEntities(context);
1318
+ const services = generateServices(entities, context, options);
1319
+ const maps = generateMaps(enums, entities, services, context, options);
1320
+ return generateStatements(generateBlockComment('BASE', base), generateBlockComment('ENUMS', generateStatements(...[...enums.values()].map((v) => v.source))), generateBlockComment('ENTITIES', generateStatements(...[...entities.values()].map((v) => v.source))), generateBlockComment('FILTERS', generateStatements(...[...entities.values()].map((v) => v.filterSource))), generateBlockComment('SERVICES', generateStatements(...[...services.values()].map((v) => v.source))), generateBlockComment('MAPS', maps));
1321
+ };
1322
+
1323
+ const hash = (content, algorithm = 'sha256') => {
1324
+ const hash = createHash(algorithm);
1325
+ if (Array.isArray(content)) {
1326
+ content.map(hash.update.bind(hash));
1327
+ }
1328
+ else {
1329
+ hash.update(content);
1330
+ }
1331
+ return hash.digest('hex');
1332
+ };
1333
+
1334
+ /* eslint-disable @typescript-eslint/no-unsafe-assignment */
1251
1335
  const cli = async () => {
1252
- const version = pkg.version;
1253
- const { argv } = yargs(hideBin(process.argv)).scriptName("build-weclapp-sdk").usage("Usage: $0 <source> [flags]").version(version).example("$0 openapi.json", "Generate the SDK based on a local openapi file").example("$0 openapi.json", "Generate the SDK based on a local openapi file").example("$0 xxx.weclapp.com --key ...", "Generate the SDK based on the openapi file from the given weclapp instance").help("h").alias("v", "version").alias("h", "help").option("k", {
1254
- alias: "key",
1255
- describe: "API Key (only needed when not using a local file)",
1256
- type: "string"
1257
- }).option("c", {
1258
- alias: "cache",
1259
- describe: "If the generated SDK should cached",
1260
- type: "boolean"
1261
- }).option("q", {
1262
- alias: "query",
1263
- describe: "Extra query params when fetching the openapi.json from a server",
1264
- type: "string"
1265
- }).option("generate-unique", {
1266
- describe: "Generate .unique functions",
1267
- type: "boolean"
1268
- }).option("d", {
1269
- alias: "deprecated",
1270
- describe: "Include deprecated functions and services",
1271
- type: "boolean"
1272
- }).option("e", {
1273
- alias: "from-env",
1274
- describe: "Use env variables WECLAPP_BACKEND_URL and WECLAPP_API_KEY as credentials",
1275
- type: "boolean"
1276
- }).option("t", {
1277
- alias: "target",
1278
- describe: "Specify the target platform",
1279
- type: "string",
1280
- choices: [
1281
- "browser",
1282
- "browser.rx",
1283
- "node",
1284
- "node.rx"
1285
- ]
1286
- }).option("use-query-language", {
1287
- describe: "Generate the new where property for some and count queries",
1288
- type: "boolean"
1289
- }).option("apiVersion", {
1290
- describe: "Specify the api version (only needed when not using a local file)",
1291
- type: "string"
1292
- }).epilog(`Copyright ${(/* @__PURE__ */ new Date()).getFullYear()} weclapp GmbH`);
1293
- if (argv.fromEnv) config();
1294
- const { WECLAPP_API_KEY, WECLAPP_BACKEND_URL } = process.env;
1295
- const { query, cache = false, deprecated = false, key = WECLAPP_API_KEY, apiVersion, _: [src = WECLAPP_BACKEND_URL] } = argv;
1296
- const options = {
1297
- deprecated,
1298
- generateUnique: argv.generateUnique ?? false,
1299
- target: argv.target ?? Target.BROWSER_PROMISES,
1300
- useQueryLanguage: argv.useQueryLanguage ?? false
1301
- };
1302
- if (!src || typeof src === "number") return Promise.reject(/* @__PURE__ */ new Error("Expected string as command"));
1303
- if (!Object.values(Target).includes(options.target)) {
1304
- logger.errorLn(`Unknown target: ${options.target}. Possible values are ${Object.values(Target).join(", ")}`);
1305
- return Promise.reject(/* @__PURE__ */ new Error());
1306
- }
1307
- if (await stat(src).catch(() => false)) {
1308
- logger.infoLn(`Source is a file`);
1309
- return {
1310
- cache,
1311
- content: JSON.parse(await readFile(src, "utf-8")),
1312
- options
1313
- };
1314
- }
1315
- logger.infoLn(`Source is a URL`);
1316
- if (!key) return Promise.reject(/* @__PURE__ */ new Error("API key is missing"));
1317
- if (!apiVersion) return Promise.reject(/* @__PURE__ */ new Error("API version is missing"));
1318
- const url = new URL(src.startsWith("http") ? src : `https://${src}`);
1319
- url.pathname = `/webapp/api/${apiVersion}/meta/openapi.json`;
1320
- if (query?.length) for (const param of query.split(",")) {
1321
- const [name, value] = param.split("=");
1322
- url.searchParams.set(name, value);
1323
- }
1324
- const content = await fetch(url.toString(), { headers: {
1325
- Accept: "application/json",
1326
- AuthenticationToken: key
1327
- } }).then((res) => res.ok ? res.json() : void 0);
1328
- if (!content) {
1329
- logger.errorLn(`Couldn't fetch file ${url.toString()} `);
1330
- return Promise.reject(/* @__PURE__ */ new Error());
1331
- } else logger.infoLn(`Use remote file: ${url.toString()}`);
1332
- return {
1333
- cache,
1334
- content,
1335
- options
1336
- };
1337
- };
1338
- //#endregion
1339
- //#region src/index.ts
1340
- const workingDir = resolve(currentDirname(), "./sdk");
1341
- const cacheDir = resolve(currentDirname(), "./.cache");
1342
- (async () => {
1343
- const start = process.hrtime.bigint();
1344
- const { content: doc, cache: useCache, options } = await cli();
1345
- const workingDirPath = async (...paths) => {
1346
- const fullPath = resolve(workingDir, ...paths);
1347
- await mkdir(dirname(fullPath), { recursive: true });
1348
- return fullPath;
1349
- };
1350
- const cacheKey = hash([
1351
- pkg.version,
1352
- JSON.stringify(doc),
1353
- JSON.stringify(options)
1354
- ]).slice(-8);
1355
- const cachedSdkDir = resolve(cacheDir, cacheKey);
1356
- await rm(workingDir, {
1357
- recursive: true,
1358
- force: true
1359
- });
1360
- if (useCache) logger.infoLn(`Cache ID: ${cacheKey}`);
1361
- if (useCache && await stat(cachedSdkDir).catch(() => false)) {
1362
- logger.successLn(`Cache match! (${cachedSdkDir})`);
1363
- await cp(cachedSdkDir, workingDir, { recursive: true });
1364
- } else {
1365
- await writeFile(await workingDirPath("openapi.json"), JSON.stringify(doc, null, 2));
1366
- logger.infoLn(`Generate sdk (target: ${options.target})`);
1367
- const sdk = generate(doc, options);
1368
- await writeFile(await workingDirPath("src", "index.ts"), sdk.trim() + "\n");
1369
- logger.infoLn("Bundle... (this may take some time)");
1370
- await bundle(workingDir, options.target);
1371
- await rm(await workingDirPath("src"), {
1372
- recursive: true,
1373
- force: true
1374
- });
1375
- if (useCache) {
1376
- logger.successLn(`Caching SDK: (${cachedSdkDir})`);
1377
- await mkdir(cachedSdkDir, { recursive: true });
1378
- await cp(workingDir, cachedSdkDir, { recursive: true });
1379
- }
1380
- }
1381
- const duration = (process.hrtime.bigint() - start) / 1000000n;
1382
- logger.successLn(`SDK built in ${prettyMs(Number(duration))}`);
1383
- logger.printSummary();
1384
- })().catch((error) => {
1385
- logger.errorLn(`Fatal error:`);
1386
- console.error(error);
1387
- }).finally(() => {
1388
- if (logger.errors) process.exit(1);
1336
+ const version = pkg.version;
1337
+ const { argv } = yargs(hideBin(process.argv))
1338
+ .scriptName('build-weclapp-sdk')
1339
+ .usage('Usage: $0 <source> [flags]')
1340
+ .version(version)
1341
+ .example('$0 openapi.json', 'Generate the SDK based on a local openapi file')
1342
+ .example('$0 openapi.json', 'Generate the SDK based on a local openapi file')
1343
+ .example('$0 xxx.weclapp.com --key ...', 'Generate the SDK based on the openapi file from the given weclapp instance')
1344
+ .help('h')
1345
+ .alias('v', 'version')
1346
+ .alias('h', 'help')
1347
+ .option('k', {
1348
+ alias: 'key',
1349
+ describe: 'API Key (only needed when not using a local file)',
1350
+ type: 'string'
1351
+ })
1352
+ .option('c', {
1353
+ alias: 'cache',
1354
+ describe: 'If the generated SDK should cached',
1355
+ type: 'boolean'
1356
+ })
1357
+ .option('q', {
1358
+ alias: 'query',
1359
+ describe: 'Extra query params when fetching the openapi.json from a server',
1360
+ type: 'string'
1361
+ })
1362
+ .option('generate-unique', {
1363
+ describe: 'Generate .unique functions',
1364
+ type: 'boolean'
1365
+ })
1366
+ .option('d', {
1367
+ alias: 'deprecated',
1368
+ describe: 'Include deprecated functions and services',
1369
+ type: 'boolean'
1370
+ })
1371
+ .option('e', {
1372
+ alias: 'from-env',
1373
+ describe: 'Use env variables WECLAPP_BACKEND_URL and WECLAPP_API_KEY as credentials',
1374
+ type: 'boolean'
1375
+ })
1376
+ .option('t', {
1377
+ alias: 'target',
1378
+ describe: 'Specify the target platform',
1379
+ type: 'string',
1380
+ choices: ['browser', 'browser.rx', 'node', 'node.rx']
1381
+ })
1382
+ .option('use-query-language', {
1383
+ describe: 'Generate the new where property for some and count queries',
1384
+ type: 'boolean'
1385
+ })
1386
+ .option('apiVersion', {
1387
+ describe: 'Specify the api version (only needed when not using a local file)',
1388
+ type: 'string'
1389
+ })
1390
+ .epilog(`Copyright ${new Date().getFullYear()} weclapp GmbH`);
1391
+ if (argv.fromEnv) {
1392
+ config();
1393
+ }
1394
+ const { WECLAPP_API_KEY, WECLAPP_BACKEND_URL } = process.env;
1395
+ const { query, cache = false, deprecated = false, key = WECLAPP_API_KEY, apiVersion, _: [src = WECLAPP_BACKEND_URL] } = argv;
1396
+ const options = {
1397
+ deprecated,
1398
+ generateUnique: argv.generateUnique ?? false,
1399
+ target: argv.target ?? Target.BROWSER_PROMISES,
1400
+ useQueryLanguage: argv.useQueryLanguage ?? false
1401
+ };
1402
+ if (!src || typeof src === 'number') {
1403
+ return Promise.reject(new Error('Expected string as command'));
1404
+ }
1405
+ if (!Object.values(Target).includes(options.target)) {
1406
+ logger.errorLn(`Unknown target: ${options.target}. Possible values are ${Object.values(Target).join(', ')}`);
1407
+ return Promise.reject(new Error());
1408
+ }
1409
+ if (await stat(src).catch(() => false)) {
1410
+ logger.infoLn(`Source is a file`);
1411
+ const content = JSON.parse(await readFile(src, 'utf-8'));
1412
+ return { cache, content, options };
1413
+ }
1414
+ logger.infoLn(`Source is a URL`);
1415
+ if (!key) {
1416
+ return Promise.reject(new Error('API key is missing'));
1417
+ }
1418
+ if (!apiVersion) {
1419
+ return Promise.reject(new Error('API version is missing'));
1420
+ }
1421
+ const url = new URL(src.startsWith('http') ? src : `https://${src}`);
1422
+ url.pathname = `/webapp/api/${apiVersion}/meta/openapi.json`;
1423
+ if (query?.length) {
1424
+ for (const param of query.split(',')) {
1425
+ const [name, value] = param.split('=');
1426
+ url.searchParams.set(name, value);
1427
+ }
1428
+ }
1429
+ const content = await fetch(url.toString(), {
1430
+ headers: { Accept: 'application/json', AuthenticationToken: key }
1431
+ }).then((res) => (res.ok ? res.json() : undefined));
1432
+ if (!content) {
1433
+ logger.errorLn(`Couldn't fetch file ${url.toString()} `);
1434
+ return Promise.reject(new Error());
1435
+ }
1436
+ else {
1437
+ logger.infoLn(`Use remote file: ${url.toString()}`);
1438
+ }
1439
+ return { cache, content, options };
1440
+ };
1441
+
1442
+ const workingDir = resolve(currentDirname(), './sdk');
1443
+ const cacheDir = resolve(currentDirname(), './.cache');
1444
+ void (async () => {
1445
+ const start = process.hrtime.bigint();
1446
+ const { content: doc, cache: useCache, options } = await cli();
1447
+ const workingDirPath = async (...paths) => {
1448
+ const fullPath = resolve(workingDir, ...paths);
1449
+ await mkdir(dirname(fullPath), { recursive: true });
1450
+ return fullPath;
1451
+ };
1452
+ // Resolve cache dir and key
1453
+ const cacheKey = hash([pkg.version, JSON.stringify(doc), JSON.stringify(options)]).slice(-8);
1454
+ const cachedSdkDir = resolve(cacheDir, cacheKey);
1455
+ // Remove old SDK
1456
+ await rm(workingDir, { recursive: true, force: true });
1457
+ if (useCache) {
1458
+ logger.infoLn(`Cache ID: ${cacheKey}`);
1459
+ }
1460
+ if (useCache && (await stat(cachedSdkDir).catch(() => false))) {
1461
+ // Copy cached SDK to working dir
1462
+ logger.successLn(`Cache match! (${cachedSdkDir})`);
1463
+ await cp(cachedSdkDir, workingDir, { recursive: true });
1464
+ }
1465
+ else {
1466
+ // Write openapi.json file
1467
+ await writeFile(await workingDirPath('openapi.json'), JSON.stringify(doc, null, 2));
1468
+ logger.infoLn(`Generate sdk (target: ${options.target})`);
1469
+ // Generate and write SDK (index.ts)
1470
+ const sdk = generate(doc, options);
1471
+ await writeFile(await workingDirPath('src', 'index.ts'), sdk.trim() + '\n');
1472
+ // Bundle and write SDK
1473
+ logger.infoLn('Bundle... (this may take some time)');
1474
+ await bundle(workingDir, options.target);
1475
+ // Remove index.ts (only bundle is required)
1476
+ await rm(await workingDirPath('src'), { recursive: true, force: true });
1477
+ if (useCache) {
1478
+ // Copy SDK to cache
1479
+ logger.successLn(`Caching SDK: (${cachedSdkDir})`);
1480
+ await mkdir(cachedSdkDir, { recursive: true });
1481
+ await cp(workingDir, cachedSdkDir, { recursive: true });
1482
+ }
1483
+ }
1484
+ // Print job summary
1485
+ const duration = (process.hrtime.bigint() - start) / 1000000n;
1486
+ logger.successLn(`SDK built in ${prettyMs(Number(duration))}`);
1487
+ logger.printSummary();
1488
+ })()
1489
+ .catch((error) => {
1490
+ logger.errorLn(`Fatal error:`);
1491
+ /* eslint-disable no-console */
1492
+ console.error(error);
1493
+ })
1494
+ .finally(() => {
1495
+ if (logger.errors)
1496
+ process.exit(1);
1389
1497
  });
1390
- //#endregion