Added openapi generator
This commit is contained in:
@@ -0,0 +1,160 @@
|
||||
import { HttpParams, HttpParameterCodec } from '@angular/common/http';
|
||||
import { CustomHttpParameterCodec, IdentityHttpParameterCodec } from './encoder';
|
||||
|
||||
export enum QueryParamStyle {
|
||||
Json,
|
||||
Form,
|
||||
DeepObject,
|
||||
SpaceDelimited,
|
||||
PipeDelimited,
|
||||
}
|
||||
|
||||
export type Delimiter = "," | " " | "|" | "\t";
|
||||
|
||||
export interface ParamOptions {
|
||||
/** When true, serialized as multiple repeated key=value pairs. When false, serialized as a single key with joined values using `delimiter`. */
|
||||
explode?: boolean;
|
||||
/** Delimiter used when explode=false. The delimiter itself is inserted unencoded between encoded values. */
|
||||
delimiter?: Delimiter;
|
||||
}
|
||||
|
||||
interface ParamEntry {
|
||||
values: string[];
|
||||
options: Required<ParamOptions>;
|
||||
}
|
||||
|
||||
export class OpenApiHttpParams {
|
||||
private params: Map<string, ParamEntry> = new Map();
|
||||
private defaults: Required<ParamOptions>;
|
||||
private encoder: HttpParameterCodec;
|
||||
|
||||
/**
|
||||
* @param encoder Parameter serializer
|
||||
* @param defaults Global defaults used when a specific parameter has no explicit options.
|
||||
* By OpenAPI default, explode is true for query params with style=form.
|
||||
*/
|
||||
constructor(encoder?: HttpParameterCodec, defaults?: { explode?: boolean; delimiter?: Delimiter }) {
|
||||
this.encoder = encoder || new CustomHttpParameterCodec();
|
||||
this.defaults = {
|
||||
explode: defaults?.explode ?? true,
|
||||
delimiter: defaults?.delimiter ?? ",",
|
||||
};
|
||||
}
|
||||
|
||||
private resolveOptions(local?: ParamOptions): Required<ParamOptions> {
|
||||
return {
|
||||
explode: local?.explode ?? this.defaults.explode,
|
||||
delimiter: local?.delimiter ?? this.defaults.delimiter,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the parameter's values and (optionally) its options.
|
||||
* Options are stored per-parameter (not global).
|
||||
*/
|
||||
set(key: string, values: string[] | string, options?: ParamOptions): this {
|
||||
const arr = Array.isArray(values) ? values.slice() : [values];
|
||||
const opts = this.resolveOptions(options);
|
||||
this.params.set(key, {values: arr, options: opts});
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a single value to the parameter. If the parameter didn't exist it will be created
|
||||
* and use resolved options (global defaults merged with any provided options).
|
||||
*/
|
||||
append(key: string, value: string, options?: ParamOptions): this {
|
||||
const entry = this.params.get(key);
|
||||
if (entry) {
|
||||
// If new options provided, override the stored options for subsequent serialization
|
||||
if (options) {
|
||||
entry.options = this.resolveOptions({...entry.options, ...options});
|
||||
}
|
||||
entry.values.push(value);
|
||||
} else {
|
||||
this.set(key, [value], options);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize to a query string according to per-parameter OpenAPI options.
|
||||
* - If explode=true for that parameter → repeated key=value pairs (each value encoded).
|
||||
* - If explode=false for that parameter → single key=value where values are individually encoded
|
||||
* and joined using the configured delimiter. The delimiter character is inserted AS-IS
|
||||
* (not percent-encoded).
|
||||
*/
|
||||
toString(): string {
|
||||
const records = this.toRecord();
|
||||
const parts: string[] = [];
|
||||
|
||||
for (const key in records) {
|
||||
parts.push(`${key}=${records[key]}`);
|
||||
}
|
||||
|
||||
return parts.join("&");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return parameters as a plain record.
|
||||
* - If a parameter has exactly one value, returns that value directly.
|
||||
* - If a parameter has multiple values, returns a readonly array of values.
|
||||
*/
|
||||
toRecord(): Record<string, string | number | boolean | ReadonlyArray<string | number | boolean>> {
|
||||
const parts: Record<string, string | number | boolean | ReadonlyArray<string | number | boolean>> = {};
|
||||
|
||||
for (const [key, entry] of this.params.entries()) {
|
||||
const encodedKey = this.encoder.encodeKey(key);
|
||||
|
||||
if (entry.options.explode) {
|
||||
parts[encodedKey] = entry.values.map((v) => this.encoder.encodeValue(v));
|
||||
} else {
|
||||
const encodedValues = entry.values.map((v) => this.encoder.encodeValue(v));
|
||||
|
||||
// join with the delimiter *unencoded*
|
||||
parts[encodedKey] = encodedValues.join(entry.options.delimiter);
|
||||
}
|
||||
}
|
||||
|
||||
return parts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an Angular's HttpParams with an identity parameter codec as the parameters are already encoded.
|
||||
*/
|
||||
toHttpParams(): HttpParams {
|
||||
const records = this.toRecord();
|
||||
|
||||
let httpParams = new HttpParams({encoder: new IdentityHttpParameterCodec()});
|
||||
|
||||
return httpParams.appendAll(records);
|
||||
}
|
||||
}
|
||||
|
||||
export function concatHttpParamsObject(httpParams: OpenApiHttpParams, key: string, item: {
|
||||
[index: string]: any
|
||||
}, delimiter: Delimiter): OpenApiHttpParams {
|
||||
let keyAndValues: string[] = [];
|
||||
|
||||
for (const k in item) {
|
||||
keyAndValues.push(k);
|
||||
|
||||
const value = item[k];
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
keyAndValues.push(...value.map(convertToString));
|
||||
} else {
|
||||
keyAndValues.push(convertToString(value));
|
||||
}
|
||||
}
|
||||
|
||||
return httpParams.set(key, keyAndValues, {explode: false, delimiter: delimiter});
|
||||
}
|
||||
|
||||
function convertToString(value: any): string {
|
||||
if (value instanceof Date) {
|
||||
return value.toISOString();
|
||||
} else {
|
||||
return value.toString();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user