@budiauktioner/buildi-primitives 0.2.0 → 0.2.1

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 (91) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/PARITY.md +1 -1
  3. package/dist/cjs/internal/scan-boundaries.js +26 -0
  4. package/dist/cjs/internal/scan-boundaries.js.map +7 -0
  5. package/dist/cjs/measurement/area.js +2 -1
  6. package/dist/cjs/measurement/area.js.map +2 -2
  7. package/dist/cjs/measurement/data-size.js +1 -1
  8. package/dist/cjs/measurement/data-size.js.map +1 -1
  9. package/dist/cjs/measurement/electric-charge.js +1 -1
  10. package/dist/cjs/measurement/electric-charge.js.map +1 -1
  11. package/dist/cjs/measurement/electric-current.js +1 -1
  12. package/dist/cjs/measurement/electric-current.js.map +1 -1
  13. package/dist/cjs/measurement/energy.js +1 -1
  14. package/dist/cjs/measurement/energy.js.map +1 -1
  15. package/dist/cjs/measurement/flow-rate.js +1 -1
  16. package/dist/cjs/measurement/flow-rate.js.map +1 -1
  17. package/dist/cjs/measurement/frequency.js +1 -1
  18. package/dist/cjs/measurement/frequency.js.map +1 -1
  19. package/dist/cjs/measurement/length.js +1 -1
  20. package/dist/cjs/measurement/length.js.map +1 -1
  21. package/dist/cjs/measurement/luminance.js +1 -1
  22. package/dist/cjs/measurement/luminance.js.map +1 -1
  23. package/dist/cjs/measurement/luminous-flux.js +4 -1
  24. package/dist/cjs/measurement/luminous-flux.js.map +2 -2
  25. package/dist/cjs/measurement/percentage.js +1 -1
  26. package/dist/cjs/measurement/percentage.js.map +1 -1
  27. package/dist/cjs/measurement/power.js +7 -3
  28. package/dist/cjs/measurement/power.js.map +2 -2
  29. package/dist/cjs/measurement/pressure.js +1 -1
  30. package/dist/cjs/measurement/pressure.js.map +1 -1
  31. package/dist/cjs/measurement/rotational-speed.js +1 -1
  32. package/dist/cjs/measurement/rotational-speed.js.map +1 -1
  33. package/dist/cjs/measurement/sound-level.js +5 -1
  34. package/dist/cjs/measurement/sound-level.js.map +2 -2
  35. package/dist/cjs/measurement/speed.js +1 -1
  36. package/dist/cjs/measurement/speed.js.map +1 -1
  37. package/dist/cjs/measurement/temperature.js +1 -1
  38. package/dist/cjs/measurement/temperature.js.map +2 -2
  39. package/dist/cjs/measurement/torque.js +1 -1
  40. package/dist/cjs/measurement/torque.js.map +1 -1
  41. package/dist/cjs/measurement/voltage.js +1 -1
  42. package/dist/cjs/measurement/voltage.js.map +1 -1
  43. package/dist/cjs/measurement/volume.js +1 -1
  44. package/dist/cjs/measurement/volume.js.map +1 -1
  45. package/dist/cjs/measurement/weight.js +1 -1
  46. package/dist/cjs/measurement/weight.js.map +1 -1
  47. package/dist/esm/internal/scan-boundaries.js +6 -0
  48. package/dist/esm/internal/scan-boundaries.js.map +7 -0
  49. package/dist/esm/measurement/area.js +2 -1
  50. package/dist/esm/measurement/area.js.map +2 -2
  51. package/dist/esm/measurement/data-size.js +1 -1
  52. package/dist/esm/measurement/data-size.js.map +1 -1
  53. package/dist/esm/measurement/electric-charge.js +1 -1
  54. package/dist/esm/measurement/electric-charge.js.map +1 -1
  55. package/dist/esm/measurement/electric-current.js +1 -1
  56. package/dist/esm/measurement/electric-current.js.map +1 -1
  57. package/dist/esm/measurement/energy.js +1 -1
  58. package/dist/esm/measurement/energy.js.map +1 -1
  59. package/dist/esm/measurement/flow-rate.js +1 -1
  60. package/dist/esm/measurement/flow-rate.js.map +1 -1
  61. package/dist/esm/measurement/frequency.js +1 -1
  62. package/dist/esm/measurement/frequency.js.map +1 -1
  63. package/dist/esm/measurement/length.js +1 -1
  64. package/dist/esm/measurement/length.js.map +1 -1
  65. package/dist/esm/measurement/luminance.js +1 -1
  66. package/dist/esm/measurement/luminance.js.map +1 -1
  67. package/dist/esm/measurement/luminous-flux.js +4 -1
  68. package/dist/esm/measurement/luminous-flux.js.map +2 -2
  69. package/dist/esm/measurement/percentage.js +1 -1
  70. package/dist/esm/measurement/percentage.js.map +1 -1
  71. package/dist/esm/measurement/power.js +7 -3
  72. package/dist/esm/measurement/power.js.map +2 -2
  73. package/dist/esm/measurement/pressure.js +1 -1
  74. package/dist/esm/measurement/pressure.js.map +1 -1
  75. package/dist/esm/measurement/rotational-speed.js +1 -1
  76. package/dist/esm/measurement/rotational-speed.js.map +1 -1
  77. package/dist/esm/measurement/sound-level.js +5 -1
  78. package/dist/esm/measurement/sound-level.js.map +2 -2
  79. package/dist/esm/measurement/speed.js +1 -1
  80. package/dist/esm/measurement/speed.js.map +1 -1
  81. package/dist/esm/measurement/temperature.js +1 -1
  82. package/dist/esm/measurement/temperature.js.map +2 -2
  83. package/dist/esm/measurement/torque.js +1 -1
  84. package/dist/esm/measurement/torque.js.map +1 -1
  85. package/dist/esm/measurement/voltage.js +1 -1
  86. package/dist/esm/measurement/voltage.js.map +1 -1
  87. package/dist/esm/measurement/volume.js +1 -1
  88. package/dist/esm/measurement/volume.js.map +1 -1
  89. package/dist/esm/measurement/weight.js +1 -1
  90. package/dist/esm/measurement/weight.js.map +1 -1
  91. package/package.json +1 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/measurement/temperature.ts"],
