@stryke/string-format 0.13.2 → 0.13.3

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 (94) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/acronyms.cjs +411 -1
  3. package/dist/acronyms.mjs +407 -1
  4. package/dist/acronyms.mjs.map +1 -1
  5. package/dist/articles.cjs +10 -1
  6. package/dist/articles.mjs +9 -1
  7. package/dist/articles.mjs.map +1 -1
  8. package/dist/camel-case.cjs +32 -1
  9. package/dist/camel-case.mjs +31 -1
  10. package/dist/camel-case.mjs.map +1 -1
  11. package/dist/combine.cjs +15 -1
  12. package/dist/combine.mjs +14 -1
  13. package/dist/combine.mjs.map +1 -1
  14. package/dist/conjunctions.cjs +32 -1
  15. package/dist/conjunctions.mjs +31 -1
  16. package/dist/conjunctions.mjs.map +1 -1
  17. package/dist/constant-case.cjs +32 -1
  18. package/dist/constant-case.mjs +31 -1
  19. package/dist/constant-case.mjs.map +1 -1
  20. package/dist/deburr.cjs +28 -1
  21. package/dist/deburr.mjs +28 -1
  22. package/dist/deburr.mjs.map +1 -1
  23. package/dist/decamelize.cjs +14 -1
  24. package/dist/decamelize.mjs +13 -1
  25. package/dist/decamelize.mjs.map +1 -1
  26. package/dist/escape.cjs +49 -1
  27. package/dist/escape.mjs +47 -1
  28. package/dist/escape.mjs.map +1 -1
  29. package/dist/format-special-cases.cjs +33 -1
  30. package/dist/format-special-cases.mjs +33 -1
  31. package/dist/format-special-cases.mjs.map +1 -1
  32. package/dist/get-words.cjs +40 -1
  33. package/dist/get-words.mjs +37 -1
  34. package/dist/get-words.mjs.map +1 -1
  35. package/dist/helpers/src/remove-accents.cjs +415 -1
  36. package/dist/helpers/src/remove-accents.mjs +414 -1
  37. package/dist/helpers/src/remove-accents.mjs.map +1 -1
  38. package/dist/index.cjs +75 -1
  39. package/dist/index.mjs +30 -1
  40. package/dist/kebab-case.cjs +34 -1
  41. package/dist/kebab-case.mjs +33 -1
  42. package/dist/kebab-case.mjs.map +1 -1
  43. package/dist/lower-case-first.cjs +17 -1
  44. package/dist/lower-case-first.mjs +16 -1
  45. package/dist/lower-case-first.mjs.map +1 -1
  46. package/dist/normalize-email.cjs +31 -1
  47. package/dist/normalize-email.mjs +30 -1
  48. package/dist/normalize-email.mjs.map +1 -1
  49. package/dist/package.cjs +124 -1
  50. package/dist/package.mjs +120 -1
  51. package/dist/package.mjs.map +1 -1
  52. package/dist/pad.cjs +25 -1
  53. package/dist/pad.mjs +24 -1
  54. package/dist/pad.mjs.map +1 -1
  55. package/dist/pascal-case.cjs +32 -1
  56. package/dist/pascal-case.mjs +31 -1
  57. package/dist/pascal-case.mjs.map +1 -1
  58. package/dist/period-split.cjs +38 -1
  59. package/dist/period-split.mjs +37 -1
  60. package/dist/period-split.mjs.map +1 -1
  61. package/dist/prepositions.cjs +68 -1
  62. package/dist/prepositions.mjs +67 -1
  63. package/dist/prepositions.mjs.map +1 -1
  64. package/dist/pretty-bytes.cjs +129 -1
  65. package/dist/pretty-bytes.mjs +127 -1
  66. package/dist/pretty-bytes.mjs.map +1 -1
  67. package/dist/snake-case.cjs +42 -1
  68. package/dist/snake-case.mjs +41 -1
  69. package/dist/snake-case.mjs.map +1 -1
  70. package/dist/special-cases.cjs +53 -1
  71. package/dist/special-cases.mjs +52 -1
  72. package/dist/special-cases.mjs.map +1 -1
  73. package/dist/start-case.cjs +46 -1
  74. package/dist/start-case.mjs +45 -1
  75. package/dist/start-case.mjs.map +1 -1
  76. package/dist/strip-indents.cjs +24 -3
  77. package/dist/strip-indents.mjs +23 -3
  78. package/dist/strip-indents.mjs.map +1 -1
  79. package/dist/title-case.cjs +19 -1
  80. package/dist/title-case.mjs +19 -1
  81. package/dist/title-case.mjs.map +1 -1
  82. package/dist/types/src/base.cjs +6 -1
  83. package/dist/types/src/base.mjs +5 -1
  84. package/dist/types/src/base.mjs.map +1 -1
  85. package/dist/unescape.cjs +30 -1
  86. package/dist/unescape.mjs +29 -1
  87. package/dist/unescape.mjs.map +1 -1
  88. package/dist/upper-case-first.cjs +17 -1
  89. package/dist/upper-case-first.mjs +16 -1
  90. package/dist/upper-case-first.mjs.map +1 -1
  91. package/dist/vowels.cjs +40 -1
  92. package/dist/vowels.mjs +38 -1
  93. package/dist/vowels.mjs.map +1 -1
  94. package/package.json +2 -2
@@ -1,2 +1,38 @@
1
- import{EMPTY_STRING as e}from"./types/src/base.mjs";import{upperCaseFirst as t}from"./upper-case-first.mjs";function n(e){return e?/^[a-z]+(?:\.[a-z0-9]+)*$/.test(e):!1}function r(r){if(!r||n(r))return r;let i=r?.replace(/[A-Z]+/g,n=>t(n)??e)?.split(/(?=[A-Z])|[\s._-]/).map(e=>e.toLowerCase())??[];return i.length===0?``:i.length===1?i[0]:i.reduce((e,t)=>`${e}.${t.toLowerCase()}`.toLowerCase())}export{n as isPeriodSplit,r as periodSplit};
1
+ import { EMPTY_STRING } from "./types/src/base.mjs";
2
+ import { upperCaseFirst } from "./upper-case-first.mjs";
3
+
4
+ //#region src/period-split.ts
5
+ /**
6
+ * Check if the input string is in snake case.
7
+ *
8
+ * @remarks
9
+ * Snake case is defined as all lowercase letters with underscores separating words - "this_is_an_example"
10
+ *
11
+ * @param input - The input string to check.
12
+ * @returns True if the input is in snake case, false otherwise.
13
+ */
14
+ function isPeriodSplit(input) {
15
+ return input ? /^[a-z]+(?:\.[a-z0-9]+)*$/.test(input) : false;
16
+ }
17
+ /**
18
+ * Make all characters lowercase and add a period in between each word
19
+ *
20
+ * @remarks
21
+ * "this.is.an.example"
22
+ *
23
+ * @param input - The input string.
24
+ * @returns The period-split string.
25
+ */
26
+ function periodSplit(input) {
27
+ if (!input || isPeriodSplit(input)) return input;
28
+ const parts = input?.replace(/[A-Z]+/g, (input$1) => upperCaseFirst(input$1) ?? EMPTY_STRING)?.split(/(?=[A-Z])|[\s._-]/).map((x) => x.toLowerCase()) ?? [];
29
+ if (parts.length === 0) return "";
30
+ if (parts.length === 1) return parts[0];
31
+ return parts.reduce((ret, part) => {
32
+ return `${ret}.${part.toLowerCase()}`.toLowerCase();
33
+ });
34
+ }
35
+
36
+ //#endregion
37
+ export { isPeriodSplit, periodSplit };
2
38
  //# sourceMappingURL=period-split.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"period-split.mjs","names":["input"],"sources":["../src/period-split.ts"],"sourcesContent":["/* -------------------------------------------------------------------\n\n ⚡ Storm Software - Stryke\n\n This code was released as part of the Stryke project. Stryke\n is maintained by Storm Software under the Apache-2.0 license, and is\n free for commercial and private use. For more information, please visit\n our licensing page at https://stormsoftware.com/licenses/projects/stryke.\n\n Website: https://stormsoftware.com\n Repository: https://github.com/storm-software/stryke\n Documentation: https://docs.stormsoftware.com/projects/stryke\n Contact: https://stormsoftware.com/contact\n\n SPDX-License-Identifier: Apache-2.0\n\n ------------------------------------------------------------------- */\n\nimport { EMPTY_STRING } from \"@stryke/types\";\nimport { upperCaseFirst } from \"./upper-case-first\";\n\n/**\n * Check if the input string is in snake case.\n *\n * @remarks\n * Snake case is defined as all lowercase letters with underscores separating words - \"this_is_an_example\"\n *\n * @param input - The input string to check.\n * @returns True if the input is in snake case, false otherwise.\n */\nexport function isPeriodSplit(input: string | undefined): boolean {\n return input ? /^[a-z]+(?:\\.[a-z0-9]+)*$/.test(input) : false;\n}\n\n/**\n * Make all characters lowercase and add a period in between each word\n *\n * @remarks\n * \"this.is.an.example\"\n *\n * @param input - The input string.\n * @returns The period-split string.\n */\nexport function periodSplit<T extends string | undefined>(input?: T): T {\n if (!input || isPeriodSplit(input)) {\n return input as T;\n }\n\n const parts =\n input\n ?.replace(\n /[A-Z]+/g,\n (input?: string) => upperCaseFirst(input) ?? EMPTY_STRING\n )\n ?.split(/(?=[A-Z])|[\\s._-]/)\n .map(x => x.toLowerCase()) ?? [];\n if (parts.length === 0) {\n return \"\" as T;\n }\n if (parts.length === 1) {\n return parts[0] as T;\n }\n\n return parts.reduce((ret: string, part: string) => {\n return `${ret}.${part.toLowerCase()}`.toLowerCase();\n }) as T;\n}\n"],"mappings":"4GA8BA,SAAgB,EAAc,EAAoC,CAChE,OAAO,EAAQ,2BAA2B,KAAK,EAAM,CAAG,GAY1D,SAAgB,EAA0C,EAAc,CACtE,GAAI,CAAC,GAAS,EAAc,EAAM,CAChC,OAAO,EAGT,IAAM,EACJ,GACI,QACA,UACC,GAAmB,EAAeA,EAAM,EAAI,EAC9C,EACC,MAAM,oBAAoB,CAC3B,IAAI,GAAK,EAAE,aAAa,CAAC,EAAI,EAAE,CAQpC,OAPI,EAAM,SAAW,EACZ,GAEL,EAAM,SAAW,EACZ,EAAM,GAGR,EAAM,QAAQ,EAAa,IACzB,GAAG,EAAI,GAAG,EAAK,aAAa,GAAG,aAAa,CACnD"}
