UNPKG

typia

Version:

Superfast runtime validators with only one line

1 lines 6.28 kB
{"version":3,"file":"_createStandardSchema.mjs","names":[],"sources":["../../src/internal/_createStandardSchema.ts"],"sourcesContent":["import { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport { IValidation } from \"@typia/interface\";\n\nexport const _createStandardSchema = <T>(\n fn: (input: unknown) => IValidation<T>,\n): ((input: unknown) => IValidation<T>) & StandardSchemaV1<T, T> =>\n Object.assign(fn, {\n \"~standard\": {\n version: 1,\n vendor: \"typia\",\n validate: (input: unknown): StandardSchemaV1.Result<T> => {\n const result = fn(input);\n if (result.success) {\n return {\n value: result.data,\n } satisfies StandardSchemaV1.SuccessResult<T>;\n } else {\n return {\n issues: result.errors.map((error) => ({\n message: `expected ${error.expected}, got ${formatValue(error.value)}`,\n path: typiaPathToStandardSchemaPath(error.path),\n })),\n } satisfies StandardSchemaV1.FailureResult;\n }\n },\n },\n } satisfies StandardSchemaV1<T, T>);\n\nconst formatValue = (value: unknown): string => {\n if (typeof value === \"object\") {\n if (value === null) return \"null\";\n try {\n if (Array.isArray(value)) return \"[object Array]\";\n } catch {\n // A revoked proxy can throw even for Array.isArray().\n }\n return \"[object Object]\";\n }\n if (typeof value === \"function\") return \"[function]\";\n return String(value);\n};\n\nenum PathParserState {\n // Start of a new segment\n // When the parser is in this state,\n // the pointer must point `.` or `[` or equal to length of the path\n Start,\n // Parsing a property key (`.hoge`)\n Property,\n // Parsing a string key (`[\"fuga\"]`)\n StringKey,\n // Parsing a number key (`[42]`)\n NumberKey,\n}\n\nconst typiaPathToStandardSchemaPath = (\n path: string,\n): ReadonlyArray<StandardSchemaV1.PathSegment> => {\n if (!path.startsWith(\"$input\")) {\n throw new Error(`Invalid path: ${JSON.stringify(path)}`);\n }\n\n const segments: StandardSchemaV1.PathSegment[] = [];\n let currentSegment = \"\";\n let state: PathParserState = PathParserState.Start;\n let index = \"$input\".length - 1;\n while (index < path.length - 1) {\n index++;\n const char = path[index];\n\n if (state === PathParserState.Property) {\n if (char === \".\" || char === \"[\") {\n // End of property\n segments.push({\n key: currentSegment,\n });\n state = PathParserState.Start;\n } else if (index === path.length - 1) {\n // End of path\n currentSegment += char;\n segments.push({\n key: currentSegment,\n });\n index++;\n state = PathParserState.Start;\n } else {\n currentSegment += char;\n }\n } else if (state === PathParserState.StringKey) {\n if (char === '\"') {\n // End of string key\n segments.push({\n key: JSON.parse(currentSegment + char),\n });\n // Skip `\"` and `]`\n index += 2;\n state = PathParserState.Start;\n } else if (char === \"\\\\\") {\n // Skip the next character from parsing\n currentSegment += path[index];\n index++;\n currentSegment += path[index];\n } else {\n currentSegment += char;\n }\n } else if (state === PathParserState.NumberKey) {\n if (char === \"]\") {\n // End of number key\n segments.push({\n key: Number.parseInt(currentSegment),\n });\n index++;\n state = PathParserState.Start;\n } else {\n currentSegment += char;\n }\n }\n\n if (state === PathParserState.Start && index < path.length - 1) {\n const newChar = path[index];\n currentSegment = \"\";\n if (newChar === \"[\") {\n if (path[index + 1] === '\"') {\n // Start of string key\n // NOTE: Typia uses JSON.stringify for this kind of keys, so `'` will not used as a string delimiter\n state = PathParserState.StringKey;\n index++;\n currentSegment = '\"';\n } else {\n // Start of number key\n state = PathParserState.NumberKey;\n }\n } else if (newChar === \".\") {\n // Start of property\n state = PathParserState.Property;\n } else {\n throw new Error(\"Unreachable: pointer points invalid character\");\n }\n }\n }\n\n if (state !== PathParserState.Start) {\n throw new Error(`Failed to parse path: ${JSON.stringify(path)}`);\n }\n\n return segments;\n};\n"],"mappings":";AAGA,MAAa,yBACX,OAEA,OAAO,OAAO,IAAI,EAChB,aAAa;CACX,SAAS;CACT,QAAQ;CACR,WAAW,UAA+C;EACxD,MAAM,SAAS,GAAG,KAAK;EACvB,IAAI,OAAO,SACT,OAAO,EACL,OAAO,OAAO,KAChB;OAEA,OAAO,EACL,QAAQ,OAAO,OAAO,KAAK,WAAW;GACpC,SAAS,YAAY,MAAM,SAAS,QAAQ,YAAY,MAAM,KAAK;GACnE,MAAM,8BAA8B,MAAM,IAAI;EAChD,EAAE,EACJ;CAEJ;AACF,EACF,CAAkC;AAEpC,MAAM,eAAe,UAA2B;CAC9C,IAAI,OAAO,UAAU,UAAU;EAC7B,IAAI,UAAU,MAAM,OAAO;EAC3B,IAAI;GACF,IAAI,MAAM,QAAQ,KAAK,GAAG,OAAO;EACnC,QAAQ,CAER;EACA,OAAO;CACT;CACA,IAAI,OAAO,UAAU,YAAY,OAAO;CACxC,OAAO,OAAO,KAAK;AACrB;AAeA,MAAM,iCACJ,SACgD;CAChD,IAAI,CAAC,KAAK,WAAW,QAAQ,GAC3B,MAAM,IAAI,MAAM,iBAAiB,KAAK,UAAU,IAAI,GAAG;CAGzD,MAAM,WAA2C,CAAC;CAClD,IAAI,iBAAiB;CACrB,IAAI,QAAA;CACJ,IAAI,QAAQ;CACZ,OAAO,QAAQ,KAAK,SAAS,GAAG;EAC9B;EACA,MAAM,OAAO,KAAK;EAElB,IAAI,UAAA,GACF,IAAI,SAAS,OAAO,SAAS,KAAK;GAEhC,SAAS,KAAK,EACZ,KAAK,eACP,CAAC;GACD,QAAA;EACF,OAAO,IAAI,UAAU,KAAK,SAAS,GAAG;GAEpC,kBAAkB;GAClB,SAAS,KAAK,EACZ,KAAK,eACP,CAAC;GACD;GACA,QAAA;EACF,OACE,kBAAkB;OAEf,IAAI,UAAA,GACT,IAAI,SAAS,MAAK;GAEhB,SAAS,KAAK,EACZ,KAAK,KAAK,MAAM,iBAAiB,IAAI,EACvC,CAAC;GAED,SAAS;GACT,QAAA;EACF,OAAO,IAAI,SAAS,MAAM;GAExB,kBAAkB,KAAK;GACvB;GACA,kBAAkB,KAAK;EACzB,OACE,kBAAkB;OAEf,IAAI,UAAA,GACT,IAAI,SAAS,KAAK;GAEhB,SAAS,KAAK,EACZ,KAAK,OAAO,SAAS,cAAc,EACrC,CAAC;GACD;GACA,QAAA;EACF,OACE,kBAAkB;EAItB,IAAI,UAAA,KAAmC,QAAQ,KAAK,SAAS,GAAG;GAC9D,MAAM,UAAU,KAAK;GACrB,iBAAiB;GACjB,IAAI,YAAY,KACd,IAAI,KAAK,QAAQ,OAAO,MAAK;IAG3B,QAAA;IACA;IACA,iBAAiB;GACnB,OAEE,QAAA;QAEG,IAAI,YAAY,KAErB,QAAA;QAEA,MAAM,IAAI,MAAM,+CAA+C;EAEnE;CACF;CAEA,IAAI,UAAA,GACF,MAAM,IAAI,MAAM,yBAAyB,KAAK,UAAU,IAAI,GAAG;CAGjE,OAAO;AACT"}