4
- "sourcesContent": ["import { Decimal } from \"../internal/decimal.js\";\nimport { trySplitMeasurement } from \"../internal/measurement-unit-parser.js\";\nimport { formatQuantityDecimal } from \"../internal/quantity.js\";\nimport type { PrimitiveTypeInfo } from \"../primitive-type-info.js\";\nimport { TextCandidate } from \"../text-scanning/text-candidate.js\";\nimport { TextCandidateCategory } from \"../text-scanning/text-candidate-category.js\";\nimport { TextMatchConfidence } from \"../text-scanning/text-match-confidence.js\";\nimport { TemperatureDelta } from \"./temperature-delta.js\";\nimport { TemperatureUnit } from \"./temperature-unit.js\";\n\n/** Options for {@link Temperature.format} and {@link Temperature.normalize}. */\nexport interface TemperatureFormatOptions {\n fallbackToTrimmedInputWhenInvalid?: boolean;\n /** Convert to this scale instead of preserving the parsed one. */\n unit?: TemperatureUnit;\n /** Round to this many fractional digits, away from zero. */\n decimals?: number;\n}\n\nconst CELSIUS_OFFSET = Decimal.parse(\"273.15\")!;\nconst NINE = Decimal.parse(\"9\")!;\nconst FIVE = Decimal.parse(\"5\")!;\nconst THIRTY_TWO = Decimal.parse(\"32\")!;\n\nconst SCAN_PATTERN = /(?<!\\w)(?:[+-]\\s*)?\\d+[0-9 .,]*\\s*(?:\u00B0[CF]|[CFK])\\b/giu;\n\n/**\n * An absolute temperature stored internally in kelvin, parsed from Celsius,\n * Fahrenheit or kelvin.\n *\n * This is the one dimension that cannot share the machinery the other\n * measurement types use: its scales differ by an offset as well as a factor, so\n * conversion is affine rather than a single multiplication.\n *\n * Sources:\n * - https://www.bipm.org/en/measurement-units/si-base-units \u2014 kelvin definition\n * - https://en.wikipedia.org/wiki/Conversion_of_units\n */\nexport class Temperature {\n static readonly typeInfo: PrimitiveTypeInfo = Object.freeze({\n englishName: \"Temperature\",\n localizedName: \"Temperatur\",\n emoji: \"\uD83C\uDF21\uFE0F\",\n sources: Object.freeze([\n \"https://www.bipm.org/en/measurement-units/si-base-units\",\n \"https://en.wikipedia.org/wiki/Conversion_of_units\",\n ]),\n });\n\n private constructor(\n private readonly kelvinValue: Decimal,\n /** The scale the value was originally parsed or created from. */\n readonly originalUnit: TemperatureUnit,\n ) {}\n\n /** The value in degrees Celsius, so `0` at the ice point. */\n get celsius(): number {\n return this.inDecimal(TemperatureUnit.Celsius).toNumber();\n }\n\n /** The value in degrees Fahrenheit, so `32` at 0 \u00B0C. */\n get fahrenheit(): number {\n return this.inDecimal(TemperatureUnit.Fahrenheit).toNumber();\n }\n\n /** The value in kelvin. */\n get kelvin(): number {\n return this.kelvinValue.toNumber();\n }\n\n /** The exact value converted to `unit`. */\n inDecimal(unit: TemperatureUnit): Decimal {\n TemperatureUnit.assertOwns(unit);\n if (unit === TemperatureUnit.Kelvin) return this.kelvinValue;\n\n const celsius = this.kelvinValue.minus(CELSIUS_OFFSET);\n if (unit === TemperatureUnit.Celsius) return celsius;\n if (unit === TemperatureUnit.Fahrenheit) {\n return celsius.times(NINE).dividedBy(FIVE).plus(THIRTY_TWO);\n }\n\n /* c8 ignore next */\n throw new RangeError(\"Unit belongs to another dimension.\");\n }\n\n /** The value converted to `unit`, as a `number` for ergonomic access. */\n in(unit: TemperatureUnit): number {\n return this.inDecimal(unit).toNumber();\n }\n\n static fromCelsius(value: number | Decimal): Temperature {\n return new Temperature(toDecimal(value).plus(CELSIUS_OFFSET), TemperatureUnit.Celsius);\n }\n\n static fromFahrenheit(value: number | Decimal): Temperature {\n const celsius = toDecimal(value).minus(THIRTY_TWO).times(FIVE).dividedBy(NINE);\n return new Temperature(celsius.plus(CELSIUS_OFFSET), TemperatureUnit.Fahrenheit);\n }\n\n static fromKelvin(value: number | Decimal): Temperature {\n return new Temperature(toDecimal(value), TemperatureUnit.Kelvin);\n }\n\n /** Creates a temperature from a value on the given scale. */\n static create(value: number | Decimal, unit: TemperatureUnit): Temperature {\n TemperatureUnit.assertOwns(unit);\n if (unit === TemperatureUnit.Celsius) return Temperature.fromCelsius(value);\n if (unit === TemperatureUnit.Fahrenheit) return Temperature.fromFahrenheit(value);\n if (unit === TemperatureUnit.Kelvin) return Temperature.fromKelvin(value);\n /* c8 ignore next */\n throw new RangeError(\"Unit belongs to another dimension.\");\n }\n\n static tryParse(input: string | null | undefined): Temperature | null {\n const split = trySplitMeasurement(input);\n if (split === null) return null;\n\n const unit = TemperatureUnit.tryParse(split.unitSuffix);\n if (unit === null) return null;\n\n try {\n return Temperature.create(split.value, unit);\n } catch {\n return null;\n }\n }\n\n static parse(input: string): Temperature {\n const result = Temperature.tryParse(input);\n if (result === null) throw new Error(\"Invalid temperature.\");\n return result;\n }\n\n static isValid(input: string | null | undefined): boolean {\n return Temperature.tryParse(input) !== null;\n }\n\n /** Display form on the parsed scale, or `null` when the input is invalid. */\n static format(\n input: string | null | undefined,\n options?: TemperatureFormatOptions,\n ): string | null {\n const parsed = Temperature.tryParse(input);\n if (parsed !== null) {\n if (options?.unit !== undefined || options?.decimals !== undefined) {\n return parsed.toStringInUnit(options.unit ?? parsed.originalUnit, options.decimals);\n }\n return parsed.toString();\n }\n return Temperature.fallback(input, options);\n }\n\n /** The value in kelvin, or `null` when the input is invalid. */\n static normalize(\n input: string | null | undefined,\n options?: TemperatureFormatOptions,\n ): string | null {\n const parsed = Temperature.tryParse(input);\n if (parsed !== null) return parsed.toNormalizedString();\n return Temperature.fallback(input, options);\n }\n\n static isNormalized(input: string | null | undefined): boolean {\n return input != null && Temperature.normalize(input) === input;\n }\n\n /** The value in kelvin, e.g. `293.15 K`. */\n toNormalizedString(): string {\n return `${formatQuantityDecimal(this.kelvinValue)} ${TemperatureUnit.Kelvin.symbol}`;\n }\n\n /** The value on the scale it was parsed from, e.g. `20 \u00B0C`. */\n toString(): string {\n return this.toStringInUnit(this.originalUnit);\n }\n\n /** The value converted to `unit`, e.g. `68 \u00B0F`. */\n toStringInUnit(unit: TemperatureUnit, decimals?: number): string {\n return `${formatQuantityDecimal(this.inDecimal(unit), decimals)} ${unit.symbol}`;\n }\n\n /** Adds a temperature difference, keeping the original scale. */\n plus(delta: TemperatureDelta): Temperature {\n return new Temperature(this.kelvinValue.plus(delta.exactKelvin), this.originalUnit);\n }\n\n /** Subtracts a temperature difference, keeping the original scale. */\n minus(delta: TemperatureDelta): Temperature {\n return new Temperature(this.kelvinValue.minus(delta.exactKelvin), this.originalUnit);\n }\n\n /** The difference between two temperatures. */\n difference(other: Temperature): TemperatureDelta {\n return TemperatureDelta.fromKelvin(this.kelvinValue.minus(other.kelvinValue));\n }\n\n compareTo(other: Temperature | null | undefined): number {\n if (other == null) return 1;\n return this.kelvinValue.compareTo(other.kelvinValue);\n }\n\n equals(other: Temperature | null | undefined): boolean {\n return other != null && this.kelvinValue.equals(other.kelvinValue);\n }\n\n isLessThan(other: Temperature): boolean {\n return this.compareTo(other) < 0;\n }\n\n isGreaterThan(other: Temperature): boolean {\n return this.compareTo(other) > 0;\n }\n\n static findCandidatesInText(text: string): readonly TextCandidate<Temperature>[] {\n if (!text) return [];\n\n const out: TextCandidate<Temperature>[] = [];\n const pattern = new RegExp(SCAN_PATTERN.source, SCAN_PATTERN.flags);\n let match: RegExpExecArray | null;\n\n while ((match = pattern.exec(text)) !== null) {\n const value = Temperature.tryParse(match[0]);\n if (value === null) continue;\n out.push(\n new TextCandidate<Temperature>({\n startIndex: match.index,\n length: match[0].length,\n originalText: match[0],\n typeName: \"Temperature\",\n category: TextCandidateCategory.Measurement,\n normalizedForm: value.toNormalizedString(),\n formattedForm: value.toString(),\n maskedForm: maskTemperature(value),\n confidence: TextMatchConfidence.Medium,\n value,\n }),\n );\n }\n\n return out;\n }\n\n private static fallback(\n input: string | null | undefined,\n options?: TemperatureFormatOptions,\n ): string | null {\n if (options?.fallbackToTrimmedInputWhenInvalid !== true) return null;\n if (input == null) return null;\n const trimmed = input.trim();\n return trimmed.length > 0 ? trimmed : null;\n }\n}\n\nfunction toDecimal(value: number | Decimal): Decimal {\n if (value instanceof Decimal) return value;\n const parsed = Decimal.fromNumber(value);\n if (parsed === null) throw new Error(`Value cannot be represented as a temperature: ${value}`);\n return parsed;\n}\n\n/** Returns a masked temperature, e.g. `20 \u00B0C` becomes `*** \u00B0C`. */\nexport function maskTemperature(value: Temperature): string {\n return `*** ${value.originalUnit.symbol}`;\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { Decimal } from \"../internal/decimal.js\";\nimport { trySplitMeasurement } from \"../internal/measurement-unit-parser.js\";\nimport { formatQuantityDecimal } from \"../internal/quantity.js\";\nimport type { PrimitiveTypeInfo } from \"../primitive-type-info.js\";\nimport { TextCandidate } from \"../text-scanning/text-candidate.js\";\nimport { TextCandidateCategory } from \"../text-scanning/text-candidate-category.js\";\nimport { TextMatchConfidence } from \"../text-scanning/text-match-confidence.js\";\nimport { TemperatureDelta } from \"./temperature-delta.js\";\nimport { TemperatureUnit } from \"./temperature-unit.js\";\n\n/** Options for {@link Temperature.format} and {@link Temperature.normalize}. */\nexport interface TemperatureFormatOptions {\n fallbackToTrimmedInputWhenInvalid?: boolean;\n /** Convert to this scale instead of preserving the parsed one. */\n unit?: TemperatureUnit;\n /** Round to this many fractional digits, away from zero. */\n decimals?: number;\n}\n\nconst CELSIUS_OFFSET = Decimal.parse(\"273.15\")!;\nconst NINE = Decimal.parse(\"9\")!;\nconst FIVE = Decimal.parse(\"5\")!;\nconst THIRTY_TWO = Decimal.parse(\"32\")!;\n\nconst SCAN_PATTERN =\n /(?<![\\p{L}\\p{N}_])(?:[+-]\\s*)?\\d+[0-9 .,]*\\s*(?:\u00B0[CF]|[CFK])(?![\\p{L}\\p{N}_])/giu;\n\n/**\n * An absolute temperature stored internally in kelvin, parsed from Celsius,\n * Fahrenheit or kelvin.\n *\n * This is the one dimension that cannot share the machinery the other\n * measurement types use: its scales differ by an offset as well as a factor, so\n * conversion is affine rather than a single multiplication.\n *\n * Sources:\n * - https://www.bipm.org/en/measurement-units/si-base-units \u2014 kelvin definition\n * - https://en.wikipedia.org/wiki/Conversion_of_units\n */\nexport class Temperature {\n static readonly typeInfo: PrimitiveTypeInfo = Object.freeze({\n englishName: \"Temperature\",\n localizedName: \"Temperatur\",\n emoji: \"\uD83C\uDF21\uFE0F\",\n sources: Object.freeze([\n \"https://www.bipm.org/en/measurement-units/si-base-units\",\n \"https://en.wikipedia.org/wiki/Conversion_of_units\",\n ]),\n });\n\n private constructor(\n private readonly kelvinValue: Decimal,\n /** The scale the value was originally parsed or created from. */\n readonly originalUnit: TemperatureUnit,\n ) {}\n\n /** The value in degrees Celsius, so `0` at the ice point. */\n get celsius(): number {\n return this.inDecimal(TemperatureUnit.Celsius).toNumber();\n }\n\n /** The value in degrees Fahrenheit, so `32` at 0 \u00B0C. */\n get fahrenheit(): number {\n return this.inDecimal(TemperatureUnit.Fahrenheit).toNumber();\n }\n\n /** The value in kelvin. */\n get kelvin(): number {\n return this.kelvinValue.toNumber();\n }\n\n /** The exact value converted to `unit`. */\n inDecimal(unit: TemperatureUnit): Decimal {\n TemperatureUnit.assertOwns(unit);\n if (unit === TemperatureUnit.Kelvin) return this.kelvinValue;\n\n const celsius = this.kelvinValue.minus(CELSIUS_OFFSET);\n if (unit === TemperatureUnit.Celsius) return celsius;\n if (unit === TemperatureUnit.Fahrenheit) {\n return celsius.times(NINE).dividedBy(FIVE).plus(THIRTY_TWO);\n }\n\n /* c8 ignore next */\n throw new RangeError(\"Unit belongs to another dimension.\");\n }\n\n /** The value converted to `unit`, as a `number` for ergonomic access. */\n in(unit: TemperatureUnit): number {\n return this.inDecimal(unit).toNumber();\n }\n\n static fromCelsius(value: number | Decimal): Temperature {\n return new Temperature(toDecimal(value).plus(CELSIUS_OFFSET), TemperatureUnit.Celsius);\n }\n\n static fromFahrenheit(value: number | Decimal): Temperature {\n const celsius = toDecimal(value).minus(THIRTY_TWO).times(FIVE).dividedBy(NINE);\n return new Temperature(celsius.plus(CELSIUS_OFFSET), TemperatureUnit.Fahrenheit);\n }\n\n static fromKelvin(value: number | Decimal): Temperature {\n return new Temperature(toDecimal(value), TemperatureUnit.Kelvin);\n }\n\n /** Creates a temperature from a value on the given scale. */\n static create(value: number | Decimal, unit: TemperatureUnit): Temperature {\n TemperatureUnit.assertOwns(unit);\n if (unit === TemperatureUnit.Celsius) return Temperature.fromCelsius(value);\n if (unit === TemperatureUnit.Fahrenheit) return Temperature.fromFahrenheit(value);\n if (unit === TemperatureUnit.Kelvin) return Temperature.fromKelvin(value);\n /* c8 ignore next */\n throw new RangeError(\"Unit belongs to another dimension.\");\n }\n\n static tryParse(input: string | null | undefined): Temperature | null {\n const split = trySplitMeasurement(input);\n if (split === null) return null;\n\n const unit = TemperatureUnit.tryParse(split.unitSuffix);\n if (unit === null) return null;\n\n try {\n return Temperature.create(split.value, unit);\n } catch {\n return null;\n }\n }\n\n static parse(input: string): Temperature {\n const result = Temperature.tryParse(input);\n if (result === null) throw new Error(\"Invalid temperature.\");\n return result;\n }\n\n static isValid(input: string | null | undefined): boolean {\n return Temperature.tryParse(input) !== null;\n }\n\n /** Display form on the parsed scale, or `null` when the input is invalid. */\n static format(\n input: string | null | undefined,\n options?: TemperatureFormatOptions,\n ): string | null {\n const parsed = Temperature.tryParse(input);\n if (parsed !== null) {\n if (options?.unit !== undefined || options?.decimals !== undefined) {\n return parsed.toStringInUnit(options.unit ?? parsed.originalUnit, options.decimals);\n }\n return parsed.toString();\n }\n return Temperature.fallback(input, options);\n }\n\n /** The value in kelvin, or `null` when the input is invalid. */\n static normalize(\n input: string | null | undefined,\n options?: TemperatureFormatOptions,\n ): string | null {\n const parsed = Temperature.tryParse(input);\n if (parsed !== null) return parsed.toNormalizedString();\n return Temperature.fallback(input, options);\n }\n\n static isNormalized(input: string | null | undefined): boolean {\n return input != null && Temperature.normalize(input) === input;\n }\n\n /** The value in kelvin, e.g. `293.15 K`. */\n toNormalizedString(): string {\n return `${formatQuantityDecimal(this.kelvinValue)} ${TemperatureUnit.Kelvin.symbol}`;\n }\n\n /** The value on the scale it was parsed from, e.g. `20 \u00B0C`. */\n toString(): string {\n return this.toStringInUnit(this.originalUnit);\n }\n\n /** The value converted to `unit`, e.g. `68 \u00B0F`. */\n toStringInUnit(unit: TemperatureUnit, decimals?: number): string {\n return `${formatQuantityDecimal(this.inDecimal(unit), decimals)} ${unit.symbol}`;\n }\n\n /** Adds a temperature difference, keeping the original scale. */\n plus(delta: TemperatureDelta): Temperature {\n return new Temperature(this.kelvinValue.plus(delta.exactKelvin), this.originalUnit);\n }\n\n /** Subtracts a temperature difference, keeping the original scale. */\n minus(delta: TemperatureDelta): Temperature {\n return new Temperature(this.kelvinValue.minus(delta.exactKelvin), this.originalUnit);\n }\n\n /** The difference between two temperatures. */\n difference(other: Temperature): TemperatureDelta {\n return TemperatureDelta.fromKelvin(this.kelvinValue.minus(other.kelvinValue));\n }\n\n compareTo(other: Temperature | null | undefined): number {\n if (other == null) return 1;\n return this.kelvinValue.compareTo(other.kelvinValue);\n }\n\n equals(other: Temperature | null | undefined): boolean {\n return other != null && this.kelvinValue.equals(other.kelvinValue);\n }\n\n isLessThan(other: Temperature): boolean {\n return this.compareTo(other) < 0;\n }\n\n isGreaterThan(other: Temperature): boolean {\n return this.compareTo(other) > 0;\n }\n\n static findCandidatesInText(text: string): readonly TextCandidate<Temperature>[] {\n if (!text) return [];\n\n const out: TextCandidate<Temperature>[] = [];\n const pattern = new RegExp(SCAN_PATTERN.source, SCAN_PATTERN.flags);\n let match: RegExpExecArray | null;\n\n while ((match = pattern.exec(text)) !== null) {\n const value = Temperature.tryParse(match[0]);\n if (value === null) continue;\n out.push(\n new TextCandidate<Temperature>({\n startIndex: match.index,\n length: match[0].length,\n originalText: match[0],\n typeName: \"Temperature\",\n category: TextCandidateCategory.Measurement,\n normalizedForm: value.toNormalizedString(),\n formattedForm: value.toString(),\n maskedForm: maskTemperature(value),\n confidence: TextMatchConfidence.Medium,\n value,\n }),\n );\n }\n\n return out;\n }\n\n private static fallback(\n input: string | null | undefined,\n options?: TemperatureFormatOptions,\n ): string | null {\n if (options?.fallbackToTrimmedInputWhenInvalid !== true) return null;\n if (input == null) return null;\n const trimmed = input.trim();\n return trimmed.length > 0 ? trimmed : null;\n }\n}\n\nfunction toDecimal(value: number | Decimal): Decimal {\n if (value instanceof Decimal) return value;\n const parsed = Decimal.fromNumber(value);\n if (parsed === null) throw new Error(`Value cannot be represented as a temperature: ${value}`);\n return parsed;\n}\n\n/** Returns a masked temperature, e.g. `20 \u00B0C` becomes `*** \u00B0C`. */\nexport function maskTemperature(value: Temperature): string {\n return `*** ${value.originalUnit.symbol}`;\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -29,7 +29,7 @@ var import_text_candidate_category = require("../text-scanning/text-candidate-ca
29
29
  var import_text_match_confidence = require("../text-scanning/text-match-confidence.js");
30
30
  var import_torque_unit = require("./torque-unit.js");
31
31
  const SCAN_PATTERN = new RegExp(
32
- String.raw`(?<!\w)(?:[+-]\s*)?\d+[0-9 .,]*\s*(?:foot-pounds|foot-pound|inch-pounds|inch-pound|kilogramkraftmeter|kilonewton[\s-]?meters?|millinewton[\s-]?meters?|newtonmeter|fotpund|tumpund|kgf-m|kgf·m|kgfm|ft-lb|ft·lb|in-lb|in·lb|kN·m|kNm|mN·m|mNm|N·m|Nm)\b`,
32
+ String.raw`(?<![\p{L}\p{N}_])(?:[+-]\s*)?\d+[0-9 .,]*\s*(?:foot-pounds|foot-pound|inch-pounds|inch-pound|kilogramkraftmeter|kilonewton[\s-]?meters?|millinewton[\s-]?meters?|newtonmeter|fotpund|tumpund|kgf-m|kgf·m|kgfm|ft-lb|ft·lb|in-lb|in·lb|kN·m|kNm|mN·m|mNm|N·m|Nm)(?![\p{L}\p{N}_])`,
33
33
  "giu"
34
34
  );
35
35
  class Torque extends import_quantity.Quantity {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/measurement/torque.ts"],
4
- "sourcesContent": ["import { Decimal } from \"../internal/decimal.js\";\nimport type { MeasurementUnitIndex } from \"../internal/measurement-unit.js\";\nimport { Quantity, tryParseQuantity } from \"../internal/quantity.js\";\nimport type { PrimitiveTypeInfo } from \"../primitive-type-info.js\";\nimport { TextCandidate } from \"../text-scanning/text-candidate.js\";\nimport { TextCandidateCategory } from \"../text-scanning/text-candidate-category.js\";\nimport { TextMatchConfidence } from \"../text-scanning/text-match-confidence.js\";\nimport { TorqueUnit } from \"./torque-unit.js\";\n\n/** Options for {@link Torque.format} and {@link Torque.normalize}. */\nexport interface TorqueFormatOptions {\n fallbackToTrimmedInputWhenInvalid?: boolean;\n /** Convert to this unit instead of preserving the parsed one. */\n unit?: TorqueUnit;\n /** Round to this many fractional digits, away from zero. */\n decimals?: number;\n}\n\nconst SCAN_PATTERN = new RegExp(\n String.raw`(?<!\\w)(?:[+-]\\s*)?\\d+[0-9 .,]*\\s*(?:foot-pounds|foot-pound|inch-pounds|inch-pound|kilogramkraftmeter|kilonewton[\\s-]?meters?|millinewton[\\s-]?meters?|newtonmeter|fotpund|tumpund|kgf-m|kgf\u00B7m|kgfm|ft-lb|ft\u00B7lb|in-lb|in\u00B7lb|kN\u00B7m|kNm|mN\u00B7m|mNm|N\u00B7m|Nm)\\b`,\n \"giu\",\n);\n\n/**\n * A torque stored internally in newton meters,\n * parsed from any supported unit and convertible between all of them.\n */\nexport class Torque extends Quantity<TorqueUnit> {\n static readonly typeInfo: PrimitiveTypeInfo = Object.freeze({\n englishName: \"Torque\",\n localizedName: \"Vridmoment\",\n emoji: \"\uD83D\uDD27\",\n sources: Object.freeze([\n \"https://www.bipm.org/en/measurement-units/si-derived-units\",\n \"https://en.wikipedia.org/wiki/Conversion_of_units\",\n ]),\n });\n\n protected get units(): MeasurementUnitIndex<TorqueUnit> {\n return TorqueUnit.index;\n }\n\n protected withBaseValue(baseValue: Decimal, unit: TorqueUnit): this {\n return new Torque(baseValue, unit) as this;\n }\n\n get millinewtonMeters(): number {\n return this.in(TorqueUnit.MillinewtonMeter);\n }\n get newtonMeters(): number {\n return this.in(TorqueUnit.NewtonMeter);\n }\n get kilonewtonMeters(): number {\n return this.in(TorqueUnit.KilonewtonMeter);\n }\n get footPounds(): number {\n return this.in(TorqueUnit.FootPound);\n }\n get kilogramForceMeters(): number {\n return this.in(TorqueUnit.KilogramForceMeter);\n }\n get inchPounds(): number {\n return this.in(TorqueUnit.InchPound);\n }\n\n /** Creates a torque from a value and unit. */\n static create(value: number | Decimal, unit: TorqueUnit): Torque {\n TorqueUnit.index.assertOwns(unit);\n const amount = value instanceof Decimal ? value : Torque.decimalOf(value);\n return new Torque(unit.toBase(amount), unit);\n }\n\n static fromMillinewtonMeters(value: number | Decimal): Torque {\n return Torque.create(value, TorqueUnit.MillinewtonMeter);\n }\n static fromNewtonMeters(value: number | Decimal): Torque {\n return Torque.create(value, TorqueUnit.NewtonMeter);\n }\n static fromKilonewtonMeters(value: number | Decimal): Torque {\n return Torque.create(value, TorqueUnit.KilonewtonMeter);\n }\n static fromFootPounds(value: number | Decimal): Torque {\n return Torque.create(value, TorqueUnit.FootPound);\n }\n static fromKilogramForceMeters(value: number | Decimal): Torque {\n return Torque.create(value, TorqueUnit.KilogramForceMeter);\n }\n static fromInchPounds(value: number | Decimal): Torque {\n return Torque.create(value, TorqueUnit.InchPound);\n }\n\n static tryParse(input: string | null | undefined): Torque | null {\n const parsed = tryParseQuantity(input, TorqueUnit.index);\n return parsed === null ? null : new Torque(parsed.baseValue, parsed.unit);\n }\n\n static parse(input: string): Torque {\n const result = Torque.tryParse(input);\n if (result === null) throw new Error(\"Invalid torque.\");\n return result;\n }\n\n static isValid(input: string | null | undefined): boolean {\n return Torque.tryParse(input) !== null;\n }\n\n /** Display form in the parsed unit, or `null` when the input is invalid. */\n static format(input: string | null | undefined, options?: TorqueFormatOptions): string | null {\n const parsed = Torque.tryParse(input);\n if (parsed !== null) {\n if (options?.unit !== undefined || options?.decimals !== undefined) {\n return parsed.toStringInUnit(options.unit ?? parsed.originalUnit, options.decimals);\n }\n return parsed.toString();\n }\n return Torque.fallback(input, options);\n }\n\n /** The value in newton meters, or `null` when the input is invalid. */\n static normalize(input: string | null | undefined, options?: TorqueFormatOptions): string | null {\n const parsed = Torque.tryParse(input);\n if (parsed !== null) return parsed.toNormalizedString();\n return Torque.fallback(input, options);\n }\n\n static isNormalized(input: string | null | undefined): boolean {\n return input != null && Torque.normalize(input) === input;\n }\n\n static findCandidatesInText(text: string): readonly TextCandidate<Torque>[] {\n if (!text) return [];\n\n const out: TextCandidate<Torque>[] = [];\n const pattern = new RegExp(SCAN_PATTERN.source, SCAN_PATTERN.flags);\n let match: RegExpExecArray | null;\n\n while ((match = pattern.exec(text)) !== null) {\n const value = Torque.tryParse(match[0]);\n if (value === null) continue;\n out.push(\n new TextCandidate<Torque>({\n startIndex: match.index,\n length: match[0].length,\n originalText: match[0],\n typeName: \"Torque\",\n category: TextCandidateCategory.Measurement,\n normalizedForm: value.toNormalizedString(),\n formattedForm: value.toString(),\n maskedForm: maskTorque(value),\n confidence: TextMatchConfidence.Medium,\n value,\n }),\n );\n }\n\n return out;\n }\n\n private static fallback(\n input: string | null | undefined,\n options?: TorqueFormatOptions,\n ): string | null {\n if (options?.fallbackToTrimmedInputWhenInvalid !== true) return null;\n if (input == null) return null;\n const trimmed = input.trim();\n return trimmed.length > 0 ? trimmed : null;\n }\n\n private static decimalOf(value: number): Decimal {\n const parsed = Decimal.fromNumber(value);\n if (parsed === null) throw new Error(`Value cannot be represented as a torque: ${value}`);\n return parsed;\n }\n}\n\n/** Returns a masked torque, e.g. `10 Nm` becomes `*** Nm`. */\nexport function maskTorque(value: Torque): string {\n return `*** ${value.originalUnit.symbol}`;\n}\n"],
4
+ "sourcesContent": ["import { Decimal } from \"../internal/decimal.js\";\nimport type { MeasurementUnitIndex } from \"../internal/measurement-unit.js\";\nimport { Quantity, tryParseQuantity } from \"../internal/quantity.js\";\nimport type { PrimitiveTypeInfo } from \"../primitive-type-info.js\";\nimport { TextCandidate } from \"../text-scanning/text-candidate.js\";\nimport { TextCandidateCategory } from \"../text-scanning/text-candidate-category.js\";\nimport { TextMatchConfidence } from \"../text-scanning/text-match-confidence.js\";\nimport { TorqueUnit } from \"./torque-unit.js\";\n\n/** Options for {@link Torque.format} and {@link Torque.normalize}. */\nexport interface TorqueFormatOptions {\n fallbackToTrimmedInputWhenInvalid?: boolean;\n /** Convert to this unit instead of preserving the parsed one. */\n unit?: TorqueUnit;\n /** Round to this many fractional digits, away from zero. */\n decimals?: number;\n}\n\nconst SCAN_PATTERN = new RegExp(\n String.raw`(?<![\\p{L}\\p{N}_])(?:[+-]\\s*)?\\d+[0-9 .,]*\\s*(?:foot-pounds|foot-pound|inch-pounds|inch-pound|kilogramkraftmeter|kilonewton[\\s-]?meters?|millinewton[\\s-]?meters?|newtonmeter|fotpund|tumpund|kgf-m|kgf\u00B7m|kgfm|ft-lb|ft\u00B7lb|in-lb|in\u00B7lb|kN\u00B7m|kNm|mN\u00B7m|mNm|N\u00B7m|Nm)(?![\\p{L}\\p{N}_])`,\n \"giu\",\n);\n\n/**\n * A torque stored internally in newton meters,\n * parsed from any supported unit and convertible between all of them.\n */\nexport class Torque extends Quantity<TorqueUnit> {\n static readonly typeInfo: PrimitiveTypeInfo = Object.freeze({\n englishName: \"Torque\",\n localizedName: \"Vridmoment\",\n emoji: \"\uD83D\uDD27\",\n sources: Object.freeze([\n \"https://www.bipm.org/en/measurement-units/si-derived-units\",\n \"https://en.wikipedia.org/wiki/Conversion_of_units\",\n ]),\n });\n\n protected get units(): MeasurementUnitIndex<TorqueUnit> {\n return TorqueUnit.index;\n }\n\n protected withBaseValue(baseValue: Decimal, unit: TorqueUnit): this {\n return new Torque(baseValue, unit) as this;\n }\n\n get millinewtonMeters(): number {\n return this.in(TorqueUnit.MillinewtonMeter);\n }\n get newtonMeters(): number {\n return this.in(TorqueUnit.NewtonMeter);\n }\n get kilonewtonMeters(): number {\n return this.in(TorqueUnit.KilonewtonMeter);\n }\n get footPounds(): number {\n return this.in(TorqueUnit.FootPound);\n }\n get kilogramForceMeters(): number {\n return this.in(TorqueUnit.KilogramForceMeter);\n }\n get inchPounds(): number {\n return this.in(TorqueUnit.InchPound);\n }\n\n /** Creates a torque from a value and unit. */\n static create(value: number | Decimal, unit: TorqueUnit): Torque {\n TorqueUnit.index.assertOwns(unit);\n const amount = value instanceof Decimal ? value : Torque.decimalOf(value);\n return new Torque(unit.toBase(amount), unit);\n }\n\n static fromMillinewtonMeters(value: number | Decimal): Torque {\n return Torque.create(value, TorqueUnit.MillinewtonMeter);\n }\n static fromNewtonMeters(value: number | Decimal): Torque {\n return Torque.create(value, TorqueUnit.NewtonMeter);\n }\n static fromKilonewtonMeters(value: number | Decimal): Torque {\n return Torque.create(value, TorqueUnit.KilonewtonMeter);\n }\n static fromFootPounds(value: number | Decimal): Torque {\n return Torque.create(value, TorqueUnit.FootPound);\n }\n static fromKilogramForceMeters(value: number | Decimal): Torque {\n return Torque.create(value, TorqueUnit.KilogramForceMeter);\n }\n static fromInchPounds(value: number | Decimal): Torque {\n return Torque.create(value, TorqueUnit.InchPound);\n }\n\n static tryParse(input: string | null | undefined): Torque | null {\n const parsed = tryParseQuantity(input, TorqueUnit.index);\n return parsed === null ? null : new Torque(parsed.baseValue, parsed.unit);\n }\n\n static parse(input: string): Torque {\n const result = Torque.tryParse(input);\n if (result === null) throw new Error(\"Invalid torque.\");\n return result;\n }\n\n static isValid(input: string | null | undefined): boolean {\n return Torque.tryParse(input) !== null;\n }\n\n /** Display form in the parsed unit, or `null` when the input is invalid. */\n static format(input: string | null | undefined, options?: TorqueFormatOptions): string | null {\n const parsed = Torque.tryParse(input);\n if (parsed !== null) {\n if (options?.unit !== undefined || options?.decimals !== undefined) {\n return parsed.toStringInUnit(options.unit ?? parsed.originalUnit, options.decimals);\n }\n return parsed.toString();\n }\n return Torque.fallback(input, options);\n }\n\n /** The value in newton meters, or `null` when the input is invalid. */\n static normalize(input: string | null | undefined, options?: TorqueFormatOptions): string | null {\n const parsed = Torque.tryParse(input);\n if (parsed !== null) return parsed.toNormalizedString();\n return Torque.fallback(input, options);\n }\n\n static isNormalized(input: string | null | undefined): boolean {\n return input != null && Torque.normalize(input) === input;\n }\n\n static findCandidatesInText(text: string): readonly TextCandidate<Torque>[] {\n if (!text) return [];\n\n const out: TextCandidate<Torque>[] = [];\n const pattern = new RegExp(SCAN_PATTERN.source, SCAN_PATTERN.flags);\n let match: RegExpExecArray | null;\n\n while ((match = pattern.exec(text)) !== null) {\n const value = Torque.tryParse(match[0]);\n if (value === null) continue;\n out.push(\n new TextCandidate<Torque>({\n startIndex: match.index,\n length: match[0].length,\n originalText: match[0],\n typeName: \"Torque\",\n category: TextCandidateCategory.Measurement,\n normalizedForm: value.toNormalizedString(),\n formattedForm: value.toString(),\n maskedForm: maskTorque(value),\n confidence: TextMatchConfidence.Medium,\n value,\n }),\n );\n }\n\n return out;\n }\n\n private static fallback(\n input: string | null | undefined,\n options?: TorqueFormatOptions,\n ): string | null {\n if (options?.fallbackToTrimmedInputWhenInvalid !== true) return null;\n if (input == null) return null;\n const trimmed = input.trim();\n return trimmed.length > 0 ? trimmed : null;\n }\n\n private static decimalOf(value: number): Decimal {\n const parsed = Decimal.fromNumber(value);\n if (parsed === null) throw new Error(`Value cannot be represented as a torque: ${value}`);\n return parsed;\n }\n}\n\n/** Returns a masked torque, e.g. `10 Nm` becomes `*** Nm`. */\nexport function maskTorque(value: Torque): string {\n return `*** ${value.originalUnit.symbol}`;\n}\n"],
5
5
  "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAAwB;AAExB,sBAA2C;AAE3C,4BAA8B;AAC9B,qCAAsC;AACtC,mCAAoC;AACpC,yBAA2B;AAW3B,MAAM,eAAe,IAAI;AAAA,EACvB,OAAO;AAAA,EACP;AACF;AAMO,MAAM,eAAe,yBAAqB;AAAA,EAC/C,OAAgB,WAA8B,OAAO,OAAO;AAAA,IAC1D,aAAa;AAAA,IACb,eAAe;AAAA,IACf,OAAO;AAAA,IACP,SAAS,OAAO,OAAO;AAAA,MACrB;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AAAA,EAED,IAAc,QAA0C;AACtD,WAAO,8BAAW;AAAA,EACpB;AAAA,EAEU,cAAc,WAAoB,MAAwB;AAClE,WAAO,IAAI,OAAO,WAAW,IAAI;AAAA,EACnC;AAAA,EAEA,IAAI,oBAA4B;AAC9B,WAAO,KAAK,GAAG,8BAAW,gBAAgB;AAAA,EAC5C;AAAA,EACA,IAAI,eAAuB;AACzB,WAAO,KAAK,GAAG,8BAAW,WAAW;AAAA,EACvC;AAAA,EACA,IAAI,mBAA2B;AAC7B,WAAO,KAAK,GAAG,8BAAW,eAAe;AAAA,EAC3C;AAAA,EACA,IAAI,aAAqB;AACvB,WAAO,KAAK,GAAG,8BAAW,SAAS;AAAA,EACrC;AAAA,EACA,IAAI,sBAA8B;AAChC,WAAO,KAAK,GAAG,8BAAW,kBAAkB;AAAA,EAC9C;AAAA,EACA,IAAI,aAAqB;AACvB,WAAO,KAAK,GAAG,8BAAW,SAAS;AAAA,EACrC;AAAA;AAAA,EAGA,OAAO,OAAO,OAAyB,MAA0B;AAC/D,kCAAW,MAAM,WAAW,IAAI;AAChC,UAAM,SAAS,iBAAiB,yBAAU,QAAQ,OAAO,UAAU,KAAK;AACxE,WAAO,IAAI,OAAO,KAAK,OAAO,MAAM,GAAG,IAAI;AAAA,EAC7C;AAAA,EAEA,OAAO,sBAAsB,OAAiC;AAC5D,WAAO,OAAO,OAAO,OAAO,8BAAW,gBAAgB;AAAA,EACzD;AAAA,EACA,OAAO,iBAAiB,OAAiC;AACvD,WAAO,OAAO,OAAO,OAAO,8BAAW,WAAW;AAAA,EACpD;AAAA,EACA,OAAO,qBAAqB,OAAiC;AAC3D,WAAO,OAAO,OAAO,OAAO,8BAAW,eAAe;AAAA,EACxD;AAAA,EACA,OAAO,eAAe,OAAiC;AACrD,WAAO,OAAO,OAAO,OAAO,8BAAW,SAAS;AAAA,EAClD;AAAA,EACA,OAAO,wBAAwB,OAAiC;AAC9D,WAAO,OAAO,OAAO,OAAO,8BAAW,kBAAkB;AAAA,EAC3D;AAAA,EACA,OAAO,eAAe,OAAiC;AACrD,WAAO,OAAO,OAAO,OAAO,8BAAW,SAAS;AAAA,EAClD;AAAA,EAEA,OAAO,SAAS,OAAiD;AAC/D,UAAM,aAAS,kCAAiB,OAAO,8BAAW,KAAK;AACvD,WAAO,WAAW,OAAO,OAAO,IAAI,OAAO,OAAO,WAAW,OAAO,IAAI;AAAA,EAC1E;AAAA,EAEA,OAAO,MAAM,OAAuB;AAClC,UAAM,SAAS,OAAO,SAAS,KAAK;AACpC,QAAI,WAAW,KAAM,OAAM,IAAI,MAAM,iBAAiB;AACtD,WAAO;AAAA,EACT;AAAA,EAEA,OAAO,QAAQ,OAA2C;AACxD,WAAO,OAAO,SAAS,KAAK,MAAM;AAAA,EACpC;AAAA;AAAA,EAGA,OAAO,OAAO,OAAkC,SAA8C;AAC5F,UAAM,SAAS,OAAO,SAAS,KAAK;AACpC,QAAI,WAAW,MAAM;AACnB,UAAI,SAAS,SAAS,UAAa,SAAS,aAAa,QAAW;AAClE,eAAO,OAAO,eAAe,QAAQ,QAAQ,OAAO,cAAc,QAAQ,QAAQ;AAAA,MACpF;AACA,aAAO,OAAO,SAAS;AAAA,IACzB;AACA,WAAO,OAAO,SAAS,OAAO,OAAO;AAAA,EACvC;AAAA;AAAA,EAGA,OAAO,UAAU,OAAkC,SAA8C;AAC/F,UAAM,SAAS,OAAO,SAAS,KAAK;AACpC,QAAI,WAAW,KAAM,QAAO,OAAO,mBAAmB;AACtD,WAAO,OAAO,SAAS,OAAO,OAAO;AAAA,EACvC;AAAA,EAEA,OAAO,aAAa,OAA2C;AAC7D,WAAO,SAAS,QAAQ,OAAO,UAAU,KAAK,MAAM;AAAA,EACtD;AAAA,EAEA,OAAO,qBAAqB,MAAgD;AAC1E,QAAI,CAAC,KAAM,QAAO,CAAC;AAEnB,UAAM,MAA+B,CAAC;AACtC,UAAM,UAAU,IAAI,OAAO,aAAa,QAAQ,aAAa,KAAK;AAClE,QAAI;AAEJ,YAAQ,QAAQ,QAAQ,KAAK,IAAI,OAAO,MAAM;AAC5C,YAAM,QAAQ,OAAO,SAAS,MAAM,CAAC,CAAC;AACtC,UAAI,UAAU,KAAM;AACpB,UAAI;AAAA,QACF,IAAI,oCAAsB;AAAA,UACxB,YAAY,MAAM;AAAA,UAClB,QAAQ,MAAM,CAAC,EAAE;AAAA,UACjB,cAAc,MAAM,CAAC;AAAA,UACrB,UAAU;AAAA,UACV,UAAU,qDAAsB;AAAA,UAChC,gBAAgB,MAAM,mBAAmB;AAAA,UACzC,eAAe,MAAM,SAAS;AAAA,UAC9B,YAAY,WAAW,KAAK;AAAA,UAC5B,YAAY,iDAAoB;AAAA,UAChC;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,OAAe,SACb,OACA,SACe;AACf,QAAI,SAAS,sCAAsC,KAAM,QAAO;AAChE,QAAI,SAAS,KAAM,QAAO;AAC1B,UAAM,UAAU,MAAM,KAAK;AAC3B,WAAO,QAAQ,SAAS,IAAI,UAAU;AAAA,EACxC;AAAA,EAEA,OAAe,UAAU,OAAwB;AAC/C,UAAM,SAAS,uBAAQ,WAAW,KAAK;AACvC,QAAI,WAAW,KAAM,OAAM,IAAI,MAAM,4CAA4C,KAAK,EAAE;AACxF,WAAO;AAAA,EACT;AACF;AAGO,SAAS,WAAW,OAAuB;AAChD,SAAO,OAAO,MAAM,aAAa,MAAM;AACzC;",
6
6
  "names": []
7
7
  }
@@ -29,7 +29,7 @@ var import_text_candidate_category = require("../text-scanning/text-candidate-ca
29
29
  var import_text_match_confidence = require("../text-scanning/text-match-confidence.js");
30
30
  var import_voltage_unit = require("./voltage-unit.js");
31
31
  const SCAN_PATTERN = new RegExp(
32
- String.raw`(?<!\w)(?:[+-]\s*)?\d+[0-9 .,]*\s*(?:µV|uV|mV|kV|MV|V)\b`,
32
+ String.raw`(?<![\p{L}\p{N}_])(?:[+-]\s*)?\d+[0-9 .,]*\s*(?:µV|uV|mV|kV|MV|V)(?![\p{L}\p{N}_])`,
33
33
  "giu"
34
34
  );
35
35
  class Voltage extends import_quantity.Quantity {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/measurement/voltage.ts"],
4
- "sourcesContent": ["import { Decimal } from \"../internal/decimal.js\";\nimport type { MeasurementUnitIndex } from \"../internal/measurement-unit.js\";\nimport { Quantity, tryParseQuantity } from \"../internal/quantity.js\";\nimport type { PrimitiveTypeInfo } from \"../primitive-type-info.js\";\nimport { TextCandidate } from \"../text-scanning/text-candidate.js\";\nimport { TextCandidateCategory } from \"../text-scanning/text-candidate-category.js\";\nimport { TextMatchConfidence } from \"../text-scanning/text-match-confidence.js\";\nimport { VoltageUnit } from \"./voltage-unit.js\";\n\n/** Options for {@link Voltage.format} and {@link Voltage.normalize}. */\nexport interface VoltageFormatOptions {\n fallbackToTrimmedInputWhenInvalid?: boolean;\n /** Convert to this unit instead of preserving the parsed one. */\n unit?: VoltageUnit;\n /** Round to this many fractional digits, away from zero. */\n decimals?: number;\n}\n\nconst SCAN_PATTERN = new RegExp(\n String.raw`(?<!\\w)(?:[+-]\\s*)?\\d+[0-9 .,]*\\s*(?:\u00B5V|uV|mV|kV|MV|V)\\b`,\n \"giu\",\n);\n\n/**\n * A voltage stored internally in volts,\n * parsed from any supported unit and convertible between all of them.\n */\nexport class Voltage extends Quantity<VoltageUnit> {\n static readonly typeInfo: PrimitiveTypeInfo = Object.freeze({\n englishName: \"Voltage\",\n localizedName: \"Sp\u00E4nning\",\n emoji: \"\uD83D\uDD0C\",\n sources: Object.freeze([\n \"https://www.bipm.org/en/measurement-units/si-derived-units\",\n \"https://en.wikipedia.org/wiki/Volt\",\n ]),\n });\n\n protected get units(): MeasurementUnitIndex<VoltageUnit> {\n return VoltageUnit.index;\n }\n\n protected withBaseValue(baseValue: Decimal, unit: VoltageUnit): this {\n return new Voltage(baseValue, unit) as this;\n }\n\n get microvolts(): number {\n return this.in(VoltageUnit.Microvolt);\n }\n get millivolts(): number {\n return this.in(VoltageUnit.Millivolt);\n }\n get volts(): number {\n return this.in(VoltageUnit.Volt);\n }\n get kilovolts(): number {\n return this.in(VoltageUnit.Kilovolt);\n }\n get megavolts(): number {\n return this.in(VoltageUnit.Megavolt);\n }\n\n /** Creates a voltage from a value and unit. */\n static create(value: number | Decimal, unit: VoltageUnit): Voltage {\n VoltageUnit.index.assertOwns(unit);\n const amount = value instanceof Decimal ? value : Voltage.decimalOf(value);\n return new Voltage(unit.toBase(amount), unit);\n }\n\n static fromMicrovolts(value: number | Decimal): Voltage {\n return Voltage.create(value, VoltageUnit.Microvolt);\n }\n static fromMillivolts(value: number | Decimal): Voltage {\n return Voltage.create(value, VoltageUnit.Millivolt);\n }\n static fromVolts(value: number | Decimal): Voltage {\n return Voltage.create(value, VoltageUnit.Volt);\n }\n static fromKilovolts(value: number | Decimal): Voltage {\n return Voltage.create(value, VoltageUnit.Kilovolt);\n }\n static fromMegavolts(value: number | Decimal): Voltage {\n return Voltage.create(value, VoltageUnit.Megavolt);\n }\n\n static tryParse(input: string | null | undefined): Voltage | null {\n const parsed = tryParseQuantity(input, VoltageUnit.index, VoltageUnit.tryParse);\n return parsed === null ? null : new Voltage(parsed.baseValue, parsed.unit);\n }\n\n static parse(input: string): Voltage {\n const result = Voltage.tryParse(input);\n if (result === null) throw new Error(\"Invalid voltage.\");\n return result;\n }\n\n static isValid(input: string | null | undefined): boolean {\n return Voltage.tryParse(input) !== null;\n }\n\n /** Display form in the parsed unit, or `null` when the input is invalid. */\n static format(input: string | null | undefined, options?: VoltageFormatOptions): string | null {\n const parsed = Voltage.tryParse(input);\n if (parsed !== null) {\n if (options?.unit !== undefined || options?.decimals !== undefined) {\n return parsed.toStringInUnit(options.unit ?? parsed.originalUnit, options.decimals);\n }\n return parsed.toString();\n }\n return Voltage.fallback(input, options);\n }\n\n /** The value in volts, or `null` when the input is invalid. */\n static normalize(\n input: string | null | undefined,\n options?: VoltageFormatOptions,\n ): string | null {\n const parsed = Voltage.tryParse(input);\n if (parsed !== null) return parsed.toNormalizedString();\n return Voltage.fallback(input, options);\n }\n\n static isNormalized(input: string | null | undefined): boolean {\n return input != null && Voltage.normalize(input) === input;\n }\n\n static findCandidatesInText(text: string): readonly TextCandidate<Voltage>[] {\n if (!text) return [];\n\n const out: TextCandidate<Voltage>[] = [];\n const pattern = new RegExp(SCAN_PATTERN.source, SCAN_PATTERN.flags);\n let match: RegExpExecArray | null;\n\n while ((match = pattern.exec(text)) !== null) {\n const value = Voltage.tryParse(match[0]);\n if (value === null) continue;\n out.push(\n new TextCandidate<Voltage>({\n startIndex: match.index,\n length: match[0].length,\n originalText: match[0],\n typeName: \"Voltage\",\n category: TextCandidateCategory.Measurement,\n normalizedForm: value.toNormalizedString(),\n formattedForm: value.toString(),\n maskedForm: maskVoltage(value),\n confidence: TextMatchConfidence.Medium,\n value,\n }),\n );\n }\n\n return out;\n }\n\n private static fallback(\n input: string | null | undefined,\n options?: VoltageFormatOptions,\n ): string | null {\n if (options?.fallbackToTrimmedInputWhenInvalid !== true) return null;\n if (input == null) return null;\n const trimmed = input.trim();\n return trimmed.length > 0 ? trimmed : null;\n }\n\n private static decimalOf(value: number): Decimal {\n const parsed = Decimal.fromNumber(value);\n if (parsed === null) throw new Error(`Value cannot be represented as a voltage: ${value}`);\n return parsed;\n }\n}\n\n/** Returns a masked voltage, e.g. `10 V` becomes `*** V`. */\nexport function maskVoltage(value: Voltage): string {\n return `*** ${value.originalUnit.symbol}`;\n}\n"],
4
+ "sourcesContent": ["import { Decimal } from \"../internal/decimal.js\";\nimport type { MeasurementUnitIndex } from \"../internal/measurement-unit.js\";\nimport { Quantity, tryParseQuantity } from \"../internal/quantity.js\";\nimport type { PrimitiveTypeInfo } from \"../primitive-type-info.js\";\nimport { TextCandidate } from \"../text-scanning/text-candidate.js\";\nimport { TextCandidateCategory } from \"../text-scanning/text-candidate-category.js\";\nimport { TextMatchConfidence } from \"../text-scanning/text-match-confidence.js\";\nimport { VoltageUnit } from \"./voltage-unit.js\";\n\n/** Options for {@link Voltage.format} and {@link Voltage.normalize}. */\nexport interface VoltageFormatOptions {\n fallbackToTrimmedInputWhenInvalid?: boolean;\n /** Convert to this unit instead of preserving the parsed one. */\n unit?: VoltageUnit;\n /** Round to this many fractional digits, away from zero. */\n decimals?: number;\n}\n\nconst SCAN_PATTERN = new RegExp(\n String.raw`(?<![\\p{L}\\p{N}_])(?:[+-]\\s*)?\\d+[0-9 .,]*\\s*(?:\u00B5V|uV|mV|kV|MV|V)(?![\\p{L}\\p{N}_])`,\n \"giu\",\n);\n\n/**\n * A voltage stored internally in volts,\n * parsed from any supported unit and convertible between all of them.\n */\nexport class Voltage extends Quantity<VoltageUnit> {\n static readonly typeInfo: PrimitiveTypeInfo = Object.freeze({\n englishName: \"Voltage\",\n localizedName: \"Sp\u00E4nning\",\n emoji: \"\uD83D\uDD0C\",\n sources: Object.freeze([\n \"https://www.bipm.org/en/measurement-units/si-derived-units\",\n \"https://en.wikipedia.org/wiki/Volt\",\n ]),\n });\n\n protected get units(): MeasurementUnitIndex<VoltageUnit> {\n return VoltageUnit.index;\n }\n\n protected withBaseValue(baseValue: Decimal, unit: VoltageUnit): this {\n return new Voltage(baseValue, unit) as this;\n }\n\n get microvolts(): number {\n return this.in(VoltageUnit.Microvolt);\n }\n get millivolts(): number {\n return this.in(VoltageUnit.Millivolt);\n }\n get volts(): number {\n return this.in(VoltageUnit.Volt);\n }\n get kilovolts(): number {\n return this.in(VoltageUnit.Kilovolt);\n }\n get megavolts(): number {\n return this.in(VoltageUnit.Megavolt);\n }\n\n /** Creates a voltage from a value and unit. */\n static create(value: number | Decimal, unit: VoltageUnit): Voltage {\n VoltageUnit.index.assertOwns(unit);\n const amount = value instanceof Decimal ? value : Voltage.decimalOf(value);\n return new Voltage(unit.toBase(amount), unit);\n }\n\n static fromMicrovolts(value: number | Decimal): Voltage {\n return Voltage.create(value, VoltageUnit.Microvolt);\n }\n static fromMillivolts(value: number | Decimal): Voltage {\n return Voltage.create(value, VoltageUnit.Millivolt);\n }\n static fromVolts(value: number | Decimal): Voltage {\n return Voltage.create(value, VoltageUnit.Volt);\n }\n static fromKilovolts(value: number | Decimal): Voltage {\n return Voltage.create(value, VoltageUnit.Kilovolt);\n }\n static fromMegavolts(value: number | Decimal): Voltage {\n return Voltage.create(value, VoltageUnit.Megavolt);\n }\n\n static tryParse(input: string | null | undefined): Voltage | null {\n const parsed = tryParseQuantity(input, VoltageUnit.index, VoltageUnit.tryParse);\n return parsed === null ? null : new Voltage(parsed.baseValue, parsed.unit);\n }\n\n static parse(input: string): Voltage {\n const result = Voltage.tryParse(input);\n if (result === null) throw new Error(\"Invalid voltage.\");\n return result;\n }\n\n static isValid(input: string | null | undefined): boolean {\n return Voltage.tryParse(input) !== null;\n }\n\n /** Display form in the parsed unit, or `null` when the input is invalid. */\n static format(input: string | null | undefined, options?: VoltageFormatOptions): string | null {\n const parsed = Voltage.tryParse(input);\n if (parsed !== null) {\n if (options?.unit !== undefined || options?.decimals !== undefined) {\n return parsed.toStringInUnit(options.unit ?? parsed.originalUnit, options.decimals);\n }\n return parsed.toString();\n }\n return Voltage.fallback(input, options);\n }\n\n /** The value in volts, or `null` when the input is invalid. */\n static normalize(\n input: string | null | undefined,\n options?: VoltageFormatOptions,\n ): string | null {\n const parsed = Voltage.tryParse(input);\n if (parsed !== null) return parsed.toNormalizedString();\n return Voltage.fallback(input, options);\n }\n\n static isNormalized(input: string | null | undefined): boolean {\n return input != null && Voltage.normalize(input) === input;\n }\n\n static findCandidatesInText(text: string): readonly TextCandidate<Voltage>[] {\n if (!text) return [];\n\n const out: TextCandidate<Voltage>[] = [];\n const pattern = new RegExp(SCAN_PATTERN.source, SCAN_PATTERN.flags);\n let match: RegExpExecArray | null;\n\n while ((match = pattern.exec(text)) !== null) {\n const value = Voltage.tryParse(match[0]);\n if (value === null) continue;\n out.push(\n new TextCandidate<Voltage>({\n startIndex: match.index,\n length: match[0].length,\n originalText: match[0],\n typeName: \"Voltage\",\n category: TextCandidateCategory.Measurement,\n normalizedForm: value.toNormalizedString(),\n formattedForm: value.toString(),\n maskedForm: maskVoltage(value),\n confidence: TextMatchConfidence.Medium,\n value,\n }),\n );\n }\n\n return out;\n }\n\n private static fallback(\n input: string | null | undefined,\n options?: VoltageFormatOptions,\n ): string | null {\n if (options?.fallbackToTrimmedInputWhenInvalid !== true) return null;\n if (input == null) return null;\n const trimmed = input.trim();\n return trimmed.length > 0 ? trimmed : null;\n }\n\n private static decimalOf(value: number): Decimal {\n const parsed = Decimal.fromNumber(value);\n if (parsed === null) throw new Error(`Value cannot be represented as a voltage: ${value}`);\n return parsed;\n }\n}\n\n/** Returns a masked voltage, e.g. `10 V` becomes `*** V`. */\nexport function maskVoltage(value: Voltage): string {\n return `*** ${value.originalUnit.symbol}`;\n}\n"],
5
5
  "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -29,7 +29,7 @@ var import_text_candidate_category = require("../text-scanning/text-candidate-ca
29
29
  var import_text_match_confidence = require("../text-scanning/text-match-confidence.js");
30
30
  var import_volume_unit = require("./volume-unit.js");
31
31
  const SCAN_PATTERN = new RegExp(
32
- String.raw`(?<!\w)(?:[+-]\s*)?\d+[0-9 .,]*\s*(?:kubikmeter|hektoliter|mikroliter|vätskeans|fluid\s+ounces?|fl\s*oz|gallons?|microliters?|milliliters?|centiliters?|deciliters?|hectoliters?|liters?|cubic\s+meters?|koppar|kopp|cups?|pints?|m³|m3|cbm|µL|µl|ul|ml|cl|dl|hL|hl|gal|pt|l)\b`,
32
+ String.raw`(?<![\p{L}\p{N}_])(?:[+-]\s*)?\d+[0-9 .,]*\s*(?:kubikmeter|hektoliter|mikroliter|vätskeans|fluid\s+ounces?|fl\s*oz|gallons?|microliters?|milliliters?|centiliters?|deciliters?|hectoliters?|liters?|cubic\s+meters?|koppar|kopp|cups?|pints?|m³|m3|cbm|µL|µl|ul|ml|cl|dl|hL|hl|gal|pt|l)(?![\p{L}\p{N}_])`,
33
33
  "giu"
34
34
  );
35
35
  class Volume extends import_quantity.Quantity {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/measurement/volume.ts"],
4
- "sourcesContent": ["import { Decimal } from \"../internal/decimal.js\";\nimport type { MeasurementUnitIndex } from \"../internal/measurement-unit.js\";\nimport { Quantity, tryParseQuantity } from \"../internal/quantity.js\";\nimport type { PrimitiveTypeInfo } from \"../primitive-type-info.js\";\nimport { TextCandidate } from \"../text-scanning/text-candidate.js\";\nimport { TextCandidateCategory } from \"../text-scanning/text-candidate-category.js\";\nimport { TextMatchConfidence } from \"../text-scanning/text-match-confidence.js\";\nimport { VolumeUnit } from \"./volume-unit.js\";\n\n/** Options for {@link Volume.format} and {@link Volume.normalize}. */\nexport interface VolumeFormatOptions {\n fallbackToTrimmedInputWhenInvalid?: boolean;\n /** Convert to this unit instead of preserving the parsed one. */\n unit?: VolumeUnit;\n /** Round to this many fractional digits, away from zero. */\n decimals?: number;\n}\n\nconst SCAN_PATTERN = new RegExp(\n String.raw`(?<!\\w)(?:[+-]\\s*)?\\d+[0-9 .,]*\\s*(?:kubikmeter|hektoliter|mikroliter|v\u00E4tskeans|fluid\\s+ounces?|fl\\s*oz|gallons?|microliters?|milliliters?|centiliters?|deciliters?|hectoliters?|liters?|cubic\\s+meters?|koppar|kopp|cups?|pints?|m\u00B3|m3|cbm|\u00B5L|\u00B5l|ul|ml|cl|dl|hL|hl|gal|pt|l)\\b`,\n \"giu\",\n);\n\n/**\n * A volume stored internally in liters,\n * parsed from any supported unit and convertible between all of them.\n */\nexport class Volume extends Quantity<VolumeUnit> {\n static readonly typeInfo: PrimitiveTypeInfo = Object.freeze({\n englishName: \"Volume\",\n localizedName: \"Volym\",\n emoji: \"\uD83E\uDDEA\",\n sources: Object.freeze([\n \"https://www.bipm.org/en/measurement-units/si-derived-units\",\n \"https://en.wikipedia.org/wiki/Conversion_of_units\",\n ]),\n });\n\n protected get units(): MeasurementUnitIndex<VolumeUnit> {\n return VolumeUnit.index;\n }\n\n protected withBaseValue(baseValue: Decimal, unit: VolumeUnit): this {\n return new Volume(baseValue, unit) as this;\n }\n\n get microliters(): number {\n return this.in(VolumeUnit.Microliter);\n }\n get milliliters(): number {\n return this.in(VolumeUnit.Milliliter);\n }\n get centiliters(): number {\n return this.in(VolumeUnit.Centiliter);\n }\n get deciliters(): number {\n return this.in(VolumeUnit.Deciliter);\n }\n get liters(): number {\n return this.in(VolumeUnit.Liter);\n }\n get hectoliters(): number {\n return this.in(VolumeUnit.Hectoliter);\n }\n get cubicMeters(): number {\n return this.in(VolumeUnit.CubicMeter);\n }\n get gallons(): number {\n return this.in(VolumeUnit.Gallon);\n }\n get pints(): number {\n return this.in(VolumeUnit.Pint);\n }\n get fluidOunces(): number {\n return this.in(VolumeUnit.FluidOunce);\n }\n get cups(): number {\n return this.in(VolumeUnit.Cup);\n }\n\n /** Creates a volume from a value and unit. */\n static create(value: number | Decimal, unit: VolumeUnit): Volume {\n VolumeUnit.index.assertOwns(unit);\n const amount = value instanceof Decimal ? value : Volume.decimalOf(value);\n return new Volume(unit.toBase(amount), unit);\n }\n\n static fromMicroliters(value: number | Decimal): Volume {\n return Volume.create(value, VolumeUnit.Microliter);\n }\n static fromMilliliters(value: number | Decimal): Volume {\n return Volume.create(value, VolumeUnit.Milliliter);\n }\n static fromCentiliters(value: number | Decimal): Volume {\n return Volume.create(value, VolumeUnit.Centiliter);\n }\n static fromDeciliters(value: number | Decimal): Volume {\n return Volume.create(value, VolumeUnit.Deciliter);\n }\n static fromLiters(value: number | Decimal): Volume {\n return Volume.create(value, VolumeUnit.Liter);\n }\n static fromHectoliters(value: number | Decimal): Volume {\n return Volume.create(value, VolumeUnit.Hectoliter);\n }\n static fromCubicMeters(value: number | Decimal): Volume {\n return Volume.create(value, VolumeUnit.CubicMeter);\n }\n static fromGallons(value: number | Decimal): Volume {\n return Volume.create(value, VolumeUnit.Gallon);\n }\n static fromPints(value: number | Decimal): Volume {\n return Volume.create(value, VolumeUnit.Pint);\n }\n static fromFluidOunces(value: number | Decimal): Volume {\n return Volume.create(value, VolumeUnit.FluidOunce);\n }\n static fromCups(value: number | Decimal): Volume {\n return Volume.create(value, VolumeUnit.Cup);\n }\n\n static tryParse(input: string | null | undefined): Volume | null {\n const parsed = tryParseQuantity(input, VolumeUnit.index);\n return parsed === null ? null : new Volume(parsed.baseValue, parsed.unit);\n }\n\n static parse(input: string): Volume {\n const result = Volume.tryParse(input);\n if (result === null) throw new Error(\"Invalid volume.\");\n return result;\n }\n\n static isValid(input: string | null | undefined): boolean {\n return Volume.tryParse(input) !== null;\n }\n\n /** Display form in the parsed unit, or `null` when the input is invalid. */\n static format(input: string | null | undefined, options?: VolumeFormatOptions): string | null {\n const parsed = Volume.tryParse(input);\n if (parsed !== null) {\n if (options?.unit !== undefined || options?.decimals !== undefined) {\n return parsed.toStringInUnit(options.unit ?? parsed.originalUnit, options.decimals);\n }\n return parsed.toString();\n }\n return Volume.fallback(input, options);\n }\n\n /** The value in liters, or `null` when the input is invalid. */\n static normalize(input: string | null | undefined, options?: VolumeFormatOptions): string | null {\n const parsed = Volume.tryParse(input);\n if (parsed !== null) return parsed.toNormalizedString();\n return Volume.fallback(input, options);\n }\n\n static isNormalized(input: string | null | undefined): boolean {\n return input != null && Volume.normalize(input) === input;\n }\n\n static findCandidatesInText(text: string): readonly TextCandidate<Volume>[] {\n if (!text) return [];\n\n const out: TextCandidate<Volume>[] = [];\n const pattern = new RegExp(SCAN_PATTERN.source, SCAN_PATTERN.flags);\n let match: RegExpExecArray | null;\n\n while ((match = pattern.exec(text)) !== null) {\n const value = Volume.tryParse(match[0]);\n if (value === null) continue;\n out.push(\n new TextCandidate<Volume>({\n startIndex: match.index,\n length: match[0].length,\n originalText: match[0],\n typeName: \"Volume\",\n category: TextCandidateCategory.Measurement,\n normalizedForm: value.toNormalizedString(),\n formattedForm: value.toString(),\n maskedForm: maskVolume(value),\n confidence: TextMatchConfidence.Medium,\n value,\n }),\n );\n }\n\n return out;\n }\n\n private static fallback(\n input: string | null | undefined,\n options?: VolumeFormatOptions,\n ): string | null {\n if (options?.fallbackToTrimmedInputWhenInvalid !== true) return null;\n if (input == null) return null;\n const trimmed = input.trim();\n return trimmed.length > 0 ? trimmed : null;\n }\n\n private static decimalOf(value: number): Decimal {\n const parsed = Decimal.fromNumber(value);\n if (parsed === null) throw new Error(`Value cannot be represented as a volume: ${value}`);\n return parsed;\n }\n}\n\n/** Returns a masked volume, e.g. `10 L` becomes `*** L`. */\nexport function maskVolume(value: Volume): string {\n return `*** ${value.originalUnit.symbol}`;\n}\n"],
4
+ "sourcesContent": ["import { Decimal } from \"../internal/decimal.js\";\nimport type { MeasurementUnitIndex } from \"../internal/measurement-unit.js\";\nimport { Quantity, tryParseQuantity } from \"../internal/quantity.js\";\nimport type { PrimitiveTypeInfo } from \"../primitive-type-info.js\";\nimport { TextCandidate } from \"../text-scanning/text-candidate.js\";\nimport { TextCandidateCategory } from \"../text-scanning/text-candidate-category.js\";\nimport { TextMatchConfidence } from \"../text-scanning/text-match-confidence.js\";\nimport { VolumeUnit } from \"./volume-unit.js\";\n\n/** Options for {@link Volume.format} and {@link Volume.normalize}. */\nexport interface VolumeFormatOptions {\n fallbackToTrimmedInputWhenInvalid?: boolean;\n /** Convert to this unit instead of preserving the parsed one. */\n unit?: VolumeUnit;\n /** Round to this many fractional digits, away from zero. */\n decimals?: number;\n}\n\nconst SCAN_PATTERN = new RegExp(\n String.raw`(?<![\\p{L}\\p{N}_])(?:[+-]\\s*)?\\d+[0-9 .,]*\\s*(?:kubikmeter|hektoliter|mikroliter|v\u00E4tskeans|fluid\\s+ounces?|fl\\s*oz|gallons?|microliters?|milliliters?|centiliters?|deciliters?|hectoliters?|liters?|cubic\\s+meters?|koppar|kopp|cups?|pints?|m\u00B3|m3|cbm|\u00B5L|\u00B5l|ul|ml|cl|dl|hL|hl|gal|pt|l)(?![\\p{L}\\p{N}_])`,\n \"giu\",\n);\n\n/**\n * A volume stored internally in liters,\n * parsed from any supported unit and convertible between all of them.\n */\nexport class Volume extends Quantity<VolumeUnit> {\n static readonly typeInfo: PrimitiveTypeInfo = Object.freeze({\n englishName: \"Volume\",\n localizedName: \"Volym\",\n emoji: \"\uD83E\uDDEA\",\n sources: Object.freeze([\n \"https://www.bipm.org/en/measurement-units/si-derived-units\",\n \"https://en.wikipedia.org/wiki/Conversion_of_units\",\n ]),\n });\n\n protected get units(): MeasurementUnitIndex<VolumeUnit> {\n return VolumeUnit.index;\n }\n\n protected withBaseValue(baseValue: Decimal, unit: VolumeUnit): this {\n return new Volume(baseValue, unit) as this;\n }\n\n get microliters(): number {\n return this.in(VolumeUnit.Microliter);\n }\n get milliliters(): number {\n return this.in(VolumeUnit.Milliliter);\n }\n get centiliters(): number {\n return this.in(VolumeUnit.Centiliter);\n }\n get deciliters(): number {\n return this.in(VolumeUnit.Deciliter);\n }\n get liters(): number {\n return this.in(VolumeUnit.Liter);\n }\n get hectoliters(): number {\n return this.in(VolumeUnit.Hectoliter);\n }\n get cubicMeters(): number {\n return this.in(VolumeUnit.CubicMeter);\n }\n get gallons(): number {\n return this.in(VolumeUnit.Gallon);\n }\n get pints(): number {\n return this.in(VolumeUnit.Pint);\n }\n get fluidOunces(): number {\n return this.in(VolumeUnit.FluidOunce);\n }\n get cups(): number {\n return this.in(VolumeUnit.Cup);\n }\n\n /** Creates a volume from a value and unit. */\n static create(value: number | Decimal, unit: VolumeUnit): Volume {\n VolumeUnit.index.assertOwns(unit);\n const amount = value instanceof Decimal ? value : Volume.decimalOf(value);\n return new Volume(unit.toBase(amount), unit);\n }\n\n static fromMicroliters(value: number | Decimal): Volume {\n return Volume.create(value, VolumeUnit.Microliter);\n }\n static fromMilliliters(value: number | Decimal): Volume {\n return Volume.create(value, VolumeUnit.Milliliter);\n }\n static fromCentiliters(value: number | Decimal): Volume {\n return Volume.create(value, VolumeUnit.Centiliter);\n }\n static fromDeciliters(value: number | Decimal): Volume {\n return Volume.create(value, VolumeUnit.Deciliter);\n }\n static fromLiters(value: number | Decimal): Volume {\n return Volume.create(value, VolumeUnit.Liter);\n }\n static fromHectoliters(value: number | Decimal): Volume {\n return Volume.create(value, VolumeUnit.Hectoliter);\n }\n static fromCubicMeters(value: number | Decimal): Volume {\n return Volume.create(value, VolumeUnit.CubicMeter);\n }\n static fromGallons(value: number | Decimal): Volume {\n return Volume.create(value, VolumeUnit.Gallon);\n }\n static fromPints(value: number | Decimal): Volume {\n return Volume.create(value, VolumeUnit.Pint);\n }\n static fromFluidOunces(value: number | Decimal): Volume {\n return Volume.create(value, VolumeUnit.FluidOunce);\n }\n static fromCups(value: number | Decimal): Volume {\n return Volume.create(value, VolumeUnit.Cup);\n }\n\n static tryParse(input: string | null | undefined): Volume | null {\n const parsed = tryParseQuantity(input, VolumeUnit.index);\n return parsed === null ? null : new Volume(parsed.baseValue, parsed.unit);\n }\n\n static parse(input: string): Volume {\n const result = Volume.tryParse(input);\n if (result === null) throw new Error(\"Invalid volume.\");\n return result;\n }\n\n static isValid(input: string | null | undefined): boolean {\n return Volume.tryParse(input) !== null;\n }\n\n /** Display form in the parsed unit, or `null` when the input is invalid. */\n static format(input: string | null | undefined, options?: VolumeFormatOptions): string | null {\n const parsed = Volume.tryParse(input);\n if (parsed !== null) {\n if (options?.unit !== undefined || options?.decimals !== undefined) {\n return parsed.toStringInUnit(options.unit ?? parsed.originalUnit, options.decimals);\n }\n return parsed.toString();\n }\n return Volume.fallback(input, options);\n }\n\n /** The value in liters, or `null` when the input is invalid. */\n static normalize(input: string | null | undefined, options?: VolumeFormatOptions): string | null {\n const parsed = Volume.tryParse(input);\n if (parsed !== null) return parsed.toNormalizedString();\n return Volume.fallback(input, options);\n }\n\n static isNormalized(input: string | null | undefined): boolean {\n return input != null && Volume.normalize(input) === input;\n }\n\n static findCandidatesInText(text: string): readonly TextCandidate<Volume>[] {\n if (!text) return [];\n\n const out: TextCandidate<Volume>[] = [];\n const pattern = new RegExp(SCAN_PATTERN.source, SCAN_PATTERN.flags);\n let match: RegExpExecArray | null;\n\n while ((match = pattern.exec(text)) !== null) {\n const value = Volume.tryParse(match[0]);\n if (value === null) continue;\n out.push(\n new TextCandidate<Volume>({\n startIndex: match.index,\n length: match[0].length,\n originalText: match[0],\n typeName: \"Volume\",\n category: TextCandidateCategory.Measurement,\n normalizedForm: value.toNormalizedString(),\n formattedForm: value.toString(),\n maskedForm: maskVolume(value),\n confidence: TextMatchConfidence.Medium,\n value,\n }),\n );\n }\n\n return out;\n }\n\n private static fallback(\n input: string | null | undefined,\n options?: VolumeFormatOptions,\n ): string | null {\n if (options?.fallbackToTrimmedInputWhenInvalid !== true) return null;\n if (input == null) return null;\n const trimmed = input.trim();\n return trimmed.length > 0 ? trimmed : null;\n }\n\n private static decimalOf(value: number): Decimal {\n const parsed = Decimal.fromNumber(value);\n if (parsed === null) throw new Error(`Value cannot be represented as a volume: ${value}`);\n return parsed;\n }\n}\n\n/** Returns a masked volume, e.g. `10 L` becomes `*** L`. */\nexport function maskVolume(value: Volume): string {\n return `*** ${value.originalUnit.symbol}`;\n}\n"],
5
5
  "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -29,7 +29,7 @@ var import_text_candidate_category = require("../text-scanning/text-candidate-ca
29
29
  var import_text_match_confidence = require("../text-scanning/text-match-confidence.js");
30
30
  var import_weight_unit = require("./weight-unit.js");
31
31
  const SCAN_PATTERN = new RegExp(
32
- String.raw`(?<!\w)(?:[+-]\s*)?\d+[0-9 .,]*\s*(?:metric\s+ton|microgram|milligram|hectogram|hektogram|kilogram|gram|tonne|ton|ounces|ounce|pounds|pound|stones|stone|hekto|lbs|lb|µg|ug|mg|hg|kg|g|oz|st|t|pund|uns)\b`,
32
+ String.raw`(?<![\p{L}\p{N}_])(?:[+-]\s*)?\d+[0-9 .,]*\s*(?:metric\s+ton|microgram|milligram|hectogram|hektogram|kilogram|gram|tonne|ton|ounces|ounce|pounds|pound|stones|stone|hekto|lbs|lb|µg|ug|mg|hg|kg|g|oz|st|t|pund|uns)(?![\p{L}\p{N}_])`,
33
33
  "giu"
34
34
  );
35
35
  class Weight extends import_quantity.Quantity {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/measurement/weight.ts"],
4
- "sourcesContent": ["import { Decimal } from \"../internal/decimal.js\";\nimport type { MeasurementUnitIndex } from \"../internal/measurement-unit.js\";\nimport { Quantity, tryParseQuantity } from \"../internal/quantity.js\";\nimport type { PrimitiveTypeInfo } from \"../primitive-type-info.js\";\nimport { TextCandidate } from \"../text-scanning/text-candidate.js\";\nimport { TextCandidateCategory } from \"../text-scanning/text-candidate-category.js\";\nimport { TextMatchConfidence } from \"../text-scanning/text-match-confidence.js\";\nimport { WeightUnit } from \"./weight-unit.js\";\n\n/** Options for {@link Weight.format} and {@link Weight.normalize}. */\nexport interface WeightFormatOptions {\n fallbackToTrimmedInputWhenInvalid?: boolean;\n /** Convert to this unit instead of preserving the parsed one. */\n unit?: WeightUnit;\n /** Round to this many fractional digits, away from zero. */\n decimals?: number;\n}\n\nconst SCAN_PATTERN = new RegExp(\n String.raw`(?<!\\w)(?:[+-]\\s*)?\\d+[0-9 .,]*\\s*(?:metric\\s+ton|microgram|milligram|hectogram|hektogram|kilogram|gram|tonne|ton|ounces|ounce|pounds|pound|stones|stone|hekto|lbs|lb|\u00B5g|ug|mg|hg|kg|g|oz|st|t|pund|uns)\\b`,\n \"giu\",\n);\n\n/**\n * A weight stored internally in kilograms,\n * parsed from any supported unit and convertible between all of them.\n */\nexport class Weight extends Quantity<WeightUnit> {\n static readonly typeInfo: PrimitiveTypeInfo = Object.freeze({\n englishName: \"Weight\",\n localizedName: \"Vikt\",\n emoji: \"\u2696\uFE0F\",\n sources: Object.freeze([\n \"https://www.bipm.org/en/measurement-units/si-base-units\",\n \"https://en.wikipedia.org/wiki/Conversion_of_units\",\n ]),\n });\n\n protected get units(): MeasurementUnitIndex<WeightUnit> {\n return WeightUnit.index;\n }\n\n protected withBaseValue(baseValue: Decimal, unit: WeightUnit): this {\n return new Weight(baseValue, unit) as this;\n }\n\n get micrograms(): number {\n return this.in(WeightUnit.Microgram);\n }\n get milligrams(): number {\n return this.in(WeightUnit.Milligram);\n }\n get grams(): number {\n return this.in(WeightUnit.Gram);\n }\n get hectograms(): number {\n return this.in(WeightUnit.Hectogram);\n }\n get kilograms(): number {\n return this.in(WeightUnit.Kilogram);\n }\n get metricTons(): number {\n return this.in(WeightUnit.MetricTon);\n }\n get pounds(): number {\n return this.in(WeightUnit.Pound);\n }\n get ounces(): number {\n return this.in(WeightUnit.Ounce);\n }\n get stones(): number {\n return this.in(WeightUnit.Stone);\n }\n\n /** Creates a weight from a value and unit. */\n static create(value: number | Decimal, unit: WeightUnit): Weight {\n WeightUnit.index.assertOwns(unit);\n const amount = value instanceof Decimal ? value : Weight.decimalOf(value);\n return new Weight(unit.toBase(amount), unit);\n }\n\n static fromMicrograms(value: number | Decimal): Weight {\n return Weight.create(value, WeightUnit.Microgram);\n }\n static fromMilligrams(value: number | Decimal): Weight {\n return Weight.create(value, WeightUnit.Milligram);\n }\n static fromGrams(value: number | Decimal): Weight {\n return Weight.create(value, WeightUnit.Gram);\n }\n static fromHectograms(value: number | Decimal): Weight {\n return Weight.create(value, WeightUnit.Hectogram);\n }\n static fromKilograms(value: number | Decimal): Weight {\n return Weight.create(value, WeightUnit.Kilogram);\n }\n static fromMetricTons(value: number | Decimal): Weight {\n return Weight.create(value, WeightUnit.MetricTon);\n }\n static fromPounds(value: number | Decimal): Weight {\n return Weight.create(value, WeightUnit.Pound);\n }\n static fromOunces(value: number | Decimal): Weight {\n return Weight.create(value, WeightUnit.Ounce);\n }\n static fromStones(value: number | Decimal): Weight {\n return Weight.create(value, WeightUnit.Stone);\n }\n\n static tryParse(input: string | null | undefined): Weight | null {\n const parsed = tryParseQuantity(input, WeightUnit.index);\n return parsed === null ? null : new Weight(parsed.baseValue, parsed.unit);\n }\n\n static parse(input: string): Weight {\n const result = Weight.tryParse(input);\n if (result === null) throw new Error(\"Invalid weight.\");\n return result;\n }\n\n static isValid(input: string | null | undefined): boolean {\n return Weight.tryParse(input) !== null;\n }\n\n /** Display form in the parsed unit, or `null` when the input is invalid. */\n static format(input: string | null | undefined, options?: WeightFormatOptions): string | null {\n const parsed = Weight.tryParse(input);\n if (parsed !== null) {\n if (options?.unit !== undefined || options?.decimals !== undefined) {\n return parsed.toStringInUnit(options.unit ?? parsed.originalUnit, options.decimals);\n }\n return parsed.toString();\n }\n return Weight.fallback(input, options);\n }\n\n /** The value in kilograms, or `null` when the input is invalid. */\n static normalize(input: string | null | undefined, options?: WeightFormatOptions): string | null {\n const parsed = Weight.tryParse(input);\n if (parsed !== null) return parsed.toNormalizedString();\n return Weight.fallback(input, options);\n }\n\n static isNormalized(input: string | null | undefined): boolean {\n return input != null && Weight.normalize(input) === input;\n }\n\n static findCandidatesInText(text: string): readonly TextCandidate<Weight>[] {\n if (!text) return [];\n\n const out: TextCandidate<Weight>[] = [];\n const pattern = new RegExp(SCAN_PATTERN.source, SCAN_PATTERN.flags);\n let match: RegExpExecArray | null;\n\n while ((match = pattern.exec(text)) !== null) {\n const value = Weight.tryParse(match[0]);\n if (value === null) continue;\n out.push(\n new TextCandidate<Weight>({\n startIndex: match.index,\n length: match[0].length,\n originalText: match[0],\n typeName: \"Weight\",\n category: TextCandidateCategory.Measurement,\n normalizedForm: value.toNormalizedString(),\n formattedForm: value.toString(),\n maskedForm: maskWeight(value),\n confidence: TextMatchConfidence.Medium,\n value,\n }),\n );\n }\n\n return out;\n }\n\n private static fallback(\n input: string | null | undefined,\n options?: WeightFormatOptions,\n ): string | null {\n if (options?.fallbackToTrimmedInputWhenInvalid !== true) return null;\n if (input == null) return null;\n const trimmed = input.trim();\n return trimmed.length > 0 ? trimmed : null;\n }\n\n private static decimalOf(value: number): Decimal {\n const parsed = Decimal.fromNumber(value);\n if (parsed === null) throw new Error(`Value cannot be represented as a weight: ${value}`);\n return parsed;\n }\n}\n\n/** Returns a masked weight, e.g. `10 kg` becomes `*** kg`. */\nexport function maskWeight(value: Weight): string {\n return `*** ${value.originalUnit.symbol}`;\n}\n"],
4
+ "sourcesContent": ["import { Decimal } from \"../internal/decimal.js\";\nimport type { MeasurementUnitIndex } from \"../internal/measurement-unit.js\";\nimport { Quantity, tryParseQuantity } from \"../internal/quantity.js\";\nimport type { PrimitiveTypeInfo } from \"../primitive-type-info.js\";\nimport { TextCandidate } from \"../text-scanning/text-candidate.js\";\nimport { TextCandidateCategory } from \"../text-scanning/text-candidate-category.js\";\nimport { TextMatchConfidence } from \"../text-scanning/text-match-confidence.js\";\nimport { WeightUnit } from \"./weight-unit.js\";\n\n/** Options for {@link Weight.format} and {@link Weight.normalize}. */\nexport interface WeightFormatOptions {\n fallbackToTrimmedInputWhenInvalid?: boolean;\n /** Convert to this unit instead of preserving the parsed one. */\n unit?: WeightUnit;\n /** Round to this many fractional digits, away from zero. */\n decimals?: number;\n}\n\nconst SCAN_PATTERN = new RegExp(\n String.raw`(?<![\\p{L}\\p{N}_])(?:[+-]\\s*)?\\d+[0-9 .,]*\\s*(?:metric\\s+ton|microgram|milligram|hectogram|hektogram|kilogram|gram|tonne|ton|ounces|ounce|pounds|pound|stones|stone|hekto|lbs|lb|\u00B5g|ug|mg|hg|kg|g|oz|st|t|pund|uns)(?![\\p{L}\\p{N}_])`,\n \"giu\",\n);\n\n/**\n * A weight stored internally in kilograms,\n * parsed from any supported unit and convertible between all of them.\n */\nexport class Weight extends Quantity<WeightUnit> {\n static readonly typeInfo: PrimitiveTypeInfo = Object.freeze({\n englishName: \"Weight\",\n localizedName: \"Vikt\",\n emoji: \"\u2696\uFE0F\",\n sources: Object.freeze([\n \"https://www.bipm.org/en/measurement-units/si-base-units\",\n \"https://en.wikipedia.org/wiki/Conversion_of_units\",\n ]),\n });\n\n protected get units(): MeasurementUnitIndex<WeightUnit> {\n return WeightUnit.index;\n }\n\n protected withBaseValue(baseValue: Decimal, unit: WeightUnit): this {\n return new Weight(baseValue, unit) as this;\n }\n\n get micrograms(): number {\n return this.in(WeightUnit.Microgram);\n }\n get milligrams(): number {\n return this.in(WeightUnit.Milligram);\n }\n get grams(): number {\n return this.in(WeightUnit.Gram);\n }\n get hectograms(): number {\n return this.in(WeightUnit.Hectogram);\n }\n get kilograms(): number {\n return this.in(WeightUnit.Kilogram);\n }\n get metricTons(): number {\n return this.in(WeightUnit.MetricTon);\n }\n get pounds(): number {\n return this.in(WeightUnit.Pound);\n }\n get ounces(): number {\n return this.in(WeightUnit.Ounce);\n }\n get stones(): number {\n return this.in(WeightUnit.Stone);\n }\n\n /** Creates a weight from a value and unit. */\n static create(value: number | Decimal, unit: WeightUnit): Weight {\n WeightUnit.index.assertOwns(unit);\n const amount = value instanceof Decimal ? value : Weight.decimalOf(value);\n return new Weight(unit.toBase(amount), unit);\n }\n\n static fromMicrograms(value: number | Decimal): Weight {\n return Weight.create(value, WeightUnit.Microgram);\n }\n static fromMilligrams(value: number | Decimal): Weight {\n return Weight.create(value, WeightUnit.Milligram);\n }\n static fromGrams(value: number | Decimal): Weight {\n return Weight.create(value, WeightUnit.Gram);\n }\n static fromHectograms(value: number | Decimal): Weight {\n return Weight.create(value, WeightUnit.Hectogram);\n }\n static fromKilograms(value: number | Decimal): Weight {\n return Weight.create(value, WeightUnit.Kilogram);\n }\n static fromMetricTons(value: number | Decimal): Weight {\n return Weight.create(value, WeightUnit.MetricTon);\n }\n static fromPounds(value: number | Decimal): Weight {\n return Weight.create(value, WeightUnit.Pound);\n }\n static fromOunces(value: number | Decimal): Weight {\n return Weight.create(value, WeightUnit.Ounce);\n }\n static fromStones(value: number | Decimal): Weight {\n return Weight.create(value, WeightUnit.Stone);\n }\n\n static tryParse(input: string | null | undefined): Weight | null {\n const parsed = tryParseQuantity(input, WeightUnit.index);\n return parsed === null ? null : new Weight(parsed.baseValue, parsed.unit);\n }\n\n static parse(input: string): Weight {\n const result = Weight.tryParse(input);\n if (result === null) throw new Error(\"Invalid weight.\");\n return result;\n }\n\n static isValid(input: string | null | undefined): boolean {\n return Weight.tryParse(input) !== null;\n }\n\n /** Display form in the parsed unit, or `null` when the input is invalid. */\n static format(input: string | null | undefined, options?: WeightFormatOptions): string | null {\n const parsed = Weight.tryParse(input);\n if (parsed !== null) {\n if (options?.unit !== undefined || options?.decimals !== undefined) {\n return parsed.toStringInUnit(options.unit ?? parsed.originalUnit, options.decimals);\n }\n return parsed.toString();\n }\n return Weight.fallback(input, options);\n }\n\n /** The value in kilograms, or `null` when the input is invalid. */\n static normalize(input: string | null | undefined, options?: WeightFormatOptions): string | null {\n const parsed = Weight.tryParse(input);\n if (parsed !== null) return parsed.toNormalizedString();\n return Weight.fallback(input, options);\n }\n\n static isNormalized(input: string | null | undefined): boolean {\n return input != null && Weight.normalize(input) === input;\n }\n\n static findCandidatesInText(text: string): readonly TextCandidate<Weight>[] {\n if (!text) return [];\n\n const out: TextCandidate<Weight>[] = [];\n const pattern = new RegExp(SCAN_PATTERN.source, SCAN_PATTERN.flags);\n let match: RegExpExecArray | null;\n\n while ((match = pattern.exec(text)) !== null) {\n const value = Weight.tryParse(match[0]);\n if (value === null) continue;\n out.push(\n new TextCandidate<Weight>({\n startIndex: match.index,\n length: match[0].length,\n originalText: match[0],\n typeName: \"Weight\",\n category: TextCandidateCategory.Measurement,\n normalizedForm: value.toNormalizedString(),\n formattedForm: value.toString(),\n maskedForm: maskWeight(value),\n confidence: TextMatchConfidence.Medium,\n value,\n }),\n );\n }\n\n return out;\n }\n\n private static fallback(\n input: string | null | undefined,\n options?: WeightFormatOptions,\n ): string | null {\n if (options?.fallbackToTrimmedInputWhenInvalid !== true) return null;\n if (input == null) return null;\n const trimmed = input.trim();\n return trimmed.length > 0 ? trimmed : null;\n }\n\n private static decimalOf(value: number): Decimal {\n const parsed = Decimal.fromNumber(value);\n if (parsed === null) throw new Error(`Value cannot be represented as a weight: ${value}`);\n return parsed;\n }\n}\n\n/** Returns a masked weight, e.g. `10 kg` becomes `*** kg`. */\nexport function maskWeight(value: Weight): string {\n return `*** ${value.originalUnit.symbol}`;\n}\n"],
5
5
  "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,6 @@
1
+ const WORD = String.raw`[\p{L}\p{N}_]`;
2
+ const WORD_BOUNDARY = String.raw`(?:(?<=${WORD})(?!${WORD})|(?<!${WORD})(?=${WORD}))`;
3
+ export {
4
+ WORD_BOUNDARY
5
+ };
6
+ //# sourceMappingURL=scan-boundaries.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/internal/scan-boundaries.ts"],
4
+ "sourcesContent": ["/**\n * The Unicode-aware equivalent of a trailing `\\b` for the scanner patterns.\n *\n * JavaScript's `\\b` and `\\w` are ASCII-only even under `/u`, so `24 m` inside\n * `24 m\u00E5nader` looks like a complete match. .NET's are Unicode-aware, and .NET\n * is the behavioural spec.\n *\n * Where a unit ends in a letter or digit \u2014 which is all of them but one \u2014\n * `(?![\\p{L}\\p{N}_])` says the same thing, and the patterns use that directly.\n * This constant exists for the sound level `dB(A)` form, which ends in `)`. A\n * word boundary is a *transition*, not a plain lookahead: after a non-word\n * character it demands that the next character *be* a word character. That is\n * why .NET reads `69 dB(A) vid drift` as `69 dB` rather than `69 dB(A)`, and\n * the vectors generated from it expect exactly that.\n *\n * Internal; not re-exported publicly.\n */\n\nconst WORD = String.raw`[\\p{L}\\p{N}_]`;\n\nexport const WORD_BOUNDARY = String.raw`(?:(?<=${WORD})(?!${WORD})|(?<!${WORD})(?=${WORD}))`;\n"],
5
+ "mappings": "AAkBA,MAAM,OAAO,OAAO;AAEb,MAAM,gBAAgB,OAAO,aAAa,IAAI,OAAO,IAAI,SAAS,IAAI,OAAO,IAAI;",
6
+ "names": []
7
+ }
@@ -4,8 +4,9 @@ import { TextCandidate } from "../text-scanning/text-candidate.js";
4
4
  import { TextCandidateCategory } from "../text-scanning/text-candidate-category.js";
5
5
  import { TextMatchConfidence } from "../text-scanning/text-match-confidence.js";
6
6
  import { AreaUnit } from "./area-unit.js";
7
+ const B = String.raw`(?![\p{L}\p{N}_])`;
7
8
  const SCAN_PATTERN = new RegExp(
8
- String.raw`(?<!\w)(?:[+-]\s*)?\d+[0-9 .,]*\s*(?:(?:mm|cm|km|m)(?:²|2)|ha\b|hectare\b|hectares\b|hektar\b|acre\b|acres\b|sq\s*ft\b|sq\s*in\b|sq\s*yd\b|kvadrat(?:millimeter|centimeter|meter|kilometer|fot|tum|yard)\b)`,
9
+ String.raw`(?<![\p{L}\p{N}_])(?:[+-]\s*)?\d+[0-9 .,]*\s*(?:(?:mm|cm|km|m)(?:²|2)|ha${B}|hectare${B}|hectares${B}|hektar${B}|acre${B}|acres${B}|sq\s*ft${B}|sq\s*in${B}|sq\s*yd${B}|kvadrat(?:millimeter|centimeter|meter|kilometer|fot|tum|yard)${B})`,
9
10
  "giu"
10
11
  );
11
12
  class Area extends Quantity {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/measurement/area.ts"],
4
- "sourcesContent": ["import { Decimal } from \"../internal/decimal.js\";\nimport type { MeasurementUnitIndex } from \"../internal/measurement-unit.js\";\nimport { Quantity, tryParseQuantity } from \"../internal/quantity.js\";\nimport type { PrimitiveTypeInfo } from \"../primitive-type-info.js\";\nimport { TextCandidate } from \"../text-scanning/text-candidate.js\";\nimport { TextCandidateCategory } from \"../text-scanning/text-candidate-category.js\";\nimport { TextMatchConfidence } from \"../text-scanning/text-match-confidence.js\";\nimport { AreaUnit } from \"./area-unit.js\";\n\n/** Options for {@link Area.format} and {@link Area.normalize}. */\nexport interface AreaFormatOptions {\n fallbackToTrimmedInputWhenInvalid?: boolean;\n /** Convert to this unit instead of preserving the parsed one. */\n unit?: AreaUnit;\n /** Round to this many fractional digits, away from zero. */\n decimals?: number;\n}\n\nconst SCAN_PATTERN = new RegExp(\n String.raw`(?<!\\w)(?:[+-]\\s*)?\\d+[0-9 .,]*\\s*(?:(?:mm|cm|km|m)(?:\u00B2|2)|ha\\b|hectare\\b|hectares\\b|hektar\\b|acre\\b|acres\\b|sq\\s*ft\\b|sq\\s*in\\b|sq\\s*yd\\b|kvadrat(?:millimeter|centimeter|meter|kilometer|fot|tum|yard)\\b)`,\n \"giu\",\n);\n\n/**\n * A area stored internally in square meters,\n * parsed from any supported unit and convertible between all of them.\n */\nexport class Area extends Quantity<AreaUnit> {\n static readonly typeInfo: PrimitiveTypeInfo = Object.freeze({\n englishName: \"Area\",\n localizedName: \"Yta\",\n emoji: \"\uD83D\uDCD0\",\n sources: Object.freeze([\n \"https://www.bipm.org/en/measurement-units/si-base-units\",\n \"https://en.wikipedia.org/wiki/Conversion_of_units\",\n ]),\n });\n\n protected get units(): MeasurementUnitIndex<AreaUnit> {\n return AreaUnit.index;\n }\n\n protected withBaseValue(baseValue: Decimal, unit: AreaUnit): this {\n return new Area(baseValue, unit) as this;\n }\n\n get squareMillimeters(): number {\n return this.in(AreaUnit.SquareMillimeter);\n }\n get squareCentimeters(): number {\n return this.in(AreaUnit.SquareCentimeter);\n }\n get squareMeters(): number {\n return this.in(AreaUnit.SquareMeter);\n }\n get squareKilometers(): number {\n return this.in(AreaUnit.SquareKilometer);\n }\n get hectares(): number {\n return this.in(AreaUnit.Hectare);\n }\n get acres(): number {\n return this.in(AreaUnit.Acre);\n }\n get squareFeet(): number {\n return this.in(AreaUnit.SquareFoot);\n }\n get squareInches(): number {\n return this.in(AreaUnit.SquareInch);\n }\n get squareYards(): number {\n return this.in(AreaUnit.SquareYard);\n }\n\n /** Creates a area from a value and unit. */\n static create(value: number | Decimal, unit: AreaUnit): Area {\n AreaUnit.index.assertOwns(unit);\n const amount = value instanceof Decimal ? value : Area.decimalOf(value);\n return new Area(unit.toBase(amount), unit);\n }\n\n static fromSquareMillimeters(value: number | Decimal): Area {\n return Area.create(value, AreaUnit.SquareMillimeter);\n }\n static fromSquareCentimeters(value: number | Decimal): Area {\n return Area.create(value, AreaUnit.SquareCentimeter);\n }\n static fromSquareMeters(value: number | Decimal): Area {\n return Area.create(value, AreaUnit.SquareMeter);\n }\n static fromSquareKilometers(value: number | Decimal): Area {\n return Area.create(value, AreaUnit.SquareKilometer);\n }\n static fromHectares(value: number | Decimal): Area {\n return Area.create(value, AreaUnit.Hectare);\n }\n static fromAcres(value: number | Decimal): Area {\n return Area.create(value, AreaUnit.Acre);\n }\n static fromSquareFeet(value: number | Decimal): Area {\n return Area.create(value, AreaUnit.SquareFoot);\n }\n static fromSquareInches(value: number | Decimal): Area {\n return Area.create(value, AreaUnit.SquareInch);\n }\n static fromSquareYards(value: number | Decimal): Area {\n return Area.create(value, AreaUnit.SquareYard);\n }\n\n static tryParse(input: string | null | undefined): Area | null {\n const parsed = tryParseQuantity(input, AreaUnit.index);\n return parsed === null ? null : new Area(parsed.baseValue, parsed.unit);\n }\n\n static parse(input: string): Area {\n const result = Area.tryParse(input);\n if (result === null) throw new Error(\"Invalid area.\");\n return result;\n }\n\n static isValid(input: string | null | undefined): boolean {\n return Area.tryParse(input) !== null;\n }\n\n /** Display form in the parsed unit, or `null` when the input is invalid. */\n static format(input: string | null | undefined, options?: AreaFormatOptions): string | null {\n const parsed = Area.tryParse(input);\n if (parsed !== null) {\n if (options?.unit !== undefined || options?.decimals !== undefined) {\n return parsed.toStringInUnit(options.unit ?? parsed.originalUnit, options.decimals);\n }\n return parsed.toString();\n }\n return Area.fallback(input, options);\n }\n\n /** The value in square meters, or `null` when the input is invalid. */\n static normalize(input: string | null | undefined, options?: AreaFormatOptions): string | null {\n const parsed = Area.tryParse(input);\n if (parsed !== null) return parsed.toNormalizedString();\n return Area.fallback(input, options);\n }\n\n static isNormalized(input: string | null | undefined): boolean {\n return input != null && Area.normalize(input) === input;\n }\n\n static findCandidatesInText(text: string): readonly TextCandidate<Area>[] {\n if (!text) return [];\n\n const out: TextCandidate<Area>[] = [];\n const pattern = new RegExp(SCAN_PATTERN.source, SCAN_PATTERN.flags);\n let match: RegExpExecArray | null;\n\n while ((match = pattern.exec(text)) !== null) {\n const value = Area.tryParse(match[0]);\n if (value === null) continue;\n out.push(\n new TextCandidate<Area>({\n startIndex: match.index,\n length: match[0].length,\n originalText: match[0],\n typeName: \"Area\",\n category: TextCandidateCategory.Measurement,\n normalizedForm: value.toNormalizedString(),\n formattedForm: value.toString(),\n maskedForm: maskArea(value),\n confidence: TextMatchConfidence.Medium,\n value,\n }),\n );\n }\n\n return out;\n }\n\n private static fallback(\n input: string | null | undefined,\n options?: AreaFormatOptions,\n ): string | null {\n if (options?.fallbackToTrimmedInputWhenInvalid !== true) return null;\n if (input == null) return null;\n const trimmed = input.trim();\n return trimmed.length > 0 ? trimmed : null;\n }\n\n private static decimalOf(value: number): Decimal {\n const parsed = Decimal.fromNumber(value);\n if (parsed === null) throw new Error(`Value cannot be represented as a area: ${value}`);\n return parsed;\n }\n}\n\n/** Returns a masked area, e.g. `10 m\u00B2` becomes `*** m\u00B2`. */\nexport function maskArea(value: Area): string {\n return `*** ${value.originalUnit.symbol}`;\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { Decimal } from \"../internal/decimal.js\";\nimport type { MeasurementUnitIndex } from \"../internal/measurement-unit.js\";\nimport { Quantity, tryParseQuantity } from \"../internal/quantity.js\";\nimport type { PrimitiveTypeInfo } from \"../primitive-type-info.js\";\nimport { TextCandidate } from \"../text-scanning/text-candidate.js\";\nimport { TextCandidateCategory } from \"../text-scanning/text-candidate-category.js\";\nimport { TextMatchConfidence } from \"../text-scanning/text-match-confidence.js\";\nimport { AreaUnit } from \"./area-unit.js\";\n\n/** Options for {@link Area.format} and {@link Area.normalize}. */\nexport interface AreaFormatOptions {\n fallbackToTrimmedInputWhenInvalid?: boolean;\n /** Convert to this unit instead of preserving the parsed one. */\n unit?: AreaUnit;\n /** Round to this many fractional digits, away from zero. */\n decimals?: number;\n}\n\n// Only the spelled-out units take a boundary; the `m\u00B2` and `m2` forms end in a\n// character that already terminates the match, as in .NET.\nconst B = String.raw`(?![\\p{L}\\p{N}_])`;\n\nconst SCAN_PATTERN = new RegExp(\n String.raw`(?<![\\p{L}\\p{N}_])(?:[+-]\\s*)?\\d+[0-9 .,]*\\s*(?:(?:mm|cm|km|m)(?:\u00B2|2)|ha${B}|hectare${B}|hectares${B}|hektar${B}|acre${B}|acres${B}|sq\\s*ft${B}|sq\\s*in${B}|sq\\s*yd${B}|kvadrat(?:millimeter|centimeter|meter|kilometer|fot|tum|yard)${B})`,\n \"giu\",\n);\n\n/**\n * A area stored internally in square meters,\n * parsed from any supported unit and convertible between all of them.\n */\nexport class Area extends Quantity<AreaUnit> {\n static readonly typeInfo: PrimitiveTypeInfo = Object.freeze({\n englishName: \"Area\",\n localizedName: \"Yta\",\n emoji: \"\uD83D\uDCD0\",\n sources: Object.freeze([\n \"https://www.bipm.org/en/measurement-units/si-base-units\",\n \"https://en.wikipedia.org/wiki/Conversion_of_units\",\n ]),\n });\n\n protected get units(): MeasurementUnitIndex<AreaUnit> {\n return AreaUnit.index;\n }\n\n protected withBaseValue(baseValue: Decimal, unit: AreaUnit): this {\n return new Area(baseValue, unit) as this;\n }\n\n get squareMillimeters(): number {\n return this.in(AreaUnit.SquareMillimeter);\n }\n get squareCentimeters(): number {\n return this.in(AreaUnit.SquareCentimeter);\n }\n get squareMeters(): number {\n return this.in(AreaUnit.SquareMeter);\n }\n get squareKilometers(): number {\n return this.in(AreaUnit.SquareKilometer);\n }\n get hectares(): number {\n return this.in(AreaUnit.Hectare);\n }\n get acres(): number {\n return this.in(AreaUnit.Acre);\n }\n get squareFeet(): number {\n return this.in(AreaUnit.SquareFoot);\n }\n get squareInches(): number {\n return this.in(AreaUnit.SquareInch);\n }\n get squareYards(): number {\n return this.in(AreaUnit.SquareYard);\n }\n\n /** Creates a area from a value and unit. */\n static create(value: number | Decimal, unit: AreaUnit): Area {\n AreaUnit.index.assertOwns(unit);\n const amount = value instanceof Decimal ? value : Area.decimalOf(value);\n return new Area(unit.toBase(amount), unit);\n }\n\n static fromSquareMillimeters(value: number | Decimal): Area {\n return Area.create(value, AreaUnit.SquareMillimeter);\n }\n static fromSquareCentimeters(value: number | Decimal): Area {\n return Area.create(value, AreaUnit.SquareCentimeter);\n }\n static fromSquareMeters(value: number | Decimal): Area {\n return Area.create(value, AreaUnit.SquareMeter);\n }\n static fromSquareKilometers(value: number | Decimal): Area {\n return Area.create(value, AreaUnit.SquareKilometer);\n }\n static fromHectares(value: number | Decimal): Area {\n return Area.create(value, AreaUnit.Hectare);\n }\n static fromAcres(value: number | Decimal): Area {\n return Area.create(value, AreaUnit.Acre);\n }\n static fromSquareFeet(value: number | Decimal): Area {\n return Area.create(value, AreaUnit.SquareFoot);\n }\n static fromSquareInches(value: number | Decimal): Area {\n return Area.create(value, AreaUnit.SquareInch);\n }\n static fromSquareYards(value: number | Decimal): Area {\n return Area.create(value, AreaUnit.SquareYard);\n }\n\n static tryParse(input: string | null | undefined): Area | null {\n const parsed = tryParseQuantity(input, AreaUnit.index);\n return parsed === null ? null : new Area(parsed.baseValue, parsed.unit);\n }\n\n static parse(input: string): Area {\n const result = Area.tryParse(input);\n if (result === null) throw new Error(\"Invalid area.\");\n return result;\n }\n\n static isValid(input: string | null | undefined): boolean {\n return Area.tryParse(input) !== null;\n }\n\n /** Display form in the parsed unit, or `null` when the input is invalid. */\n static format(input: string | null | undefined, options?: AreaFormatOptions): string | null {\n const parsed = Area.tryParse(input);\n if (parsed !== null) {\n if (options?.unit !== undefined || options?.decimals !== undefined) {\n return parsed.toStringInUnit(options.unit ?? parsed.originalUnit, options.decimals);\n }\n return parsed.toString();\n }\n return Area.fallback(input, options);\n }\n\n /** The value in square meters, or `null` when the input is invalid. */\n static normalize(input: string | null | undefined, options?: AreaFormatOptions): string | null {\n const parsed = Area.tryParse(input);\n if (parsed !== null) return parsed.toNormalizedString();\n return Area.fallback(input, options);\n }\n\n static isNormalized(input: string | null | undefined): boolean {\n return input != null && Area.normalize(input) === input;\n }\n\n static findCandidatesInText(text: string): readonly TextCandidate<Area>[] {\n if (!text) return [];\n\n const out: TextCandidate<Area>[] = [];\n const pattern = new RegExp(SCAN_PATTERN.source, SCAN_PATTERN.flags);\n let match: RegExpExecArray | null;\n\n while ((match = pattern.exec(text)) !== null) {\n const value = Area.tryParse(match[0]);\n if (value === null) continue;\n out.push(\n new TextCandidate<Area>({\n startIndex: match.index,\n length: match[0].length,\n originalText: match[0],\n typeName: \"Area\",\n category: TextCandidateCategory.Measurement,\n normalizedForm: value.toNormalizedString(),\n formattedForm: value.toString(),\n maskedForm: maskArea(value),\n confidence: TextMatchConfidence.Medium,\n value,\n }),\n );\n }\n\n return out;\n }\n\n private static fallback(\n input: string | null | undefined,\n options?: AreaFormatOptions,\n ): string | null {\n if (options?.fallbackToTrimmedInputWhenInvalid !== true) return null;\n if (input == null) return null;\n const trimmed = input.trim();\n return trimmed.length > 0 ? trimmed : null;\n }\n\n private static decimalOf(value: number): Decimal {\n const parsed = Decimal.fromNumber(value);\n if (parsed === null) throw new Error(`Value cannot be represented as a area: ${value}`);\n return parsed;\n }\n}\n\n/** Returns a masked area, e.g. `10 m\u00B2` becomes `*** m\u00B2`. */\nexport function maskArea(value: Area): string {\n return `*** ${value.originalUnit.symbol}`;\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -5,7 +5,7 @@ import { TextCandidateCategory } from "../text-scanning/text-candidate-category.
5
5
  import { TextMatchConfidence } from "../text-scanning/text-match-confidence.js";
6
6
  import { DataSizeUnit } from "./data-size-unit.js";
7
7
  const SCAN_PATTERN = new RegExp(
8
- String.raw`(?<!\w)(?:[+-]\s*)?\d+[0-9 .,]*\s*(?:exbibytes|exbibyte|exabytes|exabyte|pebibytes|pebibyte|petabytes|petabyte|tebibytes|tebibyte|terabytes|terabyte|gibibytes|gibibyte|gigabytes|gigabyte|mebibytes|mebibyte|megabytes|megabyte|kibibytes|kibibyte|kilobytes|kilobyte|EiB|PiB|TiB|GiB|MiB|KiB|EB|PB|TB|GB|MB|KB|bytes|byte|B)\b`,
8
+ String.raw`(?<![\p{L}\p{N}_])(?:[+-]\s*)?\d+[0-9 .,]*\s*(?:exbibytes|exbibyte|exabytes|exabyte|pebibytes|pebibyte|petabytes|petabyte|tebibytes|tebibyte|terabytes|terabyte|gibibytes|gibibyte|gigabytes|gigabyte|mebibytes|mebibyte|megabytes|megabyte|kibibytes|kibibyte|kilobytes|kilobyte|EiB|PiB|TiB|GiB|MiB|KiB|EB|PB|TB|GB|MB|KB|bytes|byte|B)(?![\p{L}\p{N}_])`,
9
9
  "giu"
10
10
  );
11
11
  class DataSize extends Quantity {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/measurement/data-size.ts"],
4
- "sourcesContent": ["import { Decimal } from \"../internal/decimal.js\";\nimport type { MeasurementUnitIndex } from \"../internal/measurement-unit.js\";\nimport { Quantity, tryParseQuantity } from \"../internal/quantity.js\";\nimport type { PrimitiveTypeInfo } from \"../primitive-type-info.js\";\nimport { TextCandidate } from \"../text-scanning/text-candidate.js\";\nimport { TextCandidateCategory } from \"../text-scanning/text-candidate-category.js\";\nimport { TextMatchConfidence } from \"../text-scanning/text-match-confidence.js\";\nimport { DataSizeUnit } from \"./data-size-unit.js\";\n\n/** Options for {@link DataSize.format} and {@link DataSize.normalize}. */\nexport interface DataSizeFormatOptions {\n fallbackToTrimmedInputWhenInvalid?: boolean;\n /** Convert to this unit instead of preserving the parsed one. */\n unit?: DataSizeUnit;\n /** Round to this many fractional digits, away from zero. */\n decimals?: number;\n}\n\nconst SCAN_PATTERN = new RegExp(\n String.raw`(?<!\\w)(?:[+-]\\s*)?\\d+[0-9 .,]*\\s*(?:exbibytes|exbibyte|exabytes|exabyte|pebibytes|pebibyte|petabytes|petabyte|tebibytes|tebibyte|terabytes|terabyte|gibibytes|gibibyte|gigabytes|gigabyte|mebibytes|mebibyte|megabytes|megabyte|kibibytes|kibibyte|kilobytes|kilobyte|EiB|PiB|TiB|GiB|MiB|KiB|EB|PB|TB|GB|MB|KB|bytes|byte|B)\\b`,\n \"giu\",\n);\n\n/**\n * A data size stored internally in bytes,\n * parsed from any supported unit and convertible between all of them.\n */\nexport class DataSize extends Quantity<DataSizeUnit> {\n static readonly typeInfo: PrimitiveTypeInfo = Object.freeze({\n englishName: \"Data Size\",\n localizedName: \"Datastorlek\",\n emoji: \"\uD83D\uDCBE\",\n sources: Object.freeze([\n \"https://www.bipm.org/en/publications/si-brochure\",\n \"https://www.iec.ch/standardsonline/iec-standard/iec-60027-2\",\n ]),\n });\n\n protected get units(): MeasurementUnitIndex<DataSizeUnit> {\n return DataSizeUnit.index;\n }\n\n protected withBaseValue(baseValue: Decimal, unit: DataSizeUnit): this {\n return new DataSize(baseValue, unit) as this;\n }\n\n get bytes(): number {\n return this.in(DataSizeUnit.Byte);\n }\n get kilobytes(): number {\n return this.in(DataSizeUnit.Kilobyte);\n }\n get megabytes(): number {\n return this.in(DataSizeUnit.Megabyte);\n }\n get gigabytes(): number {\n return this.in(DataSizeUnit.Gigabyte);\n }\n get terabytes(): number {\n return this.in(DataSizeUnit.Terabyte);\n }\n get petabytes(): number {\n return this.in(DataSizeUnit.Petabyte);\n }\n get exabytes(): number {\n return this.in(DataSizeUnit.Exabyte);\n }\n get kibibytes(): number {\n return this.in(DataSizeUnit.Kibibyte);\n }\n get mebibytes(): number {\n return this.in(DataSizeUnit.Mebibyte);\n }\n get gibibytes(): number {\n return this.in(DataSizeUnit.Gibibyte);\n }\n get tebibytes(): number {\n return this.in(DataSizeUnit.Tebibyte);\n }\n get pebibytes(): number {\n return this.in(DataSizeUnit.Pebibyte);\n }\n get exbibytes(): number {\n return this.in(DataSizeUnit.Exbibyte);\n }\n\n /** Creates a data size from a value and unit. */\n static create(value: number | Decimal, unit: DataSizeUnit): DataSize {\n DataSizeUnit.index.assertOwns(unit);\n const amount = value instanceof Decimal ? value : DataSize.decimalOf(value);\n return new DataSize(unit.toBase(amount), unit);\n }\n\n static fromBytes(value: number | Decimal): DataSize {\n return DataSize.create(value, DataSizeUnit.Byte);\n }\n static fromKilobytes(value: number | Decimal): DataSize {\n return DataSize.create(value, DataSizeUnit.Kilobyte);\n }\n static fromMegabytes(value: number | Decimal): DataSize {\n return DataSize.create(value, DataSizeUnit.Megabyte);\n }\n static fromGigabytes(value: number | Decimal): DataSize {\n return DataSize.create(value, DataSizeUnit.Gigabyte);\n }\n static fromTerabytes(value: number | Decimal): DataSize {\n return DataSize.create(value, DataSizeUnit.Terabyte);\n }\n static fromPetabytes(value: number | Decimal): DataSize {\n return DataSize.create(value, DataSizeUnit.Petabyte);\n }\n static fromExabytes(value: number | Decimal): DataSize {\n return DataSize.create(value, DataSizeUnit.Exabyte);\n }\n static fromKibibytes(value: number | Decimal): DataSize {\n return DataSize.create(value, DataSizeUnit.Kibibyte);\n }\n static fromMebibytes(value: number | Decimal): DataSize {\n return DataSize.create(value, DataSizeUnit.Mebibyte);\n }\n static fromGibibytes(value: number | Decimal): DataSize {\n return DataSize.create(value, DataSizeUnit.Gibibyte);\n }\n static fromTebibytes(value: number | Decimal): DataSize {\n return DataSize.create(value, DataSizeUnit.Tebibyte);\n }\n static fromPebibytes(value: number | Decimal): DataSize {\n return DataSize.create(value, DataSizeUnit.Pebibyte);\n }\n static fromExbibytes(value: number | Decimal): DataSize {\n return DataSize.create(value, DataSizeUnit.Exbibyte);\n }\n\n static tryParse(input: string | null | undefined): DataSize | null {\n const parsed = tryParseQuantity(input, DataSizeUnit.index);\n return parsed === null ? null : new DataSize(parsed.baseValue, parsed.unit);\n }\n\n static parse(input: string): DataSize {\n const result = DataSize.tryParse(input);\n if (result === null) throw new Error(\"Invalid data size.\");\n return result;\n }\n\n static isValid(input: string | null | undefined): boolean {\n return DataSize.tryParse(input) !== null;\n }\n\n /** Display form in the parsed unit, or `null` when the input is invalid. */\n static format(input: string | null | undefined, options?: DataSizeFormatOptions): string | null {\n const parsed = DataSize.tryParse(input);\n if (parsed !== null) {\n if (options?.unit !== undefined || options?.decimals !== undefined) {\n return parsed.toStringInUnit(options.unit ?? parsed.originalUnit, options.decimals);\n }\n return parsed.toString();\n }\n return DataSize.fallback(input, options);\n }\n\n /** The value in bytes, or `null` when the input is invalid. */\n static normalize(\n input: string | null | undefined,\n options?: DataSizeFormatOptions,\n ): string | null {\n const parsed = DataSize.tryParse(input);\n if (parsed !== null) return parsed.toNormalizedString();\n return DataSize.fallback(input, options);\n }\n\n static isNormalized(input: string | null | undefined): boolean {\n return input != null && DataSize.normalize(input) === input;\n }\n\n static findCandidatesInText(text: string): readonly TextCandidate<DataSize>[] {\n if (!text) return [];\n\n const out: TextCandidate<DataSize>[] = [];\n const pattern = new RegExp(SCAN_PATTERN.source, SCAN_PATTERN.flags);\n let match: RegExpExecArray | null;\n\n while ((match = pattern.exec(text)) !== null) {\n const value = DataSize.tryParse(match[0]);\n if (value === null) continue;\n out.push(\n new TextCandidate<DataSize>({\n startIndex: match.index,\n length: match[0].length,\n originalText: match[0],\n typeName: \"DataSize\",\n category: TextCandidateCategory.Measurement,\n normalizedForm: value.toNormalizedString(),\n formattedForm: value.toString(),\n maskedForm: maskDataSize(value),\n confidence: TextMatchConfidence.Medium,\n value,\n }),\n );\n }\n\n return out;\n }\n\n private static fallback(\n input: string | null | undefined,\n options?: DataSizeFormatOptions,\n ): string | null {\n if (options?.fallbackToTrimmedInputWhenInvalid !== true) return null;\n if (input == null) return null;\n const trimmed = input.trim();\n return trimmed.length > 0 ? trimmed : null;\n }\n\n private static decimalOf(value: number): Decimal {\n const parsed = Decimal.fromNumber(value);\n if (parsed === null) throw new Error(`Value cannot be represented as a data size: ${value}`);\n return parsed;\n }\n}\n\n/** Returns a masked data size, e.g. `10 B` becomes `*** B`. */\nexport function maskDataSize(value: DataSize): string {\n return `*** ${value.originalUnit.symbol}`;\n}\n"],
4
+ "sourcesContent": ["import { Decimal } from \"../internal/decimal.js\";\nimport type { MeasurementUnitIndex } from \"../internal/measurement-unit.js\";\nimport { Quantity, tryParseQuantity } from \"../internal/quantity.js\";\nimport type { PrimitiveTypeInfo } from \"../primitive-type-info.js\";\nimport { TextCandidate } from \"../text-scanning/text-candidate.js\";\nimport { TextCandidateCategory } from \"../text-scanning/text-candidate-category.js\";\nimport { TextMatchConfidence } from \"../text-scanning/text-match-confidence.js\";\nimport { DataSizeUnit } from \"./data-size-unit.js\";\n\n/** Options for {@link DataSize.format} and {@link DataSize.normalize}. */\nexport interface DataSizeFormatOptions {\n fallbackToTrimmedInputWhenInvalid?: boolean;\n /** Convert to this unit instead of preserving the parsed one. */\n unit?: DataSizeUnit;\n /** Round to this many fractional digits, away from zero. */\n decimals?: number;\n}\n\nconst SCAN_PATTERN = new RegExp(\n String.raw`(?<![\\p{L}\\p{N}_])(?:[+-]\\s*)?\\d+[0-9 .,]*\\s*(?:exbibytes|exbibyte|exabytes|exabyte|pebibytes|pebibyte|petabytes|petabyte|tebibytes|tebibyte|terabytes|terabyte|gibibytes|gibibyte|gigabytes|gigabyte|mebibytes|mebibyte|megabytes|megabyte|kibibytes|kibibyte|kilobytes|kilobyte|EiB|PiB|TiB|GiB|MiB|KiB|EB|PB|TB|GB|MB|KB|bytes|byte|B)(?![\\p{L}\\p{N}_])`,\n \"giu\",\n);\n\n/**\n * A data size stored internally in bytes,\n * parsed from any supported unit and convertible between all of them.\n */\nexport class DataSize extends Quantity<DataSizeUnit> {\n static readonly typeInfo: PrimitiveTypeInfo = Object.freeze({\n englishName: \"Data Size\",\n localizedName: \"Datastorlek\",\n emoji: \"\uD83D\uDCBE\",\n sources: Object.freeze([\n \"https://www.bipm.org/en/publications/si-brochure\",\n \"https://www.iec.ch/standardsonline/iec-standard/iec-60027-2\",\n ]),\n });\n\n protected get units(): MeasurementUnitIndex<DataSizeUnit> {\n return DataSizeUnit.index;\n }\n\n protected withBaseValue(baseValue: Decimal, unit: DataSizeUnit): this {\n return new DataSize(baseValue, unit) as this;\n }\n\n get bytes(): number {\n return this.in(DataSizeUnit.Byte);\n }\n get kilobytes(): number {\n return this.in(DataSizeUnit.Kilobyte);\n }\n get megabytes(): number {\n return this.in(DataSizeUnit.Megabyte);\n }\n get gigabytes(): number {\n return this.in(DataSizeUnit.Gigabyte);\n }\n get terabytes(): number {\n return this.in(DataSizeUnit.Terabyte);\n }\n get petabytes(): number {\n return this.in(DataSizeUnit.Petabyte);\n }\n get exabytes(): number {\n return this.in(DataSizeUnit.Exabyte);\n }\n get kibibytes(): number {\n return this.in(DataSizeUnit.Kibibyte);\n }\n get mebibytes(): number {\n return this.in(DataSizeUnit.Mebibyte);\n }\n get gibibytes(): number {\n return this.in(DataSizeUnit.Gibibyte);\n }\n get tebibytes(): number {\n return this.in(DataSizeUnit.Tebibyte);\n }\n get pebibytes(): number {\n return this.in(DataSizeUnit.Pebibyte);\n }\n get exbibytes(): number {\n return this.in(DataSizeUnit.Exbibyte);\n }\n\n /** Creates a data size from a value and unit. */\n static create(value: number | Decimal, unit: DataSizeUnit): DataSize {\n DataSizeUnit.index.assertOwns(unit);\n const amount = value instanceof Decimal ? value : DataSize.decimalOf(value);\n return new DataSize(unit.toBase(amount), unit);\n }\n\n static fromBytes(value: number | Decimal): DataSize {\n return DataSize.create(value, DataSizeUnit.Byte);\n }\n static fromKilobytes(value: number | Decimal): DataSize {\n return DataSize.create(value, DataSizeUnit.Kilobyte);\n }\n static fromMegabytes(value: number | Decimal): DataSize {\n return DataSize.create(value, DataSizeUnit.Megabyte);\n }\n static fromGigabytes(value: number | Decimal): DataSize {\n return DataSize.create(value, DataSizeUnit.Gigabyte);\n }\n static fromTerabytes(value: number | Decimal): DataSize {\n return DataSize.create(value, DataSizeUnit.Terabyte);\n }\n static fromPetabytes(value: number | Decimal): DataSize {\n return DataSize.create(value, DataSizeUnit.Petabyte);\n }\n static fromExabytes(value: number | Decimal): DataSize {\n return DataSize.create(value, DataSizeUnit.Exabyte);\n }\n static fromKibibytes(value: number | Decimal): DataSize {\n return DataSize.create(value, DataSizeUnit.Kibibyte);\n }\n static fromMebibytes(value: number | Decimal): DataSize {\n return DataSize.create(value, DataSizeUnit.Mebibyte);\n }\n static fromGibibytes(value: number | Decimal): DataSize {\n return DataSize.create(value, DataSizeUnit.Gibibyte);\n }\n static fromTebibytes(value: number | Decimal): DataSize {\n return DataSize.create(value, DataSizeUnit.Tebibyte);\n }\n static fromPebibytes(value: number | Decimal): DataSize {\n return DataSize.create(value, DataSizeUnit.Pebibyte);\n }\n static fromExbibytes(value: number | Decimal): DataSize {\n return DataSize.create(value, DataSizeUnit.Exbibyte);\n }\n\n static tryParse(input: string | null | undefined): DataSize | null {\n const parsed = tryParseQuantity(input, DataSizeUnit.index);\n return parsed === null ? null : new DataSize(parsed.baseValue, parsed.unit);\n }\n\n static parse(input: string): DataSize {\n const result = DataSize.tryParse(input);\n if (result === null) throw new Error(\"Invalid data size.\");\n return result;\n }\n\n static isValid(input: string | null | undefined): boolean {\n return DataSize.tryParse(input) !== null;\n }\n\n /** Display form in the parsed unit, or `null` when the input is invalid. */\n static format(input: string | null | undefined, options?: DataSizeFormatOptions): string | null {\n const parsed = DataSize.tryParse(input);\n if (parsed !== null) {\n if (options?.unit !== undefined || options?.decimals !== undefined) {\n return parsed.toStringInUnit(options.unit ?? parsed.originalUnit, options.decimals);\n }\n return parsed.toString();\n }\n return DataSize.fallback(input, options);\n }\n\n /** The value in bytes, or `null` when the input is invalid. */\n static normalize(\n input: string | null | undefined,\n options?: DataSizeFormatOptions,\n ): string | null {\n const parsed = DataSize.tryParse(input);\n if (parsed !== null) return parsed.toNormalizedString();\n return DataSize.fallback(input, options);\n }\n\n static isNormalized(input: string | null | undefined): boolean {\n return input != null && DataSize.normalize(input) === input;\n }\n\n static findCandidatesInText(text: string): readonly TextCandidate<DataSize>[] {\n if (!text) return [];\n\n const out: TextCandidate<DataSize>[] = [];\n const pattern = new RegExp(SCAN_PATTERN.source, SCAN_PATTERN.flags);\n let match: RegExpExecArray | null;\n\n while ((match = pattern.exec(text)) !== null) {\n const value = DataSize.tryParse(match[0]);\n if (value === null) continue;\n out.push(\n new TextCandidate<DataSize>({\n startIndex: match.index,\n length: match[0].length,\n originalText: match[0],\n typeName: \"DataSize\",\n category: TextCandidateCategory.Measurement,\n normalizedForm: value.toNormalizedString(),\n formattedForm: value.toString(),\n maskedForm: maskDataSize(value),\n confidence: TextMatchConfidence.Medium,\n value,\n }),\n );\n }\n\n return out;\n }\n\n private static fallback(\n input: string | null | undefined,\n options?: DataSizeFormatOptions,\n ): string | null {\n if (options?.fallbackToTrimmedInputWhenInvalid !== true) return null;\n if (input == null) return null;\n const trimmed = input.trim();\n return trimmed.length > 0 ? trimmed : null;\n }\n\n private static decimalOf(value: number): Decimal {\n const parsed = Decimal.fromNumber(value);\n if (parsed === null) throw new Error(`Value cannot be represented as a data size: ${value}`);\n return parsed;\n }\n}\n\n/** Returns a masked data size, e.g. `10 B` becomes `*** B`. */\nexport function maskDataSize(value: DataSize): string {\n return `*** ${value.originalUnit.symbol}`;\n}\n"],
5
5
  "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -5,7 +5,7 @@ import { TextCandidateCategory } from "../text-scanning/text-candidate-category.
5
5
  import { TextMatchConfidence } from "../text-scanning/text-match-confidence.js";
6
6
  import { ElectricChargeUnit } from "./electric-charge-unit.js";
7
7
  const SCAN_PATTERN = new RegExp(
8
- String.raw`(?<!\w)(?:[+-]\s*)?\d+[0-9 .,]*\s*(?:mAh|Ah|C)\b`,
8
+ String.raw`(?<![\p{L}\p{N}_])(?:[+-]\s*)?\d+[0-9 .,]*\s*(?:mAh|Ah|C)(?![\p{L}\p{N}_])`,
9
9
  "giu"
10
10
  );
11
11
  class ElectricCharge extends Quantity {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/measurement/electric-charge.ts"],
4
- "sourcesContent": ["import { Decimal } from \"../internal/decimal.js\";\nimport type { MeasurementUnitIndex } from \"../internal/measurement-unit.js\";\nimport { Quantity, tryParseQuantity } from \"../internal/quantity.js\";\nimport type { PrimitiveTypeInfo } from \"../primitive-type-info.js\";\nimport { TextCandidate } from \"../text-scanning/text-candidate.js\";\nimport { TextCandidateCategory } from \"../text-scanning/text-candidate-category.js\";\nimport { TextMatchConfidence } from \"../text-scanning/text-match-confidence.js\";\nimport { ElectricChargeUnit } from \"./electric-charge-unit.js\";\n\n/** Options for {@link ElectricCharge.format} and {@link ElectricCharge.normalize}. */\nexport interface ElectricChargeFormatOptions {\n fallbackToTrimmedInputWhenInvalid?: boolean;\n /** Convert to this unit instead of preserving the parsed one. */\n unit?: ElectricChargeUnit;\n /** Round to this many fractional digits, away from zero. */\n decimals?: number;\n}\n\nconst SCAN_PATTERN = new RegExp(\n String.raw`(?<!\\w)(?:[+-]\\s*)?\\d+[0-9 .,]*\\s*(?:mAh|Ah|C)\\b`,\n \"giu\",\n);\n\n/**\n * A electric charge stored internally in ampere-hours,\n * parsed from any supported unit and convertible between all of them.\n */\nexport class ElectricCharge extends Quantity<ElectricChargeUnit> {\n static readonly typeInfo: PrimitiveTypeInfo = Object.freeze({\n englishName: \"Electric Charge\",\n localizedName: \"Elektrisk laddning\",\n emoji: \"\uD83D\uDD0B\",\n sources: Object.freeze([\n \"https://www.bipm.org/en/measurement-units/si-derived-units\",\n \"https://en.wikipedia.org/wiki/Ampere-hour\",\n ]),\n });\n\n protected get units(): MeasurementUnitIndex<ElectricChargeUnit> {\n return ElectricChargeUnit.index;\n }\n\n protected withBaseValue(baseValue: Decimal, unit: ElectricChargeUnit): this {\n return new ElectricCharge(baseValue, unit) as this;\n }\n\n get milliampereHours(): number {\n return this.in(ElectricChargeUnit.MilliampereHour);\n }\n get ampereHours(): number {\n return this.in(ElectricChargeUnit.AmpereHour);\n }\n get coulombs(): number {\n return this.in(ElectricChargeUnit.Coulomb);\n }\n\n /** Creates a electric charge from a value and unit. */\n static create(value: number | Decimal, unit: ElectricChargeUnit): ElectricCharge {\n ElectricChargeUnit.index.assertOwns(unit);\n const amount = value instanceof Decimal ? value : ElectricCharge.decimalOf(value);\n return new ElectricCharge(unit.toBase(amount), unit);\n }\n\n static fromMilliampereHours(value: number | Decimal): ElectricCharge {\n return ElectricCharge.create(value, ElectricChargeUnit.MilliampereHour);\n }\n static fromAmpereHours(value: number | Decimal): ElectricCharge {\n return ElectricCharge.create(value, ElectricChargeUnit.AmpereHour);\n }\n static fromCoulombs(value: number | Decimal): ElectricCharge {\n return ElectricCharge.create(value, ElectricChargeUnit.Coulomb);\n }\n\n static tryParse(input: string | null | undefined): ElectricCharge | null {\n const parsed = tryParseQuantity(input, ElectricChargeUnit.index);\n return parsed === null ? null : new ElectricCharge(parsed.baseValue, parsed.unit);\n }\n\n static parse(input: string): ElectricCharge {\n const result = ElectricCharge.tryParse(input);\n if (result === null) throw new Error(\"Invalid electric charge.\");\n return result;\n }\n\n static isValid(input: string | null | undefined): boolean {\n return ElectricCharge.tryParse(input) !== null;\n }\n\n /** Display form in the parsed unit, or `null` when the input is invalid. */\n static format(\n input: string | null | undefined,\n options?: ElectricChargeFormatOptions,\n ): string | null {\n const parsed = ElectricCharge.tryParse(input);\n if (parsed !== null) {\n if (options?.unit !== undefined || options?.decimals !== undefined) {\n return parsed.toStringInUnit(options.unit ?? parsed.originalUnit, options.decimals);\n }\n return parsed.toString();\n }\n return ElectricCharge.fallback(input, options);\n }\n\n /** The value in ampere-hours, or `null` when the input is invalid. */\n static normalize(\n input: string | null | undefined,\n options?: ElectricChargeFormatOptions,\n ): string | null {\n const parsed = ElectricCharge.tryParse(input);\n if (parsed !== null) return parsed.toNormalizedString();\n return ElectricCharge.fallback(input, options);\n }\n\n static isNormalized(input: string | null | undefined): boolean {\n return input != null && ElectricCharge.normalize(input) === input;\n }\n\n static findCandidatesInText(text: string): readonly TextCandidate<ElectricCharge>[] {\n if (!text) return [];\n\n const out: TextCandidate<ElectricCharge>[] = [];\n const pattern = new RegExp(SCAN_PATTERN.source, SCAN_PATTERN.flags);\n let match: RegExpExecArray | null;\n\n while ((match = pattern.exec(text)) !== null) {\n const value = ElectricCharge.tryParse(match[0]);\n if (value === null) continue;\n out.push(\n new TextCandidate<ElectricCharge>({\n startIndex: match.index,\n length: match[0].length,\n originalText: match[0],\n typeName: \"ElectricCharge\",\n category: TextCandidateCategory.Measurement,\n normalizedForm: value.toNormalizedString(),\n formattedForm: value.toString(),\n maskedForm: maskElectricCharge(value),\n confidence: TextMatchConfidence.Medium,\n value,\n }),\n );\n }\n\n return out;\n }\n\n private static fallback(\n input: string | null | undefined,\n options?: ElectricChargeFormatOptions,\n ): string | null {\n if (options?.fallbackToTrimmedInputWhenInvalid !== true) return null;\n if (input == null) return null;\n const trimmed = input.trim();\n return trimmed.length > 0 ? trimmed : null;\n }\n\n private static decimalOf(value: number): Decimal {\n const parsed = Decimal.fromNumber(value);\n if (parsed === null)\n throw new Error(`Value cannot be represented as a electric charge: ${value}`);\n return parsed;\n }\n}\n\n/** Returns a masked electric charge, e.g. `10 Ah` becomes `*** Ah`. */\nexport function maskElectricCharge(value: ElectricCharge): string {\n return `*** ${value.originalUnit.symbol}`;\n}\n"],
4
+ "sourcesContent": ["import { Decimal } from \"../internal/decimal.js\";\nimport type { MeasurementUnitIndex } from \"../internal/measurement-unit.js\";\nimport { Quantity, tryParseQuantity } from \"../internal/quantity.js\";\nimport type { PrimitiveTypeInfo } from \"../primitive-type-info.js\";\nimport { TextCandidate } from \"../text-scanning/text-candidate.js\";\nimport { TextCandidateCategory } from \"../text-scanning/text-candidate-category.js\";\nimport { TextMatchConfidence } from \"../text-scanning/text-match-confidence.js\";\nimport { ElectricChargeUnit } from \"./electric-charge-unit.js\";\n\n/** Options for {@link ElectricCharge.format} and {@link ElectricCharge.normalize}. */\nexport interface ElectricChargeFormatOptions {\n fallbackToTrimmedInputWhenInvalid?: boolean;\n /** Convert to this unit instead of preserving the parsed one. */\n unit?: ElectricChargeUnit;\n /** Round to this many fractional digits, away from zero. */\n decimals?: number;\n}\n\nconst SCAN_PATTERN = new RegExp(\n String.raw`(?<![\\p{L}\\p{N}_])(?:[+-]\\s*)?\\d+[0-9 .,]*\\s*(?:mAh|Ah|C)(?![\\p{L}\\p{N}_])`,\n \"giu\",\n);\n\n/**\n * A electric charge stored internally in ampere-hours,\n * parsed from any supported unit and convertible between all of them.\n */\nexport class ElectricCharge extends Quantity<ElectricChargeUnit> {\n static readonly typeInfo: PrimitiveTypeInfo = Object.freeze({\n englishName: \"Electric Charge\",\n localizedName: \"Elektrisk laddning\",\n emoji: \"\uD83D\uDD0B\",\n sources: Object.freeze([\n \"https://www.bipm.org/en/measurement-units/si-derived-units\",\n \"https://en.wikipedia.org/wiki/Ampere-hour\",\n ]),\n });\n\n protected get units(): MeasurementUnitIndex<ElectricChargeUnit> {\n return ElectricChargeUnit.index;\n }\n\n protected withBaseValue(baseValue: Decimal, unit: ElectricChargeUnit): this {\n return new ElectricCharge(baseValue, unit) as this;\n }\n\n get milliampereHours(): number {\n return this.in(ElectricChargeUnit.MilliampereHour);\n }\n get ampereHours(): number {\n return this.in(ElectricChargeUnit.AmpereHour);\n }\n get coulombs(): number {\n return this.in(ElectricChargeUnit.Coulomb);\n }\n\n /** Creates a electric charge from a value and unit. */\n static create(value: number | Decimal, unit: ElectricChargeUnit): ElectricCharge {\n ElectricChargeUnit.index.assertOwns(unit);\n const amount = value instanceof Decimal ? value : ElectricCharge.decimalOf(value);\n return new ElectricCharge(unit.toBase(amount), unit);\n }\n\n static fromMilliampereHours(value: number | Decimal): ElectricCharge {\n return ElectricCharge.create(value, ElectricChargeUnit.MilliampereHour);\n }\n static fromAmpereHours(value: number | Decimal): ElectricCharge {\n return ElectricCharge.create(value, ElectricChargeUnit.AmpereHour);\n }\n static fromCoulombs(value: number | Decimal): ElectricCharge {\n return ElectricCharge.create(value, ElectricChargeUnit.Coulomb);\n }\n\n static tryParse(input: string | null | undefined): ElectricCharge | null {\n const parsed = tryParseQuantity(input, ElectricChargeUnit.index);\n return parsed === null ? null : new ElectricCharge(parsed.baseValue, parsed.unit);\n }\n\n static parse(input: string): ElectricCharge {\n const result = ElectricCharge.tryParse(input);\n if (result === null) throw new Error(\"Invalid electric charge.\");\n return result;\n }\n\n static isValid(input: string | null | undefined): boolean {\n return ElectricCharge.tryParse(input) !== null;\n }\n\n /** Display form in the parsed unit, or `null` when the input is invalid. */\n static format(\n input: string | null | undefined,\n options?: ElectricChargeFormatOptions,\n ): string | null {\n const parsed = ElectricCharge.tryParse(input);\n if (parsed !== null) {\n if (options?.unit !== undefined || options?.decimals !== undefined) {\n return parsed.toStringInUnit(options.unit ?? parsed.originalUnit, options.decimals);\n }\n return parsed.toString();\n }\n return ElectricCharge.fallback(input, options);\n }\n\n /** The value in ampere-hours, or `null` when the input is invalid. */\n static normalize(\n input: string | null | undefined,\n options?: ElectricChargeFormatOptions,\n ): string | null {\n const parsed = ElectricCharge.tryParse(input);\n if (parsed !== null) return parsed.toNormalizedString();\n return ElectricCharge.fallback(input, options);\n }\n\n static isNormalized(input: string | null | undefined): boolean {\n return input != null && ElectricCharge.normalize(input) === input;\n }\n\n static findCandidatesInText(text: string): readonly TextCandidate<ElectricCharge>[] {\n if (!text) return [];\n\n const out: TextCandidate<ElectricCharge>[] = [];\n const pattern = new RegExp(SCAN_PATTERN.source, SCAN_PATTERN.flags);\n let match: RegExpExecArray | null;\n\n while ((match = pattern.exec(text)) !== null) {\n const value = ElectricCharge.tryParse(match[0]);\n if (value === null) continue;\n out.push(\n new TextCandidate<ElectricCharge>({\n startIndex: match.index,\n length: match[0].length,\n originalText: match[0],\n typeName: \"ElectricCharge\",\n category: TextCandidateCategory.Measurement,\n normalizedForm: value.toNormalizedString(),\n formattedForm: value.toString(),\n maskedForm: maskElectricCharge(value),\n confidence: TextMatchConfidence.Medium,\n value,\n }),\n );\n }\n\n return out;\n }\n\n private static fallback(\n input: string | null | undefined,\n options?: ElectricChargeFormatOptions,\n ): string | null {\n if (options?.fallbackToTrimmedInputWhenInvalid !== true) return null;\n if (input == null) return null;\n const trimmed = input.trim();\n return trimmed.length > 0 ? trimmed : null;\n }\n\n private static decimalOf(value: number): Decimal {\n const parsed = Decimal.fromNumber(value);\n if (parsed === null)\n throw new Error(`Value cannot be represented as a electric charge: ${value}`);\n return parsed;\n }\n}\n\n/** Returns a masked electric charge, e.g. `10 Ah` becomes `*** Ah`. */\nexport function maskElectricCharge(value: ElectricCharge): string {\n return `*** ${value.originalUnit.symbol}`;\n}\n"],
5
5
  "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -5,7 +5,7 @@ import { TextCandidateCategory } from "../text-scanning/text-candidate-category.
5
5
  import { TextMatchConfidence } from "../text-scanning/text-match-confidence.js";
6
6
  import { ElectricCurrentUnit } from "./electric-current-unit.js";
7
7
  const SCAN_PATTERN = new RegExp(
8
- String.raw`(?<!\w)(?:[+-]\s*)?\d+[0-9 .,]*\s*(?:µA|uA|mA|kA|A)\b`,
8
+ String.raw`(?<![\p{L}\p{N}_])(?:[+-]\s*)?\d+[0-9 .,]*\s*(?:µA|uA|mA|kA|A)(?![\p{L}\p{N}_])`,
9
9
  "giu"
10
10
  );
11
11
  class ElectricCurrent extends Quantity {