1
+ {"version":3,"file":"period-split.mjs","names":["input"],"sources":["../src/period-split.ts"],"sourcesContent":["/* -------------------------------------------------------------------\n\n ⚡ Storm Software - Stryke\n\n This code was released as part of the Stryke project. Stryke\n is maintained by Storm Software under the Apache-2.0 license, and is\n free for commercial and private use. For more information, please visit\n our licensing page at https://stormsoftware.com/licenses/projects/stryke.\n\n Website: https://stormsoftware.com\n Repository: https://github.com/storm-software/stryke\n Documentation: https://docs.stormsoftware.com/projects/stryke\n Contact: https://stormsoftware.com/contact\n\n SPDX-License-Identifier: Apache-2.0\n\n ------------------------------------------------------------------- */\n\nimport { EMPTY_STRING } from \"@stryke/types\";\nimport { upperCaseFirst } from \"./upper-case-first\";\n\n/**\n * Check if the input string is in snake case.\n *\n * @remarks\n * Snake case is defined as all lowercase letters with underscores separating words - \"this_is_an_example\"\n *\n * @param input - The input string to check.\n * @returns True if the input is in snake case, false otherwise.\n */\nexport function isPeriodSplit(input: string | undefined): boolean {\n return input ? /^[a-z]+(?:\\.[a-z0-9]+)*$/.test(input) : false;\n}\n\n/**\n * Make all characters lowercase and add a period in between each word\n *\n * @remarks\n * \"this.is.an.example\"\n *\n * @param input - The input string.\n * @returns The period-split string.\n */\nexport function periodSplit<T extends string | undefined>(input?: T): T {\n if (!input || isPeriodSplit(input)) {\n return input as T;\n }\n\n const parts =\n input\n ?.replace(\n /[A-Z]+/g,\n (input?: string) => upperCaseFirst(input) ?? EMPTY_STRING\n )\n ?.split(/(?=[A-Z])|[\\s._-]/)\n .map(x => x.toLowerCase()) ?? [];\n if (parts.length === 0) {\n return \"\" as T;\n }\n if (parts.length === 1) {\n return parts[0] as T;\n }\n\n return parts.reduce((ret: string, part: string) => {\n return `${ret}.${part.toLowerCase()}`.toLowerCase();\n }) as T;\n}\n"],"mappings":";;;;;;;;;;;;;AA8BA,SAAgB,cAAc,OAAoC;AAChE,QAAO,QAAQ,2BAA2B,KAAK,MAAM,GAAG;;;;;;;;;;;AAY1D,SAAgB,YAA0C,OAAc;AACtE,KAAI,CAAC,SAAS,cAAc,MAAM,CAChC,QAAO;CAGT,MAAM,QACJ,OACI,QACA,YACC,YAAmB,eAAeA,QAAM,IAAI,aAC9C,EACC,MAAM,oBAAoB,CAC3B,KAAI,MAAK,EAAE,aAAa,CAAC,IAAI,EAAE;AACpC,KAAI,MAAM,WAAW,EACnB,QAAO;AAET,KAAI,MAAM,WAAW,EACnB,QAAO,MAAM;AAGf,QAAO,MAAM,QAAQ,KAAa,SAAiB;AACjD,SAAO,GAAG,IAAI,GAAG,KAAK,aAAa,GAAG,aAAa;GACnD"}
@@ -1 +1,68 @@
1
- const e=`about.above.across.after.against.along.among.around.at.because of.before.behind.below.beneath.beside.besides.between.beyond.but.by.concerning.despite.down.during.except.excepting.for.from.in.in front of.inside.in spite of.instead of.into.like.near.of.off.on.onto.out.outside.over.past.regarding.since.through.throughout.to.toward.under.underneath.until.up.upon.up to.with.within.without.with regard to.with respect to`.split(`.`);exports.PREPOSITIONS=e;
1
+
2
+ //#region src/prepositions.ts
3
+ const PREPOSITIONS = [
4
+ "about",
5
+ "above",
6
+ "across",
7
+ "after",
8
+ "against",
9
+ "along",
10
+ "among",
11
+ "around",
12
+ "at",
13
+ "because of",
14
+ "before",
15
+ "behind",
16
+ "below",
17
+ "beneath",
18
+ "beside",
19
+ "besides",
20
+ "between",
21
+ "beyond",
22
+ "but",
23
+ "by",
24
+ "concerning",
25
+ "despite",
26
+ "down",
27
+ "during",
28
+ "except",
29
+ "excepting",
30
+ "for",
31
+ "from",
32
+ "in",
33
+ "in front of",
34
+ "inside",
35
+ "in spite of",
36
+ "instead of",
37
+ "into",
38
+ "like",
39
+ "near",
40
+ "of",
41
+ "off",
42
+ "on",
43
+ "onto",
44
+ "out",
45
+ "outside",
46
+ "over",
47
+ "past",
48
+ "regarding",
49
+ "since",
50
+ "through",
51
+ "throughout",
52
+ "to",
53
+ "toward",
54
+ "under",
55
+ "underneath",
56
+ "until",
57
+ "up",
58
+ "upon",
59
+ "up to",
60
+ "with",
61
+ "within",
62
+ "without",
63
+ "with regard to",
64
+ "with respect to"
65
+ ];
66
+
67
+ //#endregion
68
+ exports.PREPOSITIONS = PREPOSITIONS;
@@ -1,2 +1,68 @@
1
- const e=`about.above.across.after.against.along.among.around.at.because of.before.behind.below.beneath.beside.besides.between.beyond.but.by.concerning.despite.down.during.except.excepting.for.from.in.in front of.inside.in spite of.instead of.into.like.near.of.off.on.onto.out.outside.over.past.regarding.since.through.throughout.to.toward.under.underneath.until.up.upon.up to.with.within.without.with regard to.with respect to`.split(`.`);export{e as PREPOSITIONS};
1
+ //#region src/prepositions.ts
2
+ const PREPOSITIONS = [
3
+ "about",
4
+ "above",
5
+ "across",
6
+ "after",
7
+ "against",
8
+ "along",
9
+ "among",
10
+ "around",
11
+ "at",
12
+ "because of",
13
+ "before",
14
+ "behind",
15
+ "below",
16
+ "beneath",
17
+ "beside",
18
+ "besides",
19
+ "between",
20
+ "beyond",
21
+ "but",
22
+ "by",
23
+ "concerning",
24
+ "despite",
25
+ "down",
26
+ "during",
27
+ "except",
28
+ "excepting",
29
+ "for",
30
+ "from",
31
+ "in",
32
+ "in front of",
33
+ "inside",
34
+ "in spite of",
35
+ "instead of",
36
+ "into",
37
+ "like",
38
+ "near",
39
+ "of",
40
+ "off",
41
+ "on",
42
+ "onto",
43
+ "out",
44
+ "outside",
45
+ "over",
46
+ "past",
47
+ "regarding",
48
+ "since",
49
+ "through",
50
+ "throughout",
51
+ "to",
52
+ "toward",
53
+ "under",
54
+ "underneath",
55
+ "until",
56
+ "up",
57
+ "upon",
58
+ "up to",
59
+ "with",
60
+ "within",
61
+ "without",
62
+ "with regard to",
63
+ "with respect to"
64
+ ];
65
+
66
+ //#endregion
67
+ export { PREPOSITIONS };
2
68
  //# sourceMappingURL=prepositions.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"prepositions.mjs","names":[],"sources":["../src/prepositions.ts"],"sourcesContent":["/* -------------------------------------------------------------------\n\n ⚡ Storm Software - Stryke\n\n This code was released as part of the Stryke project. Stryke\n is maintained by Storm Software under the Apache-2.0 license, and is\n free for commercial and private use. For more information, please visit\n our licensing page at https://stormsoftware.com/licenses/projects/stryke.\n\n Website: https://stormsoftware.com\n Repository: https://github.com/storm-software/stryke\n Documentation: https://docs.stormsoftware.com/projects/stryke\n Contact: https://stormsoftware.com/contact\n\n SPDX-License-Identifier: Apache-2.0\n\n ------------------------------------------------------------------- */\n\nexport const PREPOSITIONS = [\n \"about\",\n \"above\",\n \"across\",\n \"after\",\n \"against\",\n \"along\",\n \"among\",\n \"around\",\n \"at\",\n \"because of\",\n \"before\",\n \"behind\",\n \"below\",\n \"beneath\",\n \"beside\",\n \"besides\",\n \"between\",\n \"beyond\",\n \"but\",\n \"by\",\n \"concerning\",\n \"despite\",\n \"down\",\n \"during\",\n \"except\",\n \"excepting\",\n \"for\",\n \"from\",\n \"in\",\n \"in front of\",\n \"inside\",\n \"in spite of\",\n \"instead of\",\n \"into\",\n \"like\",\n \"near\",\n \"of\",\n \"off\",\n \"on\",\n \"onto\",\n \"out\",\n \"outside\",\n \"over\",\n \"past\",\n \"regarding\",\n \"since\",\n \"through\",\n \"throughout\",\n \"to\",\n \"toward\",\n \"under\",\n \"underneath\",\n \"until\",\n \"up\",\n \"upon\",\n \"up to\",\n \"with\",\n \"within\",\n \"without\",\n \"with regard to\",\n \"with respect to\"\n];\n"],"mappings":"AAkBA,MAAa,EAAe,8aA8D3B"}
