@ultimat3/schema 4.0.0 → 4.1.0

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/package.json +1 -1
  2. package/src/errors.ts +30 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ultimat3/schema",
3
- "version": "4.0.0",
3
+ "version": "4.1.0",
4
4
  "description": "Ultimate's validation seam: Standard Schema interface, the t namespace, JSON Schema output",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/src/errors.ts CHANGED
@@ -4,6 +4,31 @@
4
4
 
5
5
  import { formatIssues } from './standard';
6
6
 
7
+ /**
8
+ * The same escape `@ultimat3/core`'s `singleLine` performs. **Keep in sync**, and read the reason
9
+ * there — briefly: the 3-line format is line-oriented, and a `cause` may hold a value the caller
10
+ * chose, so a newline in one writes a line an operator reads as a genuine framework message.
11
+ *
12
+ * Copied rather than imported for the same reason the brand symbol above is: `schema` and `core`
13
+ * are both tier 0, so `schema` may not import `core` (imports go DOWN, never sideways). A schema
14
+ * cause is the one most likely to carry a hostile string — it describes the value that failed
15
+ * validation, which is the request body.
16
+ */
17
+ // biome-ignore lint/suspicious/noControlCharactersInRegex: escaping them is the point.
18
+ const CONTROL = /[\u0000-\u001f\u007f\u2028\u2029]/g;
19
+ const ESCAPES: Readonly<Record<string, string>> = {
20
+ '\n': String.raw`\n`,
21
+ '\r': String.raw`\r`,
22
+ '\t': String.raw`\t`,
23
+ '\b': String.raw`\b`,
24
+ '\f': String.raw`\f`,
25
+ };
26
+ const singleLine = (text: string): string =>
27
+ text.replace(
28
+ CONTROL,
29
+ (char) => ESCAPES[char] ?? `\\u${char.charCodeAt(0).toString(16).padStart(4, '0')}`,
30
+ );
31
+
7
32
  /** Same well-known symbol `@ultimat3/core` brands with. Keep in sync, never rename. */
8
33
  export const ULTIMATE_ERROR_BRAND: unique symbol = Symbol.for('ultimate.error');
9
34
 
@@ -82,9 +107,11 @@ export class SchemaError extends Error {
82
107
 
83
108
  /** The same 3-line rendering as `UltimateError.format()`. */
84
109
  format(): string {
85
- return [`${this.code}: ${this.title}`, ` cause: ${this.cause}`, ` fix: ${this.fix}`].join(
86
- '\n',
87
- );
110
+ return [
111
+ `${singleLine(this.code)}: ${singleLine(this.title)}`,
112
+ ` cause: ${singleLine(this.cause)}`,
113
+ ` fix: ${singleLine(this.fix)}`,
114
+ ].join('\n');
88
115
  }
89
116
 
90
117
  toJSON(): SchemaErrorJSON {