@intlayer/core 9.5.12 → 9.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/formatters/compact.cjs +1 -2
- package/dist/cjs/formatters/compact.cjs.map +1 -1
- package/dist/cjs/formatters/currency.cjs +1 -2
- package/dist/cjs/formatters/currency.cjs.map +1 -1
- package/dist/cjs/formatters/date.cjs +1 -2
- package/dist/cjs/formatters/date.cjs.map +1 -1
- package/dist/cjs/formatters/list.cjs +1 -2
- package/dist/cjs/formatters/list.cjs.map +1 -1
- package/dist/cjs/formatters/number.cjs +1 -2
- package/dist/cjs/formatters/number.cjs.map +1 -1
- package/dist/cjs/formatters/percentage.cjs +1 -2
- package/dist/cjs/formatters/percentage.cjs.map +1 -1
- package/dist/cjs/formatters/relativeTime.cjs +1 -2
- package/dist/cjs/formatters/relativeTime.cjs.map +1 -1
- package/dist/cjs/formatters/units.cjs +1 -2
- package/dist/cjs/formatters/units.cjs.map +1 -1
- package/dist/cjs/index.cjs +1 -0
- package/dist/cjs/localization/localeDetector.cjs +60 -22
- package/dist/cjs/localization/localeDetector.cjs.map +1 -1
- package/dist/cjs/markdown/constants.cjs +5 -2
- package/dist/cjs/markdown/constants.cjs.map +1 -1
- package/dist/cjs/transpiler/index.cjs +1 -0
- package/dist/cjs/transpiler/plural/index.cjs +1 -0
- package/dist/cjs/transpiler/plural/plural.cjs +20 -1
- package/dist/cjs/transpiler/plural/plural.cjs.map +1 -1
- package/dist/cjs/utils/intl.cjs +2 -27
- package/dist/cjs/utils/intl.cjs.map +1 -1
- package/dist/esm/formatters/compact.mjs +1 -2
- package/dist/esm/formatters/compact.mjs.map +1 -1
- package/dist/esm/formatters/currency.mjs +1 -2
- package/dist/esm/formatters/currency.mjs.map +1 -1
- package/dist/esm/formatters/date.mjs +1 -2
- package/dist/esm/formatters/date.mjs.map +1 -1
- package/dist/esm/formatters/list.mjs +1 -2
- package/dist/esm/formatters/list.mjs.map +1 -1
- package/dist/esm/formatters/number.mjs +1 -2
- package/dist/esm/formatters/number.mjs.map +1 -1
- package/dist/esm/formatters/percentage.mjs +1 -2
- package/dist/esm/formatters/percentage.mjs.map +1 -1
- package/dist/esm/formatters/relativeTime.mjs +1 -2
- package/dist/esm/formatters/relativeTime.mjs.map +1 -1
- package/dist/esm/formatters/units.mjs +1 -2
- package/dist/esm/formatters/units.mjs.map +1 -1
- package/dist/esm/index.mjs +2 -2
- package/dist/esm/localization/localeDetector.mjs +60 -22
- package/dist/esm/localization/localeDetector.mjs.map +1 -1
- package/dist/esm/markdown/constants.mjs +5 -2
- package/dist/esm/markdown/constants.mjs.map +1 -1
- package/dist/esm/transpiler/index.mjs +2 -2
- package/dist/esm/transpiler/plural/index.mjs +2 -2
- package/dist/esm/transpiler/plural/plural.mjs +20 -2
- package/dist/esm/transpiler/plural/plural.mjs.map +1 -1
- package/dist/esm/utils/intl.mjs +2 -27
- package/dist/esm/utils/intl.mjs.map +1 -1
- package/dist/types/formatters/compact.d.ts.map +1 -1
- package/dist/types/formatters/currency.d.ts.map +1 -1
- package/dist/types/formatters/date.d.ts.map +1 -1
- package/dist/types/formatters/list.d.ts.map +1 -1
- package/dist/types/formatters/number.d.ts.map +1 -1
- package/dist/types/formatters/percentage.d.ts.map +1 -1
- package/dist/types/formatters/relativeTime.d.ts.map +1 -1
- package/dist/types/formatters/units.d.ts.map +1 -1
- package/dist/types/index.d.ts +2 -2
- package/dist/types/localization/localeDetector.d.ts +2 -0
- package/dist/types/localization/localeDetector.d.ts.map +1 -1
- package/dist/types/markdown/constants.d.ts +4 -1
- package/dist/types/markdown/constants.d.ts.map +1 -1
- package/dist/types/transpiler/index.d.ts +2 -2
- package/dist/types/transpiler/plural/index.d.ts +2 -2
- package/dist/types/transpiler/plural/plural.d.ts +31 -2
- package/dist/types/transpiler/plural/plural.d.ts.map +1 -1
- package/dist/types/utils/intl.d.ts +1 -1
- package/dist/types/utils/intl.d.ts.map +1 -1
- package/package.json +7 -7
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
2
|
const require_utils_intl = require('../utils/intl.cjs');
|
|
3
|
-
let _intlayer_config_built = require("@intlayer/config/built");
|
|
4
3
|
|
|
5
4
|
//#region src/formatters/compact.ts
|
|
6
5
|
/**
|
|
@@ -14,7 +13,7 @@ let _intlayer_config_built = require("@intlayer/config/built");
|
|
|
14
13
|
* compact("1000000", { locale: Locales.FRENCH, compactDisplay: "long" });
|
|
15
14
|
* // "1 million"
|
|
16
15
|
*/
|
|
17
|
-
const compact = (value, options) => require_utils_intl.getCachedIntl("NumberFormat", options?.locale
|
|
16
|
+
const compact = (value, options) => require_utils_intl.getCachedIntl("NumberFormat", options?.locale, {
|
|
18
17
|
...options,
|
|
19
18
|
notation: "compact"
|
|
20
19
|
}).format(Number(value));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compact.cjs","names":["getCachedIntl"
|
|
1
|
+
{"version":3,"file":"compact.cjs","names":["getCachedIntl"],"sources":["../../../src/formatters/compact.ts"],"sourcesContent":["import type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport { getCachedIntl } from '../utils/intl';\n\n/**\n * Formats a numeric value using compact notation (e.g., 1K, 1M, 1B)\n * based on locale and formatting options.\n *\n * @example\n * compact(1200); // \"1.2K\"\n *\n * @example\n * compact(\"1000000\", { locale: Locales.FRENCH, compactDisplay: \"long\" });\n * // \"1 million\"\n */\nexport const compact = (\n value: string | number,\n options?: Intl.NumberFormatOptions & { locale?: LocalesValues }\n): string =>\n getCachedIntl('NumberFormat', options?.locale, {\n ...options,\n notation: 'compact',\n }).format(Number(value));\n"],"mappings":";;;;;;;;;;;;;;;AAcA,MAAa,WACX,OACA,YAEAA,iCAAc,gBAAgB,SAAS,QAAQ;CAC7C,GAAG;CACH,UAAU;AACZ,CAAC,CAAC,CAAC,OAAO,OAAO,KAAK,CAAC"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
2
|
const require_utils_intl = require('../utils/intl.cjs');
|
|
3
|
-
let _intlayer_config_built = require("@intlayer/config/built");
|
|
4
3
|
|
|
5
4
|
//#region src/formatters/currency.ts
|
|
6
5
|
/**
|
|
@@ -14,7 +13,7 @@ let _intlayer_config_built = require("@intlayer/config/built");
|
|
|
14
13
|
* currency("5000", { locale: Locales.FRENCH, currency: "CAD", currencyDisplay: "code" });
|
|
15
14
|
* // "5 000,00 CAD"
|
|
16
15
|
*/
|
|
17
|
-
const currency = (value, options) => require_utils_intl.getCachedIntl("NumberFormat", options?.locale
|
|
16
|
+
const currency = (value, options) => require_utils_intl.getCachedIntl("NumberFormat", options?.locale, {
|
|
18
17
|
style: "currency",
|
|
19
18
|
currency: options?.currency ?? "USD",
|
|
20
19
|
currencyDisplay: options?.currencyDisplay ?? "symbol",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"currency.cjs","names":["getCachedIntl"
|
|
1
|
+
{"version":3,"file":"currency.cjs","names":["getCachedIntl"],"sources":["../../../src/formatters/currency.ts"],"sourcesContent":["import type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport { getCachedIntl } from '../utils/intl';\n\n/**\n * Formats a numeric or string value into a localized currency string using the Intl API.\n *\n * @example\n * currency(1234.5, { currency: 'EUR' });\n * // \"€1,234.50\"\n *\n * @example\n * currency(\"5000\", { locale: Locales.FRENCH, currency: \"CAD\", currencyDisplay: \"code\" });\n * // \"5 000,00 CAD\"\n */\nexport const currency = (\n value: string | number,\n options?: Intl.NumberFormatOptions & { locale?: LocalesValues }\n): string =>\n getCachedIntl('NumberFormat', options?.locale, {\n style: 'currency',\n currency: options?.currency ?? 'USD',\n currencyDisplay: options?.currencyDisplay ?? 'symbol',\n minimumFractionDigits: options?.minimumFractionDigits ?? 2,\n maximumFractionDigits: options?.maximumFractionDigits ?? 2,\n ...options,\n }).format(Number(value));\n"],"mappings":";;;;;;;;;;;;;;;AAcA,MAAa,YACX,OACA,YAEAA,iCAAc,gBAAgB,SAAS,QAAQ;CAC7C,OAAO;CACP,UAAU,SAAS,YAAY;CAC/B,iBAAiB,SAAS,mBAAmB;CAC7C,uBAAuB,SAAS,yBAAyB;CACzD,uBAAuB,SAAS,yBAAyB;CACzD,GAAG;AACL,CAAC,CAAC,CAAC,OAAO,OAAO,KAAK,CAAC"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
2
|
const require_utils_intl = require('../utils/intl.cjs');
|
|
3
|
-
let _intlayer_config_built = require("@intlayer/config/built");
|
|
4
3
|
|
|
5
4
|
//#region src/formatters/date.ts
|
|
6
5
|
const presets = {
|
|
@@ -51,7 +50,7 @@ const presets = {
|
|
|
51
50
|
const date = (date, options) => {
|
|
52
51
|
const dateTime = new Date(date);
|
|
53
52
|
const resolvedOptions = typeof options === "string" ? presets[options] ?? {} : options;
|
|
54
|
-
const locale =
|
|
53
|
+
const locale = typeof options === "object" ? options?.locale : void 0;
|
|
55
54
|
return require_utils_intl.getCachedIntl("DateTimeFormat", locale, resolvedOptions).format(dateTime);
|
|
56
55
|
};
|
|
57
56
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"date.cjs","names":["
|
|
1
|
+
{"version":3,"file":"date.cjs","names":["getCachedIntl"],"sources":["../../../src/formatters/date.ts"],"sourcesContent":["import type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport { getCachedIntl } from '../utils/intl';\n\nexport type DateTimePreset =\n | 'short'\n | 'long'\n | 'dateOnly'\n | 'timeOnly'\n | 'full';\n\nexport const presets: Record<DateTimePreset, Intl.DateTimeFormatOptions> = {\n short: {\n year: '2-digit',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n },\n long: {\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n hour: 'numeric',\n minute: 'numeric',\n },\n full: {\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n hour: 'numeric',\n minute: 'numeric',\n hour12: false,\n },\n dateOnly: {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n },\n timeOnly: {\n hour: 'numeric',\n minute: 'numeric',\n second: 'numeric',\n },\n};\n\n/**\n * Formats a date/time value into a localized string using Intl.DateTimeFormat.\n *\n * @example\n * date(new Date('2025-08-02T14:30:00Z'), { year: '2-digit', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' });\n * // \"08/02/25, 14:30\"\n *\n * @example\n * date(\"2025-08-02T14:30:00Z\", { locale: Locales.FRENCH, month: \"long\", day: \"numeric\" });\n * // \"2 août\"\n */\nexport const date = (\n date: Date | string | number,\n options?:\n | (Intl.DateTimeFormatOptions & { locale?: LocalesValues })\n | DateTimePreset\n): string => {\n const dateTime = new Date(date);\n\n const resolvedOptions =\n typeof options === 'string' ? (presets[options] ?? {}) : options;\n\n const locale = typeof options === 'object' ? options?.locale : undefined;\n\n const formatter = getCachedIntl('DateTimeFormat', locale, resolvedOptions);\n\n return formatter.format(dateTime);\n};\n"],"mappings":";;;;AAUA,MAAa,UAA8D;CACzE,OAAO;EACL,MAAM;EACN,OAAO;EACP,KAAK;EACL,MAAM;EACN,QAAQ;CACV;CACA,MAAM;EACJ,MAAM;EACN,OAAO;EACP,KAAK;EACL,MAAM;EACN,QAAQ;CACV;CACA,MAAM;EACJ,MAAM;EACN,OAAO;EACP,KAAK;EACL,MAAM;EACN,QAAQ;EACR,QAAQ;CACV;CACA,UAAU;EACR,MAAM;EACN,OAAO;EACP,KAAK;CACP;CACA,UAAU;EACR,MAAM;EACN,QAAQ;EACR,QAAQ;CACV;AACF;;;;;;;;;;;;AAaA,MAAa,QACX,MACA,YAGW;CACX,MAAM,WAAW,IAAI,KAAK,IAAI;CAE9B,MAAM,kBACJ,OAAO,YAAY,WAAY,QAAQ,YAAY,CAAC,IAAK;CAE3D,MAAM,SAAS,OAAO,YAAY,WAAW,SAAS,SAAS;CAI/D,OAFkBA,iCAAc,kBAAkB,QAAQ,eAE3C,CAAC,CAAC,OAAO,QAAQ;AAClC"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
2
|
const require_utils_intl = require('../utils/intl.cjs');
|
|
3
|
-
let _intlayer_config_built = require("@intlayer/config/built");
|
|
4
3
|
|
|
5
4
|
//#region src/formatters/list.ts
|
|
6
5
|
/**
|
|
@@ -18,7 +17,7 @@ let _intlayer_config_built = require("@intlayer/config/built");
|
|
|
18
17
|
* list([1, 2, 3], { type: 'unit' });
|
|
19
18
|
* // "1, 2, 3"
|
|
20
19
|
*/
|
|
21
|
-
const list = (values, options) => require_utils_intl.getCachedIntl("ListFormat", options?.locale
|
|
20
|
+
const list = (values, options) => require_utils_intl.getCachedIntl("ListFormat", options?.locale, {
|
|
22
21
|
type: options?.type ?? "conjunction",
|
|
23
22
|
style: options?.style ?? "long",
|
|
24
23
|
...options
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list.cjs","names":["getCachedIntl"
|
|
1
|
+
{"version":3,"file":"list.cjs","names":["getCachedIntl"],"sources":["../../../src/formatters/list.ts"],"sourcesContent":["import type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport { getCachedIntl } from '../utils/intl';\n\n/** Locally defined subset of Intl.ListFormatOptions so consumers don't need ES2021.Intl in their lib. */\nexport type ListFormatOptions = {\n localeMatcher?: 'lookup' | 'best fit';\n type?: 'conjunction' | 'disjunction' | 'unit';\n style?: 'long' | 'short' | 'narrow';\n};\n\n/**\n * Formats an array of values into a localized list string using the Intl API.\n *\n * @example\n * list(['apple', 'banana', 'orange']);\n * // \"apple, banana, and orange\"\n *\n * @example\n * list(['red', 'green', 'blue'], { locale: Locales.FRENCH, type: 'disjunction' });\n * // \"rouge, vert ou bleu\"\n *\n * @example\n * list([1, 2, 3], { type: 'unit' });\n * // \"1, 2, 3\"\n */\nexport const list = (\n values: (string | number)[],\n options?: ListFormatOptions & { locale?: LocalesValues }\n): string =>\n getCachedIntl('ListFormat', options?.locale, {\n type: options?.type ?? 'conjunction',\n style: options?.style ?? 'long',\n ...options,\n }).format(values.map(String));\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAyBA,MAAa,QACX,QACA,YAEAA,iCAAc,cAAc,SAAS,QAAQ;CAC3C,MAAM,SAAS,QAAQ;CACvB,OAAO,SAAS,SAAS;CACzB,GAAG;AACL,CAAC,CAAC,CAAC,OAAO,OAAO,IAAI,MAAM,CAAC"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
2
|
const require_utils_intl = require('../utils/intl.cjs');
|
|
3
|
-
let _intlayer_config_built = require("@intlayer/config/built");
|
|
4
3
|
|
|
5
4
|
//#region src/formatters/number.ts
|
|
6
5
|
/**
|
|
@@ -12,7 +11,7 @@ let _intlayer_config_built = require("@intlayer/config/built");
|
|
|
12
11
|
* @example
|
|
13
12
|
* number("1000000", { locale: Locales.FRENCH }); // "1 000 000"
|
|
14
13
|
*/
|
|
15
|
-
const number = (value, { locale, ...options } = {}) => require_utils_intl.getCachedIntl("NumberFormat", locale
|
|
14
|
+
const number = (value, { locale, ...options } = {}) => require_utils_intl.getCachedIntl("NumberFormat", locale, options).format(Number(value));
|
|
16
15
|
|
|
17
16
|
//#endregion
|
|
18
17
|
exports.number = number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"number.cjs","names":["getCachedIntl"
|
|
1
|
+
{"version":3,"file":"number.cjs","names":["getCachedIntl"],"sources":["../../../src/formatters/number.ts"],"sourcesContent":["import type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport { getCachedIntl } from '../utils/intl';\n\n/**\n * Formats a numeric value using locale-aware formatting.\n *\n * @example\n * number(123456.789); // \"123,456.789\"\n *\n * @example\n * number(\"1000000\", { locale: Locales.FRENCH }); // \"1 000 000\"\n */\nexport const number = (\n value: string | number,\n {\n locale,\n ...options\n }: Intl.NumberFormatOptions & { locale?: LocalesValues } = {}\n): string =>\n getCachedIntl('NumberFormat', locale, options).format(Number(value));\n"],"mappings":";;;;;;;;;;;;;AAYA,MAAa,UACX,OACA,EACE,QACA,GAAG,YACsD,CAAC,MAE5DA,iCAAc,gBAAgB,QAAQ,OAAO,CAAC,CAAC,OAAO,OAAO,KAAK,CAAC"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
2
|
const require_utils_intl = require('../utils/intl.cjs');
|
|
3
|
-
let _intlayer_config_built = require("@intlayer/config/built");
|
|
4
3
|
|
|
5
4
|
//#region src/formatters/percentage.ts
|
|
6
5
|
/**
|
|
@@ -15,7 +14,7 @@ let _intlayer_config_built = require("@intlayer/config/built");
|
|
|
15
14
|
const percentage = (value, { locale, ...options } = {}) => {
|
|
16
15
|
let numericValue = Number(value);
|
|
17
16
|
if (numericValue > 1) numericValue /= 100;
|
|
18
|
-
return require_utils_intl.getCachedIntl("NumberFormat", locale
|
|
17
|
+
return require_utils_intl.getCachedIntl("NumberFormat", locale, {
|
|
19
18
|
style: "percent",
|
|
20
19
|
...options
|
|
21
20
|
}).format(Number(numericValue));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"percentage.cjs","names":["getCachedIntl"
|
|
1
|
+
{"version":3,"file":"percentage.cjs","names":["getCachedIntl"],"sources":["../../../src/formatters/percentage.ts"],"sourcesContent":["import type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport { getCachedIntl } from '../utils/intl';\n\n/**\n * Formats a number as a percentage string (e.g., 0.25 → \"25%\").\n *\n * @example\n * percentage(0.25); // \"25%\"\n *\n * @example\n * percentage(0.25, { minimumFractionDigits: 2 }); // \"25.00%\"\n */\nexport const percentage = (\n value: string | number,\n {\n locale,\n ...options\n }: Intl.NumberFormatOptions & { locale?: LocalesValues } = {}\n): string => {\n let numericValue = Number(value);\n\n // Normalize: if user passes 10, treat it as 10% instead of 1000%\n if (numericValue > 1) {\n numericValue /= 100;\n }\n\n const formatter = getCachedIntl('NumberFormat', locale, {\n style: 'percent',\n ...options,\n });\n\n return formatter.format(Number(numericValue));\n};\n"],"mappings":";;;;;;;;;;;;;AAYA,MAAa,cACX,OACA,EACE,QACA,GAAG,YACsD,CAAC,MACjD;CACX,IAAI,eAAe,OAAO,KAAK;CAG/B,IAAI,eAAe,GACjB,gBAAgB;CAQlB,OALkBA,iCAAc,gBAAgB,QAAQ;EACtD,OAAO;EACP,GAAG;CACL,CAEe,CAAC,CAAC,OAAO,OAAO,YAAY,CAAC;AAC9C"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
2
|
const require_utils_intl = require('../utils/intl.cjs');
|
|
3
|
-
let _intlayer_config_built = require("@intlayer/config/built");
|
|
4
3
|
|
|
5
4
|
//#region src/formatters/relativeTime.ts
|
|
6
5
|
/**
|
|
@@ -34,7 +33,7 @@ const relativeTime = (from, to = /* @__PURE__ */ new Date(), options) => {
|
|
|
34
33
|
const toDate = new Date(to);
|
|
35
34
|
const unit = options?.unit ?? "second";
|
|
36
35
|
const value = diffInUnit(fromDate, toDate, unit);
|
|
37
|
-
return require_utils_intl.getCachedIntl("RelativeTimeFormat", options?.locale
|
|
36
|
+
return require_utils_intl.getCachedIntl("RelativeTimeFormat", options?.locale, options).format(Math.round(value), unit);
|
|
38
37
|
};
|
|
39
38
|
|
|
40
39
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relativeTime.cjs","names":["getCachedIntl"
|
|
1
|
+
{"version":3,"file":"relativeTime.cjs","names":["getCachedIntl"],"sources":["../../../src/formatters/relativeTime.ts"],"sourcesContent":["import type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport { getCachedIntl } from '../utils/intl';\n\ntype RelativeTimeUnit = Intl.RelativeTimeFormatUnit;\n\n/**\n * Calculate the difference between 2 dates in the given unit.\n */\nconst diffInUnit = (from: Date, to: Date, unit: RelativeTimeUnit): number => {\n const msDiff = to.getTime() - from.getTime();\n const sec = msDiff / 1000;\n\n switch (unit) {\n case 'second':\n return sec;\n case 'minute':\n return sec / 60;\n case 'hour':\n return sec / 3600;\n case 'day':\n return sec / 86400;\n case 'month':\n return sec / (30 * 86400); // approx\n case 'quarter':\n return sec / (3 * 30 * 86400); // 3 months approx\n case 'year':\n return sec / (365 * 86400); // approx\n default:\n return sec;\n }\n};\n\n/**\n * Formats the difference between two dates as a localized relative time string.\n *\n * @example\n * relativeTime(new Date(Date.now() - 30000)); // \"30 seconds ago\"\n *\n * @example\n * relativeTime(\"2025-01-01\", new Date(), { locale: Locales.FRENCH, unit: \"day\" });\n * // \"il y a 443 jours\"\n */\nexport const relativeTime = (\n from: Date | string | number,\n to: Date | string | number = new Date(),\n options?: Intl.RelativeTimeFormatOptions & {\n locale?: LocalesValues;\n unit?: RelativeTimeUnit;\n }\n): string => {\n const fromDate = new Date(from);\n const toDate = new Date(to);\n const unit = options?.unit ?? 'second';\n\n const value = diffInUnit(fromDate, toDate, unit);\n\n return getCachedIntl('RelativeTimeFormat', options?.locale, options).format(\n Math.round(value),\n unit\n );\n};\n"],"mappings":";;;;;;;AAQA,MAAM,cAAc,MAAY,IAAU,SAAmC;CAE3E,MAAM,OADS,GAAG,QAAQ,IAAI,KAAK,QAAQ,KACtB;CAErB,QAAQ,MAAR;EACE,KAAK,UACH,OAAO;EACT,KAAK,UACH,OAAO,MAAM;EACf,KAAK,QACH,OAAO,MAAM;EACf,KAAK,OACH,OAAO,MAAM;EACf,KAAK,SACH,OAAO,MAAO;EAChB,KAAK,WACH,OAAO,MAAO;EAChB,KAAK,QACH,OAAO,MAAO;EAChB,SACE,OAAO;CACX;AACF;;;;;;;;;;;AAYA,MAAa,gBACX,MACA,qBAA6B,IAAI,KAAK,GACtC,YAIW;CACX,MAAM,WAAW,IAAI,KAAK,IAAI;CAC9B,MAAM,SAAS,IAAI,KAAK,EAAE;CAC1B,MAAM,OAAO,SAAS,QAAQ;CAE9B,MAAM,QAAQ,WAAW,UAAU,QAAQ,IAAI;CAE/C,OAAOA,iCAAc,sBAAsB,SAAS,QAAQ,OAAO,CAAC,CAAC,OACnE,KAAK,MAAM,KAAK,GAChB,IACF;AACF"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
2
|
const require_utils_intl = require('../utils/intl.cjs');
|
|
3
|
-
let _intlayer_config_built = require("@intlayer/config/built");
|
|
4
3
|
|
|
5
4
|
//#region src/formatters/units.ts
|
|
6
5
|
/**
|
|
@@ -10,7 +9,7 @@ let _intlayer_config_built = require("@intlayer/config/built");
|
|
|
10
9
|
* units(5, { unit: "kilometer", unitDisplay: "long", locale: "en-GB" });
|
|
11
10
|
* // "5 kilometers"
|
|
12
11
|
*/
|
|
13
|
-
const units = (value, options) => require_utils_intl.getCachedIntl("NumberFormat", options?.locale
|
|
12
|
+
const units = (value, options) => require_utils_intl.getCachedIntl("NumberFormat", options?.locale, {
|
|
14
13
|
style: "unit",
|
|
15
14
|
unit: options?.unit ?? "day",
|
|
16
15
|
unitDisplay: options?.unitDisplay ?? "short",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"units.cjs","names":["getCachedIntl"
|
|
1
|
+
{"version":3,"file":"units.cjs","names":["getCachedIntl"],"sources":["../../../src/formatters/units.ts"],"sourcesContent":["import type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport { getCachedIntl } from '../utils/intl';\n\n/**\n * Formats a numeric value as a localized unit string.\n *\n * @example\n * units(5, { unit: \"kilometer\", unitDisplay: \"long\", locale: \"en-GB\" });\n * // \"5 kilometers\"\n */\nexport const units = (\n value: number | string,\n options?: Intl.NumberFormatOptions & { locale?: LocalesValues }\n): string =>\n getCachedIntl('NumberFormat', options?.locale, {\n style: 'unit',\n unit: options?.unit ?? 'day',\n unitDisplay: options?.unitDisplay ?? 'short',\n useGrouping: options?.useGrouping ?? false,\n }).format(Number(value));\n"],"mappings":";;;;;;;;;;;AAUA,MAAa,SACX,OACA,YAEAA,iCAAc,gBAAgB,SAAS,QAAQ;CAC7C,OAAO;CACP,MAAM,SAAS,QAAQ;CACvB,aAAa,SAAS,eAAe;CACrC,aAAa,SAAS,eAAe;AACvC,CAAC,CAAC,CAAC,OAAO,OAAO,KAAK,CAAC"}
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -137,6 +137,7 @@ exports.CONSECUTIVE_NEWLINE_R = require_markdown_constants.CONSECUTIVE_NEWLINE_R
|
|
|
137
137
|
exports.CR_NEWLINE_R = require_markdown_constants.CR_NEWLINE_R;
|
|
138
138
|
exports.CachedIntl = require_utils_intl.CachedIntl;
|
|
139
139
|
exports.Intl = require_utils_intl.CachedIntl;
|
|
140
|
+
exports.DEFAULT_PLURAL_VARIABLE = require_transpiler_plural_plural.DEFAULT_PLURAL_VARIABLE;
|
|
140
141
|
exports.DEFAULT_VARIANT_ID = require_dictionaryManipulator_qualifiedDictionary.DEFAULT_VARIANT_ID;
|
|
141
142
|
exports.DO_NOT_PROCESS_HTML_ELEMENTS = require_markdown_constants.DO_NOT_PROCESS_HTML_ELEMENTS;
|
|
142
143
|
exports.FENCE_DELIMITER_R = require_markdown_constants.FENCE_DELIMITER_R;
|
|
@@ -8,6 +8,24 @@ const require_localization_localeResolver = require('./localeResolver.cjs');
|
|
|
8
8
|
const LANGUAGE_FORMAT_REGULAR_EXPRESSION = /^\s*([^\s\-;]+)(?:-([^\s;]+))?\s*(?:;(.*))?$/;
|
|
9
9
|
const DEFAULT_QUALITY_SCORE = 1;
|
|
10
10
|
/**
|
|
11
|
+
* Upper bound of the memoization caches below. Browsers send a handful of
|
|
12
|
+
* distinct `Accept-Language` values, so a small cache holds the working set.
|
|
13
|
+
*/
|
|
14
|
+
const MAX_CACHE_ENTRIES = 512;
|
|
15
|
+
/**
|
|
16
|
+
* Longer headers are resolved without being memoized, so a client sending
|
|
17
|
+
* arbitrary headers cannot grow the cache memory.
|
|
18
|
+
*/
|
|
19
|
+
const MAX_CACHEABLE_HEADER_LENGTH = 128;
|
|
20
|
+
/**
|
|
21
|
+
* Inserts an entry in a bounded cache, evicting the oldest entry when full.
|
|
22
|
+
*/
|
|
23
|
+
const setBoundedCacheEntry = (cache, key, value) => {
|
|
24
|
+
if (cache.size >= MAX_CACHE_ENTRIES) cache.delete(cache.keys().next().value);
|
|
25
|
+
cache.set(key, value);
|
|
26
|
+
return value;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
11
29
|
* Parses a single language tag string from the Accept-Language header.
|
|
12
30
|
* Example input: "en-US;q=0.8"
|
|
13
31
|
*/
|
|
@@ -31,11 +49,26 @@ const parseLanguageTag = (tagString, index) => {
|
|
|
31
49
|
regionCode,
|
|
32
50
|
qualityScore,
|
|
33
51
|
originalIndex: index,
|
|
34
|
-
fullLocale
|
|
52
|
+
fullLocale,
|
|
53
|
+
fullLocaleLower: fullLocale.toLowerCase(),
|
|
54
|
+
languageCodeLower: languageCode.toLowerCase()
|
|
35
55
|
};
|
|
36
56
|
};
|
|
37
57
|
/**
|
|
38
|
-
*
|
|
58
|
+
* Parsed available languages. They come from the configuration, so the same
|
|
59
|
+
* few tags are parsed on every request: parse each one once.
|
|
60
|
+
*/
|
|
61
|
+
const availableLanguageCache = /* @__PURE__ */ new Map();
|
|
62
|
+
/**
|
|
63
|
+
* Parses an available language, reusing the previous parse of the same tag.
|
|
64
|
+
*/
|
|
65
|
+
const parseAvailableLanguage = (language) => {
|
|
66
|
+
const cachedLanguage = availableLanguageCache.get(language);
|
|
67
|
+
if (cachedLanguage !== void 0) return cachedLanguage;
|
|
68
|
+
return setBoundedCacheEntry(availableLanguageCache, language, parseLanguageTag(language, 0));
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* Parses the full Accept-Language header into a list of language preferences.
|
|
39
72
|
*/
|
|
40
73
|
const parseAcceptLanguageHeader = (headerValue) => {
|
|
41
74
|
const rawTags = headerValue.split(",");
|
|
@@ -50,19 +83,13 @@ const parseAcceptLanguageHeader = (headerValue) => {
|
|
|
50
83
|
return preferences;
|
|
51
84
|
};
|
|
52
85
|
/**
|
|
53
|
-
*
|
|
86
|
+
* Determines how well a specific available language matches a requested language preference.
|
|
54
87
|
*/
|
|
55
|
-
const calculateMatchSpecificity = (
|
|
56
|
-
const parsedProvided = parseLanguageTag(providedLanguage, providedIndex);
|
|
57
|
-
if (!parsedProvided) return null;
|
|
88
|
+
const calculateMatchSpecificity = (parsedProvided, preference, providedIndex) => {
|
|
58
89
|
let specificityScore = 0;
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const providedPrefixLower = parsedProvided.languageCode.toLowerCase();
|
|
63
|
-
if (preferenceFullLower === providedFullLower) specificityScore |= 4;
|
|
64
|
-
else if (preferencePrefixLower === providedFullLower) specificityScore |= 2;
|
|
65
|
-
else if (preferenceFullLower === providedPrefixLower) specificityScore |= 1;
|
|
90
|
+
if (preference.fullLocaleLower === parsedProvided.fullLocaleLower) specificityScore |= 4;
|
|
91
|
+
else if (preference.languageCodeLower === parsedProvided.fullLocaleLower) specificityScore |= 2;
|
|
92
|
+
else if (preference.fullLocaleLower === parsedProvided.languageCodeLower) specificityScore |= 1;
|
|
66
93
|
else if (preference.fullLocale !== "*") return null;
|
|
67
94
|
return {
|
|
68
95
|
providedIndex,
|
|
@@ -72,7 +99,7 @@ const calculateMatchSpecificity = (providedLanguage, preference, providedIndex)
|
|
|
72
99
|
};
|
|
73
100
|
};
|
|
74
101
|
/**
|
|
75
|
-
*
|
|
102
|
+
* Finds the best matching preference from the header for a specific available language.
|
|
76
103
|
*/
|
|
77
104
|
const getBestMatchForLanguage = (providedLanguage, acceptedPreferences, providedIndex) => {
|
|
78
105
|
let bestMatch = {
|
|
@@ -81,8 +108,10 @@ const getBestMatchForLanguage = (providedLanguage, acceptedPreferences, provided
|
|
|
81
108
|
specificityScore: 0,
|
|
82
109
|
providedIndex
|
|
83
110
|
};
|
|
111
|
+
const parsedProvided = parseAvailableLanguage(providedLanguage);
|
|
112
|
+
if (!parsedProvided) return bestMatch;
|
|
84
113
|
for (const preference of acceptedPreferences) {
|
|
85
|
-
const matchSpec = calculateMatchSpecificity(
|
|
114
|
+
const matchSpec = calculateMatchSpecificity(parsedProvided, preference, providedIndex);
|
|
86
115
|
if (matchSpec) {
|
|
87
116
|
if ((bestMatch.specificityScore - matchSpec.specificityScore || bestMatch.qualityScore - matchSpec.qualityScore || bestMatch.headerIndex - matchSpec.headerIndex) < 0) bestMatch = matchSpec;
|
|
88
117
|
}
|
|
@@ -90,12 +119,8 @@ const getBestMatchForLanguage = (providedLanguage, acceptedPreferences, provided
|
|
|
90
119
|
return bestMatch;
|
|
91
120
|
};
|
|
92
121
|
/**
|
|
93
|
-
* Comparator function to sort
|
|
94
|
-
*
|
|
95
|
-
* 1. Quality Score (Descending)
|
|
96
|
-
* 2. Specificity Score (Descending)
|
|
97
|
-
* 3. Order in Header (Ascending - lower index is better)
|
|
98
|
-
* 4. Order in Provided List (Ascending)
|
|
122
|
+
* Comparator function to sort MatchResults.
|
|
123
|
+
* Order: Quality (desc) -> Specificity (desc) -> Header Order (asc) -> Provided Order (asc)
|
|
99
124
|
*/
|
|
100
125
|
const compareMatchResults = (a, b) => {
|
|
101
126
|
return b.qualityScore - a.qualityScore || b.specificityScore - a.specificityScore || a.headerIndex - b.headerIndex || a.providedIndex - b.providedIndex || 0;
|
|
@@ -110,15 +135,28 @@ const getPreferredLanguages = (acceptHeader, availableLanguages) => {
|
|
|
110
135
|
return availableLanguages.map((language, index) => getBestMatchForLanguage(language, acceptedPreferences, index)).filter((result) => result.qualityScore > 0).sort(compareMatchResults).map((result) => availableLanguages[result.providedIndex]);
|
|
111
136
|
};
|
|
112
137
|
/**
|
|
138
|
+
* Detected locales, keyed by header, available locales and default locale.
|
|
139
|
+
*/
|
|
140
|
+
const detectedLocaleCache = /* @__PURE__ */ new Map();
|
|
141
|
+
/**
|
|
113
142
|
* Detects the locale from the request headers.
|
|
114
143
|
*
|
|
115
144
|
* Headers are provided by the browser/client and can be used to determine the user's preferred language.
|
|
116
145
|
* This function intersects the user's `Accept-Language` header with the application's available locales.
|
|
146
|
+
*
|
|
147
|
+
* The result is memoized, as it only depends on its arguments.
|
|
117
148
|
*/
|
|
118
149
|
const localeDetector = (headers, availableLocales, defaultLocale) => {
|
|
119
150
|
const acceptLanguageHeader = headers["accept-language"];
|
|
151
|
+
const cacheKey = (acceptLanguageHeader?.length ?? 0) <= MAX_CACHEABLE_HEADER_LENGTH ? `${acceptLanguageHeader === void 0 ? "\0" : `=${acceptLanguageHeader}`}\u0001${availableLocales?.join(",") ?? "\0"}\u0001${defaultLocale ?? "\0"}` : void 0;
|
|
152
|
+
if (cacheKey !== void 0) {
|
|
153
|
+
const cachedLocale = detectedLocaleCache.get(cacheKey);
|
|
154
|
+
if (cachedLocale !== void 0) return cachedLocale;
|
|
155
|
+
}
|
|
120
156
|
const preferredLocaleStrings = getPreferredLanguages(acceptLanguageHeader, availableLocales);
|
|
121
|
-
|
|
157
|
+
const detectedLocale = require_localization_localeResolver.localeResolver(preferredLocaleStrings, availableLocales, defaultLocale);
|
|
158
|
+
if (cacheKey !== void 0) setBoundedCacheEntry(detectedLocaleCache, cacheKey, detectedLocale);
|
|
159
|
+
return detectedLocale;
|
|
122
160
|
};
|
|
123
161
|
|
|
124
162
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"localeDetector.cjs","names":["localeResolver"],"sources":["../../../src/localization/localeDetector.ts"],"sourcesContent":["import type { Locale } from '@intlayer/types/allLocales';\nimport type { DeclaredLocales } from '@intlayer/types/module_augmentation';\nimport { localeResolver } from './localeResolver';\n\n/**\n * Constants\n */\nconst LANGUAGE_FORMAT_REGULAR_EXPRESSION =\n /^\\s*([^\\s\\-;]+)(?:-([^\\s;]+))?\\s*(?:;(.*))?$/;\nconst DEFAULT_QUALITY_SCORE = 1;\n\n/**\n * Enumeration for specificity weights.\n * Higher values indicate a more precise match.\n */\nenum SpecificityWeight {\n None = 0,\n Broad = 1, // Matches prefix (e.g., 'en' matches 'en-US')\n Prefix = 2, // Matches prefix in reverse (e.g., 'en-US' matches 'en')\n Exact = 4, // Matches exact string (e.g., 'en-US' matches 'en-US')\n}\n\n/**\n * Represents a parsed language tag from the header.\n */\ntype LanguagePreference = {\n languageCode: string;\n regionCode?: string;\n fullLocale: string;\n qualityScore: number;\n originalIndex: number;\n};\n\n/**\n * Represents the result of matching a requested language against an available language.\n */\ntype MatchResult = {\n providedIndex: number;\n headerIndex: number;\n qualityScore: number;\n specificityScore: number;\n};\n\n/**\n * Parses a single language tag string from the Accept-Language header.\n * Example input: \"en-US;q=0.8\"\n */\nconst parseLanguageTag = (\n tagString: string,\n index: number\n): LanguagePreference | null => {\n const match = LANGUAGE_FORMAT_REGULAR_EXPRESSION.exec(tagString);\n if (!match) {\n return null;\n }\n\n const languageCode = match[1] as string;\n const regionCode = match[2];\n const parameters = match[3];\n\n // Construct the full locale string (e.g., \"en-US\" or \"en\")\n const fullLocale = regionCode\n ? `${languageCode}-${regionCode}`\n : languageCode;\n\n let qualityScore = DEFAULT_QUALITY_SCORE;\n\n // Parse parameters to find the quality score (\"q\")\n if (parameters) {\n const parameterList = parameters.split(';');\n\n for (const parameter of parameterList) {\n const [key, value] = parameter.split('=');\n\n if (key === 'q') {\n qualityScore = parseFloat(value as string);\n }\n }\n }\n\n return {\n languageCode,\n regionCode,\n qualityScore,\n originalIndex: index,\n fullLocale,\n };\n};\n\n/**\n * Parses the entire Accept-Language header string into a list of preferences.\n */\nconst parseAcceptLanguageHeader = (\n headerValue: string\n): LanguagePreference[] => {\n const rawTags = headerValue.split(',');\n const preferences: LanguagePreference[] = [];\n\n for (let index = 0; index < rawTags.length; index++) {\n const tag = rawTags[index]?.trim();\n\n if (tag) {\n const parsedLanguage = parseLanguageTag(tag, index);\n\n if (parsedLanguage) {\n preferences.push(parsedLanguage);\n }\n }\n }\n\n return preferences;\n};\n\n/**\n * Calculates the specificity of a match between a provided language and a requested preference.\n */\nconst calculateMatchSpecificity = (\n providedLanguage: string,\n preference: LanguagePreference,\n providedIndex: number\n): MatchResult | null => {\n const parsedProvided = parseLanguageTag(providedLanguage, providedIndex);\n if (!parsedProvided) {\n return null;\n }\n\n let specificityScore = SpecificityWeight.None;\n\n const preferenceFullLower = preference.fullLocale.toLowerCase();\n const preferencePrefixLower = preference.languageCode.toLowerCase();\n const providedFullLower = parsedProvided.fullLocale.toLowerCase();\n const providedPrefixLower = parsedProvided.languageCode.toLowerCase();\n\n if (preferenceFullLower === providedFullLower) {\n specificityScore |= SpecificityWeight.Exact;\n } else if (preferencePrefixLower === providedFullLower) {\n specificityScore |= SpecificityWeight.Prefix;\n } else if (preferenceFullLower === providedPrefixLower) {\n specificityScore |= SpecificityWeight.Broad;\n } else if (preference.fullLocale !== '*') {\n return null;\n }\n\n return {\n providedIndex,\n headerIndex: preference.originalIndex,\n qualityScore: preference.qualityScore,\n specificityScore,\n };\n};\n\n/**\n * Determines the best match for a specific available language against the list of user accepted languages.\n */\nconst getBestMatchForLanguage = (\n providedLanguage: string,\n acceptedPreferences: LanguagePreference[],\n providedIndex: number\n): MatchResult => {\n // Initialize with a non-match priority\n let bestMatch: MatchResult = {\n headerIndex: -1,\n qualityScore: 0,\n specificityScore: 0,\n providedIndex,\n };\n\n for (const preference of acceptedPreferences) {\n const matchSpec = calculateMatchSpecificity(\n providedLanguage,\n preference,\n providedIndex\n );\n\n if (matchSpec) {\n // Compare current best match with new match\n const scoreDifference =\n bestMatch.specificityScore - matchSpec.specificityScore ||\n bestMatch.qualityScore - matchSpec.qualityScore ||\n bestMatch.headerIndex - matchSpec.headerIndex;\n\n // If the new match is better (difference < 0), update priority\n if (scoreDifference < 0) {\n bestMatch = matchSpec;\n }\n }\n }\n\n return bestMatch;\n};\n\n/**\n * Comparator function to sort language matches.\n * Sorting order:\n * 1. Quality Score (Descending)\n * 2. Specificity Score (Descending)\n * 3. Order in Header (Ascending - lower index is better)\n * 4. Order in Provided List (Ascending)\n */\nconst compareMatchResults = (a: MatchResult, b: MatchResult): number => {\n return (\n b.qualityScore - a.qualityScore ||\n b.specificityScore - a.specificityScore ||\n a.headerIndex - b.headerIndex ||\n a.providedIndex - b.providedIndex ||\n 0\n );\n};\n\n/**\n * Derives the list of preferred languages based on the Accept-Language header\n * and an optional list of available languages.\n */\nexport const getPreferredLanguages = (\n acceptHeader: string | undefined,\n availableLanguages?: string[]\n): string[] => {\n // RFC 2616 sec 14.4: no header implies '*'\n const headerValue = acceptHeader === undefined ? '*' : acceptHeader || '';\n const acceptedPreferences = parseAcceptLanguageHeader(headerValue);\n\n // If no specific languages are provided to filter against, return the header languages sorted by quality\n if (!availableLanguages) {\n return acceptedPreferences\n .filter((preference) => preference.qualityScore > 0)\n .sort((a, b) => b.qualityScore - a.qualityScore) // Simple sort by quality\n .map((preference) => preference.fullLocale);\n }\n\n // Map available languages to their match priority against the header\n const matchResults = availableLanguages.map((language, index) =>\n getBestMatchForLanguage(language, acceptedPreferences, index)\n );\n\n return matchResults\n .filter((result) => result.qualityScore > 0)\n .sort(compareMatchResults)\n .map((result) => availableLanguages[result.providedIndex]) as string[];\n};\n\n/**\n * Detects the locale from the request headers.\n *\n * Headers are provided by the browser/client and can be used to determine the user's preferred language.\n * This function intersects the user's `Accept-Language` header with the application's available locales.\n */\nexport const localeDetector = (\n headers: Record<string, string | undefined>,\n availableLocales?: Locale[],\n defaultLocale?: Locale\n): DeclaredLocales => {\n const acceptLanguageHeader = headers['accept-language'];\n\n const preferredLocaleStrings = getPreferredLanguages(\n acceptLanguageHeader,\n availableLocales as string[]\n );\n\n return localeResolver(\n preferredLocaleStrings as Locale[],\n availableLocales,\n defaultLocale\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"localeDetector.cjs","names":["localeResolver"],"sources":["../../../src/localization/localeDetector.ts"],"sourcesContent":["import type { Locale } from '@intlayer/types/allLocales';\nimport type { DeclaredLocales } from '@intlayer/types/module_augmentation';\nimport { localeResolver } from './localeResolver';\n\n/**\n * Constants\n */\nconst LANGUAGE_FORMAT_REGULAR_EXPRESSION =\n /^\\s*([^\\s\\-;]+)(?:-([^\\s;]+))?\\s*(?:;(.*))?$/;\nconst DEFAULT_QUALITY_SCORE = 1;\n\n/**\n * Upper bound of the memoization caches below. Browsers send a handful of\n * distinct `Accept-Language` values, so a small cache holds the working set.\n */\nconst MAX_CACHE_ENTRIES = 512;\n\n/**\n * Longer headers are resolved without being memoized, so a client sending\n * arbitrary headers cannot grow the cache memory.\n */\nconst MAX_CACHEABLE_HEADER_LENGTH = 128;\n\n/**\n * Enumeration for specificity weights.\n * Higher values indicate a more precise match.\n */\nenum SpecificityWeight {\n None = 0,\n Broad = 1, // Matches prefix (e.g., 'en' matches 'en-US')\n Prefix = 2, // Matches prefix in reverse (e.g., 'en-US' matches 'en')\n Exact = 4, // Matches exact string (e.g., 'en-US' matches 'en-US')\n}\n\n/**\n * Represents a parsed language tag from the header.\n */\ntype LanguagePreference = {\n languageCode: string;\n regionCode?: string;\n fullLocale: string;\n /** `fullLocale` lower-cased once, for case-insensitive matching */\n fullLocaleLower: string;\n /** `languageCode` lower-cased once, for case-insensitive matching */\n languageCodeLower: string;\n qualityScore: number;\n originalIndex: number;\n};\n\n/**\n * Represents the result of matching a requested language against an available language.\n */\ntype MatchResult = {\n providedIndex: number;\n headerIndex: number;\n qualityScore: number;\n specificityScore: number;\n};\n\n/**\n * Inserts an entry in a bounded cache, evicting the oldest entry when full.\n */\nconst setBoundedCacheEntry = <Value>(\n cache: Map<string, Value>,\n key: string,\n value: Value\n): Value => {\n if (cache.size >= MAX_CACHE_ENTRIES) {\n cache.delete(cache.keys().next().value as string);\n }\n\n cache.set(key, value);\n\n return value;\n};\n\n/**\n * Parses a single language tag string from the Accept-Language header.\n * Example input: \"en-US;q=0.8\"\n */\nconst parseLanguageTag = (\n tagString: string,\n index: number\n): LanguagePreference | null => {\n const match = LANGUAGE_FORMAT_REGULAR_EXPRESSION.exec(tagString);\n if (!match) {\n return null;\n }\n\n const languageCode = match[1] as string;\n const regionCode = match[2];\n const parameters = match[3];\n\n // Construct the full locale string (e.g., \"en-US\" or \"en\")\n const fullLocale = regionCode\n ? `${languageCode}-${regionCode}`\n : languageCode;\n\n let qualityScore = DEFAULT_QUALITY_SCORE;\n\n // Parse parameters to find the quality score (\"q\")\n if (parameters) {\n const parameterList = parameters.split(';');\n\n for (const parameter of parameterList) {\n const [key, value] = parameter.split('=');\n\n if (key === 'q') {\n qualityScore = parseFloat(value as string);\n }\n }\n }\n\n return {\n languageCode,\n regionCode,\n qualityScore,\n originalIndex: index,\n fullLocale,\n fullLocaleLower: fullLocale.toLowerCase(),\n languageCodeLower: languageCode.toLowerCase(),\n };\n};\n\n/**\n * Parsed available languages. They come from the configuration, so the same\n * few tags are parsed on every request: parse each one once.\n */\nconst availableLanguageCache = new Map<string, LanguagePreference | null>();\n\n/**\n * Parses an available language, reusing the previous parse of the same tag.\n */\nconst parseAvailableLanguage = (\n language: string\n): LanguagePreference | null => {\n const cachedLanguage = availableLanguageCache.get(language);\n\n if (cachedLanguage !== undefined) return cachedLanguage;\n\n return setBoundedCacheEntry(\n availableLanguageCache,\n language,\n parseLanguageTag(language, 0)\n );\n};\n\n/**\n * Parses the full Accept-Language header into a list of language preferences.\n */\nconst parseAcceptLanguageHeader = (\n headerValue: string\n): LanguagePreference[] => {\n const rawTags = headerValue.split(',');\n const preferences: LanguagePreference[] = [];\n\n for (let index = 0; index < rawTags.length; index++) {\n const tag = rawTags[index]?.trim();\n\n if (tag) {\n const parsedLanguage = parseLanguageTag(tag, index);\n\n if (parsedLanguage) {\n preferences.push(parsedLanguage);\n }\n }\n }\n\n return preferences;\n};\n\n/**\n * Determines how well a specific available language matches a requested language preference.\n */\nconst calculateMatchSpecificity = (\n parsedProvided: LanguagePreference,\n preference: LanguagePreference,\n providedIndex: number\n): MatchResult | null => {\n let specificityScore = SpecificityWeight.None;\n\n if (preference.fullLocaleLower === parsedProvided.fullLocaleLower) {\n specificityScore |= SpecificityWeight.Exact;\n } else if (preference.languageCodeLower === parsedProvided.fullLocaleLower) {\n specificityScore |= SpecificityWeight.Prefix;\n } else if (preference.fullLocaleLower === parsedProvided.languageCodeLower) {\n specificityScore |= SpecificityWeight.Broad;\n } else if (preference.fullLocale !== '*') {\n return null;\n }\n\n return {\n providedIndex,\n headerIndex: preference.originalIndex,\n qualityScore: preference.qualityScore,\n specificityScore,\n };\n};\n\n/**\n * Finds the best matching preference from the header for a specific available language.\n */\nconst getBestMatchForLanguage = (\n providedLanguage: string,\n acceptedPreferences: LanguagePreference[],\n providedIndex: number\n): MatchResult => {\n // Initialize with a non-match priority\n let bestMatch: MatchResult = {\n headerIndex: -1,\n qualityScore: 0,\n specificityScore: 0,\n providedIndex,\n };\n\n const parsedProvided = parseAvailableLanguage(providedLanguage);\n\n if (!parsedProvided) {\n return bestMatch;\n }\n\n for (const preference of acceptedPreferences) {\n const matchSpec = calculateMatchSpecificity(\n parsedProvided,\n preference,\n providedIndex\n );\n\n if (matchSpec) {\n // Compare current best match with new match\n const scoreDifference =\n bestMatch.specificityScore - matchSpec.specificityScore ||\n bestMatch.qualityScore - matchSpec.qualityScore ||\n bestMatch.headerIndex - matchSpec.headerIndex;\n\n // If the new match is better (difference < 0), update priority\n if (scoreDifference < 0) {\n bestMatch = matchSpec;\n }\n }\n }\n\n return bestMatch;\n};\n\n/**\n * Comparator function to sort MatchResults.\n * Order: Quality (desc) -> Specificity (desc) -> Header Order (asc) -> Provided Order (asc)\n */\nconst compareMatchResults = (a: MatchResult, b: MatchResult): number => {\n return (\n b.qualityScore - a.qualityScore ||\n b.specificityScore - a.specificityScore ||\n a.headerIndex - b.headerIndex ||\n a.providedIndex - b.providedIndex ||\n 0\n );\n};\n\n/**\n * Derives the list of preferred languages based on the Accept-Language header\n * and an optional list of available languages.\n */\nexport const getPreferredLanguages = (\n acceptHeader: string | undefined,\n availableLanguages?: string[]\n): string[] => {\n // RFC 2616 sec 14.4: no header implies '*'\n const headerValue = acceptHeader === undefined ? '*' : acceptHeader || '';\n const acceptedPreferences = parseAcceptLanguageHeader(headerValue);\n\n // If no specific languages are provided to filter against, return the header languages sorted by quality\n if (!availableLanguages) {\n return acceptedPreferences\n .filter((preference) => preference.qualityScore > 0)\n .sort((a, b) => b.qualityScore - a.qualityScore) // Simple sort by quality\n .map((preference) => preference.fullLocale);\n }\n\n // Map available languages to their match priority against the header\n const matchResults = availableLanguages.map((language, index) =>\n getBestMatchForLanguage(language, acceptedPreferences, index)\n );\n\n return matchResults\n .filter((result) => result.qualityScore > 0)\n .sort(compareMatchResults)\n .map((result) => availableLanguages[result.providedIndex]) as string[];\n};\n\n/**\n * Detected locales, keyed by header, available locales and default locale.\n */\nconst detectedLocaleCache = new Map<string, DeclaredLocales>();\n\n/**\n * Detects the locale from the request headers.\n *\n * Headers are provided by the browser/client and can be used to determine the user's preferred language.\n * This function intersects the user's `Accept-Language` header with the application's available locales.\n *\n * The result is memoized, as it only depends on its arguments.\n */\nexport const localeDetector = (\n headers: Record<string, string | undefined>,\n availableLocales?: Locale[],\n defaultLocale?: Locale\n): DeclaredLocales => {\n const acceptLanguageHeader = headers['accept-language'];\n\n const isCacheable =\n (acceptLanguageHeader?.length ?? 0) <= MAX_CACHEABLE_HEADER_LENGTH;\n\n // A missing header (`*`) and an empty header resolve differently\n const cacheKey = isCacheable\n ? `${acceptLanguageHeader === undefined ? '\\u0000' : `=${acceptLanguageHeader}`}\\u0001${availableLocales?.join(',') ?? '\\u0000'}\\u0001${defaultLocale ?? '\\u0000'}`\n : undefined;\n\n if (cacheKey !== undefined) {\n const cachedLocale = detectedLocaleCache.get(cacheKey);\n\n if (cachedLocale !== undefined) return cachedLocale;\n }\n\n const preferredLocaleStrings = getPreferredLanguages(\n acceptLanguageHeader,\n availableLocales as string[]\n );\n\n const detectedLocale = localeResolver(\n preferredLocaleStrings as Locale[],\n availableLocales,\n defaultLocale\n );\n\n if (cacheKey !== undefined) {\n setBoundedCacheEntry(detectedLocaleCache, cacheKey, detectedLocale);\n }\n\n return detectedLocale;\n};\n"],"mappings":"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"}
|
|
@@ -154,8 +154,11 @@ const ATTRIBUTES_TO_SANITIZE = [
|
|
|
154
154
|
"srcDoc",
|
|
155
155
|
"action"
|
|
156
156
|
];
|
|
157
|
-
/**
|
|
158
|
-
|
|
157
|
+
/**
|
|
158
|
+
* Attribute extractor regex. Values may be double/single quoted, `{…}`
|
|
159
|
+
* expressions, or unquoted `[…]` arrays (`codeFormat=["typescript", "esm"]`).
|
|
160
|
+
*/
|
|
161
|
+
const ATTR_EXTRACTOR_R = /([-A-Z0-9_:]+)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|(?:\{((?:\\.|{[^}]*?}|[^}])*)\})|(?:\[[^\]]*\])))?/gi;
|
|
159
162
|
/** First character of a valid attribute name (a letter, `_` or `:`). */
|
|
160
163
|
const ATTRIBUTE_NAME_START_R = /^[A-Z_:]/i;
|
|
161
164
|
/** Block end detection */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.cjs","names":[],"sources":["../../../src/markdown/constants.ts"],"sourcesContent":["// ============================================================================\n// RULE TYPES\n// ============================================================================\n\n/**\n * Analogous to `node.type`. Please note that the values here may change at any time,\n * so do not hard code against the value directly.\n */\nexport const RuleType = {\n blockQuote: '0',\n breakLine: '1',\n breakThematic: '2',\n codeBlock: '3',\n codeFenced: '4',\n codeInline: '5',\n footnote: '6',\n footnoteReference: '7',\n gfmTask: '8',\n heading: '9',\n headingSetext: '10',\n /** only available if not `disableHTMLParsing` */\n htmlBlock: '11',\n htmlComment: '12',\n /** only available if not `disableHTMLParsing` */\n htmlSelfClosing: '13',\n /** Custom components like <Tabs>, <TabItem> */\n customComponent: '34',\n image: '14',\n link: '15',\n /** emits a `link` 'node', does not render directly */\n linkAngleBraceStyleDetector: '16',\n /** emits a `link` 'node', does not render directly */\n linkBareUrlDetector: '17',\n newlineCoalescer: '19',\n orderedList: '20',\n paragraph: '21',\n ref: '22',\n refImage: '23',\n refLink: '24',\n table: '25',\n tableSeparator: '26',\n text: '27',\n textBolded: '28',\n textEmphasized: '29',\n textEscaped: '30',\n textMarked: '31',\n textStrikethroughed: '32',\n unorderedList: '33',\n} as const;\n\n// In test environment, use human-readable keys for easier debugging\nif (process.env.NODE_ENV === 'test') {\n Object.keys(RuleType).forEach((key) => {\n (RuleType as any)[key] = key;\n });\n}\n\nexport type RuleTypeValue = (typeof RuleType)[keyof typeof RuleType];\n\n// ============================================================================\n// PRIORITY LEVELS\n// ============================================================================\n\n/**\n * Priority levels for rule ordering.\n */\nexport const Priority = {\n /** anything that must scan the tree before everything else */\n MAX: 0,\n /** scans for block-level constructs */\n HIGH: 1,\n /** inline w/ more priority than other inline */\n MED: 2,\n /** inline elements */\n LOW: 3,\n /** bare text and stuff that is considered leftovers */\n MIN: 4,\n} as const;\n\nexport type PriorityValue = (typeof Priority)[keyof typeof Priority];\n\n// ============================================================================\n// RULE SCOPE CONSTANTS\n// ============================================================================\n\n/**\n * Parsing scope for markdown rules.\n * Bitmask representation for fast bitwise checking and bundle minification.\n * - BLOCK (1): evaluated only when !state.inline && !state.simple\n * - INLINE (2): evaluated only when state.inline || state.simple\n * - BOTH (3): evaluated in both scopes (default)\n */\nexport const RuleScope = {\n BLOCK: 1,\n INLINE: 2,\n BOTH: 3,\n} as const;\n\nexport const SCOPE_BLOCK = RuleScope.BLOCK;\nexport const SCOPE_INLINE = RuleScope.INLINE;\nexport const SCOPE_BOTH = RuleScope.BOTH;\n\nexport type RuleScopeValue =\n | (typeof RuleScope)[keyof typeof RuleScope]\n | 'block'\n | 'inline'\n | 'both';\n\n// ============================================================================\n// ATTRIBUTE MAPPING\n// ============================================================================\n\n/**\n * Map of HTML attributes to their JSX prop equivalents.\n * Some renderers use camelCase for certain attributes.\n */\nexport const ATTRIBUTE_TO_NODE_PROP_MAP: Record<string, string> = [\n 'allowFullScreen',\n 'autoComplete',\n 'autoFocus',\n 'autoPlay',\n 'cellPadding',\n 'cellSpacing',\n 'charSet',\n 'classId',\n 'colSpan',\n 'contentEditable',\n 'contextMenu',\n 'crossOrigin',\n 'encType',\n 'formAction',\n 'formEncType',\n 'formMethod',\n 'formNoValidate',\n 'formTarget',\n 'frameBorder',\n 'hrefLang',\n 'inputMode',\n 'keyParams',\n 'keyType',\n 'marginHeight',\n 'marginWidth',\n 'maxLength',\n 'mediaGroup',\n 'minLength',\n 'noValidate',\n 'radioGroup',\n 'readOnly',\n 'rowSpan',\n 'spellCheck',\n 'srcDoc',\n 'srcLang',\n 'srcSet',\n 'tabIndex',\n 'useMap',\n].reduce(\n (obj: Record<string, string>, x) => {\n obj[x.toLowerCase()] = x;\n return obj;\n },\n { class: 'className', for: 'htmlFor' }\n);\n\n// ============================================================================\n// NAMED CODES TO UNICODE\n// ============================================================================\n\n/**\n * Default HTML entity to unicode mappings.\n */\nexport const NAMED_CODES_TO_UNICODE: Record<string, string> = {\n amp: '\\u0026',\n apos: '\\u0027',\n gt: '\\u003e',\n lt: '\\u003c',\n nbsp: '\\u00a0',\n quot: '\\u201c',\n};\n\n// ============================================================================\n// SPECIAL ELEMENTS\n// ============================================================================\n\n/** HTML elements that should not have their content processed */\nexport const DO_NOT_PROCESS_HTML_ELEMENTS = ['style', 'script', 'pre'];\n\n/** Attributes that require URL sanitization */\nexport const ATTRIBUTES_TO_SANITIZE = [\n 'src',\n 'href',\n 'data',\n 'formAction',\n 'srcDoc',\n 'action',\n];\n\n// ============================================================================\n// REGEX PATTERNS\n// ============================================================================\n\n/** Attribute extractor regex */\nexport const ATTR_EXTRACTOR_R =\n /([-A-Z0-9_:]+)(?:\\s*=\\s*(?:(?:\"((?:\\\\.|[^\"])*)\")|(?:'((?:\\\\.|[^'])*)')|(?:\\{((?:\\\\.|{[^}]*?}|[^}])*)\\})))?/gi;\n\n/** First character of a valid attribute name (a letter, `_` or `:`). */\nexport const ATTRIBUTE_NAME_START_R = /^[A-Z_:]/i;\n\n/** Block end detection */\nexport const BLOCK_END_R = /\\n{2,}$/;\n\n/** Blockquote patterns */\nexport const BLOCKQUOTE_R = /^(\\s*>[\\s\\S]*?)(?=\\n\\n|$)/;\nexport const BLOCKQUOTE_TRIM_LEFT_MULTILINE_R = /^ *> ?/gm;\nexport const BLOCKQUOTE_ALERT_R = /^(?:\\[!([^\\]]*)\\]\\n)?([\\s\\S]*)/;\n\n/** Line break patterns */\nexport const BREAK_LINE_R = /^(?=( {2,}))\\1\\n/;\nexport const BREAK_THEMATIC_R = /^(?:([-*_])( *\\1){2,}) *(?:\\n *)+\\n/;\n\n/** Code block patterns */\n// The body is consumed a whole line at a time rather than character by\n// character: a closing fence only ever starts a line, so the backreference is\n// tested once per line instead of once per character. The trailing `$` branch\n// inside the loop keeps an unterminated fence that ends without a newline.\nexport const CODE_BLOCK_FENCED_R =\n /^(?: {1,3})?(`{3,}|~{3,}) *(\\S+)? *([^\\n]*?)?\\n((?:[^\\n]*(?:\\n|$))*?)(?:\\1\\n?|$)/;\nexport const CODE_BLOCK_R = /^(?: {4}[^\\n]+\\n*)+(?:\\n *)+\\n?/;\n/** A single line opening or closing a fenced code block, with its indentation. */\nexport const FENCE_DELIMITER_R = /^([ \\t]*)(`{3,}|~{3,})/;\nexport const CODE_INLINE_R = /^(`+)((?:\\\\`|(?!\\1)`|[^`])+)\\1/;\n\n/** Newline patterns */\nexport const CONSECUTIVE_NEWLINE_R = /^(?:\\n *)*\\n/;\nexport const CR_NEWLINE_R = /\\r\\n?/g;\n\n/** Footnote patterns */\nexport const FOOTNOTE_R = /^\\[\\^([^\\]]+)](:(.*)((\\n+ {4,}.*)|(\\n(?!\\[\\^).+))*)/;\nexport const FOOTNOTE_REFERENCE_R = /^\\[\\^([^\\]]+)]/;\n\n/** Form feed */\nexport const FORMFEED_R = /\\f/g;\n\n/** Front matter */\nexport const FRONT_MATTER_R = /^---[ \\t]*\\n(.|\\n)*?\\n---[ \\t]*\\n/;\n\n/** GFM task */\nexport const GFM_TASK_R = /^\\s*?\\[(x|\\s)\\]/;\n\n/** Heading patterns */\nexport const HEADING_R = /^ *(#{1,6}) *([^\\n]+?)(?: +#*)?(?:\\n *)*(?:\\n|$)/;\nexport const HEADING_ATX_COMPLIANT_R =\n /^ *(#{1,6}) +([^\\n]+?)(?: +#*)?(?:\\n *)*(?:\\n|$)/;\nexport const HEADING_SETEXT_R = /^([^\\n]+)\\n *(=|-)\\2{2,} *\\n/;\n\n/** HTML patterns */\n\nexport const HTML_CHAR_CODE_R =\n /&([a-z0-9]+|#[0-9]{1,6}|#x[0-9a-fA-F]{1,6});/gi;\nexport const HTML_COMMENT_R = /^<!--[\\s\\S]*?(?:-->)/;\nexport const HTML_CUSTOM_ATTR_R = /^(data|aria|x)-[a-z_][a-z\\d_.-]*$/;\n\n/** Interpolation */\nexport const INTERPOLATION_R = /^\\{.*\\}$/;\n\n/** Link patterns */\nexport const LINK_AUTOLINK_BARE_URL_R = /^(https?:\\/\\/[^\\s<]+[^<.,:;\"')\\]\\s])/;\nexport const LINK_AUTOLINK_R = /^<([^ >]+[:@/][^ >]+)>/;\nexport const CAPTURE_LETTER_AFTER_HYPHEN = /-([a-z])?/gi;\n\n/**\n * Table patterns.\n *\n * The row scans spell \"any character but a newline\" as `[^\\n]` rather than `.`:\n * `.` is a four-range exclusion, and matching it over rows this wide costs a\n * third more than the single-range class. It is also the more faithful reading\n * — only `\\n` ends a line here, and `\\r` is normalized away before parsing.\n */\nexport const NP_TABLE_R =\n /^(\\|[^\\n]*)\\n(?: *(\\|? *[-:]+ *\\|[-| :]*)\\n((?:[^\\n]*\\|[^\\n]*\\n)*))?\\n?/;\nexport const TABLE_TRIM_PIPES = /(^ *\\||\\| *$)/g;\nexport const TABLE_CENTER_ALIGN = /^ *:-+: *$/;\nexport const TABLE_LEFT_ALIGN = /^ *:-+ *$/;\nexport const TABLE_RIGHT_ALIGN = /^ *-+: *$/;\n\n/** Paragraph */\nexport const PARAGRAPH_R = /^[^\\n]+(?: {2}\\n|\\n{2,})/;\n\n/** Reference patterns */\nexport const REFERENCE_IMAGE_OR_LINK =\n /^\\[([^\\]]*)\\]:\\s+<?([^\\s>]+)>?\\s*(\"([^\"]*)\")?/;\nexport const REFERENCE_IMAGE_R = /^!\\[([^\\]]*)\\] ?\\[([^\\]]*)\\]/;\nexport const REFERENCE_LINK_R = /^\\[([^\\]]*)\\] ?\\[([^\\]]*)\\]/;\n\n/** Block detection */\nexport const SHOULD_RENDER_AS_BLOCK_R = /(\\n|^[-*]\\s|^#|^ {2,}|^-{2,}|^>\\s)/;\n\n/** Tabs, which `normalizeWhitespace` widens to four spaces. */\nexport const TAB_R = /\\t/g;\nexport const TRIM_STARTING_NEWLINES = /^\\n+/;\nexport const HTML_LEFT_TRIM_AMOUNT_R = /^\\n*([ \\t]*)/;\n\n/** List patterns */\nexport const ORDERED_LIST_BULLET = '(?:\\\\d+\\\\.)';\nexport const UNORDERED_LIST_BULLET = '(?:[*+-])';\n\n/** Text formatting patterns */\nexport const TEXT_ESCAPED_R = /^\\\\([^0-9A-Za-z\\s])/;\nexport const UNESCAPE_R = /\\\\([^0-9A-Za-z\\s])/g;\n\n/** Shortcode pattern */\nexport const SHORTCODE_R = /^(:[a-zA-Z0-9-_]+:)/;\n\n// ============================================================================\n// LIST TYPE CONSTANTS\n// ============================================================================\n\nexport type ListType = 1 | 2;\nexport const ORDERED: ListType = 1;\nexport const UNORDERED: ListType = 2;\n\n// ============================================================================\n// INLINE PATTERN HELPERS\n// ============================================================================\n\n/**\n * Ensure there's at least one more instance of the delimiter later\n * in the current sequence.\n */\nexport const LOOKAHEAD = (double: number): string =>\n `(?=[\\\\s\\\\S]+?\\\\1${double ? '\\\\1' : ''})`;\n\n/**\n * For inline formatting, this partial attempts to ignore characters that\n * may appear in nested formatting.\n */\nexport const INLINE_SKIP_R =\n '((?:\\\\[.*?\\\\][([].*?[)\\\\]]|<.*?>(?:.*?<.*?>)?|`.*?`|\\\\\\\\[^\\\\s]|[\\\\s\\\\S])+?)';\n\n/** Bold text pattern */\nexport const TEXT_BOLD_R = new RegExp(\n `^([*_])\\\\1${LOOKAHEAD(1)}${INLINE_SKIP_R}\\\\1\\\\1(?!\\\\1)`\n);\n\n/** Emphasized text pattern */\nexport const TEXT_EMPHASIZED_R = new RegExp(\n `^([*_])${LOOKAHEAD(0)}${INLINE_SKIP_R}\\\\1(?!\\\\1)`\n);\n\n/** Marked text pattern */\nexport const TEXT_MARKED_R = new RegExp(\n `^(==)${LOOKAHEAD(0)}${INLINE_SKIP_R}\\\\1`\n);\n\n/** Strikethrough text pattern */\nexport const TEXT_STRIKETHROUGHED_R = new RegExp(\n `^(~~)${LOOKAHEAD(0)}${INLINE_SKIP_R}\\\\1`\n);\n\n// ============================================================================\n// LIST REGEX GENERATORS\n// ============================================================================\n\nexport const generateListItemPrefix = (type: ListType): string => {\n return (\n '( *)(' +\n (type === ORDERED ? ORDERED_LIST_BULLET : UNORDERED_LIST_BULLET) +\n ') +'\n );\n};\n\nexport const ORDERED_LIST_ITEM_PREFIX = generateListItemPrefix(ORDERED);\nexport const UNORDERED_LIST_ITEM_PREFIX = generateListItemPrefix(UNORDERED);\n\nexport const generateListItemPrefixRegex = (type: ListType): RegExp => {\n return new RegExp(\n '^' +\n (type === ORDERED ? ORDERED_LIST_ITEM_PREFIX : UNORDERED_LIST_ITEM_PREFIX)\n );\n};\n\nexport const ORDERED_LIST_ITEM_PREFIX_R = generateListItemPrefixRegex(ORDERED);\nexport const UNORDERED_LIST_ITEM_PREFIX_R =\n generateListItemPrefixRegex(UNORDERED);\n\nexport const generateListItemRegex = (type: ListType): RegExp => {\n return new RegExp(\n '^' +\n (type === ORDERED\n ? ORDERED_LIST_ITEM_PREFIX\n : UNORDERED_LIST_ITEM_PREFIX) +\n '[^\\\\n]*(?:\\\\n' +\n '(?!\\\\1' +\n (type === ORDERED ? ORDERED_LIST_BULLET : UNORDERED_LIST_BULLET) +\n ' )[^\\\\n]*)*(\\\\n|$)',\n 'gm'\n );\n};\n\nexport const ORDERED_LIST_ITEM_R = generateListItemRegex(ORDERED);\nexport const UNORDERED_LIST_ITEM_R = generateListItemRegex(UNORDERED);\n\nexport const generateListRegex = (type: ListType): RegExp => {\n const bullet = type === ORDERED ? ORDERED_LIST_BULLET : UNORDERED_LIST_BULLET;\n\n return new RegExp(\n '^( *)(' +\n bullet +\n ') ' +\n // The body advances a line at a time rather than a character at a time: a\n // list can only end at a line boundary, so the terminator — the expensive\n // half, with its two nested lookaheads — is tried once per line instead of\n // once per character. The step swallows the newline that used to open the\n // terminator, which is why it now reads `\\n+` and not `\\n{2,}`, and the\n // leading lookahead keeps a source with nothing left after the bullet from\n // matching through a zero-width step.\n '(?=[\\\\s\\\\S])(?:[^\\\\n]*(?:\\\\n|$))+?' +\n '(?:\\\\n+(?! )' +\n '(?!\\\\1' +\n bullet +\n ' (?!' +\n bullet +\n ' ))\\\\n*' +\n // `\\s` already covers `\\n`, so the trailing `\\n*` the pattern used to\n // carry could only ever match empty — and paying for it at every step of\n // the lazy scan cost a third of the whole match.\n '|\\\\s*$)'\n );\n};\n\nexport const ORDERED_LIST_R = generateListRegex(ORDERED);\nexport const UNORDERED_LIST_R = generateListRegex(UNORDERED);\n"],"mappings":";;;;;;AAQA,MAAa,WAAW;CACtB,YAAY;CACZ,WAAW;CACX,eAAe;CACf,WAAW;CACX,YAAY;CACZ,YAAY;CACZ,UAAU;CACV,mBAAmB;CACnB,SAAS;CACT,SAAS;CACT,eAAe;;CAEf,WAAW;CACX,aAAa;;CAEb,iBAAiB;;CAEjB,iBAAiB;CACjB,OAAO;CACP,MAAM;;CAEN,6BAA6B;;CAE7B,qBAAqB;CACrB,kBAAkB;CAClB,aAAa;CACb,WAAW;CACX,KAAK;CACL,UAAU;CACV,SAAS;CACT,OAAO;CACP,gBAAgB;CAChB,MAAM;CACN,YAAY;CACZ,gBAAgB;CAChB,aAAa;CACb,YAAY;CACZ,qBAAqB;CACrB,eAAe;AACjB;AAGA,6BAA6B,QAC3B,OAAO,KAAK,QAAQ,CAAC,CAAC,SAAS,QAAQ;CACrC,AAAC,SAAiB,OAAO;AAC3B,CAAC;;;;AAYH,MAAa,WAAW;;CAEtB,KAAK;;CAEL,MAAM;;CAEN,KAAK;;CAEL,KAAK;;CAEL,KAAK;AACP;;;;;;;;AAeA,MAAa,YAAY;CACvB,OAAO;CACP,QAAQ;CACR,MAAM;AACR;AAEA,MAAa,cAAc,UAAU;AACrC,MAAa,eAAe,UAAU;AACtC,MAAa,aAAa,UAAU;;;;;AAgBpC,MAAa,6BAAqD;CAChE;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;AACF,CAAC,CAAC,QACC,KAA6B,MAAM;CAClC,IAAI,EAAE,YAAY,KAAK;CACvB,OAAO;AACT,GACA;CAAE,OAAO;CAAa,KAAK;AAAU,CACvC;;;;AASA,MAAa,yBAAiD;CAC5D,KAAK;CACL,MAAM;CACN,IAAI;CACJ,IAAI;CACJ,MAAM;CACN,MAAM;AACR;;AAOA,MAAa,+BAA+B;CAAC;CAAS;CAAU;AAAK;;AAGrE,MAAa,yBAAyB;CACpC;CACA;CACA;CACA;CACA;CACA;AACF;;AAOA,MAAa,mBACX;;AAGF,MAAa,yBAAyB;;AAGtC,MAAa,cAAc;;AAG3B,MAAa,eAAe;AAC5B,MAAa,mCAAmC;AAChD,MAAa,qBAAqB;;AAGlC,MAAa,eAAe;AAC5B,MAAa,mBAAmB;;AAOhC,MAAa,sBACX;AACF,MAAa,eAAe;;AAE5B,MAAa,oBAAoB;AACjC,MAAa,gBAAgB;;AAG7B,MAAa,wBAAwB;AACrC,MAAa,eAAe;;AAG5B,MAAa,aAAa;AAC1B,MAAa,uBAAuB;;AAGpC,MAAa,aAAa;;AAG1B,MAAa,iBAAiB;;AAG9B,MAAa,aAAa;;AAG1B,MAAa,YAAY;AACzB,MAAa,0BACX;AACF,MAAa,mBAAmB;;AAIhC,MAAa,mBACX;AACF,MAAa,iBAAiB;AAC9B,MAAa,qBAAqB;;AAGlC,MAAa,kBAAkB;;AAG/B,MAAa,2BAA2B;AACxC,MAAa,kBAAkB;AAC/B,MAAa,8BAA8B;;;;;;;;;AAU3C,MAAa,aACX;AACF,MAAa,mBAAmB;AAChC,MAAa,qBAAqB;AAClC,MAAa,mBAAmB;AAChC,MAAa,oBAAoB;;AAGjC,MAAa,cAAc;;AAG3B,MAAa,0BACX;AACF,MAAa,oBAAoB;AACjC,MAAa,mBAAmB;;AAGhC,MAAa,2BAA2B;;AAGxC,MAAa,QAAQ;AACrB,MAAa,yBAAyB;AACtC,MAAa,0BAA0B;;AAGvC,MAAa,sBAAsB;AACnC,MAAa,wBAAwB;;AAGrC,MAAa,iBAAiB;AAC9B,MAAa,aAAa;;AAG1B,MAAa,cAAc;AAO3B,MAAa,UAAoB;AACjC,MAAa,YAAsB;;;;;AAUnC,MAAa,aAAa,WACxB,mBAAmB,SAAS,QAAQ,GAAG;;;;;AAMzC,MAAa,gBACX;;AAGF,MAAa,cAAc,IAAI,OAC7B,aAAa,UAAU,CAAC,IAAI,cAAc,cAC5C;;AAGA,MAAa,oBAAoB,IAAI,OACnC,UAAU,UAAU,CAAC,IAAI,cAAc,WACzC;;AAGA,MAAa,gBAAgB,IAAI,OAC/B,QAAQ,UAAU,CAAC,IAAI,cAAc,IACvC;;AAGA,MAAa,yBAAyB,IAAI,OACxC,QAAQ,UAAU,CAAC,IAAI,cAAc,IACvC;AAMA,MAAa,0BAA0B,SAA2B;CAChE,OACE,WACC,aAAmB,sBAAsB,yBAC1C;AAEJ;AAEA,MAAa,2BAA2B,wBAA8B;AACtE,MAAa,6BAA6B,wBAAgC;AAE1E,MAAa,+BAA+B,SAA2B;CACrE,OAAO,IAAI,OACT,OACG,aAAmB,2BAA2B,2BACnD;AACF;AAEA,MAAa,6BAA6B,6BAAmC;AAC7E,MAAa,+BACX,6BAAqC;AAEvC,MAAa,yBAAyB,SAA2B;CAC/D,OAAO,IAAI,OACT,OACG,aACG,2BACA,8BACJ,yBAEC,aAAmB,sBAAsB,yBAC1C,sBACF,IACF;AACF;AAEA,MAAa,sBAAsB,uBAA6B;AAChE,MAAa,wBAAwB,uBAA+B;AAEpE,MAAa,qBAAqB,SAA2B;CAC3D,MAAM,SAAS,aAAmB,sBAAsB;CAExD,OAAO,IAAI,OACT,WACE,SACA,2DAWA,SACA,SACA,SACA,gBAKJ;AACF;AAEA,MAAa,iBAAiB,mBAAyB;AACvD,MAAa,mBAAmB,mBAA2B"}
|
|
1
|
+
{"version":3,"file":"constants.cjs","names":[],"sources":["../../../src/markdown/constants.ts"],"sourcesContent":["// ============================================================================\n// RULE TYPES\n// ============================================================================\n\n/**\n * Analogous to `node.type`. Please note that the values here may change at any time,\n * so do not hard code against the value directly.\n */\nexport const RuleType = {\n blockQuote: '0',\n breakLine: '1',\n breakThematic: '2',\n codeBlock: '3',\n codeFenced: '4',\n codeInline: '5',\n footnote: '6',\n footnoteReference: '7',\n gfmTask: '8',\n heading: '9',\n headingSetext: '10',\n /** only available if not `disableHTMLParsing` */\n htmlBlock: '11',\n htmlComment: '12',\n /** only available if not `disableHTMLParsing` */\n htmlSelfClosing: '13',\n /** Custom components like <Tabs>, <TabItem> */\n customComponent: '34',\n image: '14',\n link: '15',\n /** emits a `link` 'node', does not render directly */\n linkAngleBraceStyleDetector: '16',\n /** emits a `link` 'node', does not render directly */\n linkBareUrlDetector: '17',\n newlineCoalescer: '19',\n orderedList: '20',\n paragraph: '21',\n ref: '22',\n refImage: '23',\n refLink: '24',\n table: '25',\n tableSeparator: '26',\n text: '27',\n textBolded: '28',\n textEmphasized: '29',\n textEscaped: '30',\n textMarked: '31',\n textStrikethroughed: '32',\n unorderedList: '33',\n} as const;\n\n// In test environment, use human-readable keys for easier debugging\nif (process.env.NODE_ENV === 'test') {\n Object.keys(RuleType).forEach((key) => {\n (RuleType as any)[key] = key;\n });\n}\n\nexport type RuleTypeValue = (typeof RuleType)[keyof typeof RuleType];\n\n// ============================================================================\n// PRIORITY LEVELS\n// ============================================================================\n\n/**\n * Priority levels for rule ordering.\n */\nexport const Priority = {\n /** anything that must scan the tree before everything else */\n MAX: 0,\n /** scans for block-level constructs */\n HIGH: 1,\n /** inline w/ more priority than other inline */\n MED: 2,\n /** inline elements */\n LOW: 3,\n /** bare text and stuff that is considered leftovers */\n MIN: 4,\n} as const;\n\nexport type PriorityValue = (typeof Priority)[keyof typeof Priority];\n\n// ============================================================================\n// RULE SCOPE CONSTANTS\n// ============================================================================\n\n/**\n * Parsing scope for markdown rules.\n * Bitmask representation for fast bitwise checking and bundle minification.\n * - BLOCK (1): evaluated only when !state.inline && !state.simple\n * - INLINE (2): evaluated only when state.inline || state.simple\n * - BOTH (3): evaluated in both scopes (default)\n */\nexport const RuleScope = {\n BLOCK: 1,\n INLINE: 2,\n BOTH: 3,\n} as const;\n\nexport const SCOPE_BLOCK = RuleScope.BLOCK;\nexport const SCOPE_INLINE = RuleScope.INLINE;\nexport const SCOPE_BOTH = RuleScope.BOTH;\n\nexport type RuleScopeValue =\n | (typeof RuleScope)[keyof typeof RuleScope]\n | 'block'\n | 'inline'\n | 'both';\n\n// ============================================================================\n// ATTRIBUTE MAPPING\n// ============================================================================\n\n/**\n * Map of HTML attributes to their JSX prop equivalents.\n * Some renderers use camelCase for certain attributes.\n */\nexport const ATTRIBUTE_TO_NODE_PROP_MAP: Record<string, string> = [\n 'allowFullScreen',\n 'autoComplete',\n 'autoFocus',\n 'autoPlay',\n 'cellPadding',\n 'cellSpacing',\n 'charSet',\n 'classId',\n 'colSpan',\n 'contentEditable',\n 'contextMenu',\n 'crossOrigin',\n 'encType',\n 'formAction',\n 'formEncType',\n 'formMethod',\n 'formNoValidate',\n 'formTarget',\n 'frameBorder',\n 'hrefLang',\n 'inputMode',\n 'keyParams',\n 'keyType',\n 'marginHeight',\n 'marginWidth',\n 'maxLength',\n 'mediaGroup',\n 'minLength',\n 'noValidate',\n 'radioGroup',\n 'readOnly',\n 'rowSpan',\n 'spellCheck',\n 'srcDoc',\n 'srcLang',\n 'srcSet',\n 'tabIndex',\n 'useMap',\n].reduce(\n (obj: Record<string, string>, x) => {\n obj[x.toLowerCase()] = x;\n return obj;\n },\n { class: 'className', for: 'htmlFor' }\n);\n\n// ============================================================================\n// NAMED CODES TO UNICODE\n// ============================================================================\n\n/**\n * Default HTML entity to unicode mappings.\n */\nexport const NAMED_CODES_TO_UNICODE: Record<string, string> = {\n amp: '\\u0026',\n apos: '\\u0027',\n gt: '\\u003e',\n lt: '\\u003c',\n nbsp: '\\u00a0',\n quot: '\\u201c',\n};\n\n// ============================================================================\n// SPECIAL ELEMENTS\n// ============================================================================\n\n/** HTML elements that should not have their content processed */\nexport const DO_NOT_PROCESS_HTML_ELEMENTS = ['style', 'script', 'pre'];\n\n/** Attributes that require URL sanitization */\nexport const ATTRIBUTES_TO_SANITIZE = [\n 'src',\n 'href',\n 'data',\n 'formAction',\n 'srcDoc',\n 'action',\n];\n\n// ============================================================================\n// REGEX PATTERNS\n// ============================================================================\n\n/**\n * Attribute extractor regex. Values may be double/single quoted, `{…}`\n * expressions, or unquoted `[…]` arrays (`codeFormat=[\"typescript\", \"esm\"]`).\n */\nexport const ATTR_EXTRACTOR_R =\n /([-A-Z0-9_:]+)(?:\\s*=\\s*(?:(?:\"((?:\\\\.|[^\"])*)\")|(?:'((?:\\\\.|[^'])*)')|(?:\\{((?:\\\\.|{[^}]*?}|[^}])*)\\})|(?:\\[[^\\]]*\\])))?/gi;\n\n/** First character of a valid attribute name (a letter, `_` or `:`). */\nexport const ATTRIBUTE_NAME_START_R = /^[A-Z_:]/i;\n\n/** Block end detection */\nexport const BLOCK_END_R = /\\n{2,}$/;\n\n/** Blockquote patterns */\nexport const BLOCKQUOTE_R = /^(\\s*>[\\s\\S]*?)(?=\\n\\n|$)/;\nexport const BLOCKQUOTE_TRIM_LEFT_MULTILINE_R = /^ *> ?/gm;\nexport const BLOCKQUOTE_ALERT_R = /^(?:\\[!([^\\]]*)\\]\\n)?([\\s\\S]*)/;\n\n/** Line break patterns */\nexport const BREAK_LINE_R = /^(?=( {2,}))\\1\\n/;\nexport const BREAK_THEMATIC_R = /^(?:([-*_])( *\\1){2,}) *(?:\\n *)+\\n/;\n\n/** Code block patterns */\n// The body is consumed a whole line at a time rather than character by\n// character: a closing fence only ever starts a line, so the backreference is\n// tested once per line instead of once per character. The trailing `$` branch\n// inside the loop keeps an unterminated fence that ends without a newline.\nexport const CODE_BLOCK_FENCED_R =\n /^(?: {1,3})?(`{3,}|~{3,}) *(\\S+)? *([^\\n]*?)?\\n((?:[^\\n]*(?:\\n|$))*?)(?:\\1\\n?|$)/;\nexport const CODE_BLOCK_R = /^(?: {4}[^\\n]+\\n*)+(?:\\n *)+\\n?/;\n/** A single line opening or closing a fenced code block, with its indentation. */\nexport const FENCE_DELIMITER_R = /^([ \\t]*)(`{3,}|~{3,})/;\nexport const CODE_INLINE_R = /^(`+)((?:\\\\`|(?!\\1)`|[^`])+)\\1/;\n\n/** Newline patterns */\nexport const CONSECUTIVE_NEWLINE_R = /^(?:\\n *)*\\n/;\nexport const CR_NEWLINE_R = /\\r\\n?/g;\n\n/** Footnote patterns */\nexport const FOOTNOTE_R = /^\\[\\^([^\\]]+)](:(.*)((\\n+ {4,}.*)|(\\n(?!\\[\\^).+))*)/;\nexport const FOOTNOTE_REFERENCE_R = /^\\[\\^([^\\]]+)]/;\n\n/** Form feed */\nexport const FORMFEED_R = /\\f/g;\n\n/** Front matter */\nexport const FRONT_MATTER_R = /^---[ \\t]*\\n(.|\\n)*?\\n---[ \\t]*\\n/;\n\n/** GFM task */\nexport const GFM_TASK_R = /^\\s*?\\[(x|\\s)\\]/;\n\n/** Heading patterns */\nexport const HEADING_R = /^ *(#{1,6}) *([^\\n]+?)(?: +#*)?(?:\\n *)*(?:\\n|$)/;\nexport const HEADING_ATX_COMPLIANT_R =\n /^ *(#{1,6}) +([^\\n]+?)(?: +#*)?(?:\\n *)*(?:\\n|$)/;\nexport const HEADING_SETEXT_R = /^([^\\n]+)\\n *(=|-)\\2{2,} *\\n/;\n\n/** HTML patterns */\n\nexport const HTML_CHAR_CODE_R =\n /&([a-z0-9]+|#[0-9]{1,6}|#x[0-9a-fA-F]{1,6});/gi;\nexport const HTML_COMMENT_R = /^<!--[\\s\\S]*?(?:-->)/;\nexport const HTML_CUSTOM_ATTR_R = /^(data|aria|x)-[a-z_][a-z\\d_.-]*$/;\n\n/** Interpolation */\nexport const INTERPOLATION_R = /^\\{.*\\}$/;\n\n/** Link patterns */\nexport const LINK_AUTOLINK_BARE_URL_R = /^(https?:\\/\\/[^\\s<]+[^<.,:;\"')\\]\\s])/;\nexport const LINK_AUTOLINK_R = /^<([^ >]+[:@/][^ >]+)>/;\nexport const CAPTURE_LETTER_AFTER_HYPHEN = /-([a-z])?/gi;\n\n/**\n * Table patterns.\n *\n * The row scans spell \"any character but a newline\" as `[^\\n]` rather than `.`:\n * `.` is a four-range exclusion, and matching it over rows this wide costs a\n * third more than the single-range class. It is also the more faithful reading\n * — only `\\n` ends a line here, and `\\r` is normalized away before parsing.\n */\nexport const NP_TABLE_R =\n /^(\\|[^\\n]*)\\n(?: *(\\|? *[-:]+ *\\|[-| :]*)\\n((?:[^\\n]*\\|[^\\n]*\\n)*))?\\n?/;\nexport const TABLE_TRIM_PIPES = /(^ *\\||\\| *$)/g;\nexport const TABLE_CENTER_ALIGN = /^ *:-+: *$/;\nexport const TABLE_LEFT_ALIGN = /^ *:-+ *$/;\nexport const TABLE_RIGHT_ALIGN = /^ *-+: *$/;\n\n/** Paragraph */\nexport const PARAGRAPH_R = /^[^\\n]+(?: {2}\\n|\\n{2,})/;\n\n/** Reference patterns */\nexport const REFERENCE_IMAGE_OR_LINK =\n /^\\[([^\\]]*)\\]:\\s+<?([^\\s>]+)>?\\s*(\"([^\"]*)\")?/;\nexport const REFERENCE_IMAGE_R = /^!\\[([^\\]]*)\\] ?\\[([^\\]]*)\\]/;\nexport const REFERENCE_LINK_R = /^\\[([^\\]]*)\\] ?\\[([^\\]]*)\\]/;\n\n/** Block detection */\nexport const SHOULD_RENDER_AS_BLOCK_R = /(\\n|^[-*]\\s|^#|^ {2,}|^-{2,}|^>\\s)/;\n\n/** Tabs, which `normalizeWhitespace` widens to four spaces. */\nexport const TAB_R = /\\t/g;\nexport const TRIM_STARTING_NEWLINES = /^\\n+/;\nexport const HTML_LEFT_TRIM_AMOUNT_R = /^\\n*([ \\t]*)/;\n\n/** List patterns */\nexport const ORDERED_LIST_BULLET = '(?:\\\\d+\\\\.)';\nexport const UNORDERED_LIST_BULLET = '(?:[*+-])';\n\n/** Text formatting patterns */\nexport const TEXT_ESCAPED_R = /^\\\\([^0-9A-Za-z\\s])/;\nexport const UNESCAPE_R = /\\\\([^0-9A-Za-z\\s])/g;\n\n/** Shortcode pattern */\nexport const SHORTCODE_R = /^(:[a-zA-Z0-9-_]+:)/;\n\n// ============================================================================\n// LIST TYPE CONSTANTS\n// ============================================================================\n\nexport type ListType = 1 | 2;\nexport const ORDERED: ListType = 1;\nexport const UNORDERED: ListType = 2;\n\n// ============================================================================\n// INLINE PATTERN HELPERS\n// ============================================================================\n\n/**\n * Ensure there's at least one more instance of the delimiter later\n * in the current sequence.\n */\nexport const LOOKAHEAD = (double: number): string =>\n `(?=[\\\\s\\\\S]+?\\\\1${double ? '\\\\1' : ''})`;\n\n/**\n * For inline formatting, this partial attempts to ignore characters that\n * may appear in nested formatting.\n */\nexport const INLINE_SKIP_R =\n '((?:\\\\[.*?\\\\][([].*?[)\\\\]]|<.*?>(?:.*?<.*?>)?|`.*?`|\\\\\\\\[^\\\\s]|[\\\\s\\\\S])+?)';\n\n/** Bold text pattern */\nexport const TEXT_BOLD_R = new RegExp(\n `^([*_])\\\\1${LOOKAHEAD(1)}${INLINE_SKIP_R}\\\\1\\\\1(?!\\\\1)`\n);\n\n/** Emphasized text pattern */\nexport const TEXT_EMPHASIZED_R = new RegExp(\n `^([*_])${LOOKAHEAD(0)}${INLINE_SKIP_R}\\\\1(?!\\\\1)`\n);\n\n/** Marked text pattern */\nexport const TEXT_MARKED_R = new RegExp(\n `^(==)${LOOKAHEAD(0)}${INLINE_SKIP_R}\\\\1`\n);\n\n/** Strikethrough text pattern */\nexport const TEXT_STRIKETHROUGHED_R = new RegExp(\n `^(~~)${LOOKAHEAD(0)}${INLINE_SKIP_R}\\\\1`\n);\n\n// ============================================================================\n// LIST REGEX GENERATORS\n// ============================================================================\n\nexport const generateListItemPrefix = (type: ListType): string => {\n return (\n '( *)(' +\n (type === ORDERED ? ORDERED_LIST_BULLET : UNORDERED_LIST_BULLET) +\n ') +'\n );\n};\n\nexport const ORDERED_LIST_ITEM_PREFIX = generateListItemPrefix(ORDERED);\nexport const UNORDERED_LIST_ITEM_PREFIX = generateListItemPrefix(UNORDERED);\n\nexport const generateListItemPrefixRegex = (type: ListType): RegExp => {\n return new RegExp(\n '^' +\n (type === ORDERED ? ORDERED_LIST_ITEM_PREFIX : UNORDERED_LIST_ITEM_PREFIX)\n );\n};\n\nexport const ORDERED_LIST_ITEM_PREFIX_R = generateListItemPrefixRegex(ORDERED);\nexport const UNORDERED_LIST_ITEM_PREFIX_R =\n generateListItemPrefixRegex(UNORDERED);\n\nexport const generateListItemRegex = (type: ListType): RegExp => {\n return new RegExp(\n '^' +\n (type === ORDERED\n ? ORDERED_LIST_ITEM_PREFIX\n : UNORDERED_LIST_ITEM_PREFIX) +\n '[^\\\\n]*(?:\\\\n' +\n '(?!\\\\1' +\n (type === ORDERED ? ORDERED_LIST_BULLET : UNORDERED_LIST_BULLET) +\n ' )[^\\\\n]*)*(\\\\n|$)',\n 'gm'\n );\n};\n\nexport const ORDERED_LIST_ITEM_R = generateListItemRegex(ORDERED);\nexport const UNORDERED_LIST_ITEM_R = generateListItemRegex(UNORDERED);\n\nexport const generateListRegex = (type: ListType): RegExp => {\n const bullet = type === ORDERED ? ORDERED_LIST_BULLET : UNORDERED_LIST_BULLET;\n\n return new RegExp(\n '^( *)(' +\n bullet +\n ') ' +\n // The body advances a line at a time rather than a character at a time: a\n // list can only end at a line boundary, so the terminator — the expensive\n // half, with its two nested lookaheads — is tried once per line instead of\n // once per character. The step swallows the newline that used to open the\n // terminator, which is why it now reads `\\n+` and not `\\n{2,}`, and the\n // leading lookahead keeps a source with nothing left after the bullet from\n // matching through a zero-width step.\n '(?=[\\\\s\\\\S])(?:[^\\\\n]*(?:\\\\n|$))+?' +\n '(?:\\\\n+(?! )' +\n '(?!\\\\1' +\n bullet +\n ' (?!' +\n bullet +\n ' ))\\\\n*' +\n // `\\s` already covers `\\n`, so the trailing `\\n*` the pattern used to\n // carry could only ever match empty — and paying for it at every step of\n // the lazy scan cost a third of the whole match.\n '|\\\\s*$)'\n );\n};\n\nexport const ORDERED_LIST_R = generateListRegex(ORDERED);\nexport const UNORDERED_LIST_R = generateListRegex(UNORDERED);\n"],"mappings":"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"}
|
|
@@ -15,6 +15,7 @@ const require_transpiler_plural_plural = require('./plural/plural.cjs');
|
|
|
15
15
|
const require_transpiler_select_select = require('./select/select.cjs');
|
|
16
16
|
const require_transpiler_translation_translation = require('./translation/translation.cjs');
|
|
17
17
|
|
|
18
|
+
exports.DEFAULT_PLURAL_VARIABLE = require_transpiler_plural_plural.DEFAULT_PLURAL_VARIABLE;
|
|
18
19
|
exports.HTML_TAGS = require_transpiler_html_htmlTags.HTML_TAGS;
|
|
19
20
|
exports.VOID_HTML_ELEMENTS = require_transpiler_html_validateHTML.VOID_HTML_ELEMENTS;
|
|
20
21
|
exports.cond = require_transpiler_condition_condition.cond;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
2
|
const require_transpiler_plural_plural = require('./plural.cjs');
|
|
3
3
|
|
|
4
|
+
exports.DEFAULT_PLURAL_VARIABLE = require_transpiler_plural_plural.DEFAULT_PLURAL_VARIABLE;
|
|
4
5
|
exports.plural = require_transpiler_plural_plural.plural;
|
|
@@ -2,6 +2,8 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
2
2
|
let _intlayer_types_nodeType = require("@intlayer/types/nodeType");
|
|
3
3
|
|
|
4
4
|
//#region src/transpiler/plural/plural.ts
|
|
5
|
+
/** Name of the value a plural selects on when no `variable` is declared. */
|
|
6
|
+
const DEFAULT_PLURAL_VARIABLE = "count";
|
|
5
7
|
/**
|
|
6
8
|
* Function intended to be used to build intlayer dictionaries.
|
|
7
9
|
*
|
|
@@ -24,9 +26,26 @@ let _intlayer_types_nodeType = require("@intlayer/types/nodeType");
|
|
|
24
26
|
* other: '{{count}} вакансий',
|
|
25
27
|
* });
|
|
26
28
|
* ```
|
|
29
|
+
*
|
|
30
|
+
* Nest plurals declaring a `variable` to select on several quantities:
|
|
31
|
+
*
|
|
32
|
+
* ```ts
|
|
33
|
+
* plural(
|
|
34
|
+
* {
|
|
35
|
+
* one: plural(
|
|
36
|
+
* { one: '{{files}} file in {{folders}} folder', other: '…' },
|
|
37
|
+
* { variable: 'folders' }
|
|
38
|
+
* ),
|
|
39
|
+
* other: plural({ … }, { variable: 'folders' }),
|
|
40
|
+
* },
|
|
41
|
+
* { variable: 'files' }
|
|
42
|
+
* );
|
|
43
|
+
* // content.filesInFolders({ files: 1, folders: 2 })
|
|
44
|
+
* ```
|
|
27
45
|
*/
|
|
28
|
-
const plural = (content) => (0, _intlayer_types_nodeType.formatNodeType)(_intlayer_types_nodeType.PLURAL, content);
|
|
46
|
+
const plural = (content, options) => (0, _intlayer_types_nodeType.formatNodeType)(_intlayer_types_nodeType.PLURAL, content, options?.variable ? { variable: options.variable } : void 0);
|
|
29
47
|
|
|
30
48
|
//#endregion
|
|
49
|
+
exports.DEFAULT_PLURAL_VARIABLE = DEFAULT_PLURAL_VARIABLE;
|
|
31
50
|
exports.plural = plural;
|
|
32
51
|
//# sourceMappingURL=plural.cjs.map
|