1
+ {"version":3,"file":"prepositions.mjs","names":[],"sources":["../src/prepositions.ts"],"sourcesContent":["/* -------------------------------------------------------------------\n\n ⚡ Storm Software - Stryke\n\n This code was released as part of the Stryke project. Stryke\n is maintained by Storm Software under the Apache-2.0 license, and is\n free for commercial and private use. For more information, please visit\n our licensing page at https://stormsoftware.com/licenses/projects/stryke.\n\n Website: https://stormsoftware.com\n Repository: https://github.com/storm-software/stryke\n Documentation: https://docs.stormsoftware.com/projects/stryke\n Contact: https://stormsoftware.com/contact\n\n SPDX-License-Identifier: Apache-2.0\n\n ------------------------------------------------------------------- */\n\nexport const PREPOSITIONS = [\n \"about\",\n \"above\",\n \"across\",\n \"after\",\n \"against\",\n \"along\",\n \"among\",\n \"around\",\n \"at\",\n \"because of\",\n \"before\",\n \"behind\",\n \"below\",\n \"beneath\",\n \"beside\",\n \"besides\",\n \"between\",\n \"beyond\",\n \"but\",\n \"by\",\n \"concerning\",\n \"despite\",\n \"down\",\n \"during\",\n \"except\",\n \"excepting\",\n \"for\",\n \"from\",\n \"in\",\n \"in front of\",\n \"inside\",\n \"in spite of\",\n \"instead of\",\n \"into\",\n \"like\",\n \"near\",\n \"of\",\n \"off\",\n \"on\",\n \"onto\",\n \"out\",\n \"outside\",\n \"over\",\n \"past\",\n \"regarding\",\n \"since\",\n \"through\",\n \"throughout\",\n \"to\",\n \"toward\",\n \"under\",\n \"underneath\",\n \"until\",\n \"up\",\n \"upon\",\n \"up to\",\n \"with\",\n \"within\",\n \"without\",\n \"with regard to\",\n \"with respect to\"\n];\n"],"mappings":";AAkBA,MAAa,eAAe;CAC1B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD"}
@@ -1 +1,129 @@
1
- const e=[`B`,`kB`,`MB`,`GB`,`TB`,`PB`,`EB`,`ZB`,`YB`],t=[`B`,`KiB`,`MiB`,`GiB`,`TiB`,`PiB`,`EiB`,`ZiB`,`YiB`],n=[`b`,`kbit`,`Mbit`,`Gbit`,`Tbit`,`Pbit`,`Ebit`,`Zbit`,`Ybit`],r=[`b`,`kibit`,`Mibit`,`Gibit`,`Tibit`,`Pibit`,`Eibit`,`Zibit`,`Yibit`],i=(e,t,n={})=>{let r=e,i=t;return typeof i==`string`?(i||=process.env.STORM_LOCALE||`en-US`,Array.isArray(i)&&(r=e?.toLocaleString(i,n))):(i===!0||n!==void 0)&&(r=e?.toLocaleString(void 0,n)),String(r)};function a(a,o){let s=a;if(!Number.isFinite(s))throw TypeError(`Expected a finite number, got ${typeof s}: ${s}`);let c={bits:!1,binary:!1,space:!0,...o},l=c.bits?c.binary?r:n:c.binary?t:e,u=c.space?` `:``;if(c.signed&&s===0)return` 0${u}${l[0]}`;let d=s<0,f=d?`-`:c.signed?`+`:``;d&&(s=-s);let p;if(c.minimumFractionDigits!==void 0&&(p={minimumFractionDigits:c.minimumFractionDigits}),c.maximumFractionDigits!==void 0&&(p={maximumFractionDigits:c.maximumFractionDigits,...p}),s<1)return f+i(s,c.locale,p)+u+l[0];let m=Math.min(Math.floor(c.binary?Math.log(s)/Math.log(1024):Math.log10(s)/3),l.length-1);s/=(c.binary?1024:1e3)**m,p||(s=s.toPrecision(3));let h=i(Number(s),c.locale,p),g=l[m];return f+h+u+g}exports.prettyBytes=a,exports.toLocaleString=i;
1
+
2
+ //#region src/pretty-bytes.ts
3
+ const BYTE_UNITS = [
4
+ "B",
5
+ "kB",
6
+ "MB",
7
+ "GB",
8
+ "TB",
9
+ "PB",
10
+ "EB",
11
+ "ZB",
12
+ "YB"
13
+ ];
14
+ const BIBYTE_UNITS = [
15
+ "B",
16
+ "KiB",
17
+ "MiB",
18
+ "GiB",
19
+ "TiB",
20
+ "PiB",
21
+ "EiB",
22
+ "ZiB",
23
+ "YiB"
24
+ ];
25
+ const BIT_UNITS = [
26
+ "b",
27
+ "kbit",
28
+ "Mbit",
29
+ "Gbit",
30
+ "Tbit",
31
+ "Pbit",
32
+ "Ebit",
33
+ "Zbit",
34
+ "Ybit"
35
+ ];
36
+ const BIBIT_UNITS = [
37
+ "b",
38
+ "kibit",
39
+ "Mibit",
40
+ "Gibit",
41
+ "Tibit",
42
+ "Pibit",
43
+ "Eibit",
44
+ "Zibit",
45
+ "Yibit"
46
+ ];
47
+ /**
48
+ * Formats the given number using `Number#toLocaleString`.
49
+ *
50
+ * @remarks
51
+ * - If locale is a string, the value is expected to be a locale-key (for example: `de`).
52
+ * - If locale is true, the system default locale is used for translation.
53
+ * - If no value for locale is specified, the number is returned unmodified.
54
+ *
55
+ * @param number - The number to format.
56
+ * @param locale - The locale to use for formatting the number.
57
+ * @param options - The options to use for formatting the number.
58
+ * @returns The formatted number.
59
+ */
60
+ const toLocaleString = (number, locale, options = {}) => {
61
+ let result = number;
62
+ let _locale = locale;
63
+ if (typeof _locale === "string") {
64
+ if (!_locale) _locale = process.env.STORM_LOCALE || "en-US";
65
+ if (Array.isArray(_locale)) result = number?.toLocaleString(_locale, options);
66
+ } else if (_locale === true || options !== void 0) result = number?.toLocaleString(void 0, options);
67
+ return String(result);
68
+ };
69
+ /**
70
+ * Convert bytes to a human readable string: `1337` → `1.34 kB`.
71
+ *
72
+ * @param number - The number to format.
73
+ *
74
+ * @example
75
+ * ```ts
76
+ * import { prettyBytes } from '@stryke/string-fns/pretty-bytes';
77
+ *
78
+ * prettyBytes(1337);
79
+ * //=> '1.34 kB'
80
+ *
81
+ * prettyBytes(100);
82
+ * //=> '100 B'
83
+ *
84
+ * // Display file size differences
85
+ * prettyBytes(42, {signed: true});
86
+ * //=> '+42 B'
87
+ *
88
+ * // Localized output using German locale
89
+ * prettyBytes(1337, {locale: 'de'});
90
+ * //=> '1,34 kB'
91
+ * ```
92
+ *
93
+ * @param number - The number to format.
94
+ * @param options - The options to use.
95
+ * @returns The formatted string.
96
+ */
97
+ function prettyBytes(number, options) {
98
+ let _number = number;
99
+ if (!Number.isFinite(_number)) throw new TypeError(`Expected a finite number, got ${typeof _number}: ${_number}`);
100
+ const opts = {
101
+ bits: false,
102
+ binary: false,
103
+ space: true,
104
+ ...options
105
+ };
106
+ const UNITS = opts.bits ? opts.binary ? BIBIT_UNITS : BIT_UNITS : opts.binary ? BIBYTE_UNITS : BYTE_UNITS;
107
+ const separator = opts.space ? " " : "";
108
+ if (opts.signed && _number === 0) return ` 0${separator}${UNITS[0]}`;
109
+ const isNegative = _number < 0;
110
+ const prefix = isNegative ? "-" : opts.signed ? "+" : "";
111
+ if (isNegative) _number = -_number;
112
+ let localeOptions;
113
+ if (opts.minimumFractionDigits !== void 0) localeOptions = { minimumFractionDigits: opts.minimumFractionDigits };
114
+ if (opts.maximumFractionDigits !== void 0) localeOptions = {
115
+ maximumFractionDigits: opts.maximumFractionDigits,
116
+ ...localeOptions
117
+ };
118
+ if (_number < 1) return prefix + toLocaleString(_number, opts.locale, localeOptions) + separator + UNITS[0];
119
+ const exponent = Math.min(Math.floor(opts.binary ? Math.log(_number) / Math.log(1024) : Math.log10(_number) / 3), UNITS.length - 1);
120
+ _number /= (opts.binary ? 1024 : 1e3) ** exponent;
121
+ if (!localeOptions) _number = _number.toPrecision(3);
122
+ const numberString = toLocaleString(Number(_number), opts.locale, localeOptions);
123
+ const unit = UNITS[exponent];
124
+ return prefix + numberString + separator + unit;
125
+ }
126
+
127
+ //#endregion
128
+ exports.prettyBytes = prettyBytes;
129
+ exports.toLocaleString = toLocaleString;
@@ -1,2 +1,128 @@
1
- const e=[`B`,`kB`,`MB`,`GB`,`TB`,`PB`,`EB`,`ZB`,`YB`],t=[`B`,`KiB`,`MiB`,`GiB`,`TiB`,`PiB`,`EiB`,`ZiB`,`YiB`],n=[`b`,`kbit`,`Mbit`,`Gbit`,`Tbit`,`Pbit`,`Ebit`,`Zbit`,`Ybit`],r=[`b`,`kibit`,`Mibit`,`Gibit`,`Tibit`,`Pibit`,`Eibit`,`Zibit`,`Yibit`],i=(e,t,n={})=>{let r=e,i=t;return typeof i==`string`?(i||=process.env.STORM_LOCALE||`en-US`,Array.isArray(i)&&(r=e?.toLocaleString(i,n))):(i===!0||n!==void 0)&&(r=e?.toLocaleString(void 0,n)),String(r)};function a(a,o){let s=a;if(!Number.isFinite(s))throw TypeError(`Expected a finite number, got ${typeof s}: ${s}`);let c={bits:!1,binary:!1,space:!0,...o},l=c.bits?c.binary?r:n:c.binary?t:e,u=c.space?` `:``;if(c.signed&&s===0)return` 0${u}${l[0]}`;let d=s<0,f=d?`-`:c.signed?`+`:``;d&&(s=-s);let p;if(c.minimumFractionDigits!==void 0&&(p={minimumFractionDigits:c.minimumFractionDigits}),c.maximumFractionDigits!==void 0&&(p={maximumFractionDigits:c.maximumFractionDigits,...p}),s<1)return f+i(s,c.locale,p)+u+l[0];let m=Math.min(Math.floor(c.binary?Math.log(s)/Math.log(1024):Math.log10(s)/3),l.length-1);s/=(c.binary?1024:1e3)**m,p||(s=s.toPrecision(3));let h=i(Number(s),c.locale,p),g=l[m];return f+h+u+g}export{a as prettyBytes,i as toLocaleString};
1
+ //#region src/pretty-bytes.ts
2
+ const BYTE_UNITS = [
3
+ "B",
4
+ "kB",
5
+ "MB",
6
+ "GB",
7
+ "TB",
8
+ "PB",
9
+ "EB",
10
+ "ZB",
11
+ "YB"
12
+ ];
13
+ const BIBYTE_UNITS = [
14
+ "B",
15
+ "KiB",
16
+ "MiB",
17
+ "GiB",
18
+ "TiB",
19
+ "PiB",
20
+ "EiB",
21
+ "ZiB",
22
+ "YiB"
23
+ ];
24
+ const BIT_UNITS = [
25
+ "b",
26
+ "kbit",
27
+ "Mbit",
28
+ "Gbit",
29
+ "Tbit",
30
+ "Pbit",
31
+ "Ebit",
32
+ "Zbit",
33
+ "Ybit"
34
+ ];
35
+ const BIBIT_UNITS = [
36
+ "b",
37
+ "kibit",
38
+ "Mibit",
39
+ "Gibit",
40
+ "Tibit",
41
+ "Pibit",
42
+ "Eibit",
43
+ "Zibit",
44
+ "Yibit"
45
+ ];
46
+ /**
47
+ * Formats the given number using `Number#toLocaleString`.
48
+ *
49
+ * @remarks
50
+ * - If locale is a string, the value is expected to be a locale-key (for example: `de`).
51
+ * - If locale is true, the system default locale is used for translation.
52
+ * - If no value for locale is specified, the number is returned unmodified.
53
+ *
54
+ * @param number - The number to format.
55
+ * @param locale - The locale to use for formatting the number.
56
+ * @param options - The options to use for formatting the number.
57
+ * @returns The formatted number.
58
+ */
59
+ const toLocaleString = (number, locale, options = {}) => {
60
+ let result = number;
61
+ let _locale = locale;
62
+ if (typeof _locale === "string") {
63
+ if (!_locale) _locale = process.env.STORM_LOCALE || "en-US";
64
+ if (Array.isArray(_locale)) result = number?.toLocaleString(_locale, options);
65
+ } else if (_locale === true || options !== void 0) result = number?.toLocaleString(void 0, options);
66
+ return String(result);
67
+ };
68
+ /**
69
+ * Convert bytes to a human readable string: `1337` → `1.34 kB`.
70
+ *
71
+ * @param number - The number to format.
72
+ *
73
+ * @example
74
+ * ```ts
75
+ * import { prettyBytes } from '@stryke/string-fns/pretty-bytes';
76
+ *
77
+ * prettyBytes(1337);
78
+ * //=> '1.34 kB'
79
+ *
80
+ * prettyBytes(100);
81
+ * //=> '100 B'
82
+ *
83
+ * // Display file size differences
84
+ * prettyBytes(42, {signed: true});
85
+ * //=> '+42 B'
86
+ *
87
+ * // Localized output using German locale
88
+ * prettyBytes(1337, {locale: 'de'});
89
+ * //=> '1,34 kB'
90
+ * ```
91
+ *
92
+ * @param number - The number to format.
93
+ * @param options - The options to use.
94
+ * @returns The formatted string.
95
+ */
96
+ function prettyBytes(number, options) {
97
+ let _number = number;
98
+ if (!Number.isFinite(_number)) throw new TypeError(`Expected a finite number, got ${typeof _number}: ${_number}`);
99
+ const opts = {
100
+ bits: false,
101
+ binary: false,
102
+ space: true,
103
+ ...options
104
+ };
105
+ const UNITS = opts.bits ? opts.binary ? BIBIT_UNITS : BIT_UNITS : opts.binary ? BIBYTE_UNITS : BYTE_UNITS;
106
+ const separator = opts.space ? " " : "";
107
+ if (opts.signed && _number === 0) return ` 0${separator}${UNITS[0]}`;
108
+ const isNegative = _number < 0;
109
+ const prefix = isNegative ? "-" : opts.signed ? "+" : "";
110
+ if (isNegative) _number = -_number;
111
+ let localeOptions;
112
+ if (opts.minimumFractionDigits !== void 0) localeOptions = { minimumFractionDigits: opts.minimumFractionDigits };
113
+ if (opts.maximumFractionDigits !== void 0) localeOptions = {
114
+ maximumFractionDigits: opts.maximumFractionDigits,
115
+ ...localeOptions
116
+ };
117
+ if (_number < 1) return prefix + toLocaleString(_number, opts.locale, localeOptions) + separator + UNITS[0];
118
+ const exponent = Math.min(Math.floor(opts.binary ? Math.log(_number) / Math.log(1024) : Math.log10(_number) / 3), UNITS.length - 1);
119
+ _number /= (opts.binary ? 1024 : 1e3) ** exponent;
120
+ if (!localeOptions) _number = _number.toPrecision(3);
121
+ const numberString = toLocaleString(Number(_number), opts.locale, localeOptions);
122
+ const unit = UNITS[exponent];
123
+ return prefix + numberString + separator + unit;
124
+ }
125
+
126
+ //#endregion
127
+ export { prettyBytes, toLocaleString };
2
128
  //# sourceMappingURL=pretty-bytes.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"pretty-bytes.mjs","names":["_number: string | number"],"sources":["../src/pretty-bytes.ts"],"sourcesContent":["/* -------------------------------------------------------------------\n\n ⚡ Storm Software - Stryke\n\n This code was released as part of the Stryke project. Stryke\n is maintained by Storm Software under the Apache-2.0 license, and is\n free for commercial and private use. For more information, please visit\n our licensing page at https://stormsoftware.com/licenses/projects/stryke.\n\n Website: https://stormsoftware.com\n Repository: https://github.com/storm-software/stryke\n Documentation: https://docs.stormsoftware.com/projects/stryke\n Contact: https://stormsoftware.com/contact\n\n SPDX-License-Identifier: Apache-2.0\n\n ------------------------------------------------------------------- */\n\nexport interface Options {\n /**\n * Include plus sign for positive numbers. If the difference is exactly zero a space character will be prepended instead for better alignment.\n *\n * @defaultValue false\n */\n readonly signed?: boolean;\n\n /**\n * - If `false`: Output won't be localized.\n * - If `true`: Localize the output using the system/browser locale.\n * - If `string`: Expects a [BCP 47 language tag](https://en.wikipedia.org/wiki/IETF_language_tag) (For example: `en`, `de`, …)\n * - If `string[]`: Expects a list of [BCP 47 language tags](https://en.wikipedia.org/wiki/IETF_language_tag) (For example: `en`, `de`, …)\n *\n * @defaultValue false\n */\n readonly locale?: boolean | string | readonly string[];\n\n /**\n * Format the number as [bits](https://en.wikipedia.org/wiki/Bit) instead of [bytes](https://en.wikipedia.org/wiki/Byte). This can be useful when, for example, referring to [bit rate](https://en.wikipedia.org/wiki/Bit_rate).\n *\n * @defaultValue false\n *\n * @example\n * ```ts\n * import { prettyBytes } from '@stryke/string-fns/pretty-bytes';\n *\n * prettyBytes(1337, {bits: true});\n * //=> '1.34 kbit'\n * ```\n */\n readonly bits?: boolean;\n\n /**\n * Format the number using the [Binary Prefix](https://en.wikipedia.org/wiki/Binary_prefix) instead of the [SI Prefix](https://en.wikipedia.org/wiki/SI_prefix). This can be useful for presenting memory amounts. However, this should not be used for presenting file sizes.\n *\n * @defaultValue false\n *\n * @example\n * ```ts\n * import { prettyBytes } from '@stryke/string-fns/pretty-bytes';\n *\n * prettyBytes(1000, {binary: true});\n * //=> '1000 bit'\n *\n * prettyBytes(1024, {binary: true});\n * //=> '1 kiB'\n * ```\n */\n readonly binary?: boolean;\n\n /**\n * The minimum number of fraction digits to display.\n *\n * If neither `minimumFractionDigits` or `maximumFractionDigits` are set, the default behavior is to round to 3 significant digits.\n *\n * @defaultValue undefined\n *\n * @example\n * ```ts\n * import { prettyBytes } from '@stryke/string-fns/pretty-bytes';\n *\n * // Show the number with at least 3 fractional digits\n * prettyBytes(1900, {minimumFractionDigits: 3});\n * //=> '1.900 kB'\n *\n * prettyBytes(1900);\n * //=> '1.9 kB'\n * ```\n */\n readonly minimumFractionDigits?: number;\n\n /**\n * The maximum number of fraction digits to display.\n *\n * If neither `minimumFractionDigits` or `maximumFractionDigits` are set, the default behavior is to round to 3 significant digits.\n *\n * @defaultValue undefined\n *\n * @example\n * ```ts\n * import { prettyBytes } from '@stryke/string-fns/pretty-bytes';\n *\n * // Show the number with at most 1 fractional digit\n * prettyBytes(1920, {maximumFractionDigits: 1});\n * //=> '1.9 kB'\n *\n * prettyBytes(1920);\n * //=> '1.92 kB'\n * ```\n */\n readonly maximumFractionDigits?: number;\n\n /**\n * Put a space between the number and unit.\n *\n * @defaultValue true\n *\n * @example\n * ```ts\n * import { prettyBytes } from '@stryke/string-fns/pretty-bytes';\n *\n * prettyBytes(1920, {space: false});\n * //=> '1.9kB'\n *\n * prettyBytes(1920);\n * //=> '1.92 kB'\n * ```\n */\n readonly space?: boolean;\n}\n\nconst BYTE_UNITS = [\"B\", \"kB\", \"MB\", \"GB\", \"TB\", \"PB\", \"EB\", \"ZB\", \"YB\"];\nconst BIBYTE_UNITS = [\n \"B\",\n \"KiB\",\n \"MiB\",\n \"GiB\",\n \"TiB\",\n \"PiB\",\n \"EiB\",\n \"ZiB\",\n \"YiB\"\n];\nconst BIT_UNITS = [\n \"b\",\n \"kbit\",\n \"Mbit\",\n \"Gbit\",\n \"Tbit\",\n \"Pbit\",\n \"Ebit\",\n \"Zbit\",\n \"Ybit\"\n];\nconst BIBIT_UNITS = [\n \"b\",\n \"kibit\",\n \"Mibit\",\n \"Gibit\",\n \"Tibit\",\n \"Pibit\",\n \"Eibit\",\n \"Zibit\",\n \"Yibit\"\n];\n\n/**\n * Formats the given number using `Number#toLocaleString`.\n *\n * @remarks\n * - If locale is a string, the value is expected to be a locale-key (for example: `de`).\n * - If locale is true, the system default locale is used for translation.\n * - If no value for locale is specified, the number is returned unmodified.\n *\n * @param number - The number to format.\n * @param locale - The locale to use for formatting the number.\n * @param options - The options to use for formatting the number.\n * @returns The formatted number.\n */\nexport const toLocaleString = (\n number?: number | string,\n locale?: string | readonly string[] | boolean,\n options: Options = {}\n): string => {\n let result = number;\n let _locale = locale;\n if (typeof _locale === \"string\") {\n if (!_locale) {\n _locale = process.env.STORM_LOCALE || \"en-US\";\n }\n if (Array.isArray(_locale)) {\n result = number?.toLocaleString(_locale, options);\n }\n } else if (_locale === true || options !== undefined) {\n result = number?.toLocaleString(undefined, options);\n }\n\n return String(result);\n};\n\n/**\n * Convert bytes to a human readable string: `1337` → `1.34 kB`.\n *\n * @param number - The number to format.\n *\n * @example\n * ```ts\n * import { prettyBytes } from '@stryke/string-fns/pretty-bytes';\n *\n * prettyBytes(1337);\n * //=> '1.34 kB'\n *\n * prettyBytes(100);\n * //=> '100 B'\n *\n * // Display file size differences\n * prettyBytes(42, {signed: true});\n * //=> '+42 B'\n *\n * // Localized output using German locale\n * prettyBytes(1337, {locale: 'de'});\n * //=> '1,34 kB'\n * ```\n *\n * @param number - The number to format.\n * @param options - The options to use.\n * @returns The formatted string.\n */\nexport function prettyBytes(number: number, options?: Options): string {\n let _number: string | number = number;\n if (!Number.isFinite(_number)) {\n throw new TypeError(\n `Expected a finite number, got ${typeof _number}: ${_number}`\n );\n }\n\n const opts = {\n bits: false,\n binary: false,\n space: true,\n ...options\n };\n\n const UNITS = opts.bits\n ? opts.binary\n ? BIBIT_UNITS\n : BIT_UNITS\n : opts.binary\n ? BIBYTE_UNITS\n : BYTE_UNITS;\n\n const separator = opts.space ? \" \" : \"\";\n\n if (opts.signed && _number === 0) {\n return ` 0${separator}${UNITS[0]}`;\n }\n\n const isNegative = _number < 0;\n\n const prefix = isNegative ? \"-\" : opts.signed ? \"+\" : \"\";\n\n if (isNegative) {\n _number = -_number;\n }\n\n let localeOptions;\n\n if (opts.minimumFractionDigits !== undefined) {\n localeOptions = { minimumFractionDigits: opts.minimumFractionDigits };\n }\n\n if (opts.maximumFractionDigits !== undefined) {\n localeOptions = {\n maximumFractionDigits: opts.maximumFractionDigits,\n ...localeOptions\n };\n }\n\n if (_number < 1) {\n const numberString = toLocaleString(_number, opts.locale, localeOptions);\n\n return prefix + numberString + separator + UNITS[0];\n }\n\n const exponent = Math.min(\n Math.floor(\n opts.binary ? Math.log(_number) / Math.log(1024) : Math.log10(_number) / 3\n ),\n UNITS.length - 1\n );\n _number /= (opts.binary ? 1024 : 1000) ** exponent;\n\n if (!localeOptions) {\n _number = _number.toPrecision(3);\n }\n\n const numberString = toLocaleString(\n Number(_number),\n opts.locale,\n localeOptions\n );\n\n const unit = UNITS[exponent];\n\n return prefix + numberString + separator + unit;\n}\n"],"mappings":"AAkIA,MAAM,EAAa,CAAC,IAAK,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,KAAK,CAClE,EAAe,CACnB,IACA,MACA,MACA,MACA,MACA,MACA,MACA,MACA,MACD,CACK,EAAY,CAChB,IACA,OACA,OACA,OACA,OACA,OACA,OACA,OACA,OACD,CACK,EAAc,CAClB,IACA,QACA,QACA,QACA,QACA,QACA,QACA,QACA,QACD,CAeY,GACX,EACA,EACA,EAAmB,EAAE,GACV,CACX,IAAI,EAAS,EACT,EAAU,EAYd,OAXI,OAAO,GAAY,UACrB,AACE,IAAU,QAAQ,IAAI,cAAgB,QAEpC,MAAM,QAAQ,EAAQ,GACxB,EAAS,GAAQ,eAAe,EAAS,EAAQ,IAE1C,IAAY,IAAQ,IAAY,IAAA,MACzC,EAAS,GAAQ,eAAe,IAAA,GAAW,EAAQ,EAG9C,OAAO,EAAO,EA+BvB,SAAgB,EAAY,EAAgB,EAA2B,CACrE,IAAIA,EAA2B,EAC/B,GAAI,CAAC,OAAO,SAAS,EAAQ,CAC3B,MAAU,UACR,iCAAiC,OAAO,EAAQ,IAAI,IACrD,CAGH,IAAM,EAAO,CACX,KAAM,GACN,OAAQ,GACR,MAAO,GACP,GAAG,EACJ,CAEK,EAAQ,EAAK,KACf,EAAK,OACH,EACA,EACF,EAAK,OACH,EACA,EAEA,EAAY,EAAK,MAAQ,IAAM,GAErC,GAAI,EAAK,QAAU,IAAY,EAC7B,MAAO,KAAK,IAAY,EAAM,KAGhC,IAAM,EAAa,EAAU,EAEvB,EAAS,EAAa,IAAM,EAAK,OAAS,IAAM,GAElD,IACF,EAAU,CAAC,GAGb,IAAI,EAaJ,GAXI,EAAK,wBAA0B,IAAA,KACjC,EAAgB,CAAE,sBAAuB,EAAK,sBAAuB,EAGnE,EAAK,wBAA0B,IAAA,KACjC,EAAgB,CACd,sBAAuB,EAAK,sBAC5B,GAAG,EACJ,EAGC,EAAU,EAGZ,OAAO,EAFc,EAAe,EAAS,EAAK,OAAQ,EAAc,CAEzC,EAAY,EAAM,GAGnD,IAAM,EAAW,KAAK,IACpB,KAAK,MACH,EAAK,OAAS,KAAK,IAAI,EAAQ,CAAG,KAAK,IAAI,KAAK,CAAG,KAAK,MAAM,EAAQ,CAAG,EAC1E,CACD,EAAM,OAAS,EAChB,CACD,IAAY,EAAK,OAAS,KAAO,MAAS,EAErC,IACH,EAAU,EAAQ,YAAY,EAAE,EAGlC,IAAM,EAAe,EACnB,OAAO,EAAQ,CACf,EAAK,OACL,EACD,CAEK,EAAO,EAAM,GAEnB,OAAO,EAAS,EAAe,EAAY"}
