@accelint/geo 0.5.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +233 -1
  3. package/catalog-info.yaml +1 -1
  4. package/dist/cartesian.d.ts +2 -0
  5. package/dist/cartesian.js +2 -0
  6. package/dist/cartesian.js.map +1 -1
  7. package/dist/coordinates/coordinate.d.ts +41 -7
  8. package/dist/coordinates/coordinate.js +102 -12
  9. package/dist/coordinates/coordinate.js.map +1 -1
  10. package/dist/coordinates/latlon/decimal-degrees/formatter.d.ts +20 -0
  11. package/dist/coordinates/latlon/decimal-degrees/formatter.js +38 -0
  12. package/dist/coordinates/latlon/decimal-degrees/formatter.js.map +1 -1
  13. package/dist/coordinates/latlon/decimal-degrees/parser.d.ts +68 -2
  14. package/dist/coordinates/latlon/decimal-degrees/parser.js +66 -5
  15. package/dist/coordinates/latlon/decimal-degrees/parser.js.map +1 -1
  16. package/dist/coordinates/latlon/decimal-degrees/system.d.ts +32 -0
  17. package/dist/coordinates/latlon/decimal-degrees/system.js +31 -0
  18. package/dist/coordinates/latlon/decimal-degrees/system.js.map +1 -1
  19. package/dist/coordinates/latlon/degrees-decimal-minutes/formatter.d.ts +20 -0
  20. package/dist/coordinates/latlon/degrees-decimal-minutes/formatter.js +37 -0
  21. package/dist/coordinates/latlon/degrees-decimal-minutes/formatter.js.map +1 -1
  22. package/dist/coordinates/latlon/degrees-decimal-minutes/parser.d.ts +72 -2
  23. package/dist/coordinates/latlon/degrees-decimal-minutes/parser.js +66 -3
  24. package/dist/coordinates/latlon/degrees-decimal-minutes/parser.js.map +1 -1
  25. package/dist/coordinates/latlon/degrees-decimal-minutes/system.d.ts +32 -0
  26. package/dist/coordinates/latlon/degrees-decimal-minutes/system.js +31 -0
  27. package/dist/coordinates/latlon/degrees-decimal-minutes/system.js.map +1 -1
  28. package/dist/coordinates/latlon/degrees-minutes-seconds/formatter.d.ts +20 -0
  29. package/dist/coordinates/latlon/degrees-minutes-seconds/formatter.js +37 -0
  30. package/dist/coordinates/latlon/degrees-minutes-seconds/formatter.js.map +1 -1
  31. package/dist/coordinates/latlon/degrees-minutes-seconds/parser.d.ts +74 -2
  32. package/dist/coordinates/latlon/degrees-minutes-seconds/parser.js +66 -3
  33. package/dist/coordinates/latlon/degrees-minutes-seconds/parser.js.map +1 -1
  34. package/dist/coordinates/latlon/degrees-minutes-seconds/system.d.ts +32 -0
  35. package/dist/coordinates/latlon/degrees-minutes-seconds/system.js +31 -0
  36. package/dist/coordinates/latlon/degrees-minutes-seconds/system.js.map +1 -1
  37. package/dist/coordinates/latlon/internal/coordinate-system.d.ts +22 -0
  38. package/dist/coordinates/latlon/internal/create-cache.d.ts +17 -1
  39. package/dist/coordinates/latlon/internal/create-cache.js +19 -3
  40. package/dist/coordinates/latlon/internal/create-cache.js.map +1 -1
  41. package/dist/coordinates/latlon/internal/exhaustive-errors.d.ts +15 -0
  42. package/dist/coordinates/latlon/internal/exhaustive-errors.js +28 -0
  43. package/dist/coordinates/latlon/internal/exhaustive-errors.js.map +1 -1
  44. package/dist/coordinates/latlon/internal/format.d.ts +20 -0
  45. package/dist/coordinates/latlon/internal/format.js +20 -0
  46. package/dist/coordinates/latlon/internal/format.js.map +1 -1
  47. package/dist/coordinates/latlon/internal/in-range.d.ts +23 -0
  48. package/dist/coordinates/latlon/internal/in-range.js +24 -0
  49. package/dist/coordinates/latlon/internal/in-range.js.map +1 -1
  50. package/dist/coordinates/latlon/internal/index.d.ts +16 -1
  51. package/dist/coordinates/latlon/internal/index.js +25 -1
  52. package/dist/coordinates/latlon/internal/index.js.map +1 -1
  53. package/dist/coordinates/latlon/internal/lexer.d.ts +2 -0
  54. package/dist/coordinates/latlon/internal/lexer.js +26 -0
  55. package/dist/coordinates/latlon/internal/lexer.js.map +1 -1
  56. package/dist/coordinates/latlon/internal/normalize.d.ts +67 -0
  57. package/dist/coordinates/latlon/internal/normalize.js +87 -0
  58. package/dist/coordinates/latlon/internal/normalize.js.map +1 -0
  59. package/dist/coordinates/latlon/internal/ordinal.d.ts +25 -0
  60. package/dist/coordinates/latlon/internal/ordinal.js +25 -0
  61. package/dist/coordinates/latlon/internal/ordinal.js.map +1 -1
  62. package/dist/coordinates/latlon/internal/parse-format.d.ts +22 -0
  63. package/dist/coordinates/latlon/internal/parse-format.js +43 -1
  64. package/dist/coordinates/latlon/internal/parse-format.js.map +1 -1
  65. package/dist/coordinates/latlon/internal/parse.d.ts +2 -0
  66. package/dist/coordinates/latlon/internal/parse.js +4 -1
  67. package/dist/coordinates/latlon/internal/parse.js.map +1 -1
  68. package/dist/coordinates/latlon/internal/pipes/check-ambiguous.d.ts +17 -0
  69. package/dist/coordinates/latlon/internal/pipes/check-ambiguous.js +16 -0
  70. package/dist/coordinates/latlon/internal/pipes/check-ambiguous.js.map +1 -1
  71. package/dist/coordinates/latlon/internal/pipes/check-numbers.d.ts +25 -0
  72. package/dist/coordinates/latlon/internal/pipes/check-numbers.js +33 -0
  73. package/dist/coordinates/latlon/internal/pipes/check-numbers.js.map +1 -1
  74. package/dist/coordinates/latlon/internal/pipes/fix-bearings.d.ts +17 -0
  75. package/dist/coordinates/latlon/internal/pipes/fix-bearings.js +31 -0
  76. package/dist/coordinates/latlon/internal/pipes/fix-bearings.js.map +1 -1
  77. package/dist/coordinates/latlon/internal/pipes/fix-dividers.d.ts +17 -0
  78. package/dist/coordinates/latlon/internal/pipes/fix-dividers.js +29 -0
  79. package/dist/coordinates/latlon/internal/pipes/fix-dividers.js.map +1 -1
  80. package/dist/coordinates/latlon/internal/pipes/genome.d.ts +16 -0
  81. package/dist/coordinates/latlon/internal/pipes/genome.js +41 -0
  82. package/dist/coordinates/latlon/internal/pipes/genome.js.map +1 -1
  83. package/dist/coordinates/latlon/internal/pipes/index.d.ts +32 -2
  84. package/dist/coordinates/latlon/internal/pipes/index.js +57 -4
  85. package/dist/coordinates/latlon/internal/pipes/index.js.map +1 -1
  86. package/dist/coordinates/latlon/internal/pipes/simpler.d.ts +16 -3
  87. package/dist/coordinates/latlon/internal/pipes/simpler.js +15 -3
  88. package/dist/coordinates/latlon/internal/pipes/simpler.js.map +1 -1
  89. package/dist/coordinates/latlon/internal/validate.d.ts +75 -0
  90. package/dist/coordinates/latlon/internal/validate.js +105 -0
  91. package/dist/coordinates/latlon/internal/validate.js.map +1 -0
  92. package/dist/coordinates/latlon/internal/violation.d.ts +18 -0
  93. package/dist/coordinates/latlon/internal/violation.js +18 -0
  94. package/dist/coordinates/latlon/internal/violation.js.map +1 -1
  95. package/dist/coordinates/mgrs/parser.d.ts +24 -0
  96. package/dist/coordinates/mgrs/parser.js +56 -0
  97. package/dist/coordinates/mgrs/parser.js.map +1 -1
  98. package/dist/coordinates/mgrs/system.d.ts +31 -0
  99. package/dist/coordinates/mgrs/system.js +30 -0
  100. package/dist/coordinates/mgrs/system.js.map +1 -1
  101. package/dist/coordinates/utm/parser.d.ts +24 -0
  102. package/dist/coordinates/utm/parser.js +56 -0
  103. package/dist/coordinates/utm/parser.js.map +1 -1
  104. package/dist/coordinates/utm/system.d.ts +21 -0
  105. package/dist/coordinates/utm/system.js +20 -0
  106. package/dist/coordinates/utm/system.js.map +1 -1
  107. package/dist/index.d.ts +3 -1
  108. package/dist/index.js +3 -1
  109. package/dist/patterning.d.ts +12 -2
  110. package/dist/patterning.js +12 -2
  111. package/dist/patterning.js.map +1 -1
  112. package/package.json +3 -1
