punctilio 0.3.0 → 0.4.14

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/index.js CHANGED
@@ -9,10 +9,14 @@
9
9
  */
10
10
  export { niceQuotes } from "./quotes.js";
11
11
  export { hyphenReplace, enDashNumberRange, enDashDateRange, minusReplace, months, } from "./dashes.js";
12
- export { ellipsis, multiplication, mathSymbols, legalSymbols, arrows, degrees, fractions, primeMarks, symbolTransform, } from "./symbols.js";
12
+ export { ellipsis, multiplication, mathSymbols, legalSymbols, arrows, degrees, fractions, primeMarks, collapseSpaces, superscript, punctuationLigatures, symbolTransform, } from "./symbols.js";
13
13
  import { niceQuotes } from "./quotes.js";
14
14
  import { hyphenReplace } from "./dashes.js";
15
- import { symbolTransform, fractions as fractionsTransform, degrees as degreesTransform, primeMarks } from "./symbols.js";
15
+ import { symbolTransform, fractions as fractionsTransform, degrees as degreesTransform, superscript as superscriptTransform, primeMarks, collapseSpaces as collapseSpacesTransform, punctuationLigatures as ligaturesTransform } from "./symbols.js";
16
+ import { assertSeparatorCountPreserved } from "./utils.js";
17
+ import { DEFAULT_SEPARATOR } from "./constants.js";
18
+ export { assertSeparatorCountPreserved, countSeparators } from "./utils.js";
19
+ export { DEFAULT_SEPARATOR } from "./constants.js";
16
20
  /**
17
21
  * Applies all typography transformations: smart quotes, proper dashes,
18
22
  * and symbol improvements.
@@ -22,8 +26,11 @@ import { symbolTransform, fractions as fractionsTransform, degrees as degreesTra
22
26
  * 2. primeMarks (feet/inches, arcminutes/arcseconds)
23
27
  * 3. niceQuotes (smart quotes)
24
28
  * 4. symbolTransform (ellipses, multiplication, math symbols, legal symbols, arrows)
25
- * 5. fractions (optional, disabled by default)
26
- * 6. degrees (optional, disabled by default)
29
+ * 5. fractions (disabled by default)
30
+ * 6. degrees (disabled by default)
31
+ * 7. superscript (disabled by default)
32
+ * 8. ligatures (disabled by default)
33
+ * 9. collapseSpaces (collapses multiple spaces into one)
27
34
  *
28
35
  * @param text - The text to transform
29
36
  * @param options - Configuration options
@@ -44,7 +51,9 @@ import { symbolTransform, fractions as fractionsTransform, degrees as degreesTra
44
51
  * ```
45
52
  */