1
+ {"version":3,"file":"pretty-bytes.mjs","names":["_number: string | number"],"sources":["../src/pretty-bytes.ts"],"sourcesContent":["/* -------------------------------------------------------------------\n\n ⚡ Storm Software - Stryke\n\n This code was released as part of the Stryke project. Stryke\n is maintained by Storm Software under the Apache-2.0 license, and is\n free for commercial and private use. For more information, please visit\n our licensing page at https://stormsoftware.com/licenses/projects/stryke.\n\n Website: https://stormsoftware.com\n Repository: https://github.com/storm-software/stryke\n Documentation: https://docs.stormsoftware.com/projects/stryke\n Contact: https://stormsoftware.com/contact\n\n SPDX-License-Identifier: Apache-2.0\n\n ------------------------------------------------------------------- */\n\nexport interface Options {\n /**\n * Include plus sign for positive numbers. If the difference is exactly zero a space character will be prepended instead for better alignment.\n *\n * @defaultValue false\n */\n readonly signed?: boolean;\n\n /**\n * - If `false`: Output won't be localized.\n * - If `true`: Localize the output using the system/browser locale.\n * - If `string`: Expects a [BCP 47 language tag](https://en.wikipedia.org/wiki/IETF_language_tag) (For example: `en`, `de`, …)\n * - If `string[]`: Expects a list of [BCP 47 language tags](https://en.wikipedia.org/wiki/IETF_language_tag) (For example: `en`, `de`, …)\n *\n * @defaultValue false\n */\n readonly locale?: boolean | string | readonly string[];\n\n /**\n * Format the number as [bits](https://en.wikipedia.org/wiki/Bit) instead of [bytes](https://en.wikipedia.org/wiki/Byte). This can be useful when, for example, referring to [bit rate](https://en.wikipedia.org/wiki/Bit_rate).\n *\n * @defaultValue false\n *\n * @example\n * ```ts\n * import { prettyBytes } from '@stryke/string-fns/pretty-bytes';\n *\n * prettyBytes(1337, {bits: true});\n * //=> '1.34 kbit'\n * ```\n */\n readonly bits?: boolean;\n\n /**\n * Format the number using the [Binary Prefix](https://en.wikipedia.org/wiki/Binary_prefix) instead of the [SI Prefix](https://en.wikipedia.org/wiki/SI_prefix). This can be useful for presenting memory amounts. However, this should not be used for presenting file sizes.\n *\n * @defaultValue false\n *\n * @example\n * ```ts\n * import { prettyBytes } from '@stryke/string-fns/pretty-bytes';\n *\n * prettyBytes(1000, {binary: true});\n * //=> '1000 bit'\n *\n * prettyBytes(1024, {binary: true});\n * //=> '1 kiB'\n * ```\n */\n readonly binary?: boolean;\n\n /**\n * The minimum number of fraction digits to display.\n *\n * If neither `minimumFractionDigits` or `maximumFractionDigits` are set, the default behavior is to round to 3 significant digits.\n *\n * @defaultValue undefined\n *\n * @example\n * ```ts\n * import { prettyBytes } from '@stryke/string-fns/pretty-bytes';\n *\n * // Show the number with at least 3 fractional digits\n * prettyBytes(1900, {minimumFractionDigits: 3});\n * //=> '1.900 kB'\n *\n * prettyBytes(1900);\n * //=> '1.9 kB'\n * ```\n */\n readonly minimumFractionDigits?: number;\n\n /**\n * The maximum number of fraction digits to display.\n *\n * If neither `minimumFractionDigits` or `maximumFractionDigits` are set, the default behavior is to round to 3 significant digits.\n *\n * @defaultValue undefined\n *\n * @example\n * ```ts\n * import { prettyBytes } from '@stryke/string-fns/pretty-bytes';\n *\n * // Show the number with at most 1 fractional digit\n * prettyBytes(1920, {maximumFractionDigits: 1});\n * //=> '1.9 kB'\n *\n * prettyBytes(1920);\n * //=> '1.92 kB'\n * ```\n */\n readonly maximumFractionDigits?: number;\n\n /**\n * Put a space between the number and unit.\n *\n * @defaultValue true\n *\n * @example\n * ```ts\n * import { prettyBytes } from '@stryke/string-fns/pretty-bytes';\n *\n * prettyBytes(1920, {space: false});\n * //=> '1.9kB'\n *\n * prettyBytes(1920);\n * //=> '1.92 kB'\n * ```\n */\n readonly space?: boolean;\n}\n\nconst BYTE_UNITS = [\"B\", \"kB\", \"MB\", \"GB\", \"TB\", \"PB\", \"EB\", \"ZB\", \"YB\"];\nconst BIBYTE_UNITS = [\n \"B\",\n \"KiB\",\n \"MiB\",\n \"GiB\",\n \"TiB\",\n \"PiB\",\n \"EiB\",\n \"ZiB\",\n \"YiB\"\n];\nconst BIT_UNITS = [\n \"b\",\n \"kbit\",\n \"Mbit\",\n \"Gbit\",\n \"Tbit\",\n \"Pbit\",\n \"Ebit\",\n \"Zbit\",\n \"Ybit\"\n];\nconst BIBIT_UNITS = [\n \"b\",\n \"kibit\",\n \"Mibit\",\n \"Gibit\",\n \"Tibit\",\n \"Pibit\",\n \"Eibit\",\n \"Zibit\",\n \"Yibit\"\n];\n\n/**\n * Formats the given number using `Number#toLocaleString`.\n *\n * @remarks\n * - If locale is a string, the value is expected to be a locale-key (for example: `de`).\n * - If locale is true, the system default locale is used for translation.\n * - If no value for locale is specified, the number is returned unmodified.\n *\n * @param number - The number to format.\n * @param locale - The locale to use for formatting the number.\n * @param options - The options to use for formatting the number.\n * @returns The formatted number.\n */\nexport const toLocaleString = (\n number?: number | string,\n locale?: string | readonly string[] | boolean,\n options: Options = {}\n): string => {\n let result = number;\n let _locale = locale;\n if (typeof _locale === \"string\") {\n if (!_locale) {\n _locale = process.env.STORM_LOCALE || \"en-US\";\n }\n if (Array.isArray(_locale)) {\n result = number?.toLocaleString(_locale, options);\n }\n } else if (_locale === true || options !== undefined) {\n result = number?.toLocaleString(undefined, options);\n }\n\n return String(result);\n};\n\n/**\n * Convert bytes to a human readable string: `1337` → `1.34 kB`.\n *\n * @param number - The number to format.\n *\n * @example\n * ```ts\n * import { prettyBytes } from '@stryke/string-fns/pretty-bytes';\n *\n * prettyBytes(1337);\n * //=> '1.34 kB'\n *\n * prettyBytes(100);\n * //=> '100 B'\n *\n * // Display file size differences\n * prettyBytes(42, {signed: true});\n * //=> '+42 B'\n *\n * // Localized output using German locale\n * prettyBytes(1337, {locale: 'de'});\n * //=> '1,34 kB'\n * ```\n *\n * @param number - The number to format.\n * @param options - The options to use.\n * @returns The formatted string.\n */\nexport function prettyBytes(number: number, options?: Options): string {\n let _number: string | number = number;\n if (!Number.isFinite(_number)) {\n throw new TypeError(\n `Expected a finite number, got ${typeof _number}: ${_number}`\n );\n }\n\n const opts = {\n bits: false,\n binary: false,\n space: true,\n ...options\n };\n\n const UNITS = opts.bits\n ? opts.binary\n ? BIBIT_UNITS\n : BIT_UNITS\n : opts.binary\n ? BIBYTE_UNITS\n : BYTE_UNITS;\n\n const separator = opts.space ? \" \" : \"\";\n\n if (opts.signed && _number === 0) {\n return ` 0${separator}${UNITS[0]}`;\n }\n\n const isNegative = _number < 0;\n\n const prefix = isNegative ? \"-\" : opts.signed ? \"+\" : \"\";\n\n if (isNegative) {\n _number = -_number;\n }\n\n let localeOptions;\n\n if (opts.minimumFractionDigits !== undefined) {\n localeOptions = { minimumFractionDigits: opts.minimumFractionDigits };\n }\n\n if (opts.maximumFractionDigits !== undefined) {\n localeOptions = {\n maximumFractionDigits: opts.maximumFractionDigits,\n ...localeOptions\n };\n }\n\n if (_number < 1) {\n const numberString = toLocaleString(_number, opts.locale, localeOptions);\n\n return prefix + numberString + separator + UNITS[0];\n }\n\n const exponent = Math.min(\n Math.floor(\n opts.binary ? Math.log(_number) / Math.log(1024) : Math.log10(_number) / 3\n ),\n UNITS.length - 1\n );\n _number /= (opts.binary ? 1024 : 1000) ** exponent;\n\n if (!localeOptions) {\n _number = _number.toPrecision(3);\n }\n\n const numberString = toLocaleString(\n Number(_number),\n opts.locale,\n localeOptions\n );\n\n const unit = UNITS[exponent];\n\n return prefix + numberString + separator + unit;\n}\n"],"mappings":";AAkIA,MAAM,aAAa;CAAC;CAAK;CAAM;CAAM;CAAM;CAAM;CAAM;CAAM;CAAM;CAAK;AACxE,MAAM,eAAe;CACnB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AACD,MAAM,YAAY;CAChB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AACD,MAAM,cAAc;CAClB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;;;;;;;;;;;;;;AAeD,MAAa,kBACX,QACA,QACA,UAAmB,EAAE,KACV;CACX,IAAI,SAAS;CACb,IAAI,UAAU;AACd,KAAI,OAAO,YAAY,UAAU;AAC/B,MAAI,CAAC,QACH,WAAU,QAAQ,IAAI,gBAAgB;AAExC,MAAI,MAAM,QAAQ,QAAQ,CACxB,UAAS,QAAQ,eAAe,SAAS,QAAQ;YAE1C,YAAY,QAAQ,YAAY,OACzC,UAAS,QAAQ,eAAe,QAAW,QAAQ;AAGrD,QAAO,OAAO,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BvB,SAAgB,YAAY,QAAgB,SAA2B;CACrE,IAAIA,UAA2B;AAC/B,KAAI,CAAC,OAAO,SAAS,QAAQ,CAC3B,OAAM,IAAI,UACR,iCAAiC,OAAO,QAAQ,IAAI,UACrD;CAGH,MAAM,OAAO;EACX,MAAM;EACN,QAAQ;EACR,OAAO;EACP,GAAG;EACJ;CAED,MAAM,QAAQ,KAAK,OACf,KAAK,SACH,cACA,YACF,KAAK,SACH,eACA;CAEN,MAAM,YAAY,KAAK,QAAQ,MAAM;AAErC,KAAI,KAAK,UAAU,YAAY,EAC7B,QAAO,KAAK,YAAY,MAAM;CAGhC,MAAM,aAAa,UAAU;CAE7B,MAAM,SAAS,aAAa,MAAM,KAAK,SAAS,MAAM;AAEtD,KAAI,WACF,WAAU,CAAC;CAGb,IAAI;AAEJ,KAAI,KAAK,0BAA0B,OACjC,iBAAgB,EAAE,uBAAuB,KAAK,uBAAuB;AAGvE,KAAI,KAAK,0BAA0B,OACjC,iBAAgB;EACd,uBAAuB,KAAK;EAC5B,GAAG;EACJ;AAGH,KAAI,UAAU,EAGZ,QAAO,SAFc,eAAe,SAAS,KAAK,QAAQ,cAAc,GAEzC,YAAY,MAAM;CAGnD,MAAM,WAAW,KAAK,IACpB,KAAK,MACH,KAAK,SAAS,KAAK,IAAI,QAAQ,GAAG,KAAK,IAAI,KAAK,GAAG,KAAK,MAAM,QAAQ,GAAG,EAC1E,EACD,MAAM,SAAS,EAChB;AACD,aAAY,KAAK,SAAS,OAAO,QAAS;AAE1C,KAAI,CAAC,cACH,WAAU,QAAQ,YAAY,EAAE;CAGlC,MAAM,eAAe,eACnB,OAAO,QAAQ,EACf,KAAK,QACL,cACD;CAED,MAAM,OAAO,MAAM;AAEnB,QAAO,SAAS,eAAe,YAAY"}
@@ -1 +1,42 @@
1
- const e=require(`./types/src/base.cjs`),t=require(`./upper-case-first.cjs`),n=require(`./constant-case.cjs`);function r(e){return e?/^[a-z]+(?:_[a-z0-9]+)*$/.test(e):!1}function i(i,a){if(r(i)||i===void 0)return i;if(n.isConstantCase(i))return i.toLowerCase();let o=i?.replace(/[A-Z]+/g,n=>t.upperCaseFirst(n)??e.EMPTY_STRING).split(/(?=[A-Z])|[\s._-]/).map(e=>e.toLowerCase())??[];if(o.length===0)return``;if(o.length===1)return o[0];let s=o.reduce((e,t)=>`${e}_${t.toLowerCase()}`);return a?.splitOnNumber===!1?s:s.replace(/[A-Z]\d/i,e=>`${e[0]}_${e[1]}`)}exports.isSnakeCase=r,exports.snakeCase=i;
1
+ const require_base = require('./types/src/base.cjs');
2
+ const require_upper_case_first = require('./upper-case-first.cjs');
3
+ const require_constant_case = require('./constant-case.cjs');
4
+
5
+ //#region src/snake-case.ts
6
+ /**
7
+ * Check if the input string is in snake case.
8
+ *
9
+ * @remarks
10
+ * Snake case is defined as all lowercase letters with underscores separating words - "this_is_an_example"
11
+ *
12
+ * @param input - The input string to check.
13
+ * @returns True if the input is in snake case, false otherwise.
14
+ */
15
+ function isSnakeCase(input) {
16
+ return input ? /^[a-z]+(?:_[a-z0-9]+)*$/.test(input) : false;
17
+ }
18
+ /**
19
+ * Convert the input string to snake case.
20
+ *
21
+ * @remarks
22
+ * Snake case is defined as all lowercase letters with underscores separating words - "this_is_an_example"
23
+ *
24
+ * @param input - The input string.
25
+ * @param options - Options to control the behavior of the function.
26
+ * @returns The snake-cased string.
27
+ */
28
+ function snakeCase(input, options) {
29
+ if (isSnakeCase(input) || input === void 0) return input;
30
+ if (require_constant_case.isConstantCase(input)) return input.toLowerCase();
31
+ const parts = input?.replace(/[A-Z]+/g, (input$1) => require_upper_case_first.upperCaseFirst(input$1) ?? require_base.EMPTY_STRING).split(/(?=[A-Z])|[\s._-]/).map((x) => x.toLowerCase()) ?? [];
32
+ if (parts.length === 0) return "";
33
+ if (parts.length === 1) return parts[0];
34
+ const result = parts.reduce((ret, part) => {
35
+ return `${ret}_${part.toLowerCase()}`;
36
+ });
37
+ return options?.splitOnNumber === false ? result : result.replace(/[A-Z]\d/i, (val) => `${val[0]}_${val[1]}`);
38
+ }
39
+
40
+ //#endregion
41
+ exports.isSnakeCase = isSnakeCase;
42
+ exports.snakeCase = snakeCase;
@@ -1,2 +1,42 @@
1
- import{EMPTY_STRING as e}from"./types/src/base.mjs";import{upperCaseFirst as t}from"./upper-case-first.mjs";import{isConstantCase as n}from"./constant-case.mjs";function r(e){return e?/^[a-z]+(?:_[a-z0-9]+)*$/.test(e):!1}function i(i,a){if(r(i)||i===void 0)return i;if(n(i))return i.toLowerCase();let o=i?.replace(/[A-Z]+/g,n=>t(n)??e).split(/(?=[A-Z])|[\s._-]/).map(e=>e.toLowerCase())??[];if(o.length===0)return``;if(o.length===1)return o[0];let s=o.reduce((e,t)=>`${e}_${t.toLowerCase()}`);return a?.splitOnNumber===!1?s:s.replace(/[A-Z]\d/i,e=>`${e[0]}_${e[1]}`)}export{r as isSnakeCase,i as snakeCase};
1
+ import { EMPTY_STRING } from "./types/src/base.mjs";
2
+ import { upperCaseFirst } from "./upper-case-first.mjs";
3
+ import { isConstantCase } from "./constant-case.mjs";
4
+
5
+ //#region src/snake-case.ts
6
+ /**
7
+ * Check if the input string is in snake case.
8
+ *
9
+ * @remarks
10
+ * Snake case is defined as all lowercase letters with underscores separating words - "this_is_an_example"
11
+ *
12
+ * @param input - The input string to check.
13
+ * @returns True if the input is in snake case, false otherwise.
14
+ */
15
+ function isSnakeCase(input) {
16
+ return input ? /^[a-z]+(?:_[a-z0-9]+)*$/.test(input) : false;
17
+ }
18
+ /**
19
+ * Convert the input string to snake case.
20
+ *
21
+ * @remarks
22
+ * Snake case is defined as all lowercase letters with underscores separating words - "this_is_an_example"
23
+ *
24
+ * @param input - The input string.
25
+ * @param options - Options to control the behavior of the function.
26
+ * @returns The snake-cased string.
27
+ */
28
+ function snakeCase(input, options) {
29
+ if (isSnakeCase(input) || input === void 0) return input;
30
+ if (isConstantCase(input)) return input.toLowerCase();
31
+ const parts = input?.replace(/[A-Z]+/g, (input$1) => upperCaseFirst(input$1) ?? EMPTY_STRING).split(/(?=[A-Z])|[\s._-]/).map((x) => x.toLowerCase()) ?? [];
32
+ if (parts.length === 0) return "";
33
+ if (parts.length === 1) return parts[0];
34
+ const result = parts.reduce((ret, part) => {
35
+ return `${ret}_${part.toLowerCase()}`;
36
+ });
37
+ return options?.splitOnNumber === false ? result : result.replace(/[A-Z]\d/i, (val) => `${val[0]}_${val[1]}`);
38
+ }
39
+
40
+ //#endregion
41
+ export { isSnakeCase, snakeCase };
2
42
  //# sourceMappingURL=snake-case.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"snake-case.mjs","names":["input"],"sources":["../src/snake-case.ts"],"sourcesContent":["/* -------------------------------------------------------------------\n\n ⚡ Storm Software - Stryke\n\n This code was released as part of the Stryke project. Stryke\n is maintained by Storm Software under the Apache-2.0 license, and is\n free for commercial and private use. For more information, please visit\n our licensing page at https://stormsoftware.com/licenses/projects/stryke.\n\n Website: https://stormsoftware.com\n Repository: https://github.com/storm-software/stryke\n Documentation: https://docs.stormsoftware.com/projects/stryke\n Contact: https://stormsoftware.com/contact\n\n SPDX-License-Identifier: Apache-2.0\n\n ------------------------------------------------------------------- */\n\nimport { EMPTY_STRING } from \"@stryke/types\";\nimport { isConstantCase } from \"./constant-case\";\nimport { upperCaseFirst } from \"./upper-case-first\";\n\nexport interface SnakeCaseOptions {\n splitOnNumber: boolean;\n}\n\n/**\n * Check if the input string is in snake case.\n *\n * @remarks\n * Snake case is defined as all lowercase letters with underscores separating words - \"this_is_an_example\"\n *\n * @param input - The input string to check.\n * @returns True if the input is in snake case, false otherwise.\n */\nexport function isSnakeCase(input: string | undefined): boolean {\n return input ? /^[a-z]+(?:_[a-z0-9]+)*$/.test(input) : false;\n}\n\n/**\n * Convert the input string to snake case.\n *\n * @remarks\n * Snake case is defined as all lowercase letters with underscores separating words - \"this_is_an_example\"\n *\n * @param input - The input string.\n * @param options - Options to control the behavior of the function.\n * @returns The snake-cased string.\n */\nexport function snakeCase<T extends string | undefined>(\n input: T,\n options?: SnakeCaseOptions\n): T {\n if (isSnakeCase(input) || input === undefined) {\n return input;\n }\n\n if (isConstantCase(input)) {\n return input.toLowerCase() as T;\n }\n\n const parts =\n input\n ?.replace(\n /[A-Z]+/g,\n (input?: string) => upperCaseFirst(input) ?? EMPTY_STRING\n )\n .split(/(?=[A-Z])|[\\s._-]/)\n .map((x: string) => x.toLowerCase()) ?? [];\n if (parts.length === 0) {\n return \"\" as T;\n }\n if (parts.length === 1) {\n return parts[0] as T;\n }\n const result = parts.reduce((ret: string, part: string) => {\n return `${ret}_${part.toLowerCase()}`;\n });\n\n return (\n options?.splitOnNumber === false\n ? result\n : result.replace(/[A-Z]\\d/i, (val: string) => `${val[0]}_${val[1]}`)\n ) as T;\n}\n"],"mappings":"iKAmCA,SAAgB,EAAY,EAAoC,CAC9D,OAAO,EAAQ,0BAA0B,KAAK,EAAM,CAAG,GAazD,SAAgB,EACd,EACA,EACG,CACH,GAAI,EAAY,EAAM,EAAI,IAAU,IAAA,GAClC,OAAO,EAGT,GAAI,EAAe,EAAM,CACvB,OAAO,EAAM,aAAa,CAG5B,IAAM,EACJ,GACI,QACA,UACC,GAAmB,EAAeA,EAAM,EAAI,EAC9C,CACA,MAAM,oBAAoB,CAC1B,IAAK,GAAc,EAAE,aAAa,CAAC,EAAI,EAAE,CAC9C,GAAI,EAAM,SAAW,EACnB,MAAO,GAET,GAAI,EAAM,SAAW,EACnB,OAAO,EAAM,GAEf,IAAM,EAAS,EAAM,QAAQ,EAAa,IACjC,GAAG,EAAI,GAAG,EAAK,aAAa,GACnC,CAEF,OACE,GAAS,gBAAkB,GACvB,EACA,EAAO,QAAQ,WAAa,GAAgB,GAAG,EAAI,GAAG,GAAG,EAAI,KAAK"}
