@jfdevelops/multi-step-form-core 1.0.0-alpha.17 → 1.0.0-alpha.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_internals.cjs +14 -0
- package/dist/_internals.d.cts +4 -0
- package/dist/_internals.d.mts +4 -0
- package/dist/_internals.mjs +5 -0
- package/dist/index.cjs +49 -0
- package/dist/index.d.cts +14 -0
- package/dist/index.d.mts +14 -0
- package/dist/index.mjs +16 -0
- package/dist/internals/step-schema.cjs +389 -0
- package/dist/internals/step-schema.cjs.map +1 -0
- package/dist/internals/step-schema.d.cts +41 -0
- package/dist/internals/step-schema.d.cts.map +1 -0
- package/dist/internals/step-schema.d.mts +41 -0
- package/dist/internals/step-schema.d.mts.map +1 -0
- package/dist/internals/step-schema.mjs +389 -0
- package/dist/internals/step-schema.mjs.map +1 -0
- package/dist/internals/utils.cjs +94 -0
- package/dist/internals/utils.cjs.map +1 -0
- package/dist/internals/utils.d.cts +27 -0
- package/dist/internals/utils.d.cts.map +1 -0
- package/dist/internals/utils.d.mts +27 -0
- package/dist/internals/utils.d.mts.map +1 -0
- package/dist/internals/utils.mjs +91 -0
- package/dist/internals/utils.mjs.map +1 -0
- package/dist/observable.cjs +44 -0
- package/dist/observable.cjs.map +1 -0
- package/dist/observable.d.cts +26 -0
- package/dist/observable.d.cts.map +1 -0
- package/dist/observable.d.mts +26 -0
- package/dist/observable.d.mts.map +1 -0
- package/dist/observable.mjs +44 -0
- package/dist/observable.mjs.map +1 -0
- package/dist/schema.cjs +68 -0
- package/dist/schema.cjs.map +1 -0
- package/dist/schema.d.cts +28 -0
- package/dist/schema.d.cts.map +1 -0
- package/dist/schema.d.mts +28 -0
- package/dist/schema.d.mts.map +1 -0
- package/dist/schema.mjs +67 -0
- package/dist/schema.mjs.map +1 -0
- package/dist/steps/fields.cjs +23 -0
- package/dist/steps/fields.cjs.map +1 -0
- package/dist/steps/fields.d.cts +18 -0
- package/dist/steps/fields.d.cts.map +1 -0
- package/dist/steps/fields.d.mts +18 -0
- package/dist/steps/fields.d.mts.map +1 -0
- package/dist/steps/fields.mjs +18 -0
- package/dist/steps/fields.mjs.map +1 -0
- package/dist/steps/index.cjs +4 -0
- package/dist/steps/index.mjs +6 -0
- package/dist/steps/schema.cjs +194 -0
- package/dist/steps/schema.cjs.map +1 -0
- package/dist/steps/schema.d.cts +124 -0
- package/dist/steps/schema.d.cts.map +1 -0
- package/dist/steps/schema.d.mts +124 -0
- package/dist/steps/schema.d.mts.map +1 -0
- package/dist/steps/schema.mjs +194 -0
- package/dist/steps/schema.mjs.map +1 -0
- package/dist/steps/types.cjs +33 -0
- package/dist/steps/types.cjs.map +1 -0
- package/dist/steps/types.d.cts +332 -0
- package/dist/steps/types.d.cts.map +1 -0
- package/dist/steps/types.d.mts +332 -0
- package/dist/steps/types.d.mts.map +1 -0
- package/dist/steps/types.mjs +27 -0
- package/dist/steps/types.mjs.map +1 -0
- package/dist/steps/utils.cjs +96 -0
- package/dist/steps/utils.cjs.map +1 -0
- package/dist/steps/utils.d.cts +10 -0
- package/dist/steps/utils.d.cts.map +1 -0
- package/dist/steps/utils.d.mts +10 -0
- package/dist/steps/utils.d.mts.map +1 -0
- package/dist/steps/utils.mjs +94 -0
- package/dist/steps/utils.mjs.map +1 -0
- package/dist/storage.cjs +68 -0
- package/dist/storage.cjs.map +1 -0
- package/dist/storage.d.cts +33 -0
- package/dist/storage.d.cts.map +1 -0
- package/dist/storage.d.mts +33 -0
- package/dist/storage.d.mts.map +1 -0
- package/dist/storage.mjs +67 -0
- package/dist/storage.mjs.map +1 -0
- package/dist/subscribable.cjs +25 -0
- package/dist/subscribable.cjs.map +1 -0
- package/dist/subscribable.d.cts +14 -0
- package/dist/subscribable.d.cts.map +1 -0
- package/dist/subscribable.d.mts +14 -0
- package/dist/subscribable.d.mts.map +1 -0
- package/dist/subscribable.mjs +24 -0
- package/dist/subscribable.mjs.map +1 -0
- package/dist/utils/casing.cjs +63 -0
- package/dist/utils/casing.cjs.map +1 -0
- package/dist/utils/casing.d.cts +40 -0
- package/dist/utils/casing.d.cts.map +1 -0
- package/dist/utils/casing.d.mts +40 -0
- package/dist/utils/casing.d.mts.map +1 -0
- package/dist/utils/casing.mjs +57 -0
- package/dist/utils/casing.mjs.map +1 -0
- package/dist/utils/field-types.cjs +23 -0
- package/dist/utils/field-types.cjs.map +1 -0
- package/dist/utils/field-types.d.cts +11 -0
- package/dist/utils/field-types.d.cts.map +1 -0
- package/dist/utils/field-types.d.mts +11 -0
- package/dist/utils/field-types.d.mts.map +1 -0
- package/dist/utils/field-types.mjs +20 -0
- package/dist/utils/field-types.mjs.map +1 -0
- package/dist/utils/helpers.cjs +30 -0
- package/dist/utils/helpers.cjs.map +1 -0
- package/dist/utils/helpers.mjs +27 -0
- package/dist/utils/helpers.mjs.map +1 -0
- package/dist/utils/invariant.cjs +18 -0
- package/dist/utils/invariant.cjs.map +1 -0
- package/dist/utils/invariant.d.cts +5 -0
- package/dist/utils/invariant.d.cts.map +1 -0
- package/dist/utils/invariant.d.mts +5 -0
- package/dist/utils/invariant.d.mts.map +1 -0
- package/dist/utils/invariant.mjs +17 -0
- package/dist/utils/invariant.mjs.map +1 -0
- package/dist/utils/logger.cjs +58 -0
- package/dist/utils/logger.cjs.map +1 -0
- package/dist/utils/logger.d.cts +53 -0
- package/dist/utils/logger.d.cts.map +1 -0
- package/dist/utils/logger.d.mts +53 -0
- package/dist/utils/logger.d.mts.map +1 -0
- package/dist/utils/logger.mjs +56 -0
- package/dist/utils/logger.mjs.map +1 -0
- package/dist/utils/path.cjs +407 -0
- package/dist/utils/path.cjs.map +1 -0
- package/dist/utils/path.d.cts +139 -0
- package/dist/utils/path.d.cts.map +1 -0
- package/dist/utils/path.d.mts +139 -0
- package/dist/utils/path.d.mts.map +1 -0
- package/dist/utils/path.mjs +401 -0
- package/dist/utils/path.mjs.map +1 -0
- package/dist/utils/types.d.cts +25 -0
- package/dist/utils/types.d.cts.map +1 -0
- package/dist/utils/types.d.mts +25 -0
- package/dist/utils/types.d.mts.map +1 -0
- package/dist/utils/validator.cjs +12 -0
- package/dist/utils/validator.cjs.map +1 -0
- package/dist/utils/validator.d.cts +77 -0
- package/dist/utils/validator.d.cts.map +1 -0
- package/dist/utils/validator.d.mts +77 -0
- package/dist/utils/validator.d.mts.map +1 -0
- package/dist/utils/validator.mjs +11 -0
- package/dist/utils/validator.mjs.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/utils/casing.ts
|
|
3
|
+
const CASING_TYPES = [
|
|
4
|
+
"sentence",
|
|
5
|
+
"title",
|
|
6
|
+
"camel",
|
|
7
|
+
"lower",
|
|
8
|
+
"upper",
|
|
9
|
+
"pascal",
|
|
10
|
+
"snake",
|
|
11
|
+
"screaming-snake",
|
|
12
|
+
"flat",
|
|
13
|
+
"kebab"
|
|
14
|
+
];
|
|
15
|
+
const DEFAULT_CASING = "title";
|
|
16
|
+
function changeCasing(input, type) {
|
|
17
|
+
const words = input.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[-_]+/g, " ").trim().split(/\s+/).map((w) => w.toLowerCase());
|
|
18
|
+
switch (type) {
|
|
19
|
+
case "sentence": return words[0].charAt(0).toUpperCase() + words[0].slice(1) + (words.length > 1 ? " " + words.slice(1).join(" ") : "");
|
|
20
|
+
case "title": return words.map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
21
|
+
case "camel": return words[0] + words.slice(1).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join("");
|
|
22
|
+
case "pascal": return words.map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join("");
|
|
23
|
+
case "lower": return words.join(" ");
|
|
24
|
+
case "upper": return words.join(" ").toUpperCase();
|
|
25
|
+
case "snake": return words.join("_");
|
|
26
|
+
case "screaming-snake": return words.join("_").toUpperCase();
|
|
27
|
+
case "kebab": return words.join("-");
|
|
28
|
+
case "flat": return words.join("");
|
|
29
|
+
default: return input;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function quote(str, quoteChar = "\"") {
|
|
33
|
+
const startsWithQuote = str.startsWith(quoteChar);
|
|
34
|
+
const endsWithQuote = str.endsWith(quoteChar);
|
|
35
|
+
if (startsWithQuote && endsWithQuote) return str;
|
|
36
|
+
return `${quoteChar}${str.replace(/^['"]|['"]$/g, "")}${quoteChar}`;
|
|
37
|
+
}
|
|
38
|
+
function isCasingValid(value) {
|
|
39
|
+
if (typeof value !== "string") return false;
|
|
40
|
+
return CASING_TYPES.includes(value);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Validates {@linkcode input} is a valid {@linkcode CasingType}.
|
|
44
|
+
*
|
|
45
|
+
* If there is no explicit {@linkcode fallback} value provided,
|
|
46
|
+
* it will default to {@linkcode DEFAULT_CASING}.
|
|
47
|
+
* @param input The input to check.
|
|
48
|
+
* @param fallback An optional fallback value if {@linkcode input} is `undefined`.
|
|
49
|
+
* @returns The {@linkcode input} or {@linkcode fallback} if {@linkcode input} is `undefined` or an {@linkcode isCasingValid invalid} {@linkcode CasingType}.
|
|
50
|
+
*/
|
|
51
|
+
function setCasingType(input, fallback = DEFAULT_CASING) {
|
|
52
|
+
if (isCasingValid(input)) return input;
|
|
53
|
+
return fallback;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
//#endregion
|
|
57
|
+
exports.CASING_TYPES = CASING_TYPES;
|
|
58
|
+
exports.DEFAULT_CASING = DEFAULT_CASING;
|
|
59
|
+
exports.changeCasing = changeCasing;
|
|
60
|
+
exports.isCasingValid = isCasingValid;
|
|
61
|
+
exports.quote = quote;
|
|
62
|
+
exports.setCasingType = setCasingType;
|
|
63
|
+
//# sourceMappingURL=casing.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"casing.cjs","names":["DEFAULT_CASING: SetDefaultString<CasingType, 'title'>"],"sources":["../../src/utils/casing.ts"],"sourcesContent":["import type { Expand, SetDefaultString } from './types';\n\nexport type CasingType = (typeof CASING_TYPES)[number];\nexport type ToLower<S extends string> = S extends `${infer F}${infer R}`\n ? `${Lowercase<F>}${ToLower<R>}`\n : S;\n\nexport type CapitalizeWord<S extends string> = S extends `${infer F}${infer R}`\n ? `${Uppercase<F>}${ToLower<R>}`\n : S;\n// Pascal => Capitalize each \"word\" chunk\ntype Pascalize<S extends string> = Capitalize<S>; // naive\n\n// SnakeCase: turn spaces/hyphens into underscores, lowercase\ntype SnakeCase<S extends string> = Lowercase<\n S extends `${infer A} ${infer B}`\n ? `${A}_${SnakeCase<B>}`\n : S extends `${infer A}-${infer B}`\n ? `${A}_${SnakeCase<B>}`\n : S\n>;\n\n// KebabCase: same as snake but with \"-\"\ntype KebabCase<S extends string> = Lowercase<\n S extends `${infer A} ${infer B}`\n ? `${A}-${KebabCase<B>}`\n : S extends `${infer A}_${infer B}`\n ? `${A}-${KebabCase<B>}`\n : S\n>;\n\n// Flat: just strip spaces/underscores/hyphens\ntype RemoveDelimiters<S extends string> = S extends `${infer A} ${infer B}`\n ? `${A}${RemoveDelimiters<B>}`\n : S extends `${infer A}_${infer B}`\n ? `${A}${RemoveDelimiters<B>}`\n : S extends `${infer A}-${infer B}`\n ? `${A}${RemoveDelimiters<B>}`\n : S;\n\n// TitleCase: Capitalize the whole thing\ntype TitleCase<S extends string> = Capitalize<Lowercase<S>>;\n\n// SentenceCase: First word capped, rest lower\ntype SentenceCase<S extends string> = Capitalize<Lowercase<S>>;\nexport type ChangeCasing<\n S extends string,\n T extends CasingType\n> = T extends 'lower'\n ? Lowercase<S>\n : T extends 'upper'\n ? Uppercase<S>\n : T extends 'camel'\n ? Uncapitalize<Pascalize<S>>\n : T extends 'pascal'\n ? Pascalize<S>\n : T extends 'snake'\n ? SnakeCase<S>\n : T extends 'screaming-snake'\n ? Uppercase<SnakeCase<S>>\n : T extends 'kebab'\n ? KebabCase<S>\n : T extends 'flat'\n ? RemoveDelimiters<Lowercase<S>>\n : T extends 'title'\n ? TitleCase<S>\n : T extends 'sentence'\n ? SentenceCase<S>\n : S;\nexport type ChangeObjectCasing<\n T extends object,\n TCasing extends CasingType\n> = Expand<{\n [K in keyof T as K extends string ? ChangeCasing<K, TCasing> : K]: T[K];\n}>;\n\nexport const CASING_TYPES = [\n 'sentence',\n 'title',\n 'camel',\n 'lower',\n 'upper',\n 'pascal',\n 'snake',\n 'screaming-snake',\n 'flat',\n 'kebab',\n] as const;\n\nexport type DefaultCasing = typeof DEFAULT_CASING;\nexport const DEFAULT_CASING: SetDefaultString<CasingType, 'title'> = 'title';\n\n/**\n * Changes the casing of a string according to the specified casing type.\n *\n * @param input - The string to transform.\n * @param type - The casing type to apply.\n * @returns The transformed string in the specified casing.\n */\n// TODO make return type safe\nexport function changeCasing<TValue extends string, TType extends CasingType>(\n input: TValue,\n type: TType\n): ChangeCasing<TValue, TType>;\nexport function changeCasing<TValue extends string, TType extends CasingType>(\n input: TValue,\n type: TType\n) {\n // Step 1: Normalize to words\n const words = input\n // Replace camelCase boundaries with space\n .replace(/([a-z])([A-Z])/g, '$1 $2')\n // Replace separators with space\n .replace(/[-_]+/g, ' ')\n // Trim and split into words\n .trim()\n .split(/\\s+/)\n .map((w) => w.toLowerCase());\n\n // Step 2: Apply casing\n switch (type) {\n case 'sentence':\n return (\n words[0].charAt(0).toUpperCase() +\n words[0].slice(1) +\n (words.length > 1 ? ' ' + words.slice(1).join(' ') : '')\n );\n\n case 'title':\n return words.map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(' ');\n\n case 'camel':\n return (\n words[0] +\n words\n .slice(1)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1))\n .join('')\n );\n\n case 'pascal':\n return words.map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join('');\n\n case 'lower':\n return words.join(' ');\n\n case 'upper':\n return words.join(' ').toUpperCase();\n\n case 'snake':\n return words.join('_');\n\n case 'screaming-snake':\n return words.join('_').toUpperCase();\n\n case 'kebab':\n return words.join('-');\n\n case 'flat':\n return words.join('');\n\n default:\n return input;\n }\n}\n\nexport function quote(str: string, quoteChar: '\"' | \"'\" = '\"') {\n const startsWithQuote = str.startsWith(quoteChar);\n const endsWithQuote = str.endsWith(quoteChar);\n\n if (startsWithQuote && endsWithQuote) {\n // Already wrapped correctly\n return str;\n }\n\n // If it starts or ends with a quote but not both → strip those first\n const trimmed = str.replace(/^['\"]|['\"]$/g, '');\n\n // Then add new quotes consistently\n return `${quoteChar}${trimmed}${quoteChar}`;\n}\n\nexport function isCasingValid(value: unknown): value is CasingType {\n if (typeof value !== 'string') {\n return false;\n }\n\n const isValid = CASING_TYPES.includes(value as CasingType);\n\n // invariant(isValid, () => {\n // const formatter = new Intl.ListFormat('en', {\n // style: 'long',\n // type: 'conjunction',\n // });\n\n // return `${value} is not a valid casing type. Valid types include ${formatter.format(\n // CASING_TYPES.map((word) => quote(word))\n // )}`;\n // });\n\n return isValid;\n}\n\n/**\n * Validates {@linkcode input} is a valid {@linkcode CasingType}.\n *\n * If there is no explicit {@linkcode fallback} value provided,\n * it will default to {@linkcode DEFAULT_CASING}.\n * @param input The input to check.\n * @param fallback An optional fallback value if {@linkcode input} is `undefined`.\n * @returns The {@linkcode input} or {@linkcode fallback} if {@linkcode input} is `undefined` or an {@linkcode isCasingValid invalid} {@linkcode CasingType}.\n */\nexport function setCasingType<TCasing extends CasingType>(\n input: TCasing | undefined,\n fallback: CasingType = DEFAULT_CASING\n) {\n if (isCasingValid(input)) {\n return input;\n }\n\n return fallback;\n}\n"],"mappings":";;AA4EA,MAAa,eAAe;CAC1B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AAGD,MAAaA,iBAAwD;AAcrE,SAAgB,aACd,OACA,MACA;CAEA,MAAM,QAAQ,MAEX,QAAQ,mBAAmB,QAAQ,CAEnC,QAAQ,UAAU,IAAI,CAEtB,MAAM,CACN,MAAM,MAAM,CACZ,KAAK,MAAM,EAAE,aAAa,CAAC;AAG9B,SAAQ,MAAR;EACE,KAAK,WACH,QACE,MAAM,GAAG,OAAO,EAAE,CAAC,aAAa,GAChC,MAAM,GAAG,MAAM,EAAE,IAChB,MAAM,SAAS,IAAI,MAAM,MAAM,MAAM,EAAE,CAAC,KAAK,IAAI,GAAG;EAGzD,KAAK,QACH,QAAO,MAAM,KAAK,MAAM,EAAE,OAAO,EAAE,CAAC,aAAa,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,IAAI;EAE3E,KAAK,QACH,QACE,MAAM,KACN,MACG,MAAM,EAAE,CACR,KAAK,MAAM,EAAE,OAAO,EAAE,CAAC,aAAa,GAAG,EAAE,MAAM,EAAE,CAAC,CAClD,KAAK,GAAG;EAGf,KAAK,SACH,QAAO,MAAM,KAAK,MAAM,EAAE,OAAO,EAAE,CAAC,aAAa,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,GAAG;EAE1E,KAAK,QACH,QAAO,MAAM,KAAK,IAAI;EAExB,KAAK,QACH,QAAO,MAAM,KAAK,IAAI,CAAC,aAAa;EAEtC,KAAK,QACH,QAAO,MAAM,KAAK,IAAI;EAExB,KAAK,kBACH,QAAO,MAAM,KAAK,IAAI,CAAC,aAAa;EAEtC,KAAK,QACH,QAAO,MAAM,KAAK,IAAI;EAExB,KAAK,OACH,QAAO,MAAM,KAAK,GAAG;EAEvB,QACE,QAAO;;;AAIb,SAAgB,MAAM,KAAa,YAAuB,MAAK;CAC7D,MAAM,kBAAkB,IAAI,WAAW,UAAU;CACjD,MAAM,gBAAgB,IAAI,SAAS,UAAU;AAE7C,KAAI,mBAAmB,cAErB,QAAO;AAOT,QAAO,GAAG,YAHM,IAAI,QAAQ,gBAAgB,GAAG,GAGf;;AAGlC,SAAgB,cAAc,OAAqC;AACjE,KAAI,OAAO,UAAU,SACnB,QAAO;AAgBT,QAbgB,aAAa,SAAS,MAAoB;;;;;;;;;;;AAyB5D,SAAgB,cACd,OACA,WAAuB,gBACvB;AACA,KAAI,cAAc,MAAM,CACtB,QAAO;AAGT,QAAO"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Expand, SetDefaultString } from "./types.cjs";
|
|
2
|
+
|
|
3
|
+
//#region src/utils/casing.d.ts
|
|
4
|
+
type CasingType = (typeof CASING_TYPES)[number];
|
|
5
|
+
type ToLower<S extends string> = S extends `${infer F}${infer R}` ? `${Lowercase<F>}${ToLower<R>}` : S;
|
|
6
|
+
type CapitalizeWord<S extends string> = S extends `${infer F}${infer R}` ? `${Uppercase<F>}${ToLower<R>}` : S;
|
|
7
|
+
type Pascalize<S extends string> = Capitalize<S>;
|
|
8
|
+
type SnakeCase<S extends string> = Lowercase<S extends `${infer A} ${infer B}` ? `${A}_${SnakeCase<B>}` : S extends `${infer A}-${infer B}` ? `${A}_${SnakeCase<B>}` : S>;
|
|
9
|
+
type KebabCase<S extends string> = Lowercase<S extends `${infer A} ${infer B}` ? `${A}-${KebabCase<B>}` : S extends `${infer A}_${infer B}` ? `${A}-${KebabCase<B>}` : S>;
|
|
10
|
+
type RemoveDelimiters<S extends string> = S extends `${infer A} ${infer B}` ? `${A}${RemoveDelimiters<B>}` : S extends `${infer A}_${infer B}` ? `${A}${RemoveDelimiters<B>}` : S extends `${infer A}-${infer B}` ? `${A}${RemoveDelimiters<B>}` : S;
|
|
11
|
+
type TitleCase<S extends string> = Capitalize<Lowercase<S>>;
|
|
12
|
+
type SentenceCase<S extends string> = Capitalize<Lowercase<S>>;
|
|
13
|
+
type ChangeCasing<S extends string, T extends CasingType> = T extends 'lower' ? Lowercase<S> : T extends 'upper' ? Uppercase<S> : T extends 'camel' ? Uncapitalize<Pascalize<S>> : T extends 'pascal' ? Pascalize<S> : T extends 'snake' ? SnakeCase<S> : T extends 'screaming-snake' ? Uppercase<SnakeCase<S>> : T extends 'kebab' ? KebabCase<S> : T extends 'flat' ? RemoveDelimiters<Lowercase<S>> : T extends 'title' ? TitleCase<S> : T extends 'sentence' ? SentenceCase<S> : S;
|
|
14
|
+
type ChangeObjectCasing<T extends object, TCasing extends CasingType> = Expand<{ [K in keyof T as K extends string ? ChangeCasing<K, TCasing> : K]: T[K] }>;
|
|
15
|
+
declare const CASING_TYPES: readonly ["sentence", "title", "camel", "lower", "upper", "pascal", "snake", "screaming-snake", "flat", "kebab"];
|
|
16
|
+
type DefaultCasing = typeof DEFAULT_CASING;
|
|
17
|
+
declare const DEFAULT_CASING: SetDefaultString<CasingType, 'title'>;
|
|
18
|
+
/**
|
|
19
|
+
* Changes the casing of a string according to the specified casing type.
|
|
20
|
+
*
|
|
21
|
+
* @param input - The string to transform.
|
|
22
|
+
* @param type - The casing type to apply.
|
|
23
|
+
* @returns The transformed string in the specified casing.
|
|
24
|
+
*/
|
|
25
|
+
declare function changeCasing<TValue extends string, TType extends CasingType>(input: TValue, type: TType): ChangeCasing<TValue, TType>;
|
|
26
|
+
declare function quote(str: string, quoteChar?: '"' | "'"): string;
|
|
27
|
+
declare function isCasingValid(value: unknown): value is CasingType;
|
|
28
|
+
/**
|
|
29
|
+
* Validates {@linkcode input} is a valid {@linkcode CasingType}.
|
|
30
|
+
*
|
|
31
|
+
* If there is no explicit {@linkcode fallback} value provided,
|
|
32
|
+
* it will default to {@linkcode DEFAULT_CASING}.
|
|
33
|
+
* @param input The input to check.
|
|
34
|
+
* @param fallback An optional fallback value if {@linkcode input} is `undefined`.
|
|
35
|
+
* @returns The {@linkcode input} or {@linkcode fallback} if {@linkcode input} is `undefined` or an {@linkcode isCasingValid invalid} {@linkcode CasingType}.
|
|
36
|
+
*/
|
|
37
|
+
declare function setCasingType<TCasing extends CasingType>(input: TCasing | undefined, fallback?: CasingType): "sentence" | "title" | "camel" | "lower" | "upper" | "pascal" | "snake" | "screaming-snake" | "flat" | "kebab";
|
|
38
|
+
//#endregion
|
|
39
|
+
export { CASING_TYPES, CapitalizeWord, CasingType, ChangeCasing, ChangeObjectCasing, DEFAULT_CASING, DefaultCasing, ToLower, changeCasing, isCasingValid, quote, setCasingType };
|
|
40
|
+
//# sourceMappingURL=casing.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"casing.d.cts","names":[],"sources":["../../src/utils/casing.ts"],"sourcesContent":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Expand, SetDefaultString } from "./types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/utils/casing.d.ts
|
|
4
|
+
type CasingType = (typeof CASING_TYPES)[number];
|
|
5
|
+
type ToLower<S extends string> = S extends `${infer F}${infer R}` ? `${Lowercase<F>}${ToLower<R>}` : S;
|
|
6
|
+
type CapitalizeWord<S extends string> = S extends `${infer F}${infer R}` ? `${Uppercase<F>}${ToLower<R>}` : S;
|
|
7
|
+
type Pascalize<S extends string> = Capitalize<S>;
|
|
8
|
+
type SnakeCase<S extends string> = Lowercase<S extends `${infer A} ${infer B}` ? `${A}_${SnakeCase<B>}` : S extends `${infer A}-${infer B}` ? `${A}_${SnakeCase<B>}` : S>;
|
|
9
|
+
type KebabCase<S extends string> = Lowercase<S extends `${infer A} ${infer B}` ? `${A}-${KebabCase<B>}` : S extends `${infer A}_${infer B}` ? `${A}-${KebabCase<B>}` : S>;
|
|
10
|
+
type RemoveDelimiters<S extends string> = S extends `${infer A} ${infer B}` ? `${A}${RemoveDelimiters<B>}` : S extends `${infer A}_${infer B}` ? `${A}${RemoveDelimiters<B>}` : S extends `${infer A}-${infer B}` ? `${A}${RemoveDelimiters<B>}` : S;
|
|
11
|
+
type TitleCase<S extends string> = Capitalize<Lowercase<S>>;
|
|
12
|
+
type SentenceCase<S extends string> = Capitalize<Lowercase<S>>;
|
|
13
|
+
type ChangeCasing<S extends string, T extends CasingType> = T extends 'lower' ? Lowercase<S> : T extends 'upper' ? Uppercase<S> : T extends 'camel' ? Uncapitalize<Pascalize<S>> : T extends 'pascal' ? Pascalize<S> : T extends 'snake' ? SnakeCase<S> : T extends 'screaming-snake' ? Uppercase<SnakeCase<S>> : T extends 'kebab' ? KebabCase<S> : T extends 'flat' ? RemoveDelimiters<Lowercase<S>> : T extends 'title' ? TitleCase<S> : T extends 'sentence' ? SentenceCase<S> : S;
|
|
14
|
+
type ChangeObjectCasing<T extends object, TCasing extends CasingType> = Expand<{ [K in keyof T as K extends string ? ChangeCasing<K, TCasing> : K]: T[K] }>;
|
|
15
|
+
declare const CASING_TYPES: readonly ["sentence", "title", "camel", "lower", "upper", "pascal", "snake", "screaming-snake", "flat", "kebab"];
|
|
16
|
+
type DefaultCasing = typeof DEFAULT_CASING;
|
|
17
|
+
declare const DEFAULT_CASING: SetDefaultString<CasingType, 'title'>;
|
|
18
|
+
/**
|
|
19
|
+
* Changes the casing of a string according to the specified casing type.
|
|
20
|
+
*
|
|
21
|
+
* @param input - The string to transform.
|
|
22
|
+
* @param type - The casing type to apply.
|
|
23
|
+
* @returns The transformed string in the specified casing.
|
|
24
|
+
*/
|
|
25
|
+
declare function changeCasing<TValue extends string, TType extends CasingType>(input: TValue, type: TType): ChangeCasing<TValue, TType>;
|
|
26
|
+
declare function quote(str: string, quoteChar?: '"' | "'"): string;
|
|
27
|
+
declare function isCasingValid(value: unknown): value is CasingType;
|
|
28
|
+
/**
|
|
29
|
+
* Validates {@linkcode input} is a valid {@linkcode CasingType}.
|
|
30
|
+
*
|
|
31
|
+
* If there is no explicit {@linkcode fallback} value provided,
|
|
32
|
+
* it will default to {@linkcode DEFAULT_CASING}.
|
|
33
|
+
* @param input The input to check.
|
|
34
|
+
* @param fallback An optional fallback value if {@linkcode input} is `undefined`.
|
|
35
|
+
* @returns The {@linkcode input} or {@linkcode fallback} if {@linkcode input} is `undefined` or an {@linkcode isCasingValid invalid} {@linkcode CasingType}.
|
|
36
|
+
*/
|
|
37
|
+
declare function setCasingType<TCasing extends CasingType>(input: TCasing | undefined, fallback?: CasingType): "sentence" | "title" | "camel" | "lower" | "upper" | "pascal" | "snake" | "screaming-snake" | "flat" | "kebab";
|
|
38
|
+
//#endregion
|
|
39
|
+
export { CASING_TYPES, CapitalizeWord, CasingType, ChangeCasing, ChangeObjectCasing, DEFAULT_CASING, DefaultCasing, ToLower, changeCasing, isCasingValid, quote, setCasingType };
|
|
40
|
+
//# sourceMappingURL=casing.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"casing.d.mts","names":[],"sources":["../../src/utils/casing.ts"],"sourcesContent":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
//#region src/utils/casing.ts
|
|
2
|
+
const CASING_TYPES = [
|
|
3
|
+
"sentence",
|
|
4
|
+
"title",
|
|
5
|
+
"camel",
|
|
6
|
+
"lower",
|
|
7
|
+
"upper",
|
|
8
|
+
"pascal",
|
|
9
|
+
"snake",
|
|
10
|
+
"screaming-snake",
|
|
11
|
+
"flat",
|
|
12
|
+
"kebab"
|
|
13
|
+
];
|
|
14
|
+
const DEFAULT_CASING = "title";
|
|
15
|
+
function changeCasing(input, type) {
|
|
16
|
+
const words = input.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[-_]+/g, " ").trim().split(/\s+/).map((w) => w.toLowerCase());
|
|
17
|
+
switch (type) {
|
|
18
|
+
case "sentence": return words[0].charAt(0).toUpperCase() + words[0].slice(1) + (words.length > 1 ? " " + words.slice(1).join(" ") : "");
|
|
19
|
+
case "title": return words.map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
20
|
+
case "camel": return words[0] + words.slice(1).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join("");
|
|
21
|
+
case "pascal": return words.map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join("");
|
|
22
|
+
case "lower": return words.join(" ");
|
|
23
|
+
case "upper": return words.join(" ").toUpperCase();
|
|
24
|
+
case "snake": return words.join("_");
|
|
25
|
+
case "screaming-snake": return words.join("_").toUpperCase();
|
|
26
|
+
case "kebab": return words.join("-");
|
|
27
|
+
case "flat": return words.join("");
|
|
28
|
+
default: return input;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function quote(str, quoteChar = "\"") {
|
|
32
|
+
const startsWithQuote = str.startsWith(quoteChar);
|
|
33
|
+
const endsWithQuote = str.endsWith(quoteChar);
|
|
34
|
+
if (startsWithQuote && endsWithQuote) return str;
|
|
35
|
+
return `${quoteChar}${str.replace(/^['"]|['"]$/g, "")}${quoteChar}`;
|
|
36
|
+
}
|
|
37
|
+
function isCasingValid(value) {
|
|
38
|
+
if (typeof value !== "string") return false;
|
|
39
|
+
return CASING_TYPES.includes(value);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Validates {@linkcode input} is a valid {@linkcode CasingType}.
|
|
43
|
+
*
|
|
44
|
+
* If there is no explicit {@linkcode fallback} value provided,
|
|
45
|
+
* it will default to {@linkcode DEFAULT_CASING}.
|
|
46
|
+
* @param input The input to check.
|
|
47
|
+
* @param fallback An optional fallback value if {@linkcode input} is `undefined`.
|
|
48
|
+
* @returns The {@linkcode input} or {@linkcode fallback} if {@linkcode input} is `undefined` or an {@linkcode isCasingValid invalid} {@linkcode CasingType}.
|
|
49
|
+
*/
|
|
50
|
+
function setCasingType(input, fallback = DEFAULT_CASING) {
|
|
51
|
+
if (isCasingValid(input)) return input;
|
|
52
|
+
return fallback;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
//#endregion
|
|
56
|
+
export { CASING_TYPES, DEFAULT_CASING, changeCasing, isCasingValid, quote, setCasingType };
|
|
57
|
+
//# sourceMappingURL=casing.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"casing.mjs","names":["DEFAULT_CASING: SetDefaultString<CasingType, 'title'>"],"sources":["../../src/utils/casing.ts"],"sourcesContent":["import type { Expand, SetDefaultString } from './types';\n\nexport type CasingType = (typeof CASING_TYPES)[number];\nexport type ToLower<S extends string> = S extends `${infer F}${infer R}`\n ? `${Lowercase<F>}${ToLower<R>}`\n : S;\n\nexport type CapitalizeWord<S extends string> = S extends `${infer F}${infer R}`\n ? `${Uppercase<F>}${ToLower<R>}`\n : S;\n// Pascal => Capitalize each \"word\" chunk\ntype Pascalize<S extends string> = Capitalize<S>; // naive\n\n// SnakeCase: turn spaces/hyphens into underscores, lowercase\ntype SnakeCase<S extends string> = Lowercase<\n S extends `${infer A} ${infer B}`\n ? `${A}_${SnakeCase<B>}`\n : S extends `${infer A}-${infer B}`\n ? `${A}_${SnakeCase<B>}`\n : S\n>;\n\n// KebabCase: same as snake but with \"-\"\ntype KebabCase<S extends string> = Lowercase<\n S extends `${infer A} ${infer B}`\n ? `${A}-${KebabCase<B>}`\n : S extends `${infer A}_${infer B}`\n ? `${A}-${KebabCase<B>}`\n : S\n>;\n\n// Flat: just strip spaces/underscores/hyphens\ntype RemoveDelimiters<S extends string> = S extends `${infer A} ${infer B}`\n ? `${A}${RemoveDelimiters<B>}`\n : S extends `${infer A}_${infer B}`\n ? `${A}${RemoveDelimiters<B>}`\n : S extends `${infer A}-${infer B}`\n ? `${A}${RemoveDelimiters<B>}`\n : S;\n\n// TitleCase: Capitalize the whole thing\ntype TitleCase<S extends string> = Capitalize<Lowercase<S>>;\n\n// SentenceCase: First word capped, rest lower\ntype SentenceCase<S extends string> = Capitalize<Lowercase<S>>;\nexport type ChangeCasing<\n S extends string,\n T extends CasingType\n> = T extends 'lower'\n ? Lowercase<S>\n : T extends 'upper'\n ? Uppercase<S>\n : T extends 'camel'\n ? Uncapitalize<Pascalize<S>>\n : T extends 'pascal'\n ? Pascalize<S>\n : T extends 'snake'\n ? SnakeCase<S>\n : T extends 'screaming-snake'\n ? Uppercase<SnakeCase<S>>\n : T extends 'kebab'\n ? KebabCase<S>\n : T extends 'flat'\n ? RemoveDelimiters<Lowercase<S>>\n : T extends 'title'\n ? TitleCase<S>\n : T extends 'sentence'\n ? SentenceCase<S>\n : S;\nexport type ChangeObjectCasing<\n T extends object,\n TCasing extends CasingType\n> = Expand<{\n [K in keyof T as K extends string ? ChangeCasing<K, TCasing> : K]: T[K];\n}>;\n\nexport const CASING_TYPES = [\n 'sentence',\n 'title',\n 'camel',\n 'lower',\n 'upper',\n 'pascal',\n 'snake',\n 'screaming-snake',\n 'flat',\n 'kebab',\n] as const;\n\nexport type DefaultCasing = typeof DEFAULT_CASING;\nexport const DEFAULT_CASING: SetDefaultString<CasingType, 'title'> = 'title';\n\n/**\n * Changes the casing of a string according to the specified casing type.\n *\n * @param input - The string to transform.\n * @param type - The casing type to apply.\n * @returns The transformed string in the specified casing.\n */\n// TODO make return type safe\nexport function changeCasing<TValue extends string, TType extends CasingType>(\n input: TValue,\n type: TType\n): ChangeCasing<TValue, TType>;\nexport function changeCasing<TValue extends string, TType extends CasingType>(\n input: TValue,\n type: TType\n) {\n // Step 1: Normalize to words\n const words = input\n // Replace camelCase boundaries with space\n .replace(/([a-z])([A-Z])/g, '$1 $2')\n // Replace separators with space\n .replace(/[-_]+/g, ' ')\n // Trim and split into words\n .trim()\n .split(/\\s+/)\n .map((w) => w.toLowerCase());\n\n // Step 2: Apply casing\n switch (type) {\n case 'sentence':\n return (\n words[0].charAt(0).toUpperCase() +\n words[0].slice(1) +\n (words.length > 1 ? ' ' + words.slice(1).join(' ') : '')\n );\n\n case 'title':\n return words.map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(' ');\n\n case 'camel':\n return (\n words[0] +\n words\n .slice(1)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1))\n .join('')\n );\n\n case 'pascal':\n return words.map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join('');\n\n case 'lower':\n return words.join(' ');\n\n case 'upper':\n return words.join(' ').toUpperCase();\n\n case 'snake':\n return words.join('_');\n\n case 'screaming-snake':\n return words.join('_').toUpperCase();\n\n case 'kebab':\n return words.join('-');\n\n case 'flat':\n return words.join('');\n\n default:\n return input;\n }\n}\n\nexport function quote(str: string, quoteChar: '\"' | \"'\" = '\"') {\n const startsWithQuote = str.startsWith(quoteChar);\n const endsWithQuote = str.endsWith(quoteChar);\n\n if (startsWithQuote && endsWithQuote) {\n // Already wrapped correctly\n return str;\n }\n\n // If it starts or ends with a quote but not both → strip those first\n const trimmed = str.replace(/^['\"]|['\"]$/g, '');\n\n // Then add new quotes consistently\n return `${quoteChar}${trimmed}${quoteChar}`;\n}\n\nexport function isCasingValid(value: unknown): value is CasingType {\n if (typeof value !== 'string') {\n return false;\n }\n\n const isValid = CASING_TYPES.includes(value as CasingType);\n\n // invariant(isValid, () => {\n // const formatter = new Intl.ListFormat('en', {\n // style: 'long',\n // type: 'conjunction',\n // });\n\n // return `${value} is not a valid casing type. Valid types include ${formatter.format(\n // CASING_TYPES.map((word) => quote(word))\n // )}`;\n // });\n\n return isValid;\n}\n\n/**\n * Validates {@linkcode input} is a valid {@linkcode CasingType}.\n *\n * If there is no explicit {@linkcode fallback} value provided,\n * it will default to {@linkcode DEFAULT_CASING}.\n * @param input The input to check.\n * @param fallback An optional fallback value if {@linkcode input} is `undefined`.\n * @returns The {@linkcode input} or {@linkcode fallback} if {@linkcode input} is `undefined` or an {@linkcode isCasingValid invalid} {@linkcode CasingType}.\n */\nexport function setCasingType<TCasing extends CasingType>(\n input: TCasing | undefined,\n fallback: CasingType = DEFAULT_CASING\n) {\n if (isCasingValid(input)) {\n return input;\n }\n\n return fallback;\n}\n"],"mappings":";AA4EA,MAAa,eAAe;CAC1B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AAGD,MAAaA,iBAAwD;AAcrE,SAAgB,aACd,OACA,MACA;CAEA,MAAM,QAAQ,MAEX,QAAQ,mBAAmB,QAAQ,CAEnC,QAAQ,UAAU,IAAI,CAEtB,MAAM,CACN,MAAM,MAAM,CACZ,KAAK,MAAM,EAAE,aAAa,CAAC;AAG9B,SAAQ,MAAR;EACE,KAAK,WACH,QACE,MAAM,GAAG,OAAO,EAAE,CAAC,aAAa,GAChC,MAAM,GAAG,MAAM,EAAE,IAChB,MAAM,SAAS,IAAI,MAAM,MAAM,MAAM,EAAE,CAAC,KAAK,IAAI,GAAG;EAGzD,KAAK,QACH,QAAO,MAAM,KAAK,MAAM,EAAE,OAAO,EAAE,CAAC,aAAa,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,IAAI;EAE3E,KAAK,QACH,QACE,MAAM,KACN,MACG,MAAM,EAAE,CACR,KAAK,MAAM,EAAE,OAAO,EAAE,CAAC,aAAa,GAAG,EAAE,MAAM,EAAE,CAAC,CAClD,KAAK,GAAG;EAGf,KAAK,SACH,QAAO,MAAM,KAAK,MAAM,EAAE,OAAO,EAAE,CAAC,aAAa,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,GAAG;EAE1E,KAAK,QACH,QAAO,MAAM,KAAK,IAAI;EAExB,KAAK,QACH,QAAO,MAAM,KAAK,IAAI,CAAC,aAAa;EAEtC,KAAK,QACH,QAAO,MAAM,KAAK,IAAI;EAExB,KAAK,kBACH,QAAO,MAAM,KAAK,IAAI,CAAC,aAAa;EAEtC,KAAK,QACH,QAAO,MAAM,KAAK,IAAI;EAExB,KAAK,OACH,QAAO,MAAM,KAAK,GAAG;EAEvB,QACE,QAAO;;;AAIb,SAAgB,MAAM,KAAa,YAAuB,MAAK;CAC7D,MAAM,kBAAkB,IAAI,WAAW,UAAU;CACjD,MAAM,gBAAgB,IAAI,SAAS,UAAU;AAE7C,KAAI,mBAAmB,cAErB,QAAO;AAOT,QAAO,GAAG,YAHM,IAAI,QAAQ,gBAAgB,GAAG,GAGf;;AAGlC,SAAgB,cAAc,OAAqC;AACjE,KAAI,OAAO,UAAU,SACnB,QAAO;AAgBT,QAbgB,aAAa,SAAS,MAAoB;;;;;;;;;;;AAyB5D,SAAgB,cACd,OACA,WAAuB,gBACvB;AACA,KAAI,cAAc,MAAM,CACtB,QAAO;AAGT,QAAO"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/utils/field-types.ts
|
|
3
|
+
const FIELD_TYPES = [
|
|
4
|
+
"string",
|
|
5
|
+
"string.phone",
|
|
6
|
+
"string.email",
|
|
7
|
+
"string.time",
|
|
8
|
+
"number",
|
|
9
|
+
"number.counter",
|
|
10
|
+
"date",
|
|
11
|
+
"dateTime",
|
|
12
|
+
"boolean.switch"
|
|
13
|
+
];
|
|
14
|
+
const DEFAULT_FIELD_TYPE = "string";
|
|
15
|
+
function isFieldType(value) {
|
|
16
|
+
return typeof value === "string" && FIELD_TYPES.includes(value);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
//#endregion
|
|
20
|
+
exports.DEFAULT_FIELD_TYPE = DEFAULT_FIELD_TYPE;
|
|
21
|
+
exports.FIELD_TYPES = FIELD_TYPES;
|
|
22
|
+
exports.isFieldType = isFieldType;
|
|
23
|
+
//# sourceMappingURL=field-types.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"field-types.cjs","names":["DEFAULT_FIELD_TYPE: SetDefaultString<FieldType, 'string'>"],"sources":["../../src/utils/field-types.ts"],"sourcesContent":["import type { SetDefaultString } from './types';\n\nexport type FieldType = (typeof FIELD_TYPES)[number];\nexport type DefaultFieldType = typeof DEFAULT_FIELD_TYPE;\nexport const FIELD_TYPES = [\n 'string',\n 'string.phone',\n 'string.email',\n 'string.time',\n 'number',\n 'number.counter',\n 'date',\n 'dateTime',\n 'boolean.switch',\n] as const;\nexport const DEFAULT_FIELD_TYPE: SetDefaultString<FieldType, 'string'> =\n 'string';\n\nexport function isFieldType(value: unknown): value is FieldType {\n return typeof value === 'string' && FIELD_TYPES.includes(value as FieldType);\n}\n"],"mappings":";;AAIA,MAAa,cAAc;CACzB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AACD,MAAaA,qBACX;AAEF,SAAgB,YAAY,OAAoC;AAC9D,QAAO,OAAO,UAAU,YAAY,YAAY,SAAS,MAAmB"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { SetDefaultString } from "./types.cjs";
|
|
2
|
+
|
|
3
|
+
//#region src/utils/field-types.d.ts
|
|
4
|
+
type FieldType = (typeof FIELD_TYPES)[number];
|
|
5
|
+
type DefaultFieldType = typeof DEFAULT_FIELD_TYPE;
|
|
6
|
+
declare const FIELD_TYPES: readonly ["string", "string.phone", "string.email", "string.time", "number", "number.counter", "date", "dateTime", "boolean.switch"];
|
|
7
|
+
declare const DEFAULT_FIELD_TYPE: SetDefaultString<FieldType, 'string'>;
|
|
8
|
+
declare function isFieldType(value: unknown): value is FieldType;
|
|
9
|
+
//#endregion
|
|
10
|
+
export { DEFAULT_FIELD_TYPE, DefaultFieldType, FIELD_TYPES, FieldType, isFieldType };
|
|
11
|
+
//# sourceMappingURL=field-types.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"field-types.d.cts","names":[],"sources":["../../src/utils/field-types.ts"],"sourcesContent":[],"mappings":";;;KAEY,SAAA,WAAoB;KACpB,gBAAA,UAA0B;AAD1B,cAEC,WAFmB,EAAA,SAAW,CAAA,QAAA,EAAA,cAAA,EAAA,cAAA,EAAA,aAAA,EAAA,QAAA,EAAA,gBAAA,EAAA,MAAA,EAAA,UAAA,EAAA,gBAAA,CAAA;AAC/B,cAYC,kBAZyB,EAYL,gBAZuB,CAYN,SAZM,EAAA,QAAA,CAAA;AAC3C,iBAcG,WAAA,CAJN,KAAA,EAAA,OAAA,CAAA,EAAA,KAAA,IAI4C,SAJ5C"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { SetDefaultString } from "./types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/utils/field-types.d.ts
|
|
4
|
+
type FieldType = (typeof FIELD_TYPES)[number];
|
|
5
|
+
type DefaultFieldType = typeof DEFAULT_FIELD_TYPE;
|
|
6
|
+
declare const FIELD_TYPES: readonly ["string", "string.phone", "string.email", "string.time", "number", "number.counter", "date", "dateTime", "boolean.switch"];
|
|
7
|
+
declare const DEFAULT_FIELD_TYPE: SetDefaultString<FieldType, 'string'>;
|
|
8
|
+
declare function isFieldType(value: unknown): value is FieldType;
|
|
9
|
+
//#endregion
|
|
10
|
+
export { DEFAULT_FIELD_TYPE, DefaultFieldType, FIELD_TYPES, FieldType, isFieldType };
|
|
11
|
+
//# sourceMappingURL=field-types.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"field-types.d.mts","names":[],"sources":["../../src/utils/field-types.ts"],"sourcesContent":[],"mappings":";;;KAEY,SAAA,WAAoB;KACpB,gBAAA,UAA0B;AAD1B,cAEC,WAFmB,EAAA,SAAW,CAAA,QAAA,EAAA,cAAA,EAAA,cAAA,EAAA,aAAA,EAAA,QAAA,EAAA,gBAAA,EAAA,MAAA,EAAA,UAAA,EAAA,gBAAA,CAAA;AAC/B,cAYC,kBAZyB,EAYL,gBAZuB,CAYN,SAZM,EAAA,QAAA,CAAA;AAC3C,iBAcG,WAAA,CAJN,KAAA,EAAA,OAAA,CAAA,EAAA,KAAA,IAI4C,SAJ5C"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
//#region src/utils/field-types.ts
|
|
2
|
+
const FIELD_TYPES = [
|
|
3
|
+
"string",
|
|
4
|
+
"string.phone",
|
|
5
|
+
"string.email",
|
|
6
|
+
"string.time",
|
|
7
|
+
"number",
|
|
8
|
+
"number.counter",
|
|
9
|
+
"date",
|
|
10
|
+
"dateTime",
|
|
11
|
+
"boolean.switch"
|
|
12
|
+
];
|
|
13
|
+
const DEFAULT_FIELD_TYPE = "string";
|
|
14
|
+
function isFieldType(value) {
|
|
15
|
+
return typeof value === "string" && FIELD_TYPES.includes(value);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
//#endregion
|
|
19
|
+
export { DEFAULT_FIELD_TYPE, FIELD_TYPES, isFieldType };
|
|
20
|
+
//# sourceMappingURL=field-types.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"field-types.mjs","names":["DEFAULT_FIELD_TYPE: SetDefaultString<FieldType, 'string'>"],"sources":["../../src/utils/field-types.ts"],"sourcesContent":["import type { SetDefaultString } from './types';\n\nexport type FieldType = (typeof FIELD_TYPES)[number];\nexport type DefaultFieldType = typeof DEFAULT_FIELD_TYPE;\nexport const FIELD_TYPES = [\n 'string',\n 'string.phone',\n 'string.email',\n 'string.time',\n 'number',\n 'number.counter',\n 'date',\n 'dateTime',\n 'boolean.switch',\n] as const;\nexport const DEFAULT_FIELD_TYPE: SetDefaultString<FieldType, 'string'> =\n 'string';\n\nexport function isFieldType(value: unknown): value is FieldType {\n return typeof value === 'string' && FIELD_TYPES.includes(value as FieldType);\n}\n"],"mappings":";AAIA,MAAa,cAAc;CACzB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AACD,MAAaA,qBACX;AAEF,SAAgB,YAAY,OAAoC;AAC9D,QAAO,OAAO,UAAU,YAAY,YAAY,SAAS,MAAmB"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/utils/helpers.ts
|
|
3
|
+
function comparePartialArray(compareArray, actualArray, formatter) {
|
|
4
|
+
const errors = [];
|
|
5
|
+
const compareSet = new Set(compareArray);
|
|
6
|
+
const printedArray = formatter ? formatter.format(compareArray.map((value) => `${value}`)) : `[${compareArray.join(", ")}]`;
|
|
7
|
+
for (let i = 0; i < actualArray.length; i++) {
|
|
8
|
+
const value = actualArray[i];
|
|
9
|
+
if (!compareSet.has(value)) errors.push(`Extra element at index ${i}: "${value}" is not in ${printedArray}`);
|
|
10
|
+
}
|
|
11
|
+
if (!actualArray.some((v) => compareSet.has(v))) errors.push(`Array must contain at least one valid element from ${printedArray}`);
|
|
12
|
+
if (errors.length > 0) return {
|
|
13
|
+
status: "error",
|
|
14
|
+
errors
|
|
15
|
+
};
|
|
16
|
+
return { status: "success" };
|
|
17
|
+
}
|
|
18
|
+
function printErrors(errors, mapper) {
|
|
19
|
+
const defaultMapper = (e, i) => `❌ ${i + 1}. ${e}`;
|
|
20
|
+
return errors.map((e, i) => mapper?.(e, i) ?? defaultMapper(e, i)).join("\n");
|
|
21
|
+
}
|
|
22
|
+
function typedObjectKeys(value) {
|
|
23
|
+
return Object.keys(value);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
//#endregion
|
|
27
|
+
exports.comparePartialArray = comparePartialArray;
|
|
28
|
+
exports.printErrors = printErrors;
|
|
29
|
+
exports.typedObjectKeys = typedObjectKeys;
|
|
30
|
+
//# sourceMappingURL=helpers.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.cjs","names":["errors: string[]"],"sources":["../../src/utils/helpers.ts"],"sourcesContent":["export function comparePartialArray<T>(\n compareArray: T[],\n actualArray: T[],\n formatter?: Intl.ListFormat\n): { status: 'success' } | { status: 'error'; errors: string[] } {\n const errors: string[] = [];\n const compareSet = new Set(compareArray);\n const printedArray = formatter\n ? formatter.format(compareArray.map((value) => `${value}`))\n : `[${compareArray.join(', ')}]`;\n\n // Check extras: elements in b that aren't in a\n for (let i = 0; i < actualArray.length; i++) {\n const value = actualArray[i];\n if (!compareSet.has(value)) {\n errors.push(\n `Extra element at index ${i}: \"${value}\" is not in ${printedArray}`\n );\n }\n }\n\n // Check that at least one element from a is present in b\n const hasAtLeastOne = actualArray.some((v) => compareSet.has(v));\n if (!hasAtLeastOne) {\n errors.push(\n `Array must contain at least one valid element from ${printedArray}`\n );\n }\n\n if (errors.length > 0) {\n return { status: 'error', errors };\n }\n\n return { status: 'success' };\n}\n\nexport function printErrors<T>(\n errors: T[],\n mapper?: (value: T, index: number) => string\n) {\n const defaultMapper = (e: unknown, i: number) => `❌ ${i + 1}. ${e}`;\n return errors.map((e, i) => mapper?.(e, i) ?? defaultMapper(e, i)).join('\\n');\n}\n\nexport function typedObjectKeys<T extends Record<string, unknown>, TOverrideKey = keyof T>(value: T) {\n return Object.keys(value) as Array<TOverrideKey>;\n}\n"],"mappings":";;AAAA,SAAgB,oBACd,cACA,aACA,WAC+D;CAC/D,MAAMA,SAAmB,EAAE;CAC3B,MAAM,aAAa,IAAI,IAAI,aAAa;CACxC,MAAM,eAAe,YACjB,UAAU,OAAO,aAAa,KAAK,UAAU,GAAG,QAAQ,CAAC,GACzD,IAAI,aAAa,KAAK,KAAK,CAAC;AAGhC,MAAK,IAAI,IAAI,GAAG,IAAI,YAAY,QAAQ,KAAK;EAC3C,MAAM,QAAQ,YAAY;AAC1B,MAAI,CAAC,WAAW,IAAI,MAAM,CACxB,QAAO,KACL,0BAA0B,EAAE,KAAK,MAAM,cAAc,eACtD;;AAML,KAAI,CADkB,YAAY,MAAM,MAAM,WAAW,IAAI,EAAE,CAAC,CAE9D,QAAO,KACL,sDAAsD,eACvD;AAGH,KAAI,OAAO,SAAS,EAClB,QAAO;EAAE,QAAQ;EAAS;EAAQ;AAGpC,QAAO,EAAE,QAAQ,WAAW;;AAG9B,SAAgB,YACd,QACA,QACA;CACA,MAAM,iBAAiB,GAAY,MAAc,KAAK,IAAI,EAAE,IAAI;AAChE,QAAO,OAAO,KAAK,GAAG,MAAM,SAAS,GAAG,EAAE,IAAI,cAAc,GAAG,EAAE,CAAC,CAAC,KAAK,KAAK;;AAG/E,SAAgB,gBAA2E,OAAU;AACnG,QAAO,OAAO,KAAK,MAAM"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
//#region src/utils/helpers.ts
|
|
2
|
+
function comparePartialArray(compareArray, actualArray, formatter) {
|
|
3
|
+
const errors = [];
|
|
4
|
+
const compareSet = new Set(compareArray);
|
|
5
|
+
const printedArray = formatter ? formatter.format(compareArray.map((value) => `${value}`)) : `[${compareArray.join(", ")}]`;
|
|
6
|
+
for (let i = 0; i < actualArray.length; i++) {
|
|
7
|
+
const value = actualArray[i];
|
|
8
|
+
if (!compareSet.has(value)) errors.push(`Extra element at index ${i}: "${value}" is not in ${printedArray}`);
|
|
9
|
+
}
|
|
10
|
+
if (!actualArray.some((v) => compareSet.has(v))) errors.push(`Array must contain at least one valid element from ${printedArray}`);
|
|
11
|
+
if (errors.length > 0) return {
|
|
12
|
+
status: "error",
|
|
13
|
+
errors
|
|
14
|
+
};
|
|
15
|
+
return { status: "success" };
|
|
16
|
+
}
|
|
17
|
+
function printErrors(errors, mapper) {
|
|
18
|
+
const defaultMapper = (e, i) => `❌ ${i + 1}. ${e}`;
|
|
19
|
+
return errors.map((e, i) => mapper?.(e, i) ?? defaultMapper(e, i)).join("\n");
|
|
20
|
+
}
|
|
21
|
+
function typedObjectKeys(value) {
|
|
22
|
+
return Object.keys(value);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
//#endregion
|
|
26
|
+
export { comparePartialArray, printErrors, typedObjectKeys };
|
|
27
|
+
//# sourceMappingURL=helpers.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.mjs","names":["errors: string[]"],"sources":["../../src/utils/helpers.ts"],"sourcesContent":["export function comparePartialArray<T>(\n compareArray: T[],\n actualArray: T[],\n formatter?: Intl.ListFormat\n): { status: 'success' } | { status: 'error'; errors: string[] } {\n const errors: string[] = [];\n const compareSet = new Set(compareArray);\n const printedArray = formatter\n ? formatter.format(compareArray.map((value) => `${value}`))\n : `[${compareArray.join(', ')}]`;\n\n // Check extras: elements in b that aren't in a\n for (let i = 0; i < actualArray.length; i++) {\n const value = actualArray[i];\n if (!compareSet.has(value)) {\n errors.push(\n `Extra element at index ${i}: \"${value}\" is not in ${printedArray}`\n );\n }\n }\n\n // Check that at least one element from a is present in b\n const hasAtLeastOne = actualArray.some((v) => compareSet.has(v));\n if (!hasAtLeastOne) {\n errors.push(\n `Array must contain at least one valid element from ${printedArray}`\n );\n }\n\n if (errors.length > 0) {\n return { status: 'error', errors };\n }\n\n return { status: 'success' };\n}\n\nexport function printErrors<T>(\n errors: T[],\n mapper?: (value: T, index: number) => string\n) {\n const defaultMapper = (e: unknown, i: number) => `❌ ${i + 1}. ${e}`;\n return errors.map((e, i) => mapper?.(e, i) ?? defaultMapper(e, i)).join('\\n');\n}\n\nexport function typedObjectKeys<T extends Record<string, unknown>, TOverrideKey = keyof T>(value: T) {\n return Object.keys(value) as Array<TOverrideKey>;\n}\n"],"mappings":";AAAA,SAAgB,oBACd,cACA,aACA,WAC+D;CAC/D,MAAMA,SAAmB,EAAE;CAC3B,MAAM,aAAa,IAAI,IAAI,aAAa;CACxC,MAAM,eAAe,YACjB,UAAU,OAAO,aAAa,KAAK,UAAU,GAAG,QAAQ,CAAC,GACzD,IAAI,aAAa,KAAK,KAAK,CAAC;AAGhC,MAAK,IAAI,IAAI,GAAG,IAAI,YAAY,QAAQ,KAAK;EAC3C,MAAM,QAAQ,YAAY;AAC1B,MAAI,CAAC,WAAW,IAAI,MAAM,CACxB,QAAO,KACL,0BAA0B,EAAE,KAAK,MAAM,cAAc,eACtD;;AAML,KAAI,CADkB,YAAY,MAAM,MAAM,WAAW,IAAI,EAAE,CAAC,CAE9D,QAAO,KACL,sDAAsD,eACvD;AAGH,KAAI,OAAO,SAAS,EAClB,QAAO;EAAE,QAAQ;EAAS;EAAQ;AAGpC,QAAO,EAAE,QAAQ,WAAW;;AAG9B,SAAgB,YACd,QACA,QACA;CACA,MAAM,iBAAiB,GAAY,MAAc,KAAK,IAAI,EAAE,IAAI;AAChE,QAAO,OAAO,KAAK,GAAG,MAAM,SAAS,GAAG,EAAE,IAAI,cAAc,GAAG,EAAE,CAAC,CAAC,KAAK,KAAK;;AAG/E,SAAgB,gBAA2E,OAAU;AACnG,QAAO,OAAO,KAAK,MAAM"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/utils/invariant.ts
|
|
3
|
+
function lazy(strings, ...values) {
|
|
4
|
+
return () => String.raw({ raw: strings }, ...values);
|
|
5
|
+
}
|
|
6
|
+
function invariant(condition, message, error = Error) {
|
|
7
|
+
if (!condition) {
|
|
8
|
+
const formatter = new Intl.ListFormat("en", {
|
|
9
|
+
style: "long",
|
|
10
|
+
type: "conjunction"
|
|
11
|
+
});
|
|
12
|
+
throw new error(typeof message === "function" ? message(formatter) : lazy`${message}`());
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
//#endregion
|
|
17
|
+
exports.invariant = invariant;
|
|
18
|
+
//# sourceMappingURL=invariant.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invariant.cjs","names":[],"sources":["../../src/utils/invariant.ts"],"sourcesContent":["function lazy(strings: TemplateStringsArray, ...values: any[]) {\n return () => String.raw({ raw: strings }, ...values);\n}\n\nexport function invariant<T>(\n condition: T,\n message: string | ((formatter: Intl.ListFormat) => string),\n error: new (message: string) => Error = Error\n): asserts condition {\n if (!condition) {\n const formatter = new Intl.ListFormat('en', {\n style: 'long',\n type: 'conjunction',\n });\n const resolvedMessage =\n typeof message === 'function' ? message(formatter) : lazy`${message}`();\n\n throw new error(resolvedMessage);\n }\n}\n"],"mappings":";;AAAA,SAAS,KAAK,SAA+B,GAAG,QAAe;AAC7D,cAAa,OAAO,IAAI,EAAE,KAAK,SAAS,EAAE,GAAG,OAAO;;AAGtD,SAAgB,UACd,WACA,SACA,QAAwC,OACrB;AACnB,KAAI,CAAC,WAAW;EACd,MAAM,YAAY,IAAI,KAAK,WAAW,MAAM;GAC1C,OAAO;GACP,MAAM;GACP,CAAC;AAIF,QAAM,IAAI,MAFR,OAAO,YAAY,aAAa,QAAQ,UAAU,GAAG,IAAI,GAAG,WAAW,CAEzC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
//#region src/utils/invariant.d.ts
|
|
2
|
+
declare function invariant<T>(condition: T, message: string | ((formatter: Intl.ListFormat) => string), error?: new (message: string) => Error): asserts condition;
|
|
3
|
+
//#endregion
|
|
4
|
+
export { invariant };
|
|
5
|
+
//# sourceMappingURL=invariant.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invariant.d.cts","names":[],"sources":["../../src/utils/invariant.ts"],"sourcesContent":[],"mappings":";iBAIgB,wBACH,kCACoB,IAAA,CAAK,yDACJ"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
//#region src/utils/invariant.d.ts
|
|
2
|
+
declare function invariant<T>(condition: T, message: string | ((formatter: Intl.ListFormat) => string), error?: new (message: string) => Error): asserts condition;
|
|
3
|
+
//#endregion
|
|
4
|
+
export { invariant };
|
|
5
|
+
//# sourceMappingURL=invariant.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invariant.d.mts","names":[],"sources":["../../src/utils/invariant.ts"],"sourcesContent":[],"mappings":";iBAIgB,wBACH,kCACoB,IAAA,CAAK,yDACJ"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/utils/invariant.ts
|
|
2
|
+
function lazy(strings, ...values) {
|
|
3
|
+
return () => String.raw({ raw: strings }, ...values);
|
|
4
|
+
}
|
|
5
|
+
function invariant(condition, message, error = Error) {
|
|
6
|
+
if (!condition) {
|
|
7
|
+
const formatter = new Intl.ListFormat("en", {
|
|
8
|
+
style: "long",
|
|
9
|
+
type: "conjunction"
|
|
10
|
+
});
|
|
11
|
+
throw new error(typeof message === "function" ? message(formatter) : lazy`${message}`());
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
//#endregion
|
|
16
|
+
export { invariant };
|
|
17
|
+
//# sourceMappingURL=invariant.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invariant.mjs","names":[],"sources":["../../src/utils/invariant.ts"],"sourcesContent":["function lazy(strings: TemplateStringsArray, ...values: any[]) {\n return () => String.raw({ raw: strings }, ...values);\n}\n\nexport function invariant<T>(\n condition: T,\n message: string | ((formatter: Intl.ListFormat) => string),\n error: new (message: string) => Error = Error\n): asserts condition {\n if (!condition) {\n const formatter = new Intl.ListFormat('en', {\n style: 'long',\n type: 'conjunction',\n });\n const resolvedMessage =\n typeof message === 'function' ? message(formatter) : lazy`${message}`();\n\n throw new error(resolvedMessage);\n }\n}\n"],"mappings":";AAAA,SAAS,KAAK,SAA+B,GAAG,QAAe;AAC7D,cAAa,OAAO,IAAI,EAAE,KAAK,SAAS,EAAE,GAAG,OAAO;;AAGtD,SAAgB,UACd,WACA,SACA,QAAwC,OACrB;AACnB,KAAI,CAAC,WAAW;EACd,MAAM,YAAY,IAAI,KAAK,WAAW,MAAM;GAC1C,OAAO;GACP,MAAM;GACP,CAAC;AAIF,QAAM,IAAI,MAFR,OAAO,YAAY,aAAa,QAAQ,UAAU,GAAG,IAAI,GAAG,WAAW,CAEzC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/utils/logger.ts
|
|
3
|
+
const DEFAULT_LOGGER_PREFIX = "MultiStepFormSchema";
|
|
4
|
+
var MultiStepFormLogger = class {
|
|
5
|
+
debug;
|
|
6
|
+
prefix = DEFAULT_LOGGER_PREFIX;
|
|
7
|
+
includeTimestamp = false;
|
|
8
|
+
throwOnError = false;
|
|
9
|
+
constructor(options) {
|
|
10
|
+
this.debug = options?.debug ?? false;
|
|
11
|
+
if (this.debug && options?.debug) {
|
|
12
|
+
const { includeTimestamp = false, prefix = DEFAULT_LOGGER_PREFIX, throwOnError = false } = options;
|
|
13
|
+
this.includeTimestamp = includeTimestamp;
|
|
14
|
+
this.prefix = typeof prefix === "string" ? prefix : prefix(DEFAULT_LOGGER_PREFIX);
|
|
15
|
+
this.throwOnError = throwOnError;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
wrapValue(wrapWith, value) {
|
|
19
|
+
if (wrapWith === "[]") return `[${value}]`;
|
|
20
|
+
if (wrapWith === "{}") return `{${value}}`;
|
|
21
|
+
if (wrapWith === "none") return value;
|
|
22
|
+
throw new Error(`The first argument ${wrapWith} is not valid. Valid options include: "[]", "{}", and "none"`);
|
|
23
|
+
}
|
|
24
|
+
formatPrefix(options) {
|
|
25
|
+
if (!options) return this.prefix;
|
|
26
|
+
const { action, value, wrapWith } = options;
|
|
27
|
+
if (action === "replace") return this.wrapValue(wrapWith ?? "[]", value);
|
|
28
|
+
const { delimiter } = options;
|
|
29
|
+
if (action === "append") return `${this.wrapValue(wrapWith?.originalPrefix ?? "[]", this.prefix)}${delimiter}${this.wrapValue(wrapWith?.addedPrefix ?? "[]", value)}`.trim();
|
|
30
|
+
if (action === "prepend") return `${this.wrapValue(wrapWith?.addedPrefix ?? "[]", value)}${delimiter}${this.wrapValue(wrapWith?.originalPrefix ?? "[]", this.prefix)}`.trim();
|
|
31
|
+
return this.prefix;
|
|
32
|
+
}
|
|
33
|
+
formatMessage(level, message, options) {
|
|
34
|
+
const { includeTimestamp = this.includeTimestamp, prefix, logLevelOptions } = options ?? {};
|
|
35
|
+
const formattedMessage = `${this.formatPrefix(prefix)} ${this.wrapValue(logLevelOptions?.wrapWith ?? "[]", (logLevelOptions?.level ?? level).toUpperCase())} ${message}`;
|
|
36
|
+
if (includeTimestamp) return `[${(/* @__PURE__ */ new Date()).toISOString()}] ${formattedMessage}`;
|
|
37
|
+
return formattedMessage;
|
|
38
|
+
}
|
|
39
|
+
info(message, options) {
|
|
40
|
+
if (!this.debug) return;
|
|
41
|
+
console.info(this.formatMessage("info", message, options));
|
|
42
|
+
}
|
|
43
|
+
warn(message, options) {
|
|
44
|
+
if (!this.debug) return;
|
|
45
|
+
console.warn(this.formatMessage("warn", message, options));
|
|
46
|
+
}
|
|
47
|
+
error(message, options) {
|
|
48
|
+
if (!this.debug) return;
|
|
49
|
+
const formatted = this.formatMessage("error", message, options);
|
|
50
|
+
console.error(formatted);
|
|
51
|
+
if (options?.throw ?? this.throwOnError) throw new Error(formatted);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
//#endregion
|
|
56
|
+
exports.DEFAULT_LOGGER_PREFIX = DEFAULT_LOGGER_PREFIX;
|
|
57
|
+
exports.MultiStepFormLogger = MultiStepFormLogger;
|
|
58
|
+
//# sourceMappingURL=logger.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.cjs","names":[],"sources":["../../src/utils/logger.ts"],"sourcesContent":["type LogLevel = 'info' | 'warn' | 'error';\ntype MultiStepFormLoggerOptions = {\n debug?: boolean;\n prefix?: string | ((prefix: typeof DEFAULT_LOGGER_PREFIX) => string);\n includeTimestamp?: boolean;\n throwOnError?: boolean;\n};\n\ntype WrapWithOptions = '[]' | '{}' | 'none';\ntype ReplacePrefixOptions = {\n action: 'replace';\n value: string;\n wrapWith?: WrapWithOptions;\n};\ntype AppendOrPrependPrefixOptions = {\n action: 'append' | 'prepend';\n value: string;\n delimiter?: string;\n wrapWith?: {\n originalPrefix?: WrapWithOptions;\n addedPrefix?: WrapWithOptions;\n };\n};\ntype PrefixOptions = ReplacePrefixOptions | AppendOrPrependPrefixOptions;\ntype BaseLogOptions = {\n prefix?: PrefixOptions;\n logLevelOptions?: {\n level?: LogLevel;\n wrapWith?: WrapWithOptions;\n };\n includeTimestamp?: boolean;\n};\ntype ErrorLogOptions = BaseLogOptions & {\n throw?: boolean;\n};\n\nexport const DEFAULT_LOGGER_PREFIX = 'MultiStepFormSchema';\nexport class MultiStepFormLogger {\n private readonly debug: boolean;\n private readonly prefix: string = DEFAULT_LOGGER_PREFIX;\n private readonly includeTimestamp: boolean = false;\n private readonly throwOnError: boolean = false;\n\n constructor(options?: MultiStepFormLoggerOptions) {\n this.debug = options?.debug ?? false;\n if (this.debug && options?.debug) {\n const {\n includeTimestamp = false,\n prefix = DEFAULT_LOGGER_PREFIX,\n throwOnError = false,\n } = options;\n\n this.includeTimestamp = includeTimestamp;\n this.prefix =\n typeof prefix === 'string' ? prefix : prefix(DEFAULT_LOGGER_PREFIX);\n this.throwOnError = throwOnError;\n }\n }\n\n private wrapValue(wrapWith: WrapWithOptions, value: string) {\n if (wrapWith === '[]') {\n return `[${value}]`;\n }\n\n if (wrapWith === '{}') {\n return `{${value}}`;\n }\n\n if (wrapWith === 'none') {\n return value;\n }\n\n throw new Error(\n `The first argument ${wrapWith} is not valid. Valid options include: \"[]\", \"{}\", and \"none\"`\n );\n }\n\n private formatPrefix(options: PrefixOptions | undefined) {\n if (!options) {\n return this.prefix;\n }\n\n const { action, value, wrapWith } = options;\n\n if (action === 'replace') {\n return this.wrapValue(wrapWith ?? '[]', value);\n }\n\n const { delimiter } = options;\n\n if (action === 'append') {\n return `${this.wrapValue(\n wrapWith?.originalPrefix ?? '[]',\n this.prefix\n )}${delimiter}${this.wrapValue(\n wrapWith?.addedPrefix ?? '[]',\n value\n )}`.trim();\n }\n\n if (action === 'prepend') {\n return `${this.wrapValue(\n wrapWith?.addedPrefix ?? '[]',\n value\n )}${delimiter}${this.wrapValue(\n wrapWith?.originalPrefix ?? '[]',\n this.prefix\n )}`.trim();\n }\n\n return this.prefix;\n }\n\n private formatMessage(\n level: LogLevel,\n message: string,\n options?: BaseLogOptions\n ) {\n const {\n includeTimestamp = this.includeTimestamp,\n prefix,\n logLevelOptions,\n } = options ?? {};\n const formattedPrefix = this.formatPrefix(prefix);\n const formattedLogLevel = this.wrapValue(\n logLevelOptions?.wrapWith ?? '[]',\n (logLevelOptions?.level ?? level).toUpperCase()\n );\n const formattedMessage = `${formattedPrefix} ${formattedLogLevel} ${message}`;\n\n if (includeTimestamp) {\n const timestamp = new Date().toISOString();\n\n return `[${timestamp}] ${formattedMessage}`;\n }\n\n return formattedMessage;\n }\n\n info(message: string, options?: BaseLogOptions) {\n if (!this.debug) {\n return;\n }\n\n console.info(this.formatMessage('info', message, options));\n }\n\n warn(message: string, options?: BaseLogOptions) {\n if (!this.debug) {\n return;\n }\n\n console.warn(this.formatMessage('warn', message, options));\n }\n\n error(message: string, options?: BaseLogOptions): void;\n error(message: string, options?: ErrorLogOptions): never;\n error(message: string, options?: ErrorLogOptions) {\n if (!this.debug) {\n return;\n }\n\n const formatted = this.formatMessage('error', message, options);\n\n console.error(formatted);\n\n const throwOnError = options?.throw ?? this.throwOnError;\n\n if (throwOnError) {\n throw new Error(formatted);\n }\n }\n}\n"],"mappings":";;AAoCA,MAAa,wBAAwB;AACrC,IAAa,sBAAb,MAAiC;CAC/B,AAAiB;CACjB,AAAiB,SAAiB;CAClC,AAAiB,mBAA4B;CAC7C,AAAiB,eAAwB;CAEzC,YAAY,SAAsC;AAChD,OAAK,QAAQ,SAAS,SAAS;AAC/B,MAAI,KAAK,SAAS,SAAS,OAAO;GAChC,MAAM,EACJ,mBAAmB,OACnB,SAAS,uBACT,eAAe,UACb;AAEJ,QAAK,mBAAmB;AACxB,QAAK,SACH,OAAO,WAAW,WAAW,SAAS,OAAO,sBAAsB;AACrE,QAAK,eAAe;;;CAIxB,AAAQ,UAAU,UAA2B,OAAe;AAC1D,MAAI,aAAa,KACf,QAAO,IAAI,MAAM;AAGnB,MAAI,aAAa,KACf,QAAO,IAAI,MAAM;AAGnB,MAAI,aAAa,OACf,QAAO;AAGT,QAAM,IAAI,MACR,sBAAsB,SAAS,8DAChC;;CAGH,AAAQ,aAAa,SAAoC;AACvD,MAAI,CAAC,QACH,QAAO,KAAK;EAGd,MAAM,EAAE,QAAQ,OAAO,aAAa;AAEpC,MAAI,WAAW,UACb,QAAO,KAAK,UAAU,YAAY,MAAM,MAAM;EAGhD,MAAM,EAAE,cAAc;AAEtB,MAAI,WAAW,SACb,QAAO,GAAG,KAAK,UACb,UAAU,kBAAkB,MAC5B,KAAK,OACN,GAAG,YAAY,KAAK,UACnB,UAAU,eAAe,MACzB,MACD,GAAG,MAAM;AAGZ,MAAI,WAAW,UACb,QAAO,GAAG,KAAK,UACb,UAAU,eAAe,MACzB,MACD,GAAG,YAAY,KAAK,UACnB,UAAU,kBAAkB,MAC5B,KAAK,OACN,GAAG,MAAM;AAGZ,SAAO,KAAK;;CAGd,AAAQ,cACN,OACA,SACA,SACA;EACA,MAAM,EACJ,mBAAmB,KAAK,kBACxB,QACA,oBACE,WAAW,EAAE;EAMjB,MAAM,mBAAmB,GALD,KAAK,aAAa,OAAO,CAKL,GAJlB,KAAK,UAC7B,iBAAiB,YAAY,OAC5B,iBAAiB,SAAS,OAAO,aAAa,CAChD,CACgE,GAAG;AAEpE,MAAI,iBAGF,QAAO,qBAFW,IAAI,MAAM,EAAC,aAAa,CAErB,IAAI;AAG3B,SAAO;;CAGT,KAAK,SAAiB,SAA0B;AAC9C,MAAI,CAAC,KAAK,MACR;AAGF,UAAQ,KAAK,KAAK,cAAc,QAAQ,SAAS,QAAQ,CAAC;;CAG5D,KAAK,SAAiB,SAA0B;AAC9C,MAAI,CAAC,KAAK,MACR;AAGF,UAAQ,KAAK,KAAK,cAAc,QAAQ,SAAS,QAAQ,CAAC;;CAK5D,MAAM,SAAiB,SAA2B;AAChD,MAAI,CAAC,KAAK,MACR;EAGF,MAAM,YAAY,KAAK,cAAc,SAAS,SAAS,QAAQ;AAE/D,UAAQ,MAAM,UAAU;AAIxB,MAFqB,SAAS,SAAS,KAAK,aAG1C,OAAM,IAAI,MAAM,UAAU"}
|