youtrack-client
Version:
Client library for accessing the YouTrack REST and Widget API
72 lines (71 loc) • 3.04 kB
TypeScript
/**
* FieldSchema is a read-only array of Field, which allows for a mix of flat fields (strings)
* and nested fields (objects).
*
* Example:
* const personFields: FieldsSchema = [
* 'name', // flat field
* {
* address: [ // nested fields
* 'city',
* {
* details: [
* 'zip'
* ]
* }
* ]
* }
* ]
*/
export type FieldsSchema = ReadonlyArray<Field>;
type Field = string | Record<string, FieldsSchema>;
/**
* Parses a schema from a string into a structured `FieldsSchema`.
*
* The input string is expected to contain field names separated by commas, with nested
* fields enclosed in parentheses.
*
* Example:
* - Input: `"name,level,topic(id,name,value(name),test),color"`
* - Output: `["name", "level", { topic: ["id", "name", { value: ["name"] }, "test"] }, "color"]`
*
* @template T - The input string schema to be parsed.
*/
export type ParseSchema<T extends string> = ParseSubSchema<T> extends [infer Schema, infer Rest] ? Rest extends "" ? Schema : never : never;
/**
* Finds a name from the input string and returns a tuple with the name,
* the character immediately following the name (such as "," or "("),
* and the remaining string.
*
* If the string ends, the name is returned alone.
*
* Example:
* - Input: `"topic(id,name)"`
* - Output: `["topic", "(", "id,name)"]`
*
* @template T - The input string to extract a name from.
* @template Name - A string accumulator to build the name recursively.
* @result - Tuple [Name, Char, RestString]
*/
type FindName<T, Name extends string = ""> = T extends `${Name}${infer Char}${infer Rest}` ? Char extends "," | "(" | ")" ? [Name, Char, Rest] : FindName<T, `${Name}${Char}`> : Name extends "" ? [] : [Name];
/**
* Recursively parses a string schema and builds a `FieldsSchema` array.
*
* The parsing process looks for field names separated by commas, and recognizes
* nested schemas enclosed in parentheses. When a nested schema is encountered, it is
* parsed recursively and appended to the resulting `FieldsSchema`.
*
* Example:
* - Input: `"id,name),rest"`
* - Output: `[["id", "name"], ",rest"]`
*
* @template T - The input string to parse into a schema.
* @template Items - The accumulator for parsed schema items, defaulting to an empty array.
* @result - Tuple [FieldsSchema, RestString]
*/
type ParseSubSchema<T, Items extends FieldsSchema = []> = FindName<T> extends [infer Name, infer Char, infer Rest] ? Name extends string ? Char extends "," ? ParseSubSchema<Rest, Name extends "" ? Items : [...Items, Name]> : Char extends "(" ? ParseSubSchema<Rest> extends [infer SubSchema, infer Rest2] ? SubSchema extends FieldsSchema ? Rest2 extends "" ? [[...Items, {
[K in Name]: SubSchema;
}], ""] : ParseSubSchema<Rest2, [...Items, {
[K in Name]: SubSchema;
}]> : never : never : Char extends ")" ? Name extends "" ? [Items, Rest] : [[...Items, Name], Rest] : never : never : FindName<T> extends [infer Name] ? [[...Items, Name], ""] : [Items, ""];
export {};