1
+ {"version":3,"file":"snake-case.mjs","names":["input"],"sources":["../src/snake-case.ts"],"sourcesContent":["/* -------------------------------------------------------------------\n\n ⚡ Storm Software - Stryke\n\n This code was released as part of the Stryke project. Stryke\n is maintained by Storm Software under the Apache-2.0 license, and is\n free for commercial and private use. For more information, please visit\n our licensing page at https://stormsoftware.com/licenses/projects/stryke.\n\n Website: https://stormsoftware.com\n Repository: https://github.com/storm-software/stryke\n Documentation: https://docs.stormsoftware.com/projects/stryke\n Contact: https://stormsoftware.com/contact\n\n SPDX-License-Identifier: Apache-2.0\n\n ------------------------------------------------------------------- */\n\nimport { EMPTY_STRING } from \"@stryke/types\";\nimport { isConstantCase } from \"./constant-case\";\nimport { upperCaseFirst } from \"./upper-case-first\";\n\nexport interface SnakeCaseOptions {\n splitOnNumber: boolean;\n}\n\n/**\n * Check if the input string is in snake case.\n *\n * @remarks\n * Snake case is defined as all lowercase letters with underscores separating words - \"this_is_an_example\"\n *\n * @param input - The input string to check.\n * @returns True if the input is in snake case, false otherwise.\n */\nexport function isSnakeCase(input: string | undefined): boolean {\n return input ? /^[a-z]+(?:_[a-z0-9]+)*$/.test(input) : false;\n}\n\n/**\n * Convert the input string to snake case.\n *\n * @remarks\n * Snake case is defined as all lowercase letters with underscores separating words - \"this_is_an_example\"\n *\n * @param input - The input string.\n * @param options - Options to control the behavior of the function.\n * @returns The snake-cased string.\n */\nexport function snakeCase<T extends string | undefined>(\n input: T,\n options?: SnakeCaseOptions\n): T {\n if (isSnakeCase(input) || input === undefined) {\n return input;\n }\n\n if (isConstantCase(input)) {\n return input.toLowerCase() as T;\n }\n\n const parts =\n input\n ?.replace(\n /[A-Z]+/g,\n (input?: string) => upperCaseFirst(input) ?? EMPTY_STRING\n )\n .split(/(?=[A-Z])|[\\s._-]/)\n .map((x: string) => x.toLowerCase()) ?? [];\n if (parts.length === 0) {\n return \"\" as T;\n }\n if (parts.length === 1) {\n return parts[0] as T;\n }\n const result = parts.reduce((ret: string, part: string) => {\n return `${ret}_${part.toLowerCase()}`;\n });\n\n return (\n options?.splitOnNumber === false\n ? result\n : result.replace(/[A-Z]\\d/i, (val: string) => `${val[0]}_${val[1]}`)\n ) as T;\n}\n"],"mappings":";;;;;;;;;;;;;;AAmCA,SAAgB,YAAY,OAAoC;AAC9D,QAAO,QAAQ,0BAA0B,KAAK,MAAM,GAAG;;;;;;;;;;;;AAazD,SAAgB,UACd,OACA,SACG;AACH,KAAI,YAAY,MAAM,IAAI,UAAU,OAClC,QAAO;AAGT,KAAI,eAAe,MAAM,CACvB,QAAO,MAAM,aAAa;CAG5B,MAAM,QACJ,OACI,QACA,YACC,YAAmB,eAAeA,QAAM,IAAI,aAC9C,CACA,MAAM,oBAAoB,CAC1B,KAAK,MAAc,EAAE,aAAa,CAAC,IAAI,EAAE;AAC9C,KAAI,MAAM,WAAW,EACnB,QAAO;AAET,KAAI,MAAM,WAAW,EACnB,QAAO,MAAM;CAEf,MAAM,SAAS,MAAM,QAAQ,KAAa,SAAiB;AACzD,SAAO,GAAG,IAAI,GAAG,KAAK,aAAa;GACnC;AAEF,QACE,SAAS,kBAAkB,QACvB,SACA,OAAO,QAAQ,aAAa,QAAgB,GAAG,IAAI,GAAG,GAAG,IAAI,KAAK"}