46
53
  export function transform(text, options = {}) {
47
- const { symbols = true, fractions = false, degrees = false, ...separatorOpts } = options;
54
+ const separator = options.separator ?? DEFAULT_SEPARATOR;
55
+ const original = text;
56
+ const { symbols = true, fractions = false, degrees = false, superscript = false, ligatures = false, collapseSpaces = true, ...separatorOpts } = options;
48
57
  text = hyphenReplace(text, separatorOpts);
49
58
  text = primeMarks(text, separatorOpts);
50
59
  text = niceQuotes(text, separatorOpts);
@@ -57,11 +66,16 @@ export function transform(text, options = {}) {
57
66
  if (degrees) {
58
67
  text = degreesTransform(text);
59
68
  }
69
+ if (superscript) {
70
+ text = superscriptTransform(text, separatorOpts);
71
+ }
72
+ if (ligatures) {
73
+ text = ligaturesTransform(text, separatorOpts);
74
+ }
75
+ if (collapseSpaces) {
76
+ text = collapseSpacesTransform(text);
77
+ }
78
+ assertSeparatorCountPreserved(original, text, separator, "transform");
60
79
  return text;
61
80
  }
62
- /**
63
- * Default separator character for boundary marking.
64
- * Uses Unicode Private Use Area character U+E000.
65
- */
66
- export const DEFAULT_SEPARATOR = "\uE000";
67
81
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAA4C,MAAM,aAAa,CAAA;AAElF,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,YAAY,EACZ,MAAM,GAGP,MAAM,aAAa,CAAA;AAEpB,OAAO,EACL,QAAQ,EACR,cAAc,EACd,WAAW,EACX,YAAY,EACZ,MAAM,EACN,OAAO,EACP,SAAS,EACT,UAAU,EACV,eAAe,GAEhB,MAAM,cAAc,CAAA;AAwDrB,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,eAAe,EAAE,SAAS,IAAI,kBAAkB,EAAE,OAAO,IAAI,gBAAgB,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAExH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,UAA4B,EAAE;IACpE,MAAM,EAAE,OAAO,GAAG,IAAI,EAAE,SAAS,GAAG,KAAK,EAAE,OAAO,GAAG,KAAK,EAAE,GAAG,aAAa,EAAE,GAAG,OAAO,CAAA;IAExF,IAAI,GAAG,aAAa,CAAC,IAAI,EAAE,aAAa,CAAC,CAAA;IACzC,IAAI,GAAG,UAAU,CAAC,IAAI,EAAE,aAAa,CAAC,CAAA;IACtC,IAAI,GAAG,UAAU,CAAC,IAAI,EAAE,aAAa,CAAC,CAAA;IAEtC,IAAI,OAAO,EAAE,CAAC;QACZ,IAAI,GAAG,eAAe,CAAC,IAAI,EAAE,aAAa,CAAC,CAAA;IAC7C,CAAC;IAED,IAAI,SAAS,EAAE,CAAC;QACd,IAAI,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAA;IACjC,CAAC;IAED,IAAI,OAAO,EAAE,CAAC;QACZ,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAA;IAC/B,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,QAAQ,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAA4C,MAAM,aAAa,CAAA;AAElF,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,YAAY,EACZ,MAAM,GAGP,MAAM,aAAa,CAAA;AAEpB,OAAO,EACL,QAAQ,EACR,cAAc,EACd,WAAW,EACX,YAAY,EACZ,MAAM,EACN,OAAO,EACP,SAAS,EACT,UAAU,EACV,cAAc,EACd,WAAW,EACX,oBAAoB,EACpB,eAAe,GAEhB,MAAM,cAAc,CAAA;AAiFrB,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,eAAe,EAAE,SAAS,IAAI,kBAAkB,EAAE,OAAO,IAAI,gBAAgB,EAAE,WAAW,IAAI,oBAAoB,EAAE,UAAU,EAAE,cAAc,IAAI,uBAAuB,EAAE,oBAAoB,IAAI,kBAAkB,EAAE,MAAM,cAAc,CAAA;AACpP,OAAO,EAAE,6BAA6B,EAAE,MAAM,YAAY,CAAA;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAElD,OAAO,EAAE,6BAA6B,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAC3E,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAElD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,UAA4B,EAAE;IACpE,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,iBAAiB,CAAA;IACxD,MAAM,QAAQ,GAAG,IAAI,CAAA;IACrB,MAAM,EAAE,OAAO,GAAG,IAAI,EAAE,SAAS,GAAG,KAAK,EAAE,OAAO,GAAG,KAAK,EAAE,WAAW,GAAG,KAAK,EAAE,SAAS,GAAG,KAAK,EAAE,cAAc,GAAG,IAAI,EAAE,GAAG,aAAa,EAAE,GAAG,OAAO,CAAA;IAEvJ,IAAI,GAAG,aAAa,CAAC,IAAI,EAAE,aAAa,CAAC,CAAA;IACzC,IAAI,GAAG,UAAU,CAAC,IAAI,EAAE,aAAa,CAAC,CAAA;IACtC,IAAI,GAAG,UAAU,CAAC,IAAI,EAAE,aAAa,CAAC,CAAA;IAEtC,IAAI,OAAO,EAAE,CAAC;QACZ,IAAI,GAAG,eAAe,CAAC,IAAI,EAAE,aAAa,CAAC,CAAA;IAC7C,CAAC;IAED,IAAI,SAAS,EAAE,CAAC;QACd,IAAI,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAA;IACjC,CAAC;IAED,IAAI,OAAO,EAAE,CAAC;QACZ,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAA;IAC/B,CAAC;IAED,IAAI,WAAW,EAAE,CAAC;QAChB,IAAI,GAAG,oBAAoB,CAAC,IAAI,EAAE,aAAa,CAAC,CAAA;IAClD,CAAC;IAED,IAAI,SAAS,EAAE,CAAC;QACd,IAAI,GAAG,kBAAkB,CAAC,IAAI,EAAE,aAAa,CAAC,CAAA;IAChD,CAAC;IAED,IAAI,cAAc,EAAE,CAAC;QACnB,IAAI,GAAG,uBAAuB,CAAC,IAAI,CAAC,CAAA;IACtC,CAAC;IAED,6BAA6B,CAAC,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,CAAC,CAAA;IAErE,OAAO,IAAI,CAAA;AACb,CAAC"}
package/dist/quotes.js CHANGED
@@ -18,18 +18,18 @@ function convertSingleQuotes(text, sep) {
18
18
  const endQuoteNotContraction = `(?!${contraction})${RIGHT_SINGLE_QUOTE}${afterEndingSingle}`;
19
19
  const apostropheRegex = new RegExp(`(?<=^|[^\\w])'(${apostropheWhitelist}|(?![^${LEFT_SINGLE_QUOTE}'\\n]*${endQuoteNotContraction}))`, "gm");
20
20
  text = text.replace(apostropheRegex, RIGHT_SINGLE_QUOTE);
21
- const beginningSingle = `((?:^|[\\s${LEFT_DOUBLE_QUOTE}${RIGHT_DOUBLE_QUOTE}\\-\\(])${sep}?)['](?=${sep}?\\S)`;
22
- text = text.replace(new RegExp(beginningSingle, "gm"), `$1${LEFT_SINGLE_QUOTE}`);
21
+ const beginningSingle = `(?<beforeContext>(?:^|[\\s${LEFT_DOUBLE_QUOTE}${RIGHT_DOUBLE_QUOTE}\\-\\(])${sep}?)['](?=${sep}?\\S)`;
22
+ text = text.replace(new RegExp(beginningSingle, "gm"), `$<beforeContext>${LEFT_SINGLE_QUOTE}`);
23
23
  return text;
24
24
  }
25
25
  /** Convert straight double quotes to curly quotes */
26
26
  function convertDoubleQuotes(text, sep) {
27
- const beginningDouble = new RegExp(`(?<=^|[\\s\\(\\/\\[\\{\\-${EM_DASH}${sep}])(?<beforeChr>${sep}?)["](?<afterChr>(${sep}[ .,])|(?=${sep}?\\.{3}|${sep}?[^\\s\\)\\${EM_DASH},!?${sep};:.\\}]))`, "gm");
27
+ const beginningDouble = new RegExp(`(?<=^|[\\s\\(\\/\\[\\{\\-${EM_DASH}${sep}])(?<beforeChr>${sep}?)["](?<afterChr>(?<sepWithPunct>${sep}[ .,])|(?=${sep}?\\.{3}|${sep}?[^\\s\\)\\${EM_DASH},!?${sep};:.\\}]))`, "gm");
28
28
  text = text.replace(beginningDouble, `$<beforeChr>${LEFT_DOUBLE_QUOTE}$<afterChr>`);
29
- text = text.replace(new RegExp(`(?<=\\{)(${sep}? )?["]`, "g"), `$1${LEFT_DOUBLE_QUOTE}`);
30
- const endingDouble = `([^\\s\\(])["](${sep}?)(?=${sep}|[\\s/\\).,;${EM_DASH}:\\-\\}!?s]|$)`;
31
- text = text.replace(new RegExp(endingDouble, "g"), `$1${RIGHT_DOUBLE_QUOTE}$2`);
32
- text = text.replace(new RegExp(`["](${sep}?)$`, "g"), `${RIGHT_DOUBLE_QUOTE}$1`);
29
+ text = text.replace(new RegExp(`(?<=\\{)(?<sepSpace>${sep}? )?["]`, "g"), `$<sepSpace>${LEFT_DOUBLE_QUOTE}`);
30
+ const endingDouble = `(?<beforeQuote>[^\\s\\(])["]((?<sepAfter>${sep})?)(?=${sep}|[\\s/\\).,;${EM_DASH}:\\-\\}!?s]|$)`;
31
+ text = text.replace(new RegExp(endingDouble, "g"), `$<beforeQuote>${RIGHT_DOUBLE_QUOTE}$<sepAfter>`);
32
+ text = text.replace(new RegExp(`["](?<sepEnd>${sep}?)$`, "g"), `${RIGHT_DOUBLE_QUOTE}$<sepEnd>`);
33
33
  text = text.replace(new RegExp(`'(?=${RIGHT_DOUBLE_QUOTE})`, "gu"), RIGHT_SINGLE_QUOTE);
34
34
  return text;
35
35
  }
@@ -37,19 +37,19 @@ function convertDoubleQuotes(text, sep) {
37
37
  function applyPunctuationStyle(text, sep, style) {
38
38
  if (style === "american") {
39
39
  // Period outside → inside: "Hello". → "Hello."
40
- const periodOutsideRegex = new RegExp(`(?<![!?:\\.${ELLIPSIS}])(${sep}?)([${RIGHT_SINGLE_QUOTE}${RIGHT_DOUBLE_QUOTE}])(${sep}?)(?!\\.\\.\\.)\\.`, "g");
41
- text = text.replace(periodOutsideRegex, "$1.$2$3");
40
+ const periodOutsideRegex = new RegExp(`(?<![!?:\\.${ELLIPSIS}])(?<sepBefore>${sep}?)(?<quote>[${RIGHT_SINGLE_QUOTE}${RIGHT_DOUBLE_QUOTE}])(?<sepAfter>${sep}?)(?!\\.\\.\\.)\\.`, "g");
41
+ text = text.replace(periodOutsideRegex, "$<sepBefore>.$<quote>$<sepAfter>");
42
42
  // Comma outside → inside: "Hello", → "Hello,"
43
- const commaOutsideRegex = new RegExp(`(${sep}?)([${RIGHT_SINGLE_QUOTE}${RIGHT_DOUBLE_QUOTE}])(${sep}?),`, "g");
44
- text = text.replace(commaOutsideRegex, "$1,$2$3");
43
+ const commaOutsideRegex = new RegExp(`(?<sepBefore>${sep}?)(?<quote>[${RIGHT_SINGLE_QUOTE}${RIGHT_DOUBLE_QUOTE}])(?<sepAfter>${sep}?),`, "g");
44
+ text = text.replace(commaOutsideRegex, "$<sepBefore>,$<quote>$<sepAfter>");
45
45
  }
46
46
  else if (style === "british") {
47
47
  // Period inside → outside: "Hello." → "Hello".
48
- const periodInsideRegex = new RegExp(`(?<![!?:\\.${ELLIPSIS}])(${sep}?)\\.(${sep}?)([${RIGHT_SINGLE_QUOTE}${RIGHT_DOUBLE_QUOTE}])`, "g");
49
- text = text.replace(periodInsideRegex, "$1$2$3.");
48
+ const periodInsideRegex = new RegExp(`(?<![!?:\\.${ELLIPSIS}])(?<sepBefore>${sep}?)\\.(?<sepMiddle>${sep}?)(?<quote>[${RIGHT_SINGLE_QUOTE}${RIGHT_DOUBLE_QUOTE}])`, "g");
49
+ text = text.replace(periodInsideRegex, "$<sepBefore>$<sepMiddle>$<quote>.");
50
50
  // Comma inside → outside: "Hello," → "Hello",
51
- const commaInsideRegex = new RegExp(`(?<![!?]),(${sep}?[${RIGHT_DOUBLE_QUOTE}${RIGHT_SINGLE_QUOTE}])`, "g");
52
- text = text.replace(commaInsideRegex, "$1,");
51
+ const commaInsideRegex = new RegExp(`(?<![!?]),(?<sepAndQuote>${sep}?[${RIGHT_DOUBLE_QUOTE}${RIGHT_SINGLE_QUOTE}])`, "g");
52
+ text = text.replace(commaInsideRegex, "$<sepAndQuote>,");
53
53
  }
54
54
  return text;
55
55
  }
@@ -1 +1 @@
1
- {"version":3,"file":"quotes.js","sourceRoot":"","sources":["../src/quotes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"quotes.js","sourceRoot":"","sources":["../src/quotes.ts"],"names":[],"mappings":"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"}
package/dist/symbols.d.ts CHANGED
@@ -35,28 +35,10 @@ export declare function ellipsis(text: string, options?: SymbolOptions): string;
35
35
  * - Dimensions: "5x5" → "5×5"
36
36
  * - Trailing multiplier: "5x" → "5×" (when followed by word boundary)
37
37
  * - Asterisk multiplication: "5*3" → "5×3" (when between numbers)
38
- *
39
- * @example
40
- * ```ts
41
- * multiplication("The room is 10x12 feet")
42
- * // → "The room is 10×12 feet"
43
- *
44
- * multiplication("2x speed")
45
- * // → "2× speed"
46
- * ```
47
38
  */
48
39
  export declare function multiplication(text: string, options?: SymbolOptions): string;
49
40
  /**
50
41
  * Converts ASCII mathematical symbols to proper Unicode equivalents.
51
- *
52
- * @example
53
- * ```ts
54
- * mathSymbols("x != y and a <= b")
55
- * // → "x ≠ y and a ≤ b"
56
- *
57
- * mathSymbols("The answer is +- 5%")
58
- * // → "The answer is ± 5%"
59
- * ```
60
42
  */
61
43
  export declare function mathSymbols(text: string): string;
62
44
  /**
@@ -74,15 +56,6 @@ export declare function legalSymbols(text: string): string;
74
56
  *
75
57
  * Note: Only converts when surrounded by spaces or at word boundaries
76
58
  * to avoid false matches in code or URLs.
77
- *
78
- * @example
79
- * ```ts
80
- * arrows("A -> B -> C")
81
- * // → "A → B → C"
82
- *
83
- * arrows("left <-> right")
84
- * // → "left ↔ right"
85
- * ```
86
59
  */
87
60
  export declare function arrows(text: string, options?: SymbolOptions): string;
88
61
  /**
@@ -94,15 +67,6 @@ export declare function arrows(text: string, options?: SymbolOptions): string;
94
67
  *
95
68
  * Only matches when followed by C or F (case insensitive) to avoid
96
69
  * false positives.
97
- *
98
- * @example
99
- * ```ts
100
- * degrees("The temperature is 20 C")
101
- * // → "The temperature is 20 °C"
102
- *
103
- * degrees("Water boils at 212F")
104
- * // → "Water boils at 212 °F"
105
- * ```
106
70
  */
107
71
  export declare function degrees(text: string, options?: SymbolOptions): string;
108
72
  /**
@@ -114,15 +78,6 @@ export declare function degrees(text: string, options?: SymbolOptions): string;
114
78
  *
115
79
  * This should be called BEFORE smart quote transformations to prevent
116
80
  * quotes in measurements from being curled.
117
- *
118
- * @example
119
- * ```ts
120
- * primeMarks("He's 5'10\" tall")
121
- * // → "He's 5′10″ tall"
122
- *
123
- * primeMarks("Location: 45° 30' 15\"")
124
- * // → "Location: 45° 30′ 15″"
125
- * ```
126
81
  */
127
82
  export declare function primeMarks(text: string, options?: SymbolOptions): string;
128
83
  /**
@@ -144,6 +99,60 @@ export declare function primeMarks(text: string, options?: SymbolOptions): strin
144
99
  * ```
145
100
  */
146
101
  export declare function fractions(text: string, options?: SymbolOptions): string;
102
+ /**
103
+ * Converts ordinal suffixes to Unicode superscript characters.
104
+ *
105
+ * Handles ordinal numbers like:
106
+ * - "1st" → "1ˢᵗ"
107
+ * - "2nd" → "2ⁿᵈ"
108
+ * - "3rd" → "3ʳᵈ"
109
+ * - "4th" → "4ᵗʰ"
110
+ *
111
+ * Works with any number ending in appropriate suffixes (21st, 42nd, 103rd, etc.)
112
+ *
113
+ * @example
114
+ * ```ts
115
+ * superscript("The 1st place winner")
116
+ * // → "The 1ˢᵗ place winner"
117
+ *
118
+ * superscript("Born on the 30th of June")
119
+ * // → "Born on the 30ᵗʰ of June"
120
+ * ```
121
+ */
122
+ export declare function superscript(text: string, options?: SymbolOptions): string;
123
+ /**
124
+ * Collapses multiple consecutive spaces (including non-breaking spaces) into a single space.
125
+ *
126
+ * When multiple spaces or non-breaking spaces appear in sequence, this function
127
+ * keeps only the first space character, preserving its type.
128
+ *
129
+ * @example
130
+ * ```ts
131
+ * collapseSpaces("hello world")
132
+ * // → "hello world"
133
+ *
134
+ * collapseSpaces("foo\u00A0\u00A0bar") // two nbsp
135
+ * // → "foo\u00A0bar" // single nbsp
136
+ *
137
+ * collapseSpaces("a \u00A0b") // space followed by nbsp
138
+ * // → "a b" // keeps the first (regular space)
139
+ * ```
140
+ */
141
+ export declare function collapseSpaces(text: string): string;
142
+ /**
143
+ * Converts repeated punctuation marks to Unicode ligature characters,
144
+ * squashing multiple marks to a single character.
145
+ *
146
+ * Handles:
147
+ * - "??" or "???" etc → "⁇" (squashed to double question mark ligature)
148
+ * - "?!" or "?!!" etc → "⁈" (question exclamation mark)
149
+ * - "!?" or "!??" etc → "⁉" (exclamation question mark)
150
+ * - "!!" or "!!!" etc → "!" (squashed to single exclamation)
151
+ *
152
+ * Note: These ligatures have poor font support, so this function is
153
+ * disabled by default.
154
+ */
155
+ export declare function punctuationLigatures(text: string, options?: SymbolOptions): string;
147
156
  /**
148
157
  * Applies all symbol transformations.
149
158
  *
@@ -1 +1 @@
1
- {"version":3,"file":"symbols.d.ts","sourceRoot":"","sources":["../src/symbols.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,MAAM,WAAW,aAAa;IAC5B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB;AA4BD;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAW1E;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAkBhF;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAShD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKjD;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAyBxE;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAWzE;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CA+B5E;AAwBD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAkB3E;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CASjF"}
1
+ {"version":3,"file":"symbols.d.ts","sourceRoot":"","sources":["../src/symbols.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,MAAM,WAAW,aAAa;IAC5B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB;AAoCD;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAe1E;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAkBhF;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAShD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKjD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAyBxE;AAED;;;;;;;;;GASG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAWzE;AAED;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CA+B5E;AAwBD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAkB3E;AAYD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAgB7E;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAiCtF;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CASjF"}
package/dist/symbols.js CHANGED
@@ -13,7 +13,7 @@ import { UNICODE_SYMBOLS, ESCAPED_DEFAULT_SEPARATOR } from "./constants.js";
13
13
  function escapeRegex(str) {
14
14
  return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
15
15
  }
16
- const { ELLIPSIS, MULTIPLICATION, NOT_EQUAL, PLUS_MINUS, COPYRIGHT, REGISTERED, TRADEMARK, DEGREE, ARROW_RIGHT, ARROW_LEFT, ARROW_LEFT_RIGHT, APPROXIMATE, LESS_EQUAL, GREATER_EQUAL, PRIME, DOUBLE_PRIME, } = UNICODE_SYMBOLS;
16
+ const { ELLIPSIS, MULTIPLICATION, NOT_EQUAL, PLUS_MINUS, COPYRIGHT, REGISTERED, TRADEMARK, DEGREE, ARROW_RIGHT, ARROW_LEFT, ARROW_LEFT_RIGHT, APPROXIMATE, LESS_EQUAL, GREATER_EQUAL, PRIME, DOUBLE_PRIME, NBSP, SUPERSCRIPT_ST, SUPERSCRIPT_ND, SUPERSCRIPT_RD, SUPERSCRIPT_TH, DOUBLE_QUESTION, QUESTION_EXCLAMATION, EXCLAMATION_QUESTION } = UNICODE_SYMBOLS;
17
17
  /**
18
18
  * Converts three periods to a proper ellipsis character.
19
19
  *
@@ -27,8 +27,12 @@ export function ellipsis(text, options = {}) {
27
27
  const chr = options.separator
28
28
  ? escapeRegex(options.separator)
29
29
  : ESCAPED_DEFAULT_SEPARATOR;
30
- const pattern = new RegExp(`\\.${chr}?\\.${chr}?\\.`, "g");
31
- text = text.replace(pattern, ELLIPSIS);
30
+ // Capture groups preserve separators: .(sep1)?.(sep2)?.
31
+ const pattern = new RegExp(`\\.(${chr})?\\.(${chr})?\\.`, "g");
32
+ text = text.replace(pattern, (_match, sep1, sep2) => {
33
+ // Preserve separators by appending them after the ellipsis
34
+ return ELLIPSIS + (sep1 || "") + (sep2 || "");
35
+ });
32
36
  text = text.replace(new RegExp(`${ELLIPSIS}(?=\\w)`, "gu"), `${ELLIPSIS} `);
33
37
  return text;
34
38
  }
@@ -39,42 +43,24 @@ export function ellipsis(text, options = {}) {
39
43
  * - Dimensions: "5x5" → "5×5"
40
44
  * - Trailing multiplier: "5x" → "5×" (when followed by word boundary)
41
45
  * - Asterisk multiplication: "5*3" → "5×3" (when between numbers)
42
- *
43
- * @example
44
- * ```ts
45
- * multiplication("The room is 10x12 feet")
46
- * // → "The room is 10×12 feet"
47
- *
48
- * multiplication("2x speed")
49
- * // → "2× speed"
50
- * ```
51
46
  */
52
47
  export function multiplication(text, options = {}) {
53
48
  const chr = options.separator
54
49
  ? escapeRegex(options.separator)
55
50
  : ESCAPED_DEFAULT_SEPARATOR;
56
51
  // Dimensions with spaces: preserve spacing
57
- const loosePattern = new RegExp(`(\\d${chr}?)\\s+[xX*]\\s+(${chr}?\\d)`, "g");
58
- text = text.replace(loosePattern, `$1 ${MULTIPLICATION} $2`);
52
+ const loosePattern = new RegExp(`(?<leftNum>\\d${chr}?)\\s+[xX*]\\s+(?<rightNum>${chr}?\\d)`, "g");
53
+ text = text.replace(loosePattern, `$<leftNum> ${MULTIPLICATION} $<rightNum>`);
59
54
  // Dimensions without spaces: keep tight
60
- const tightPattern = new RegExp(`(\\d${chr}?)[xX*](${chr}?\\d)`, "g");
61
- text = text.replace(tightPattern, `$1${MULTIPLICATION}$2`);
55
+ const tightPattern = new RegExp(`(?<leftNum>\\d${chr}?)[xX*](?<rightNum>${chr}?\\d)`, "g");
56
+ text = text.replace(tightPattern, `$<leftNum>${MULTIPLICATION}$<rightNum>`);
62
57
  // Trailing multiplier: 5x (followed by word boundary - space, punctuation, etc.)
63
- const trailingPattern = new RegExp(`(\\d${chr}?)[xX*]\\b`, "g");
64
- text = text.replace(trailingPattern, `$1${MULTIPLICATION}`);
58
+ const trailingPattern = new RegExp(`(?<num>\\d${chr}?)[xX*]\\b`, "g");
59
+ text = text.replace(trailingPattern, `$<num>${MULTIPLICATION}`);
65
60
  return text;
66
61
  }
67
62
  /**
68
63
  * Converts ASCII mathematical symbols to proper Unicode equivalents.
69
- *
70
- * @example
71
- * ```ts
72
- * mathSymbols("x != y and a <= b")
73
- * // → "x ≠ y and a ≤ b"
74
- *
75
- * mathSymbols("The answer is +- 5%")
76
- * // → "The answer is ± 5%"
77
- * ```
78
64
  */
79
65
  export function mathSymbols(text) {
80
66
  return text
@@ -106,15 +92,6 @@ export function legalSymbols(text) {
106
92
  *
107
93
  * Note: Only converts when surrounded by spaces or at word boundaries
108
94
  * to avoid false matches in code or URLs.
109
- *
110
- * @example
111
- * ```ts
112
- * arrows("A -> B -> C")
113
- * // → "A → B → C"
114
- *
115
- * arrows("left <-> right")
116
- * // → "left ↔ right"
117
- * ```
118
95
  */
119
96
  export function arrows(text, options = {}) {
120
97
  const chr = options.separator
@@ -138,15 +115,6 @@ export function arrows(text, options = {}) {
138
115
  *
139
116
  * Only matches when followed by C or F (case insensitive) to avoid
140
117
  * false positives.
141
- *
142
- * @example
143
- * ```ts
144
- * degrees("The temperature is 20 C")
145
- * // → "The temperature is 20 °C"
146
- *
147
- * degrees("Water boils at 212F")
148
- * // → "Water boils at 212 °F"
149
- * ```
150
118
  */
151
119
  export function degrees(text, options = {}) {
152
120
  const chr = options.separator
@@ -154,7 +122,7 @@ export function degrees(text, options = {}) {
154
122
  : ESCAPED_DEFAULT_SEPARATOR;
155
123
  // Temperature with optional space before C or F
156
124
  // Handles separator between digit and unit
157
- return text.replace(new RegExp(`(\\d${chr}?) ?([CF])\\b`, "gi"), (_, num, unit) => `${num} ${DEGREE}${unit.toUpperCase()}`);
125
+ return text.replace(new RegExp(`(?<num>\\d${chr}?) ?(?<unit>[CF])\\b`, "gi"), (_, num, unit) => `${num} ${DEGREE}${unit.toUpperCase()}`);
158
126
  }
159
127
  /**
160
128
  * Converts straight quotes after numbers to prime marks.
@@ -165,15 +133,6 @@ export function degrees(text, options = {}) {
165
133
  *
166
134
  * This should be called BEFORE smart quote transformations to prevent
167
135
  * quotes in measurements from being curled.
168
- *
169
- * @example
170
- * ```ts
171
- * primeMarks("He's 5'10\" tall")
172
- * // → "He's 5′10″ tall"
173
- *
174
- * primeMarks("Location: 45° 30' 15\"")
175
- * // → "Location: 45° 30′ 15″"
176
- * ```
177
136
  */
178
137
  export function primeMarks(text, options = {}) {
179
138
  const chr = options.separator
@@ -182,19 +141,19 @@ export function primeMarks(text, options = {}) {
182
141
  // Single prime: Matches digit + optional separator + apostrophe
183
142
  // Lookahead ensures it's followed by: another digit, double quote, end of string, or punctuation
184
143
  // Examples: 5' (feet), 30' (arcminutes)
185
- const singlePrimePattern = new RegExp(`(\\d${chr}?)'(?=${chr}?(?:\\d|"|$|[\\s.,;:!?)]))`, "g");
186
- text = text.replace(singlePrimePattern, `$1${PRIME}`);
144
+ const singlePrimePattern = new RegExp(`(?<numWithSep>\\d${chr}?)'(?=${chr}?(?:\\d|"|$|[\\s.,;:!?)]))`, "g");
145
+ text = text.replace(singlePrimePattern, `$<numWithSep>${PRIME}`);
187
146
  // Double prime Pattern 1: Feet-inches pattern
188
147
  // Matches: prime symbol + optional separator + digit + optional separator + double quote
189
148
  // Examples: 5′10" or 5'10" → 5′10″
190
- const feetInchesPattern = new RegExp(`(${PRIME}${chr}?\\d${chr}?)"`, "g");
191
- text = text.replace(feetInchesPattern, `$1${DOUBLE_PRIME}`);
149
+ const feetInchesPattern = new RegExp(`(?<primeAndNum>${PRIME}${chr}?\\d${chr}?)"`, "g");
150
+ text = text.replace(feetInchesPattern, `$<primeAndNum>${DOUBLE_PRIME}`);
192
151
  // Double prime Pattern 2: Standalone inches
193
152
  // Negative lookbehind: ensures no opening quote within 20 chars before the digit
194
153
  // Negative lookahead: ensures not followed by word characters
195
154
  // Matches: 12" wide ✓, but not: "Term 1" ✗
196
- const standaloneInchesPattern = new RegExp(`(?<!["\u201C]${chr}?[^"${chr}]{0,20})(\\d${chr}?)"(?!${chr}?[\\w])`, "g");
197
- text = text.replace(standaloneInchesPattern, `$1${DOUBLE_PRIME}`);
155
+ const standaloneInchesPattern = new RegExp(`(?<!["\u201C]${chr}?[^"${chr}]{0,20})(?<numWithSep>\\d${chr}?)"(?!${chr}?[\\w])`, "g");
156
+ text = text.replace(standaloneInchesPattern, `$<numWithSep>${DOUBLE_PRIME}`);
198
157
  return text;
199
158
  }
200
159
  /**
@@ -250,6 +209,97 @@ export function fractions(text, options = {}) {
250
209
  }
251
210
  return text;
252
211
  }
212
+ /**
213
+ * Map of ordinal suffixes to their Unicode superscript equivalents.
214
+ */
215
+ const ORDINAL_MAP = {
216
+ st: SUPERSCRIPT_ST,
217
+ nd: SUPERSCRIPT_ND,
218
+ rd: SUPERSCRIPT_RD,
219
+ th: SUPERSCRIPT_TH,
220
+ };
221
+ /**
222
+ * Converts ordinal suffixes to Unicode superscript characters.
223
+ *
224
+ * Handles ordinal numbers like:
225
+ * - "1st" → "1ˢᵗ"
226
+ * - "2nd" → "2ⁿᵈ"
227
+ * - "3rd" → "3ʳᵈ"
228
+ * - "4th" → "4ᵗʰ"
229
+ *
230
+ * Works with any number ending in appropriate suffixes (21st, 42nd, 103rd, etc.)
231
+ *
232
+ * @example
233
+ * ```ts
234
+ * superscript("The 1st place winner")
235
+ * // → "The 1ˢᵗ place winner"
236
+ *
237
+ * superscript("Born on the 30th of June")
238
+ * // → "Born on the 30ᵗʰ of June"
239
+ * ```
240
+ */
241
+ export function superscript(text, options = {}) {
242
+ const chr = options.separator
243
+ ? escapeRegex(options.separator)
244
+ : ESCAPED_DEFAULT_SEPARATOR;
245
+ // Match number + optional separator + ordinal suffix at word boundary
246
+ // Use case-insensitive matching for the suffix
247
+ const pattern = new RegExp(`(?<num>\\d${chr}?)(?<suffix>st|nd|rd|th)\\b`, "gi");
248
+ return text.replace(pattern, (_match, num, suffix) => {
249
+ const superscriptSuffix = ORDINAL_MAP[suffix.toLowerCase()];
250
+ return num + superscriptSuffix;
251
+ });
252
+ }
253
+ /**
254
+ * Collapses multiple consecutive spaces (including non-breaking spaces) into a single space.
255
+ *
256
+ * When multiple spaces or non-breaking spaces appear in sequence, this function
257
+ * keeps only the first space character, preserving its type.
258
+ *
259
+ * @example
260
+ * ```ts
261
+ * collapseSpaces("hello world")
262
+ * // → "hello world"
263
+ *
264
+ * collapseSpaces("foo\u00A0\u00A0bar") // two nbsp
265
+ * // → "foo\u00A0bar" // single nbsp
266
+ *
267
+ * collapseSpaces("a \u00A0b") // space followed by nbsp
268
+ * // → "a b" // keeps the first (regular space)
269
+ * ```
270
+ */
271
+ export function collapseSpaces(text) {
272
+ return text.replace(new RegExp(`(?<first>[ ${NBSP}])[ ${NBSP}]+`, "g"), "$<first>");
273
+ }
274
+ /**
275
+ * Converts repeated punctuation marks to Unicode ligature characters,
276
+ * squashing multiple marks to a single character.
277
+ *
278
+ * Handles:
279
+ * - "??" or "???" etc → "⁇" (squashed to double question mark ligature)
280
+ * - "?!" or "?!!" etc → "⁈" (question exclamation mark)
281
+ * - "!?" or "!??" etc → "⁉" (exclamation question mark)
282
+ * - "!!" or "!!!" etc → "!" (squashed to single exclamation)
283
+ *
284
+ * Note: These ligatures have poor font support, so this function is
285
+ * disabled by default.
286
+ */
287
+ export function punctuationLigatures(text, options = {}) {
288
+ const chr = options.separator
289
+ ? escapeRegex(options.separator)
290
+ : ESCAPED_DEFAULT_SEPARATOR;
291
+ // Order matters: handle mixed punctuation first, then repeated
292
+ // Patterns capture separators between characters and preserve them after the ligature
293
+ // ?!+ → ⁈ (question followed by one or more exclamation marks)
294
+ text = text.replace(new RegExp(`\\?(${chr})?!(?:${chr}?!)*`, "g"), (_match, sep) => QUESTION_EXCLAMATION + (sep || ""));
295
+ // !?+ → ⁉ (exclamation followed by one or more question marks)
296
+ text = text.replace(new RegExp(`!(${chr})?\\?(?:${chr}?\\?)*`, "g"), (_match, sep) => EXCLAMATION_QUESTION + (sep || ""));
297
+ // ??+ → ⁇ (two or more question marks squashed to ligature)
298
+ text = text.replace(new RegExp(`\\?(${chr})?\\?(?:${chr}?\\?)*`, "g"), (_match, sep) => DOUBLE_QUESTION + (sep || ""));
299
+ // !!+ → ! (two or more exclamation marks squashed to single)
300
+ text = text.replace(new RegExp(`!(${chr})?!(?:${chr}?!)*`, "g"), (_match, sep) => "!" + (sep || ""));
301
+ return text;
302
+ }
253
303
  /**
254
304
  * Applies all symbol transformations.
255
305
  *
@@ -1 +1 @@
1
- {"version":3,"file":"symbols.js","sourceRoot":"","sources":["../src/symbols.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"symbols.js","sourceRoot":"","sources":["../src/symbols.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Utility functions for text transformation validation.
3
+ *
4
+ * @module utils
5
+ */
6
+ export declare function countSeparators(text: string, separator?: string): number;
7
+ /**
8
+ * Validates that a transformation preserved the separator count.
9
+ * Throws an error if separators were added or removed.
10
+ *
11
+ * @param original - The original text before transformation
12
+ * @param transformed - The text after transformation
13
+ * @param separator - The separator character to check (default: DEFAULT_SEPARATOR)
14
+ * @param transformName - Name of the transform for error messages (default: "transform")
15
+ * @throws Error if separator count changed
16
+ */
17
+ export declare function assertSeparatorCountPreserved(original: string, transformed: string, separator?: string, transformName?: string): void;
18
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,GAAE,MAA0B,GAAG,MAAM,CAM3F;AAED;;;;;;;;;GASG;AACH,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,SAAS,GAAE,MAA0B,EACrC,aAAa,GAAE,MAAoB,GAClC,IAAI,CAQN"}
package/dist/utils.js ADDED
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Utility functions for text transformation validation.
3
+ *
4
+ * @module utils
5
+ */
6
+ import { DEFAULT_SEPARATOR } from "./constants.js";
7
+ export function countSeparators(text, separator = DEFAULT_SEPARATOR) {
8
+ let count = 0;
9
+ for (const char of text) {
10
+ if (char === separator)
11
+ count++;
12
+ }
13
+ return count;
14
+ }
15
+ /**
16
+ * Validates that a transformation preserved the separator count.
17
+ * Throws an error if separators were added or removed.
18
+ *
19
+ * @param original - The original text before transformation
20
+ * @param transformed - The text after transformation
21
+ * @param separator - The separator character to check (default: DEFAULT_SEPARATOR)
22
+ * @param transformName - Name of the transform for error messages (default: "transform")
23
+ * @throws Error if separator count changed
24
+ */
25
+ export function assertSeparatorCountPreserved(original, transformed, separator = DEFAULT_SEPARATOR, transformName = "transform") {
26
+ const originalCount = countSeparators(original, separator);
27
+ const transformedCount = countSeparators(transformed, separator);
28
+ if (originalCount !== transformedCount) {
29
+ throw new Error(`${transformName} altered separator count: expected ${originalCount}, got ${transformedCount}`);
30
+ }
31
+ }
32
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAElD,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,YAAoB,iBAAiB;IACjF,IAAI,KAAK,GAAG,CAAC,CAAA;IACb,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;QACxB,IAAI,IAAI,KAAK,SAAS;YAAE,KAAK,EAAE,CAAA;IACjC,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,6BAA6B,CAC3C,QAAgB,EAChB,WAAmB,EACnB,YAAoB,iBAAiB,EACrC,gBAAwB,WAAW;IAEnC,MAAM,aAAa,GAAG,eAAe,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAA;IAC1D,MAAM,gBAAgB,GAAG,eAAe,CAAC,WAAW,EAAE,SAAS,CAAC,CAAA;IAChE,IAAI,aAAa,KAAK,gBAAgB,EAAE,CAAC;QACvC,MAAM,IAAI,KAAK,CACb,GAAG,aAAa,sCAAsC,aAAa,SAAS,gBAAgB,EAAE,CAC/F,CAAA;IACH,CAAC;AACH,CAAC"}