@@ -1 +1 @@
1
- {"version":3,"file":"formatter.js","names":[],"sources":["../../../../src/coordinates/latlon/decimal-degrees/formatter.ts"],"sourcesContent":["/*\n * Copyright 2025 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport { createFormatter } from '../internal/format';\n\nconst toDecimalDegrees = (num: number, withOrdinal?: boolean): string => {\n const value = withOrdinal ? Math.abs(num) : num;\n return `${value.toFixed(6)}°`;\n};\n\nexport const formatDecimalDegrees = createFormatter(toDecimalDegrees);\n"],"mappings":";;;;;;;;;;;;;;;;AAcA,MAAM,oBAAoB,KAAa,gBAAkC;AAEvE,QAAO,IADO,cAAc,KAAK,IAAI,IAAI,GAAG,KAC5B,QAAQ,EAAE,CAAC;;AAG7B,MAAa,uBAAuB,gBAAgB,iBAAiB"}
1
+ {"version":3,"file":"formatter.js","names":[],"sources":["../../../../src/coordinates/latlon/decimal-degrees/formatter.ts"],"sourcesContent":["/*\n * Copyright 2025 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport { createFormatter } from '../internal/format';\n\n/**\n * Converts a coordinate value to decimal degrees format.\n *\n * @param num - The coordinate value to format.\n * @param withOrdinal - Whether to use absolute value (when ordinal directions are shown separately).\n * @returns Formatted coordinate string with degree symbol and 6 decimal places.\n *\n * @example\n * ```typescript\n * toDecimalDegrees(45.123456);\n * // '45.123456°'\n * ```\n *\n * @example\n * ```typescript\n * toDecimalDegrees(-122.4194, true);\n * // '122.419400°'\n * ```\n */\nconst toDecimalDegrees = (num: number, withOrdinal?: boolean): string => {\n const value = withOrdinal ? Math.abs(num) : num;\n return `${value.toFixed(6)}°`;\n};\n\n/**\n * Formats latitude/longitude coordinates in decimal degrees notation.\n *\n * @param coordinates - Tuple of [latitude, longitude] values.\n * @param config - Optional formatting configuration.\n * @returns Formatted coordinate string in decimal degrees format.\n *\n * @example\n * ```typescript\n * formatDecimalDegrees([37.7749, -122.4194]);\n * // '37.774900° N, 122.419400° W'\n * ```\n *\n * @example\n * ```typescript\n * formatDecimalDegrees([37.7749, -122.4194], { separator: ' / ' });\n * // '37.774900° N / 122.419400° W'\n * ```\n */\nexport const formatDecimalDegrees = createFormatter(toDecimalDegrees);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiCA,MAAM,oBAAoB,KAAa,gBAAkC;AAEvE,QAAO,IADO,cAAc,KAAK,IAAI,IAAI,GAAG,KAC5B,QAAQ,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;;AAsB7B,MAAa,uBAAuB,gBAAgB,iBAAiB"}
@@ -14,8 +14,74 @@ import { Format } from "../internal/index.js";
14
14
  import { ParseResults } from "../internal/parse.js";
15
15
 
16
16
  //#region src/coordinates/latlon/decimal-degrees/parser.d.ts
17
- /** Parse a Decimal Degrees coordinate. */
17
+ type DecimalDegrees = {
18
+ bear: string;
19
+ deg: string;
20
+ };
21
+ /**
22
+ * Creates an error identification function for decimal degrees coordinates.
23
+ *
24
+ * Validates that degree values are within acceptable ranges and that
25
+ * minutes/seconds indicators are not present in decimal degrees notation.
26
+ *
27
+ * @param format - The coordinate format (LATLON or LONLAT).
28
+ * @returns Function that validates coordinate components and returns parse results.
29
+ *
30
+ * @example
31
+ * ```typescript
32
+ * const validator = identifyErrors('LATLON');
33
+ * const result = validator({ deg: '91', bear: 'N' }, 0);
34
+ * // [[], ['Degrees value (91) exceeds max value (90).']]
35
+ * ```
36
+ */
37
+ declare function identifyErrors(format: Format): (arg: DecimalDegrees | undefined, i: number) => ParseResults;
38
+ /**
39
+ * Identifies and organizes coordinate components from parsed tokens.
40
+ *
41
+ * Separates bearing indicators (N/S/E/W) from degree values in a coordinate half.
42
+ *
43
+ * @param half - Array of tokens representing one coordinate component.
44
+ * @returns Object with `bear` and `deg` properties, or undefined if invalid.
45
+ *
46
+ * @example
47
+ * ```typescript
48
+ * identifyPieces(['45.5', 'N']);
49
+ * // { bear: 'N', deg: '45.5' }
50
+ * ```
51
+ *
52
+ * @example
53
+ * ```typescript
54
+ * identifyPieces(['122.4', 'W']);
55
+ * // { bear: 'W', deg: '122.4' }
56
+ * ```
57
+ */
58
+ declare function identifyPieces(half: string[]): {
59
+ bear: string;
60
+ deg: string;
61
+ } | undefined;
62
+ /**
63
+ * Parses a Decimal Degrees coordinate string.
64
+ *
65
+ * Accepts coordinates in decimal degrees format with optional bearing indicators.
66
+ * Validates ranges and ensures no minutes/seconds indicators are present.
67
+ *
68
+ * @param input - Raw coordinate string to parse.
69
+ * @param format - Expected format (LATLON or LONLAT).
70
+ * @returns Parsed coordinate values or errors.
71
+ *
72
+ * @example
73
+ * ```typescript
74
+ * parseDecimalDegrees('37.7749° N / 122.4194° W', 'LATLON');
75
+ * // [[37.7749, -122.4194], []]
76
+ * ```
77
+ *
78
+ * @example
79
+ * ```typescript
80
+ * parseDecimalDegrees('45.5 N, 122.6 W');
81
+ * // [[45.5, -122.6], []]
82
+ * ```
83
+ */
18
84
  declare const parseDecimalDegrees: (format: Format, input: string) => ParseResults;
19
85
  //#endregion
20
- export { parseDecimalDegrees };
86
+ export { identifyErrors as _identifyErrors, identifyPieces as _identifyPieces, parseDecimalDegrees };
21
87
  //# sourceMappingURL=parser.d.ts.map
@@ -18,7 +18,9 @@ import { createParser } from "../internal/parse-format.js";
18
18
  //#region src/coordinates/latlon/decimal-degrees/parser.ts
19
19
  const checks = {
20
20
  deg: (deg, limit) => {
21
- if (Number.parseFloat(deg) > limit) return `Degrees value (${deg}) exceeds max value (${limit}).`;
21
+ const num = Number.parseFloat(deg);
22
+ if (Number.isNaN(num)) return `Degrees value (${deg}) is not a valid number.`;
23
+ if (num > limit) return `Degrees value (${deg}) exceeds max value (${limit}).`;
22
24
  },
23
25
  min: (val) => {
24
26
  if (val.includes(SYMBOLS.MINUTES)) return `Seconds indicator (${SYMBOLS.MINUTES}) not valid in Decimal Degrees.`;
@@ -31,6 +33,22 @@ const formats = {
31
33
  LATLON: fromTemplate(PARTIAL_PATTERNS, `degLatDec NS ${SYMBOLS.DIVIDER} degLonDec EW`),
32
34
  LONLAT: fromTemplate(PARTIAL_PATTERNS, `degLonDec EW ${SYMBOLS.DIVIDER} degLatDec NS`)
33
35
  };
36
+ /**
37
+ * Creates an error identification function for decimal degrees coordinates.
38
+ *
39
+ * Validates that degree values are within acceptable ranges and that
40
+ * minutes/seconds indicators are not present in decimal degrees notation.
41
+ *
42
+ * @param format - The coordinate format (LATLON or LONLAT).
43
+ * @returns Function that validates coordinate components and returns parse results.
44
+ *
45
+ * @example
46
+ * ```typescript
47
+ * const validator = identifyErrors('LATLON');
48
+ * const result = validator({ deg: '91', bear: 'N' }, 0);
49
+ * // [[], ['Degrees value (91) exceeds max value (90).']]
50
+ * ```
51
+ */
34
52
  function identifyErrors(format) {
35
53
  return (arg, i) => {
36
54
  if (!arg) return [[], ["Invalid coordinate value."]];
@@ -51,18 +69,61 @@ function identifyErrors(format) {
51
69
  return errors.length ? [[], errors] : [[deg, bear], []];
52
70
  };
53
71
  }
72
+ /**
73
+ * Identifies and organizes coordinate components from parsed tokens.
74
+ *
75
+ * Separates bearing indicators (N/S/E/W) from degree values in a coordinate half.
76
+ *
77
+ * @param half - Array of tokens representing one coordinate component.
78
+ * @returns Object with `bear` and `deg` properties, or undefined if invalid.
79
+ *
80
+ * @example
81
+ * ```typescript
82
+ * identifyPieces(['45.5', 'N']);
83
+ * // { bear: 'N', deg: '45.5' }
84
+ * ```
85
+ *
86
+ * @example
87
+ * ```typescript
88
+ * identifyPieces(['122.4', 'W']);
89
+ * // { bear: 'W', deg: '122.4' }
90
+ * ```
91
+ */
54
92
  function identifyPieces(half) {
55
93
  if (half.length > 2 || half.length < 1) return;
56
94
  return half.reduce((acc, token) => {
57
- if (SYMBOL_PATTERNS.NSEW.test(token) && !acc.bear) acc.bear ||= token;
58
- else acc.deg ||= token;
95
+ const isBearing = SYMBOL_PATTERNS.NSEW.test(token) && !acc?.bear;
96
+ if (!acc || !isBearing && acc.deg) return;
97
+ if (isBearing) acc.bear = token;
98
+ else acc.deg = token;
59
99
  return acc;
60
100
  }, {
61
101
  bear: "",
62
102
  deg: ""
63
103
  });
64
104
  }
65
- /** Parse a Decimal Degrees coordinate. */
105
+ /**
106
+ * Parses a Decimal Degrees coordinate string.
107
+ *
108
+ * Accepts coordinates in decimal degrees format with optional bearing indicators.
109
+ * Validates ranges and ensures no minutes/seconds indicators are present.
110
+ *
111
+ * @param input - Raw coordinate string to parse.
112
+ * @param format - Expected format (LATLON or LONLAT).
113
+ * @returns Parsed coordinate values or errors.
114
+ *
115
+ * @example
116
+ * ```typescript
117
+ * parseDecimalDegrees('37.7749° N / 122.4194° W', 'LATLON');
118
+ * // [[37.7749, -122.4194], []]
119
+ * ```
120
+ *
121
+ * @example
122
+ * ```typescript
123
+ * parseDecimalDegrees('45.5 N, 122.6 W');
124
+ * // [[45.5, -122.6], []]
125
+ * ```
126
+ */
66
127
  const parseDecimalDegrees = createParser({
67
128
  formats,
68
129
  identifyErrors,
@@ -70,5 +131,5 @@ const parseDecimalDegrees = createParser({
70
131
  });
71
132
 
72
133
  //#endregion
73
- export { parseDecimalDegrees };
134
+ export { identifyErrors as _identifyErrors, identifyPieces as _identifyPieces, parseDecimalDegrees };
74
135
  //# sourceMappingURL=parser.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"parser.js","names":["Patterning.fromTemplate","isNegative: 0 | 1"],"sources":["../../../../src/coordinates/latlon/decimal-degrees/parser.ts"],"sourcesContent":["/*\n * Copyright 2024 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport * as Patterning from '@/patterning';\nimport {\n BEARINGS,\n type Format,\n LIMITS,\n PARTIAL_PATTERNS,\n SYMBOL_PATTERNS,\n SYMBOLS,\n} from '../internal';\nimport { createParser } from '../internal/parse-format';\nimport type { ParseResults } from '../internal/parse';\n\ntype DecimalDegrees = {\n bear: string;\n deg: string;\n};\n\nconst checks = {\n deg: (deg: string, limit: number) => {\n if (Number.parseFloat(deg) > limit) {\n return `Degrees value (${deg}) exceeds max value (${limit}).`;\n }\n },\n min: (val: string) => {\n if (val.includes(SYMBOLS.MINUTES)) {\n return `Seconds indicator (${SYMBOLS.MINUTES}) not valid in Decimal Degrees.`;\n }\n },\n sec: (val: string) => {\n if (val.includes(SYMBOLS.SECONDS)) {\n return `Seconds indicator (${SYMBOLS.SECONDS}) not valid in Decimal Degrees.`;\n }\n },\n};\n\nconst formats = {\n LATLON: Patterning.fromTemplate(\n PARTIAL_PATTERNS,\n `degLatDec NS ${SYMBOLS.DIVIDER} degLonDec EW`,\n ),\n LONLAT: Patterning.fromTemplate(\n PARTIAL_PATTERNS,\n `degLonDec EW ${SYMBOLS.DIVIDER} degLatDec NS`,\n ),\n};\n\nfunction identifyErrors(format: Format) {\n return (arg: DecimalDegrees | undefined, i: number) => {\n if (!arg) {\n return [[], ['Invalid coordinate value.']] as ParseResults;\n }\n\n let { bear, deg } = arg;\n\n deg ??= '0';\n\n let isNegative: 0 | 1 = SYMBOL_PATTERNS.NEGATIVE_SIGN.test(deg) ? 1 : 0;\n const bearingOptions = BEARINGS[format][i] as [string, string];\n\n if (!bear || isNegative) {\n bear = bearingOptions[isNegative];\n deg = Math.abs(Number.parseFloat(deg)).toString();\n isNegative = 0;\n }\n\n const errors = [\n ...[checks.deg(deg, LIMITS[format][i] ?? 0)],\n ...[checks.min([bear, deg].join(''))],\n ...[checks.sec([bear, deg].join(''))],\n ].filter(Boolean);\n\n return (errors.length ? [[], errors] : [[deg, bear], []]) as ParseResults;\n };\n}\n\nfunction identifyPieces(half: string[]) {\n if (half.length > 2 || half.length < 1) {\n return;\n }\n\n const places = { bear: '', deg: '' };\n\n return half.reduce((acc, token) => {\n if (SYMBOL_PATTERNS.NSEW.test(token) && !acc.bear) {\n acc.bear ||= token;\n } else {\n acc.deg ||= token;\n }\n\n return acc;\n }, places);\n}\n\n/** Parse a Decimal Degrees coordinate. */\nexport const parseDecimalDegrees = createParser<DecimalDegrees>({\n formats,\n identifyErrors,\n identifyPieces,\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;AA6BA,MAAM,SAAS;CACb,MAAM,KAAa,UAAkB;AACnC,MAAI,OAAO,WAAW,IAAI,GAAG,MAC3B,QAAO,kBAAkB,IAAI,uBAAuB,MAAM;;CAG9D,MAAM,QAAgB;AACpB,MAAI,IAAI,SAAS,QAAQ,QAAQ,CAC/B,QAAO,sBAAsB,QAAQ,QAAQ;;CAGjD,MAAM,QAAgB;AACpB,MAAI,IAAI,SAAS,QAAQ,QAAQ,CAC/B,QAAO,sBAAsB,QAAQ,QAAQ;;CAGlD;AAED,MAAM,UAAU;CACd,QAAQA,aACN,kBACA,gBAAgB,QAAQ,QAAQ,eACjC;CACD,QAAQA,aACN,kBACA,gBAAgB,QAAQ,QAAQ,eACjC;CACF;AAED,SAAS,eAAe,QAAgB;AACtC,SAAQ,KAAiC,MAAc;AACrD,MAAI,CAAC,IACH,QAAO,CAAC,EAAE,EAAE,CAAC,4BAA4B,CAAC;EAG5C,IAAI,EAAE,MAAM,QAAQ;AAEpB,UAAQ;EAER,IAAIC,aAAoB,gBAAgB,cAAc,KAAK,IAAI,GAAG,IAAI;EACtE,MAAM,iBAAiB,SAAS,QAAQ;AAExC,MAAI,CAAC,QAAQ,YAAY;AACvB,UAAO,eAAe;AACtB,SAAM,KAAK,IAAI,OAAO,WAAW,IAAI,CAAC,CAAC,UAAU;AACjD,gBAAa;;EAGf,MAAM,SAAS;GACb,GAAG,CAAC,OAAO,IAAI,KAAK,OAAO,QAAQ,MAAM,EAAE,CAAC;GAC5C,GAAG,CAAC,OAAO,IAAI,CAAC,MAAM,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;GACrC,GAAG,CAAC,OAAO,IAAI,CAAC,MAAM,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;GACtC,CAAC,OAAO,QAAQ;AAEjB,SAAQ,OAAO,SAAS,CAAC,EAAE,EAAE,OAAO,GAAG,CAAC,CAAC,KAAK,KAAK,EAAE,EAAE,CAAC;;;AAI5D,SAAS,eAAe,MAAgB;AACtC,KAAI,KAAK,SAAS,KAAK,KAAK,SAAS,EACnC;AAKF,QAAO,KAAK,QAAQ,KAAK,UAAU;AACjC,MAAI,gBAAgB,KAAK,KAAK,MAAM,IAAI,CAAC,IAAI,KAC3C,KAAI,SAAS;MAEb,KAAI,QAAQ;AAGd,SAAO;IATM;EAAE,MAAM;EAAI,KAAK;EAAI,CAU1B;;;AAIZ,MAAa,sBAAsB,aAA6B;CAC9D;CACA;CACA;CACD,CAAC"}
1
+ {"version":3,"file":"parser.js","names":["Patterning.fromTemplate","isNegative: 0 | 1"],"sources":["../../../../src/coordinates/latlon/decimal-degrees/parser.ts"],"sourcesContent":["/*\n * Copyright 2024 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport * as Patterning from '@/patterning';\nimport {\n BEARINGS,\n type Format,\n LIMITS,\n PARTIAL_PATTERNS,\n SYMBOL_PATTERNS,\n SYMBOLS,\n} from '../internal';\nimport { createParser } from '../internal/parse-format';\nimport type { ParseResults } from '../internal/parse';\n\ntype DecimalDegrees = {\n bear: string;\n deg: string;\n};\n\nconst checks = {\n deg: (deg: string, limit: number) => {\n const num = Number.parseFloat(deg);\n if (Number.isNaN(num)) {\n return `Degrees value (${deg}) is not a valid number.`;\n }\n if (num > limit) {\n return `Degrees value (${deg}) exceeds max value (${limit}).`;\n }\n },\n min: (val: string) => {\n if (val.includes(SYMBOLS.MINUTES)) {\n return `Seconds indicator (${SYMBOLS.MINUTES}) not valid in Decimal Degrees.`;\n }\n },\n sec: (val: string) => {\n if (val.includes(SYMBOLS.SECONDS)) {\n return `Seconds indicator (${SYMBOLS.SECONDS}) not valid in Decimal Degrees.`;\n }\n },\n};\n\nconst formats = {\n LATLON: Patterning.fromTemplate(\n PARTIAL_PATTERNS,\n `degLatDec NS ${SYMBOLS.DIVIDER} degLonDec EW`,\n ),\n LONLAT: Patterning.fromTemplate(\n PARTIAL_PATTERNS,\n `degLonDec EW ${SYMBOLS.DIVIDER} degLatDec NS`,\n ),\n};\n\n/**\n * Creates an error identification function for decimal degrees coordinates.\n *\n * Validates that degree values are within acceptable ranges and that\n * minutes/seconds indicators are not present in decimal degrees notation.\n *\n * @param format - The coordinate format (LATLON or LONLAT).\n * @returns Function that validates coordinate components and returns parse results.\n *\n * @example\n * ```typescript\n * const validator = identifyErrors('LATLON');\n * const result = validator({ deg: '91', bear: 'N' }, 0);\n * // [[], ['Degrees value (91) exceeds max value (90).']]\n * ```\n */\nfunction identifyErrors(format: Format) {\n return (arg: DecimalDegrees | undefined, i: number) => {\n if (!arg) {\n return [[], ['Invalid coordinate value.']] as ParseResults;\n }\n\n let { bear, deg } = arg;\n\n deg ??= '0';\n\n let isNegative: 0 | 1 = SYMBOL_PATTERNS.NEGATIVE_SIGN.test(deg) ? 1 : 0;\n const bearingOptions = BEARINGS[format][i] as [string, string];\n\n if (!bear || isNegative) {\n bear = bearingOptions[isNegative];\n deg = Math.abs(Number.parseFloat(deg)).toString();\n isNegative = 0;\n }\n\n const errors = [\n ...[checks.deg(deg, LIMITS[format][i] ?? 0)],\n ...[checks.min([bear, deg].join(''))],\n ...[checks.sec([bear, deg].join(''))],\n ].filter(Boolean);\n\n return (errors.length ? [[], errors] : [[deg, bear], []]) as ParseResults;\n };\n}\n\n/**\n * Identifies and organizes coordinate components from parsed tokens.\n *\n * Separates bearing indicators (N/S/E/W) from degree values in a coordinate half.\n *\n * @param half - Array of tokens representing one coordinate component.\n * @returns Object with `bear` and `deg` properties, or undefined if invalid.\n *\n * @example\n * ```typescript\n * identifyPieces(['45.5', 'N']);\n * // { bear: 'N', deg: '45.5' }\n * ```\n *\n * @example\n * ```typescript\n * identifyPieces(['122.4', 'W']);\n * // { bear: 'W', deg: '122.4' }\n * ```\n */\nfunction identifyPieces(half: string[]) {\n if (half.length > 2 || half.length < 1) {\n return;\n }\n\n const places = { bear: '', deg: '' };\n\n return half.reduce<typeof places | undefined>((acc, token) => {\n const isBearing = SYMBOL_PATTERNS.NSEW.test(token) && !acc?.bear;\n\n if (!acc || (!isBearing && acc.deg)) {\n return undefined;\n }\n\n if (isBearing) {\n acc.bear = token;\n } else {\n acc.deg = token;\n }\n\n return acc;\n }, places);\n}\n\n/**\n * Parses a Decimal Degrees coordinate string.\n *\n * Accepts coordinates in decimal degrees format with optional bearing indicators.\n * Validates ranges and ensures no minutes/seconds indicators are present.\n *\n * @param input - Raw coordinate string to parse.\n * @param format - Expected format (LATLON or LONLAT).\n * @returns Parsed coordinate values or errors.\n *\n * @example\n * ```typescript\n * parseDecimalDegrees('37.7749° N / 122.4194° W', 'LATLON');\n * // [[37.7749, -122.4194], []]\n * ```\n *\n * @example\n * ```typescript\n * parseDecimalDegrees('45.5 N, 122.6 W');\n * // [[45.5, -122.6], []]\n * ```\n */\nexport const parseDecimalDegrees = createParser<DecimalDegrees>({\n formats,\n identifyErrors,\n identifyPieces,\n});\n\nexport { identifyErrors as _identifyErrors, identifyPieces as _identifyPieces };\n"],"mappings":";;;;;;;;;;;;;;;;;;AA6BA,MAAM,SAAS;CACb,MAAM,KAAa,UAAkB;EACnC,MAAM,MAAM,OAAO,WAAW,IAAI;AAClC,MAAI,OAAO,MAAM,IAAI,CACnB,QAAO,kBAAkB,IAAI;AAE/B,MAAI,MAAM,MACR,QAAO,kBAAkB,IAAI,uBAAuB,MAAM;;CAG9D,MAAM,QAAgB;AACpB,MAAI,IAAI,SAAS,QAAQ,QAAQ,CAC/B,QAAO,sBAAsB,QAAQ,QAAQ;;CAGjD,MAAM,QAAgB;AACpB,MAAI,IAAI,SAAS,QAAQ,QAAQ,CAC/B,QAAO,sBAAsB,QAAQ,QAAQ;;CAGlD;AAED,MAAM,UAAU;CACd,QAAQA,aACN,kBACA,gBAAgB,QAAQ,QAAQ,eACjC;CACD,QAAQA,aACN,kBACA,gBAAgB,QAAQ,QAAQ,eACjC;CACF;;;;;;;;;;;;;;;;;AAkBD,SAAS,eAAe,QAAgB;AACtC,SAAQ,KAAiC,MAAc;AACrD,MAAI,CAAC,IACH,QAAO,CAAC,EAAE,EAAE,CAAC,4BAA4B,CAAC;EAG5C,IAAI,EAAE,MAAM,QAAQ;AAEpB,UAAQ;EAER,IAAIC,aAAoB,gBAAgB,cAAc,KAAK,IAAI,GAAG,IAAI;EACtE,MAAM,iBAAiB,SAAS,QAAQ;AAExC,MAAI,CAAC,QAAQ,YAAY;AACvB,UAAO,eAAe;AACtB,SAAM,KAAK,IAAI,OAAO,WAAW,IAAI,CAAC,CAAC,UAAU;AACjD,gBAAa;;EAGf,MAAM,SAAS;GACb,GAAG,CAAC,OAAO,IAAI,KAAK,OAAO,QAAQ,MAAM,EAAE,CAAC;GAC5C,GAAG,CAAC,OAAO,IAAI,CAAC,MAAM,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;GACrC,GAAG,CAAC,OAAO,IAAI,CAAC,MAAM,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;GACtC,CAAC,OAAO,QAAQ;AAEjB,SAAQ,OAAO,SAAS,CAAC,EAAE,EAAE,OAAO,GAAG,CAAC,CAAC,KAAK,KAAK,EAAE,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;AAwB5D,SAAS,eAAe,MAAgB;AACtC,KAAI,KAAK,SAAS,KAAK,KAAK,SAAS,EACnC;AAKF,QAAO,KAAK,QAAmC,KAAK,UAAU;EAC5D,MAAM,YAAY,gBAAgB,KAAK,KAAK,MAAM,IAAI,CAAC,KAAK;AAE5D,MAAI,CAAC,OAAQ,CAAC,aAAa,IAAI,IAC7B;AAGF,MAAI,UACF,KAAI,OAAO;MAEX,KAAI,MAAM;AAGZ,SAAO;IAfM;EAAE,MAAM;EAAI,KAAK;EAAI,CAgB1B;;;;;;;;;;;;;;;;;;;;;;;;AAyBZ,MAAa,sBAAsB,aAA6B;CAC9D;CACA;CACA;CACD,CAAC"}
@@ -13,6 +13,38 @@
13
13
  import { CoordinateSystem } from "../internal/coordinate-system.js";
14
14
 
15
15
  //#region src/coordinates/latlon/decimal-degrees/system.d.ts
16
+
17
+ /**
18
+ * Decimal Degrees coordinate system implementation.
19
+ *
20
+ * Provides parsing, conversion, and formatting for coordinates in decimal degrees notation.
21
+ * Coordinates are expressed as decimal numbers with degree symbols (e.g., 37.7749° N).
22
+ *
23
+ * @property name - Human-readable name of the coordinate system.
24
+ * @property parse - Parses decimal degrees coordinate strings.
25
+ * @property toFloat - Converts parsed coordinate components to floating point numbers.
26
+ * @property toFormat - Formats numeric coordinates back to decimal degrees string.
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * // Parse a coordinate string
31
+ * const [coords, errors] = systemDecimalDegrees.parse('37.7749° N / 122.4194° W', 'LATLON');
32
+ * ```
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * // Convert to float
37
+ * const lat = systemDecimalDegrees.toFloat(['37.7749', 'N']);
38
+ * // 37.7749
39
+ * ```
40
+ *
41
+ * @example
42
+ * ```ts
43
+ * // Format to string
44
+ * const formatted = systemDecimalDegrees.toFormat('LATLON', [37.7749, -122.4194]);
45
+ * // '37.7749 N / 122.4194 W'
46
+ * ```
47
+ */
16
48
  declare const systemDecimalDegrees: CoordinateSystem;
17
49
  //#endregion
18
50
  export { systemDecimalDegrees };
@@ -15,6 +15,37 @@ import { BEARINGS, SYMBOLS, SYMBOL_PATTERNS } from "../internal/index.js";
15
15
  import { parseDecimalDegrees } from "./parser.js";
16
16
 
17
17
  //#region src/coordinates/latlon/decimal-degrees/system.ts
18
+ /**
19
+ * Decimal Degrees coordinate system implementation.
20
+ *
21
+ * Provides parsing, conversion, and formatting for coordinates in decimal degrees notation.
22
+ * Coordinates are expressed as decimal numbers with degree symbols (e.g., 37.7749° N).
23
+ *
24
+ * @property name - Human-readable name of the coordinate system.
25
+ * @property parse - Parses decimal degrees coordinate strings.
26
+ * @property toFloat - Converts parsed coordinate components to floating point numbers.
27
+ * @property toFormat - Formats numeric coordinates back to decimal degrees string.
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * // Parse a coordinate string
32
+ * const [coords, errors] = systemDecimalDegrees.parse('37.7749° N / 122.4194° W', 'LATLON');
33
+ * ```
34
+ *
35
+ * @example
36
+ * ```ts
37
+ * // Convert to float
38
+ * const lat = systemDecimalDegrees.toFloat(['37.7749', 'N']);
39
+ * // 37.7749
40
+ * ```
41
+ *
42
+ * @example
43
+ * ```ts
44
+ * // Format to string
45
+ * const formatted = systemDecimalDegrees.toFormat('LATLON', [37.7749, -122.4194]);
46
+ * // '37.7749 N / 122.4194 W'
47
+ * ```
48
+ */
18
49
  const systemDecimalDegrees = {
19
50
  name: "Decimal Degrees",
20
51
  parse: parseDecimalDegrees,
@@ -1 +1 @@
1
- {"version":3,"file":"system.js","names":["systemDecimalDegrees: CoordinateSystem"],"sources":["../../../../src/coordinates/latlon/decimal-degrees/system.ts"],"sourcesContent":["// __private-exports\n/*\n * Copyright 2024 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {\n BEARINGS,\n type Compass,\n type Format,\n SYMBOL_PATTERNS,\n SYMBOLS,\n} from '../internal';\nimport { parseDecimalDegrees } from './parser';\nimport type { CoordinateSystem } from '../internal/coordinate-system';\n\nexport const systemDecimalDegrees: CoordinateSystem = {\n name: 'Decimal Degrees',\n\n parse: parseDecimalDegrees,\n\n toFloat(arg) {\n const [num, bear] = arg as [string, Compass];\n\n return (\n Number.parseFloat(num) *\n (SYMBOL_PATTERNS.NEGATIVE_BEARINGS.test(bear) ? -1 : 1)\n );\n },\n\n toFormat(format: Format, [left, right]: [number, number]) {\n return [left, right]\n .map(\n (num, index) =>\n `${Math.abs(num)} ${BEARINGS[format][index as 0 | 1][+(num < 0)]}`,\n )\n .join(` ${SYMBOLS.DIVIDER} `);\n },\n};\n"],"mappings":";;;;;;;;;;;;;;;;;AAuBA,MAAaA,uBAAyC;CACpD,MAAM;CAEN,OAAO;CAEP,QAAQ,KAAK;EACX,MAAM,CAAC,KAAK,QAAQ;AAEpB,SACE,OAAO,WAAW,IAAI,IACrB,gBAAgB,kBAAkB,KAAK,KAAK,GAAG,KAAK;;CAIzD,SAAS,QAAgB,CAAC,MAAM,QAA0B;AACxD,SAAO,CAAC,MAAM,MAAM,CACjB,KACE,KAAK,UACJ,GAAG,KAAK,IAAI,IAAI,CAAC,GAAG,SAAS,QAAQ,OAAgB,EAAE,MAAM,MAChE,CACA,KAAK,IAAI,QAAQ,QAAQ,GAAG;;CAElC"}
1
+ {"version":3,"file":"system.js","names":["systemDecimalDegrees: CoordinateSystem"],"sources":["../../../../src/coordinates/latlon/decimal-degrees/system.ts"],"sourcesContent":["// __private-exports\n/*\n * Copyright 2024 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {\n BEARINGS,\n type Compass,\n type Format,\n SYMBOL_PATTERNS,\n SYMBOLS,\n} from '../internal';\nimport { parseDecimalDegrees } from './parser';\nimport type { CoordinateSystem } from '../internal/coordinate-system';\n\n/**\n * Decimal Degrees coordinate system implementation.\n *\n * Provides parsing, conversion, and formatting for coordinates in decimal degrees notation.\n * Coordinates are expressed as decimal numbers with degree symbols (e.g., 37.7749° N).\n *\n * @property name - Human-readable name of the coordinate system.\n * @property parse - Parses decimal degrees coordinate strings.\n * @property toFloat - Converts parsed coordinate components to floating point numbers.\n * @property toFormat - Formats numeric coordinates back to decimal degrees string.\n *\n * @example\n * ```ts\n * // Parse a coordinate string\n * const [coords, errors] = systemDecimalDegrees.parse('37.7749° N / 122.4194° W', 'LATLON');\n * ```\n *\n * @example\n * ```ts\n * // Convert to float\n * const lat = systemDecimalDegrees.toFloat(['37.7749', 'N']);\n * // 37.7749\n * ```\n *\n * @example\n * ```ts\n * // Format to string\n * const formatted = systemDecimalDegrees.toFormat('LATLON', [37.7749, -122.4194]);\n * // '37.7749 N / 122.4194 W'\n * ```\n */\nexport const systemDecimalDegrees: CoordinateSystem = {\n name: 'Decimal Degrees',\n\n parse: parseDecimalDegrees,\n\n toFloat(arg) {\n const [num, bear] = arg as [string, Compass];\n\n return (\n Number.parseFloat(num) *\n (SYMBOL_PATTERNS.NEGATIVE_BEARINGS.test(bear) ? -1 : 1)\n );\n },\n\n toFormat(format: Format, [left, right]: [number, number]) {\n return [left, right]\n .map(\n (num, index) =>\n `${Math.abs(num)} ${BEARINGS[format][index as 0 | 1][+(num < 0)]}`,\n )\n .join(` ${SYMBOLS.DIVIDER} `);\n },\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsDA,MAAaA,uBAAyC;CACpD,MAAM;CAEN,OAAO;CAEP,QAAQ,KAAK;EACX,MAAM,CAAC,KAAK,QAAQ;AAEpB,SACE,OAAO,WAAW,IAAI,IACrB,gBAAgB,kBAAkB,KAAK,KAAK,GAAG,KAAK;;CAIzD,SAAS,QAAgB,CAAC,MAAM,QAA0B;AACxD,SAAO,CAAC,MAAM,MAAM,CACjB,KACE,KAAK,UACJ,GAAG,KAAK,IAAI,IAAI,CAAC,GAAG,SAAS,QAAQ,OAAgB,EAAE,MAAM,MAChE,CACA,KAAK,IAAI,QAAQ,QAAQ,GAAG;;CAElC"}
@@ -13,6 +13,26 @@
13
13
  import { FormatOptions } from "../internal/format.js";
14
14
 
15
15
  //#region src/coordinates/latlon/degrees-decimal-minutes/formatter.d.ts
16
+
17
+ /**
18
+ * Formats latitude/longitude coordinates in degrees decimal minutes notation.
19
+ *
20
+ * @param coordinates - Tuple of [latitude, longitude] values.
21
+ * @param config - Optional formatting configuration.
22
+ * @returns Formatted coordinate string in degrees decimal minutes format.
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * formatDegreesDecimalMinutes([37.7749, -122.4194]);
27
+ * // '37° 46.4940' N, 122° 25.1640' W'
28
+ * ```
29
+ *
30
+ * @example
31
+ * ```typescript
32
+ * formatDegreesDecimalMinutes([37.7749, -122.4194], { separator: ' / ' });
33
+ * // '37° 46.4940' N / 122° 25.1640' W'
34
+ * ```
35
+ */
16
36
  declare const formatDegreesDecimalMinutes: (coordinates: [number, number], config?: FormatOptions) => string;
17
37
  //#endregion
18
38
  export { formatDegreesDecimalMinutes };
@@ -14,10 +14,47 @@
14
14
  import { createFormatter } from "../internal/format.js";
15
15
 
16
16
  //#region src/coordinates/latlon/degrees-decimal-minutes/formatter.ts
17
+ /**
18
+ * Converts a coordinate value to degrees decimal minutes format.
19
+ *
20
+ * @param num - The coordinate value to format.
21
+ * @returns Formatted coordinate string with degrees and decimal minutes (e.g., "45° 30.1234'").
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * toDegreesDecimalMinutes(45.5);
26
+ * // '45° 30.0000''
27
+ * ```
28
+ *
29
+ * @example
30
+ * ```typescript
31
+ * toDegreesDecimalMinutes(-122.4194);
32
+ * // '122° 25.1640''
33
+ * ```
34
+ */
17
35
  const toDegreesDecimalMinutes = (num) => {
18
36
  const degrees = Math.floor(Math.abs(num));
19
37
  return `${degrees}° ${((Math.abs(num) - degrees) * 60).toFixed(4)}'`;
20
38
  };
39
+ /**
40
+ * Formats latitude/longitude coordinates in degrees decimal minutes notation.
41
+ *
42
+ * @param coordinates - Tuple of [latitude, longitude] values.
43
+ * @param config - Optional formatting configuration.
44
+ * @returns Formatted coordinate string in degrees decimal minutes format.
45
+ *
46
+ * @example
47
+ * ```typescript
48
+ * formatDegreesDecimalMinutes([37.7749, -122.4194]);
49
+ * // '37° 46.4940' N, 122° 25.1640' W'
50
+ * ```
51
+ *
52
+ * @example
53
+ * ```typescript
54
+ * formatDegreesDecimalMinutes([37.7749, -122.4194], { separator: ' / ' });
55
+ * // '37° 46.4940' N / 122° 25.1640' W'
56
+ * ```
57
+ */
21
58
  const formatDegreesDecimalMinutes = createFormatter(toDegreesDecimalMinutes);
22
59
 
23
60
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"formatter.js","names":[],"sources":["../../../../src/coordinates/latlon/degrees-decimal-minutes/formatter.ts"],"sourcesContent":["/*\n * Copyright 2025 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport { createFormatter } from '../internal/format';\n\nconst toDegreesDecimalMinutes = (num: number): string => {\n const degrees = Math.floor(Math.abs(num));\n const minutes = ((Math.abs(num) - degrees) * 60).toFixed(4);\n\n return `${degrees}° ${minutes}'`;\n};\n\nexport const formatDegreesDecimalMinutes = createFormatter(\n toDegreesDecimalMinutes,\n);\n"],"mappings":";;;;;;;;;;;;;;;;AAcA,MAAM,2BAA2B,QAAwB;CACvD,MAAM,UAAU,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC;AAGzC,QAAO,GAAG,QAAQ,MAFA,KAAK,IAAI,IAAI,GAAG,WAAW,IAAI,QAAQ,EAAE,CAE7B;;AAGhC,MAAa,8BAA8B,gBACzC,wBACD"}
1
+ {"version":3,"file":"formatter.js","names":[],"sources":["../../../../src/coordinates/latlon/degrees-decimal-minutes/formatter.ts"],"sourcesContent":["/*\n * Copyright 2025 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport { createFormatter } from '../internal/format';\n\n/**\n * Converts a coordinate value to degrees decimal minutes format.\n *\n * @param num - The coordinate value to format.\n * @returns Formatted coordinate string with degrees and decimal minutes (e.g., \"45° 30.1234'\").\n *\n * @example\n * ```typescript\n * toDegreesDecimalMinutes(45.5);\n * // '45° 30.0000''\n * ```\n *\n * @example\n * ```typescript\n * toDegreesDecimalMinutes(-122.4194);\n * // '122° 25.1640''\n * ```\n */\nconst toDegreesDecimalMinutes = (num: number): string => {\n const degrees = Math.floor(Math.abs(num));\n const minutes = ((Math.abs(num) - degrees) * 60).toFixed(4);\n\n return `${degrees}° ${minutes}'`;\n};\n\n/**\n * Formats latitude/longitude coordinates in degrees decimal minutes notation.\n *\n * @param coordinates - Tuple of [latitude, longitude] values.\n * @param config - Optional formatting configuration.\n * @returns Formatted coordinate string in degrees decimal minutes format.\n *\n * @example\n * ```typescript\n * formatDegreesDecimalMinutes([37.7749, -122.4194]);\n * // '37° 46.4940' N, 122° 25.1640' W'\n * ```\n *\n * @example\n * ```typescript\n * formatDegreesDecimalMinutes([37.7749, -122.4194], { separator: ' / ' });\n * // '37° 46.4940' N / 122° 25.1640' W'\n * ```\n */\nexport const formatDegreesDecimalMinutes = createFormatter(\n toDegreesDecimalMinutes,\n);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,MAAM,2BAA2B,QAAwB;CACvD,MAAM,UAAU,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC;AAGzC,QAAO,GAAG,QAAQ,MAFA,KAAK,IAAI,IAAI,GAAG,WAAW,IAAI,QAAQ,EAAE,CAE7B;;;;;;;;;;;;;;;;;;;;;AAsBhC,MAAa,8BAA8B,gBACzC,wBACD"}
@@ -14,8 +14,78 @@ import { Format } from "../internal/index.js";
14
14
  import { ParseResults } from "../internal/parse.js";
15
15
 
16
16
  //#region src/coordinates/latlon/degrees-decimal-minutes/parser.d.ts
17
- /** Parse a Degrees Decimal Minutes coordinate. */
17
+ type DegreesDecimalMinutes = {
18
+ bear: string;
19
+ deg: string;
20
+ min: string;
21
+ };
22
+ /**
23
+ * Creates an error identification function for degrees decimal minutes coordinates.
24
+ *
25
+ * Validates that degree values are integers, minutes are in valid range (0-59.999...),
26
+ * and that seconds indicators are not present.
27
+ *
28
+ * @param format - The coordinate format (LATLON or LONLAT).
29
+ * @returns Function that validates coordinate components and returns parse results.
30
+ *
31
+ * @example
32
+ * ```typescript
33
+ * const validator = identifyErrors('LATLON');
34
+ * const result = validator({ deg: '91', min: '0', bear: 'N' }, 0);
35
+ * // [[], ['Degrees value (91) exceeds max value (90).']]
36
+ * ```
37
+ */
38
+ declare function identifyErrors(format: Format): (arg: DegreesDecimalMinutes | undefined, i: number) => ParseResults;
39
+ /**
40
+ * Identifies and organizes coordinate components from parsed tokens.
41
+ *
42
+ * Separates bearing indicators (N/S/E/W), degree values, and minute values from tokens.
43
+ * Uses symbol patterns to identify component types and positional logic as fallback.
44
+ *
45
+ * @param half - Array of tokens representing one coordinate component.
46
+ * @returns Object with `bear`, `deg`, and `min` properties, or undefined if invalid.
47
+ *
48
+ * @example
49
+ * ```typescript
50
+ * identifyPieces(['45', '30.5', 'N']);
51
+ * // { bear: 'N', deg: '45', min: '30.5' }
52
+ * ```
53
+ *
54
+ * @example
55
+ * ```typescript
56
+ * identifyPieces(['122°', '25.164'', 'W']);
57
+ * // { bear: 'W', deg: '122', min: '25.164' }
58
+ * ```
59
+ */
60
+ declare function identifyPieces(half: string[]): {
61
+ bear: string;
62
+ deg: string;
63
+ min: string;
64
+ } | undefined;
65
+ /**
66
+ * Parses a Degrees Decimal Minutes coordinate string.
67
+ *
68
+ * Accepts coordinates in degrees decimal minutes format with bearing indicators.
69
+ * Validates that degrees are integers, minutes are in valid range (0-59.999...),
70
+ * and ensures no seconds indicators are present.
71
+ *
72
+ * @param input - Raw coordinate string to parse.
73
+ * @param format - Expected format (LATLON or LONLAT).
74
+ * @returns Parsed coordinate values or errors.
75
+ *
76
+ * @example
77
+ * ```typescript
78
+ * parseDegreesDecimalMinutes('37° 46.4940' N / 122° 25.1640' W', 'LATLON');
79
+ * // [[37.7749, -122.4194], []]
80
+ * ```
81
+ *
82
+ * @example
83
+ * ```typescript
84
+ * parseDegreesDecimalMinutes('45 30.5 N, 122 15.3 W');
85
+ * // [[45.508333, -122.255], []]
86
+ * ```
87
+ */
18
88
  declare const parseDegreesDecimalMinutes: (format: Format, input: string) => ParseResults;
19
89
  //#endregion
20
- export { parseDegreesDecimalMinutes };
90
+ export { identifyErrors as _identifyErrors, identifyPieces as _identifyPieces, parseDegreesDecimalMinutes };
21
91
  //# sourceMappingURL=parser.d.ts.map
@@ -19,7 +19,9 @@ import { inRange } from "../internal/in-range.js";
19
19
  //#region src/coordinates/latlon/degrees-decimal-minutes/parser.ts
20
20
  const checks = {
21
21
  deg: (deg, limit) => {
22
- if (Number.parseFloat(deg) > limit) return `Degrees value (${deg}) exceeds max value (${limit}).`;
22
+ const num = Number.parseFloat(deg);
23
+ if (Number.isNaN(num)) return `Degrees value (${deg}) is not a valid number.`;
24
+ if (num > limit) return `Degrees value (${deg}) exceeds max value (${limit}).`;
23
25
  if (/\./.test(deg)) return `Degrees value (${deg}) must not include decimal value.`;
24
26
  },
25
27
  min: (min) => inRange("Minutes", min, 59.999999999),
@@ -31,6 +33,22 @@ const formats = {
31
33
  LATLON: fromTemplate(PARTIAL_PATTERNS, `degLat minDec NS ${SYMBOLS.DIVIDER} degLon minDec EW`),
32
34
  LONLAT: fromTemplate(PARTIAL_PATTERNS, `degLon minDec EW ${SYMBOLS.DIVIDER} degLat minDec NS`)
33
35
  };
36
+ /**
37
+ * Creates an error identification function for degrees decimal minutes coordinates.
38
+ *
39
+ * Validates that degree values are integers, minutes are in valid range (0-59.999...),
40
+ * and that seconds indicators are not present.
41
+ *
42
+ * @param format - The coordinate format (LATLON or LONLAT).
43
+ * @returns Function that validates coordinate components and returns parse results.
44
+ *
45
+ * @example
46
+ * ```typescript
47
+ * const validator = identifyErrors('LATLON');
48
+ * const result = validator({ deg: '91', min: '0', bear: 'N' }, 0);
49
+ * // [[], ['Degrees value (91) exceeds max value (90).']]
50
+ * ```
51
+ */
34
52
  function identifyErrors(format) {
35
53
  return (arg, i) => {
36
54
  if (!arg) return [[], ["Invalid coordinate value."]];
@@ -60,6 +78,27 @@ function identifyErrors(format) {
60
78
  ], []];
61
79
  };
62
80
  }
81
+ /**
82
+ * Identifies and organizes coordinate components from parsed tokens.
83
+ *
84
+ * Separates bearing indicators (N/S/E/W), degree values, and minute values from tokens.
85
+ * Uses symbol patterns to identify component types and positional logic as fallback.
86
+ *
87
+ * @param half - Array of tokens representing one coordinate component.
88
+ * @returns Object with `bear`, `deg`, and `min` properties, or undefined if invalid.
89
+ *
90
+ * @example
91
+ * ```typescript
92
+ * identifyPieces(['45', '30.5', 'N']);
93
+ * // { bear: 'N', deg: '45', min: '30.5' }
94
+ * ```
95
+ *
96
+ * @example
97
+ * ```typescript
98
+ * identifyPieces(['122°', '25.164'', 'W']);
99
+ * // { bear: 'W', deg: '122', min: '25.164' }
100
+ * ```
101
+ */
63
102
  function identifyPieces(half) {
64
103
  if (half.length < 1 || half.length > 3) return;
65
104
  const asString = half.join(" ");
@@ -71,17 +110,41 @@ function identifyPieces(half) {
71
110
  const keys = ["deg", "min"];
72
111
  const test = (r, b, v) => r.test(v) || r.test(asString) && b;
73
112
  return half.reduce((acc, token, i, { length }) => {
113
+ if (!acc) return;
74
114
  if (test(SYMBOL_PATTERNS.NSEW, i === length - 1, token)) acc.bear ||= token;
75
115
  else if (test(SYMBOL_PATTERNS.DEGREES, i === 0, token)) acc.deg ||= token;
76
116
  else if (test(SYMBOL_PATTERNS.MINUTES, i === 1, token)) acc.min ||= token;
77
117
  else {
78
118
  const key = keys.find((k) => !acc[k]);
119
+ if (!key) return;
79
120
  acc[key] = token;
80
121
  }
81
122
  return acc;
82
123
  }, places);
83
124
  }
84
- /** Parse a Degrees Decimal Minutes coordinate. */
125
+ /**
126
+ * Parses a Degrees Decimal Minutes coordinate string.
127
+ *
128
+ * Accepts coordinates in degrees decimal minutes format with bearing indicators.
129
+ * Validates that degrees are integers, minutes are in valid range (0-59.999...),
130
+ * and ensures no seconds indicators are present.
131
+ *
132
+ * @param input - Raw coordinate string to parse.
133
+ * @param format - Expected format (LATLON or LONLAT).
134
+ * @returns Parsed coordinate values or errors.
135
+ *
136
+ * @example
137
+ * ```typescript
138
+ * parseDegreesDecimalMinutes('37° 46.4940' N / 122° 25.1640' W', 'LATLON');
139
+ * // [[37.7749, -122.4194], []]
140
+ * ```
141
+ *
142
+ * @example
143
+ * ```typescript
144
+ * parseDegreesDecimalMinutes('45 30.5 N, 122 15.3 W');
145
+ * // [[45.508333, -122.255], []]
146
+ * ```
147
+ */
85
148
  const parseDegreesDecimalMinutes = createParser({
86
149
  formats,
87
150
  identifyErrors,
@@ -89,5 +152,5 @@ const parseDegreesDecimalMinutes = createParser({
89
152
  });
90
153
 
91
154
  //#endregion
92
- export { parseDegreesDecimalMinutes };
155
+ export { identifyErrors as _identifyErrors, identifyPieces as _identifyPieces, parseDegreesDecimalMinutes };
93
156
  //# sourceMappingURL=parser.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"parser.js","names":["Patterning.fromTemplate","isNegative: 0 | 1"],"sources":["../../../../src/coordinates/latlon/degrees-decimal-minutes/parser.ts"],"sourcesContent":["/*\n * Copyright 2024 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport * as Patterning from '@/patterning';\nimport {\n BEARINGS,\n type Format,\n LIMITS,\n PARTIAL_PATTERNS,\n SYMBOL_PATTERNS,\n SYMBOLS,\n} from '../internal';\nimport { inRange } from '../internal/in-range';\nimport { createParser } from '../internal/parse-format';\nimport type { ParseResults } from '../internal/parse';\n\ntype DegreesDecimalMinutes = {\n bear: string;\n deg: string;\n min: string;\n};\n\nconst checks = {\n deg: (deg: string, limit: number) => {\n if (Number.parseFloat(deg) > limit) {\n return `Degrees value (${deg}) exceeds max value (${limit}).`;\n }\n\n if (/\\./.test(deg)) {\n return `Degrees value (${deg}) must not include decimal value.`;\n }\n },\n min: (min: string) => inRange('Minutes', min, 59.999999999),\n sec: (val: string) => {\n if (val.includes(SYMBOLS.SECONDS)) {\n return `Seconds indicator (${SYMBOLS.SECONDS}) not valid in Degree Decimal Minutes.`;\n }\n },\n};\n\nconst formats = {\n LATLON: Patterning.fromTemplate(\n PARTIAL_PATTERNS,\n `degLat minDec NS ${SYMBOLS.DIVIDER} degLon minDec EW`,\n ),\n LONLAT: Patterning.fromTemplate(\n PARTIAL_PATTERNS,\n `degLon minDec EW ${SYMBOLS.DIVIDER} degLat minDec NS`,\n ),\n};\n\nfunction identifyErrors(format: Format) {\n return (arg: DegreesDecimalMinutes | undefined, i: number) => {\n if (!arg) {\n return [[], ['Invalid coordinate value.']] as ParseResults;\n }\n\n let { bear, deg, min } = arg;\n\n deg ??= '0';\n min ??= '0';\n\n let isNegative: 0 | 1 = SYMBOL_PATTERNS.NEGATIVE_SIGN.test(deg) ? 1 : 0;\n const bearingOptions = BEARINGS[format][i] as [string, string];\n\n if (!bear || isNegative) {\n bear = bearingOptions[isNegative];\n deg = Math.abs(Number.parseFloat(deg)).toString();\n isNegative = 0;\n }\n\n const errors = [\n ...[checks.deg(deg, LIMITS[format][i] ?? 0)],\n ...[checks.min(min)],\n ...[checks.sec([bear, deg, min].join(''))],\n ].filter(Boolean);\n\n return (\n errors.length ? [[], errors] : [[deg, min, bear], []]\n ) as ParseResults;\n };\n}\n\nfunction identifyPieces(half: string[]) {\n if (half.length < 1 || half.length > 3) {\n return;\n }\n\n const asString = half.join(' ');\n const places = { bear: '', deg: '', min: '' };\n const keys = ['deg', 'min'] as (keyof typeof places)[];\n const test = (r: RegExp, b: boolean, v: string) =>\n r.test(v) || (r.test(asString) && b);\n\n return half.reduce((acc, token, i, { length }) => {\n if (test(SYMBOL_PATTERNS.NSEW, i === length - 1, token)) {\n acc.bear ||= token;\n } else if (test(SYMBOL_PATTERNS.DEGREES, i === 0, token)) {\n acc.deg ||= token;\n } else if (test(SYMBOL_PATTERNS.MINUTES, i === 1, token)) {\n acc.min ||= token;\n } else {\n const key = keys.find((k) => !acc[k]);\n\n acc[key as keyof typeof acc] = token;\n }\n\n return acc;\n }, places);\n}\n\n/** Parse a Degrees Decimal Minutes coordinate. */\nexport const parseDegreesDecimalMinutes = createParser<DegreesDecimalMinutes>({\n formats,\n identifyErrors,\n identifyPieces,\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;AA+BA,MAAM,SAAS;CACb,MAAM,KAAa,UAAkB;AACnC,MAAI,OAAO,WAAW,IAAI,GAAG,MAC3B,QAAO,kBAAkB,IAAI,uBAAuB,MAAM;AAG5D,MAAI,KAAK,KAAK,IAAI,CAChB,QAAO,kBAAkB,IAAI;;CAGjC,MAAM,QAAgB,QAAQ,WAAW,KAAK,aAAa;CAC3D,MAAM,QAAgB;AACpB,MAAI,IAAI,SAAS,QAAQ,QAAQ,CAC/B,QAAO,sBAAsB,QAAQ,QAAQ;;CAGlD;AAED,MAAM,UAAU;CACd,QAAQA,aACN,kBACA,oBAAoB,QAAQ,QAAQ,mBACrC;CACD,QAAQA,aACN,kBACA,oBAAoB,QAAQ,QAAQ,mBACrC;CACF;AAED,SAAS,eAAe,QAAgB;AACtC,SAAQ,KAAwC,MAAc;AAC5D,MAAI,CAAC,IACH,QAAO,CAAC,EAAE,EAAE,CAAC,4BAA4B,CAAC;EAG5C,IAAI,EAAE,MAAM,KAAK,QAAQ;AAEzB,UAAQ;AACR,UAAQ;EAER,IAAIC,aAAoB,gBAAgB,cAAc,KAAK,IAAI,GAAG,IAAI;EACtE,MAAM,iBAAiB,SAAS,QAAQ;AAExC,MAAI,CAAC,QAAQ,YAAY;AACvB,UAAO,eAAe;AACtB,SAAM,KAAK,IAAI,OAAO,WAAW,IAAI,CAAC,CAAC,UAAU;AACjD,gBAAa;;EAGf,MAAM,SAAS;GACb,GAAG,CAAC,OAAO,IAAI,KAAK,OAAO,QAAQ,MAAM,EAAE,CAAC;GAC5C,GAAG,CAAC,OAAO,IAAI,IAAI,CAAC;GACpB,GAAG,CAAC,OAAO,IAAI;IAAC;IAAM;IAAK;IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;GAC3C,CAAC,OAAO,QAAQ;AAEjB,SACE,OAAO,SAAS,CAAC,EAAE,EAAE,OAAO,GAAG,CAAC;GAAC;GAAK;GAAK;GAAK,EAAE,EAAE,CAAC;;;AAK3D,SAAS,eAAe,MAAgB;AACtC,KAAI,KAAK,SAAS,KAAK,KAAK,SAAS,EACnC;CAGF,MAAM,WAAW,KAAK,KAAK,IAAI;CAC/B,MAAM,SAAS;EAAE,MAAM;EAAI,KAAK;EAAI,KAAK;EAAI;CAC7C,MAAM,OAAO,CAAC,OAAO,MAAM;CAC3B,MAAM,QAAQ,GAAW,GAAY,MACnC,EAAE,KAAK,EAAE,IAAK,EAAE,KAAK,SAAS,IAAI;AAEpC,QAAO,KAAK,QAAQ,KAAK,OAAO,GAAG,EAAE,aAAa;AAChD,MAAI,KAAK,gBAAgB,MAAM,MAAM,SAAS,GAAG,MAAM,CACrD,KAAI,SAAS;WACJ,KAAK,gBAAgB,SAAS,MAAM,GAAG,MAAM,CACtD,KAAI,QAAQ;WACH,KAAK,gBAAgB,SAAS,MAAM,GAAG,MAAM,CACtD,KAAI,QAAQ;OACP;GACL,MAAM,MAAM,KAAK,MAAM,MAAM,CAAC,IAAI,GAAG;AAErC,OAAI,OAA2B;;AAGjC,SAAO;IACN,OAAO;;;AAIZ,MAAa,6BAA6B,aAAoC;CAC5E;CACA;CACA;CACD,CAAC"}
1
+ {"version":3,"file":"parser.js","names":["Patterning.fromTemplate","isNegative: 0 | 1"],"sources":["../../../../src/coordinates/latlon/degrees-decimal-minutes/parser.ts"],"sourcesContent":["/*\n * Copyright 2024 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport * as Patterning from '@/patterning';\nimport {\n BEARINGS,\n type Format,\n LIMITS,\n PARTIAL_PATTERNS,\n SYMBOL_PATTERNS,\n SYMBOLS,\n} from '../internal';\nimport { inRange } from '../internal/in-range';\nimport { createParser } from '../internal/parse-format';\nimport type { ParseResults } from '../internal/parse';\n\ntype DegreesDecimalMinutes = {\n bear: string;\n deg: string;\n min: string;\n};\n\nconst checks = {\n deg: (deg: string, limit: number) => {\n const num = Number.parseFloat(deg);\n if (Number.isNaN(num)) {\n return `Degrees value (${deg}) is not a valid number.`;\n }\n if (num > limit) {\n return `Degrees value (${deg}) exceeds max value (${limit}).`;\n }\n\n if (/\\./.test(deg)) {\n return `Degrees value (${deg}) must not include decimal value.`;\n }\n },\n min: (min: string) => inRange('Minutes', min, 59.999999999),\n sec: (val: string) => {\n if (val.includes(SYMBOLS.SECONDS)) {\n return `Seconds indicator (${SYMBOLS.SECONDS}) not valid in Degree Decimal Minutes.`;\n }\n },\n};\n\nconst formats = {\n LATLON: Patterning.fromTemplate(\n PARTIAL_PATTERNS,\n `degLat minDec NS ${SYMBOLS.DIVIDER} degLon minDec EW`,\n ),\n LONLAT: Patterning.fromTemplate(\n PARTIAL_PATTERNS,\n `degLon minDec EW ${SYMBOLS.DIVIDER} degLat minDec NS`,\n ),\n};\n\n/**\n * Creates an error identification function for degrees decimal minutes coordinates.\n *\n * Validates that degree values are integers, minutes are in valid range (0-59.999...),\n * and that seconds indicators are not present.\n *\n * @param format - The coordinate format (LATLON or LONLAT).\n * @returns Function that validates coordinate components and returns parse results.\n *\n * @example\n * ```typescript\n * const validator = identifyErrors('LATLON');\n * const result = validator({ deg: '91', min: '0', bear: 'N' }, 0);\n * // [[], ['Degrees value (91) exceeds max value (90).']]\n * ```\n */\nfunction identifyErrors(format: Format) {\n return (arg: DegreesDecimalMinutes | undefined, i: number) => {\n if (!arg) {\n return [[], ['Invalid coordinate value.']] as ParseResults;\n }\n\n let { bear, deg, min } = arg;\n\n deg ??= '0';\n min ??= '0';\n\n let isNegative: 0 | 1 = SYMBOL_PATTERNS.NEGATIVE_SIGN.test(deg) ? 1 : 0;\n const bearingOptions = BEARINGS[format][i] as [string, string];\n\n if (!bear || isNegative) {\n bear = bearingOptions[isNegative];\n deg = Math.abs(Number.parseFloat(deg)).toString();\n isNegative = 0;\n }\n\n const errors = [\n ...[checks.deg(deg, LIMITS[format][i] ?? 0)],\n ...[checks.min(min)],\n ...[checks.sec([bear, deg, min].join(''))],\n ].filter(Boolean);\n\n return (\n errors.length ? [[], errors] : [[deg, min, bear], []]\n ) as ParseResults;\n };\n}\n\n/**\n * Identifies and organizes coordinate components from parsed tokens.\n *\n * Separates bearing indicators (N/S/E/W), degree values, and minute values from tokens.\n * Uses symbol patterns to identify component types and positional logic as fallback.\n *\n * @param half - Array of tokens representing one coordinate component.\n * @returns Object with `bear`, `deg`, and `min` properties, or undefined if invalid.\n *\n * @example\n * ```typescript\n * identifyPieces(['45', '30.5', 'N']);\n * // { bear: 'N', deg: '45', min: '30.5' }\n * ```\n *\n * @example\n * ```typescript\n * identifyPieces(['122°', '25.164'', 'W']);\n * // { bear: 'W', deg: '122', min: '25.164' }\n * ```\n */\nfunction identifyPieces(half: string[]) {\n if (half.length < 1 || half.length > 3) {\n return;\n }\n\n const asString = half.join(' ');\n const places = { bear: '', deg: '', min: '' };\n const keys = ['deg', 'min'] as (keyof typeof places)[];\n const test = (r: RegExp, b: boolean, v: string) =>\n r.test(v) || (r.test(asString) && b);\n\n return half.reduce<typeof places | undefined>((acc, token, i, { length }) => {\n if (!acc) {\n return undefined;\n }\n if (test(SYMBOL_PATTERNS.NSEW, i === length - 1, token)) {\n acc.bear ||= token;\n } else if (test(SYMBOL_PATTERNS.DEGREES, i === 0, token)) {\n acc.deg ||= token;\n } else if (test(SYMBOL_PATTERNS.MINUTES, i === 1, token)) {\n acc.min ||= token;\n } else {\n const key = keys.find((k) => !acc[k]);\n if (!key) {\n return undefined;\n }\n acc[key] = token;\n }\n\n return acc;\n }, places);\n}\n\n/**\n * Parses a Degrees Decimal Minutes coordinate string.\n *\n * Accepts coordinates in degrees decimal minutes format with bearing indicators.\n * Validates that degrees are integers, minutes are in valid range (0-59.999...),\n * and ensures no seconds indicators are present.\n *\n * @param input - Raw coordinate string to parse.\n * @param format - Expected format (LATLON or LONLAT).\n * @returns Parsed coordinate values or errors.\n *\n * @example\n * ```typescript\n * parseDegreesDecimalMinutes('37° 46.4940' N / 122° 25.1640' W', 'LATLON');\n * // [[37.7749, -122.4194], []]\n * ```\n *\n * @example\n * ```typescript\n * parseDegreesDecimalMinutes('45 30.5 N, 122 15.3 W');\n * // [[45.508333, -122.255], []]\n * ```\n */\nexport const parseDegreesDecimalMinutes = createParser<DegreesDecimalMinutes>({\n formats,\n identifyErrors,\n identifyPieces,\n});\n\nexport { identifyErrors as _identifyErrors, identifyPieces as _identifyPieces };\n"],"mappings":";;;;;;;;;;;;;;;;;;;AA+BA,MAAM,SAAS;CACb,MAAM,KAAa,UAAkB;EACnC,MAAM,MAAM,OAAO,WAAW,IAAI;AAClC,MAAI,OAAO,MAAM,IAAI,CACnB,QAAO,kBAAkB,IAAI;AAE/B,MAAI,MAAM,MACR,QAAO,kBAAkB,IAAI,uBAAuB,MAAM;AAG5D,MAAI,KAAK,KAAK,IAAI,CAChB,QAAO,kBAAkB,IAAI;;CAGjC,MAAM,QAAgB,QAAQ,WAAW,KAAK,aAAa;CAC3D,MAAM,QAAgB;AACpB,MAAI,IAAI,SAAS,QAAQ,QAAQ,CAC/B,QAAO,sBAAsB,QAAQ,QAAQ;;CAGlD;AAED,MAAM,UAAU;CACd,QAAQA,aACN,kBACA,oBAAoB,QAAQ,QAAQ,mBACrC;CACD,QAAQA,aACN,kBACA,oBAAoB,QAAQ,QAAQ,mBACrC;CACF;;;;;;;;;;;;;;;;;AAkBD,SAAS,eAAe,QAAgB;AACtC,SAAQ,KAAwC,MAAc;AAC5D,MAAI,CAAC,IACH,QAAO,CAAC,EAAE,EAAE,CAAC,4BAA4B,CAAC;EAG5C,IAAI,EAAE,MAAM,KAAK,QAAQ;AAEzB,UAAQ;AACR,UAAQ;EAER,IAAIC,aAAoB,gBAAgB,cAAc,KAAK,IAAI,GAAG,IAAI;EACtE,MAAM,iBAAiB,SAAS,QAAQ;AAExC,MAAI,CAAC,QAAQ,YAAY;AACvB,UAAO,eAAe;AACtB,SAAM,KAAK,IAAI,OAAO,WAAW,IAAI,CAAC,CAAC,UAAU;AACjD,gBAAa;;EAGf,MAAM,SAAS;GACb,GAAG,CAAC,OAAO,IAAI,KAAK,OAAO,QAAQ,MAAM,EAAE,CAAC;GAC5C,GAAG,CAAC,OAAO,IAAI,IAAI,CAAC;GACpB,GAAG,CAAC,OAAO,IAAI;IAAC;IAAM;IAAK;IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;GAC3C,CAAC,OAAO,QAAQ;AAEjB,SACE,OAAO,SAAS,CAAC,EAAE,EAAE,OAAO,GAAG,CAAC;GAAC;GAAK;GAAK;GAAK,EAAE,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;AA0B3D,SAAS,eAAe,MAAgB;AACtC,KAAI,KAAK,SAAS,KAAK,KAAK,SAAS,EACnC;CAGF,MAAM,WAAW,KAAK,KAAK,IAAI;CAC/B,MAAM,SAAS;EAAE,MAAM;EAAI,KAAK;EAAI,KAAK;EAAI;CAC7C,MAAM,OAAO,CAAC,OAAO,MAAM;CAC3B,MAAM,QAAQ,GAAW,GAAY,MACnC,EAAE,KAAK,EAAE,IAAK,EAAE,KAAK,SAAS,IAAI;AAEpC,QAAO,KAAK,QAAmC,KAAK,OAAO,GAAG,EAAE,aAAa;AAC3E,MAAI,CAAC,IACH;AAEF,MAAI,KAAK,gBAAgB,MAAM,MAAM,SAAS,GAAG,MAAM,CACrD,KAAI,SAAS;WACJ,KAAK,gBAAgB,SAAS,MAAM,GAAG,MAAM,CACtD,KAAI,QAAQ;WACH,KAAK,gBAAgB,SAAS,MAAM,GAAG,MAAM,CACtD,KAAI,QAAQ;OACP;GACL,MAAM,MAAM,KAAK,MAAM,MAAM,CAAC,IAAI,GAAG;AACrC,OAAI,CAAC,IACH;AAEF,OAAI,OAAO;;AAGb,SAAO;IACN,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;AA0BZ,MAAa,6BAA6B,aAAoC;CAC5E;CACA;CACA;CACD,CAAC"}