@speleotica/frcsdata 4.3.1 → 5.0.0-beta.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 (133) hide show
  1. package/ParseIssue.d.ts +98 -0
  2. package/ParseIssue.d.ts.map +1 -0
  3. package/ParseIssue.js +17 -0
  4. package/ParseIssue.js.map +1 -0
  5. package/SourceLoc.d.ts +67 -0
  6. package/SourceLoc.d.ts.map +1 -0
  7. package/SourceLoc.js +18 -0
  8. package/SourceLoc.js.map +1 -0
  9. package/chunksToLines.d.ts +5 -0
  10. package/chunksToLines.d.ts.map +1 -0
  11. package/chunksToLines.js +139 -0
  12. package/chunksToLines.js.map +1 -0
  13. package/cli/check-survey.d.ts +2 -0
  14. package/cli/check-survey.d.ts.map +1 -0
  15. package/cli/check-survey.js +88 -0
  16. package/cli/check-survey.js.map +1 -0
  17. package/cli/parse-survey.d.ts +2 -0
  18. package/cli/parse-survey.d.ts.map +1 -0
  19. package/cli/parse-survey.js +37 -0
  20. package/cli/parse-survey.js.map +1 -0
  21. package/cli.d.ts +2 -0
  22. package/cli.d.ts.map +1 -0
  23. package/cli.js +83 -0
  24. package/cli.js.map +1 -0
  25. package/index.d.ts +5 -7
  26. package/index.d.ts.map +1 -1
  27. package/index.js +3 -36
  28. package/index.js.map +1 -1
  29. package/node/index.d.ts +1 -1
  30. package/node/index.d.ts.map +1 -1
  31. package/node/index.js +13 -5
  32. package/node/index.js.map +1 -1
  33. package/package.json +8 -6
  34. package/src/ParseIssue.ts +19 -0
  35. package/src/SourceLoc.ts +13 -0
  36. package/src/chunksToLines.ts +26 -0
  37. package/src/cli/check-survey.ts +84 -0
  38. package/src/cli/parse-survey.ts +10 -0
  39. package/src/cli.ts +30 -0
  40. package/src/index.ts +9 -7
  41. package/src/node/index.ts +18 -5
  42. package/src/string/index.ts +18 -5
  43. package/src/survey/FrcsSurveyFile.ts +217 -0
  44. package/src/survey/FrcsSurveyFileJson.ts +46 -0
  45. package/src/survey/ZodFrcsSurveyFileJson.ts +260 -0
  46. package/src/survey/ZodFrcsSurveyFileToJson.ts +297 -0
  47. package/src/{formatFrcsShot.ts → survey/formatFrcsShot.ts} +39 -22
  48. package/src/{formatFrcsSurveyFile.ts → survey/formatFrcsSurveyFile.ts} +4 -5
  49. package/src/survey/getColumnRanges.ts +82 -0
  50. package/src/survey/normalizeTeamMemberName.ts +10 -0
  51. package/src/survey/parseFrcsSurveyFile.ts +862 -0
  52. package/src/survey/parsers.ts +128 -0
  53. package/src/survey/validators.ts +24 -0
  54. package/src/underlineSource.ts +34 -0
  55. package/src/web/index.ts +27 -21
  56. package/string/index.d.ts +1 -1
  57. package/string/index.d.ts.map +1 -1
  58. package/string/index.js +13 -5
  59. package/string/index.js.map +1 -1
  60. package/survey/FrcsSurveyFile.d.ts +172 -0
  61. package/survey/FrcsSurveyFile.d.ts.map +1 -0
  62. package/{FrcsSurveyFile.js → survey/FrcsSurveyFile.js} +2 -0
  63. package/survey/FrcsSurveyFile.js.map +1 -0
  64. package/survey/FrcsSurveyFileJson.d.ts +15 -0
  65. package/survey/FrcsSurveyFileJson.d.ts.map +1 -0
  66. package/{FrcsTrip.js → survey/FrcsSurveyFileJson.js} +1 -1
  67. package/survey/FrcsSurveyFileJson.js.map +1 -0
  68. package/survey/ZodFrcsSurveyFileJson.d.ts +60549 -0
  69. package/survey/ZodFrcsSurveyFileJson.d.ts.map +1 -0
  70. package/survey/ZodFrcsSurveyFileJson.js +188 -0
  71. package/survey/ZodFrcsSurveyFileJson.js.map +1 -0
  72. package/survey/ZodFrcsSurveyFileToJson.d.ts +60390 -0
  73. package/survey/ZodFrcsSurveyFileToJson.d.ts.map +1 -0
  74. package/survey/ZodFrcsSurveyFileToJson.js +219 -0
  75. package/survey/ZodFrcsSurveyFileToJson.js.map +1 -0
  76. package/{formatFrcsShot.d.ts → survey/formatFrcsShot.d.ts} +2 -3
  77. package/survey/formatFrcsShot.d.ts.map +1 -0
  78. package/{formatFrcsShot.js → survey/formatFrcsShot.js} +15 -6
  79. package/survey/formatFrcsShot.js.map +1 -0
  80. package/survey/formatFrcsSurveyFile.d.ts +3 -0
  81. package/survey/formatFrcsSurveyFile.d.ts.map +1 -0
  82. package/{formatFrcsSurveyFile.js → survey/formatFrcsSurveyFile.js} +4 -4
  83. package/survey/formatFrcsSurveyFile.js.map +1 -0
  84. package/survey/getColumnRanges.d.ts +24 -0
  85. package/survey/getColumnRanges.d.ts.map +1 -0
  86. package/survey/getColumnRanges.js +70 -0
  87. package/survey/getColumnRanges.js.map +1 -0
  88. package/survey/normalizeTeamMemberName.d.ts +2 -0
  89. package/survey/normalizeTeamMemberName.d.ts.map +1 -0
  90. package/survey/normalizeTeamMemberName.js +16 -0
  91. package/survey/normalizeTeamMemberName.js.map +1 -0
  92. package/{parseFrcsSurveyFile.d.ts → survey/parseFrcsSurveyFile.d.ts} +2 -5
  93. package/survey/parseFrcsSurveyFile.d.ts.map +1 -0
  94. package/survey/parseFrcsSurveyFile.js +818 -0
  95. package/survey/parseFrcsSurveyFile.js.map +1 -0
  96. package/survey/parsers.d.ts +11 -0
  97. package/survey/parsers.d.ts.map +1 -0
  98. package/survey/parsers.js +119 -0
  99. package/survey/parsers.js.map +1 -0
  100. package/survey/validators.d.ts +7 -0
  101. package/survey/validators.d.ts.map +1 -0
  102. package/survey/validators.js +36 -0
  103. package/survey/validators.js.map +1 -0
  104. package/underlineSource.d.ts +6 -0
  105. package/underlineSource.d.ts.map +1 -0
  106. package/underlineSource.js +30 -0
  107. package/underlineSource.js.map +1 -0
  108. package/web/index.d.ts +6 -6
  109. package/web/index.d.ts.map +1 -1
  110. package/web/index.js +9 -7
  111. package/web/index.js.map +1 -1
  112. package/FrcsShot.d.ts +0 -57
  113. package/FrcsShot.d.ts.map +0 -1
  114. package/FrcsShot.js +0 -13
  115. package/FrcsShot.js.map +0 -1
  116. package/FrcsSurveyFile.d.ts +0 -29
  117. package/FrcsSurveyFile.d.ts.map +0 -1
  118. package/FrcsSurveyFile.js.map +0 -1
  119. package/FrcsTrip.d.ts +0 -23
  120. package/FrcsTrip.d.ts.map +0 -1
  121. package/FrcsTrip.js.map +0 -1
  122. package/formatFrcsShot.d.ts.map +0 -1
  123. package/formatFrcsShot.js.map +0 -1
  124. package/formatFrcsSurveyFile.d.ts +0 -3
  125. package/formatFrcsSurveyFile.d.ts.map +0 -1
  126. package/formatFrcsSurveyFile.js.map +0 -1
  127. package/parseFrcsSurveyFile.d.ts.map +0 -1
  128. package/parseFrcsSurveyFile.js +0 -812
  129. package/parseFrcsSurveyFile.js.map +0 -1
  130. package/src/FrcsShot.ts +0 -56
  131. package/src/FrcsSurveyFile.ts +0 -47
  132. package/src/FrcsTrip.ts +0 -25
  133. package/src/parseFrcsSurveyFile.ts +0 -788
@@ -0,0 +1,297 @@
1
+ import { Angle, Length, Unit, UnitizedNumber } from '@speleotica/unitized'
2
+ import z from 'zod'
3
+ import type { DeepMapJson, JsonAngle, JsonLength } from './FrcsSurveyFileJson'
4
+ import type { SourceLoc } from '../SourceLoc'
5
+ import type {
6
+ FrcsShot,
7
+ FrcsSurveyFile,
8
+ FrcsTrip,
9
+ FrcsTripHeader,
10
+ FrcsUnits,
11
+ InvalidFrcsShot,
12
+ InvalidFrcsSurveyFile,
13
+ InvalidFrcsTrip,
14
+ InvalidFrcsTripHeader,
15
+ InvalidFrcsUnits,
16
+ } from './FrcsSurveyFile'
17
+ import { ParseIssue } from '../ParseIssue'
18
+
19
+ type DeepMapJsonSchema<T> = z.ZodType<DeepMapJson<T>, any, T>
20
+
21
+ const ZodLengthUnit = z
22
+ .instanceof<typeof Unit<Length>>(Unit)
23
+ .transform((unit) => {
24
+ switch (unit) {
25
+ case Length.meters:
26
+ return 'm'
27
+ case Length.kilometers:
28
+ return 'km'
29
+ case Length.centimeters:
30
+ return 'cm'
31
+ case Length.feet:
32
+ return 'ft'
33
+ case Length.inches:
34
+ return 'in'
35
+ case Length.yards:
36
+ return 'yd'
37
+ case Length.miles:
38
+ return 'mi'
39
+ }
40
+ throw new Error('invalid unit')
41
+ })
42
+
43
+ ZodLengthUnit satisfies DeepMapJsonSchema<Unit<Length>>
44
+
45
+ const ZodAngleUnit = z
46
+ .instanceof<typeof Unit<Angle>>(Unit)
47
+ .transform((unit) => {
48
+ switch (unit) {
49
+ case Angle.degrees:
50
+ return 'deg'
51
+ case Angle.radians:
52
+ return 'rad'
53
+ case Angle.gradians:
54
+ return 'grad'
55
+ case Angle.milsNATO:
56
+ return 'mil'
57
+ case Angle.percentGrade:
58
+ return '%'
59
+ }
60
+ throw new Error('invalid unit')
61
+ })
62
+
63
+ ZodAngleUnit satisfies DeepMapJsonSchema<Unit<Angle>>
64
+
65
+ const ZodLength = z
66
+ .instanceof<typeof UnitizedNumber<Length>>(UnitizedNumber)
67
+ .transform(
68
+ (length) =>
69
+ [
70
+ length.get(length.unit),
71
+ ZodLengthUnit.parse(length.unit),
72
+ ] satisfies JsonLength
73
+ )
74
+
75
+ ZodLength satisfies DeepMapJsonSchema<UnitizedNumber<Length>>
76
+
77
+ const ZodAngle = z
78
+ .instanceof<typeof UnitizedNumber<Angle>>(UnitizedNumber)
79
+ .transform(
80
+ (angle) =>
81
+ [
82
+ angle.get(angle.unit),
83
+ ZodAngleUnit.parse(angle.unit),
84
+ ] satisfies JsonAngle
85
+ )
86
+
87
+ ZodAngle satisfies DeepMapJsonSchema<UnitizedNumber<Angle>>
88
+
89
+ const ZodSourceLoc = z.strictObject({
90
+ start: z.strictObject({
91
+ index: z.number(),
92
+ line: z.number(),
93
+ column: z.number(),
94
+ }),
95
+ end: z.strictObject({
96
+ index: z.number(),
97
+ line: z.number(),
98
+ column: z.number(),
99
+ }),
100
+ })
101
+
102
+ ZodSourceLoc satisfies DeepMapJsonSchema<SourceLoc>
103
+
104
+ const ZodFrcsShotBase = z.strictObject({
105
+ from: z.string(),
106
+ to: z.string().optional(),
107
+ specialKind: z.enum(['horizontal', 'diagonal']).optional(),
108
+ distance: ZodLength,
109
+ horizontalDistance: ZodLength.optional(),
110
+ verticalDistance: ZodLength.optional(),
111
+ frontsightAzimuth: ZodAngle.optional(),
112
+ frontsightInclination: ZodAngle.optional(),
113
+ backsightAzimuth: ZodAngle.optional(),
114
+ backsightInclination: ZodAngle.optional(),
115
+ /**
116
+ * LRUDs at from station
117
+ */
118
+ fromLruds: z
119
+ .strictObject({
120
+ left: ZodLength.optional(),
121
+ right: ZodLength.optional(),
122
+ up: ZodLength.optional(),
123
+ down: ZodLength.optional(),
124
+ })
125
+ .optional(),
126
+ /**
127
+ * LRUDs at to station
128
+ */
129
+ toLruds: z
130
+ .strictObject({
131
+ left: ZodLength.optional(),
132
+ right: ZodLength.optional(),
133
+ up: ZodLength.optional(),
134
+ down: ZodLength.optional(),
135
+ })
136
+ .optional(),
137
+
138
+ excludeDistance: z
139
+ .boolean()
140
+ .optional()
141
+ .transform((b) => b || undefined),
142
+ isSplay: z
143
+ .boolean()
144
+ .optional()
145
+ .transform((b) => b || undefined),
146
+ comment: z.string().optional(),
147
+ loc: ZodSourceLoc.optional(),
148
+ locs: z
149
+ .strictObject({
150
+ comment: ZodSourceLoc.optional(),
151
+ })
152
+ .optional(),
153
+ })
154
+
155
+ const ZodFrcsUnits = z.strictObject({
156
+ distanceUnit: ZodLengthUnit,
157
+ azimuthUnit: ZodAngleUnit,
158
+ inclinationUnit: ZodAngleUnit,
159
+ backsightAzimuthCorrected: z.boolean().optional(),
160
+ backsightInclinationCorrected: z.boolean().optional(),
161
+ hasBacksightAzimuth: z.boolean().optional(),
162
+ hasBacksightInclination: z.boolean().optional(),
163
+ loc: ZodSourceLoc.optional(),
164
+ locs: z
165
+ .strictObject({
166
+ distanceUnit: ZodSourceLoc.optional(),
167
+ azimuthUnit: ZodSourceLoc.optional(),
168
+ inclinationUnit: ZodSourceLoc.optional(),
169
+ backsightAzimuthCorrected: ZodSourceLoc.optional(),
170
+ backsightInclinationCorrected: ZodSourceLoc.optional(),
171
+ hasBacksightAzimuth: ZodSourceLoc.optional(),
172
+ hasBacksightInclination: ZodSourceLoc.optional(),
173
+ })
174
+ .optional(),
175
+ })
176
+
177
+ ZodFrcsUnits satisfies DeepMapJsonSchema<FrcsUnits>
178
+
179
+ const ZodFrcsShot = ZodFrcsShotBase.extend({
180
+ recorded: ZodFrcsShotBase.extend({
181
+ units: ZodFrcsUnits.optional(),
182
+ }).optional(),
183
+ })
184
+
185
+ ZodFrcsShot satisfies DeepMapJsonSchema<FrcsShot>
186
+
187
+ const ZodDate = z.date().transform((d) => d.toISOString().substring(0, 10))
188
+
189
+ const ZodFrcsTripHeader = z.strictObject({
190
+ name: z.string(),
191
+ comment: z.string().optional(),
192
+ section: z.string().optional(),
193
+ date: ZodDate.optional(),
194
+ team: z.array(z.string()).optional(),
195
+ loc: ZodSourceLoc.optional(),
196
+ locs: z
197
+ .strictObject({
198
+ name: ZodSourceLoc,
199
+ comment: ZodSourceLoc.optional(),
200
+ section: ZodSourceLoc.optional(),
201
+ date: ZodSourceLoc.optional(),
202
+ team: z.array(ZodSourceLoc).optional(),
203
+ })
204
+ .optional(),
205
+ })
206
+
207
+ ZodFrcsTripHeader satisfies DeepMapJsonSchema<FrcsTripHeader>
208
+
209
+ const ZodFrcsTrip = z.strictObject({
210
+ tripNumber: z.number().int().min(1),
211
+ header: ZodFrcsTripHeader,
212
+ units: ZodFrcsUnits,
213
+ shots: z.array(ZodFrcsShot),
214
+ loc: ZodSourceLoc.optional(),
215
+ })
216
+
217
+ ZodFrcsTrip satisfies DeepMapJsonSchema<FrcsTrip>
218
+
219
+ export const ZodFrcsSurveyFileToJson = z.strictObject({
220
+ cave: z.string().optional(),
221
+ columns: z
222
+ .strictObject({
223
+ toStation: z.number(),
224
+ fromStation: z.number(),
225
+ distance: z.number(),
226
+ distanceFeet: z.number(),
227
+ distanceInches: z.number(),
228
+ kind: z.number(),
229
+ exclude: z.number(),
230
+ frontsightAzimuth: z.number(),
231
+ backsightAzimuth: z.number(),
232
+ frontsightInclination: z.number(),
233
+ backsightInclination: z.number(),
234
+ left: z.number(),
235
+ right: z.number(),
236
+ up: z.number(),
237
+ down: z.number(),
238
+ })
239
+ .optional(),
240
+ location: z.string().optional(),
241
+ comment: z.string().optional(),
242
+ trips: z.array(ZodFrcsTrip),
243
+ locs: z
244
+ .strictObject({
245
+ cave: ZodSourceLoc.optional(),
246
+ location: ZodSourceLoc.optional(),
247
+ comment: ZodSourceLoc.optional(),
248
+ })
249
+ .optional(),
250
+ issues: z.array(ParseIssue).optional(),
251
+ })
252
+
253
+ ZodFrcsSurveyFileToJson satisfies DeepMapJsonSchema<FrcsSurveyFile>
254
+
255
+ function Invalid<T extends z.ZodTypeAny>(schema: T) {
256
+ return z.strictObject({
257
+ INVALID: schema,
258
+ issues: z.array(z.number()).optional(),
259
+ })
260
+ }
261
+
262
+ const ZodInvalidFrcsShot = Invalid(ZodFrcsShot.partial())
263
+
264
+ ZodInvalidFrcsShot satisfies DeepMapJsonSchema<InvalidFrcsShot>
265
+
266
+ const ZodInvalidFrcsUnits = Invalid(ZodFrcsUnits.partial())
267
+
268
+ ZodInvalidFrcsUnits satisfies DeepMapJsonSchema<InvalidFrcsUnits>
269
+
270
+ const ZodInvalidFrcsTripHeader = Invalid(ZodFrcsTripHeader.partial())
271
+
272
+ ZodInvalidFrcsTripHeader satisfies DeepMapJsonSchema<InvalidFrcsTripHeader>
273
+
274
+ const ZodInvalidFrcsTrip = Invalid(
275
+ z.strictObject({
276
+ tripNumber: z.number().int().min(1).optional(),
277
+ header: z.union([ZodInvalidFrcsTripHeader, ZodFrcsTripHeader]),
278
+ units: z.union([ZodInvalidFrcsUnits, ZodFrcsUnits]),
279
+ shots: z.array(z.union([ZodInvalidFrcsShot, ZodFrcsShot])),
280
+ })
281
+ )
282
+
283
+ ZodInvalidFrcsTrip satisfies DeepMapJsonSchema<InvalidFrcsTrip>
284
+
285
+ export const ZodInvalidFrcsSurveyFileToJson = z.strictObject({
286
+ INVALID: ZodFrcsSurveyFileToJson.extend({
287
+ trips: z.array(z.union([ZodInvalidFrcsTrip, ZodFrcsTrip])),
288
+ }),
289
+ issues: z.array(ParseIssue),
290
+ })
291
+
292
+ ZodInvalidFrcsSurveyFileToJson satisfies DeepMapJsonSchema<InvalidFrcsSurveyFile>
293
+
294
+ export const ZodValidOrInvalidFrcsSurveyFileToJson = z.union([
295
+ ZodInvalidFrcsSurveyFileToJson,
296
+ ZodFrcsSurveyFileToJson,
297
+ ])
@@ -1,8 +1,7 @@
1
- import { FrcsUnits } from './FrcsTrip'
2
- import { FrcsShot, FrcsShotKind } from './FrcsShot'
1
+ import type { FrcsUnits, FrcsShot } from './FrcsSurveyFile'
3
2
  import { Length, Unit, UnitType, UnitizedNumber } from '@speleotica/unitized'
4
3
  import {
5
- FrcsShotColumnConfig,
4
+ type FrcsShotColumnConfig,
6
5
  defaultFrcsShotColumnConfig,
7
6
  } from './FrcsSurveyFile'
8
7
 
@@ -24,6 +23,16 @@ export function makeFormatFrcsShot({
24
23
  return station.padStart(columns.toStation, ' ')
25
24
  }
26
25
 
26
+ function formatSpecialKind(specialKind: FrcsShot['specialKind']): string {
27
+ switch (specialKind) {
28
+ case 'diagonal':
29
+ return 'D'
30
+ case 'horizontal':
31
+ return 'H'
32
+ }
33
+ return ' '
34
+ }
35
+
27
36
  function trimZeroes(str: string): string {
28
37
  const match = /(-?\d+)(\.[1-9]*)0+$/.exec(str)
29
38
  if (!match) return str
@@ -46,11 +55,13 @@ export function makeFormatFrcsShot({
46
55
  return formatNum(num.get(verbatim ? num.unit : unit || num.unit))
47
56
  }
48
57
  if (num == null || !Number.isFinite(num)) return ' '.repeat(width)
49
- const precision = Math.max(0, width - String(Math.trunc(num)).length - 1)
50
- const formatted = trimZeroes(num.toFixed(precision))
51
- return formatted.length <= width
52
- ? formatted.padStart(width, ' ')
53
- : formatted.substring(0, width)
58
+ const formatted = trimZeroes(num.toFixed(2))
59
+ if (formatted.length <= width) return formatted.padStart(width, ' ')
60
+ if (formatted.length > width + 2) return formatted.substring(0, width)
61
+ return trimZeroes(num.toFixed(2 - formatted.length + width)).padStart(
62
+ width,
63
+ ' '
64
+ )
54
65
  }
55
66
  return formatNum
56
67
  }
@@ -125,7 +136,7 @@ export function makeFormatFrcsShot({
125
136
  }
126
137
 
127
138
  const distColumnValue =
128
- shot.kind === FrcsShotKind.Horizontal
139
+ shot.specialKind === 'horizontal'
129
140
  ? shot.horizontalDistance
130
141
  : shot.distance
131
142
 
@@ -135,28 +146,34 @@ export function makeFormatFrcsShot({
135
146
  inches
136
147
  ? formatFeet(distColumnValue)
137
148
  : formatDistance(distColumnValue, distanceUnit, isRecorded),
138
- inches ? formatInches(distColumnValue) : shot.kind,
139
- inches ? shot.kind : shot.excludeDistance ? '*' : ' ',
149
+ inches
150
+ ? formatInches(distColumnValue)
151
+ : formatSpecialKind(shot.specialKind),
152
+ inches
153
+ ? formatSpecialKind(shot.specialKind)
154
+ : shot.excludeDistance
155
+ ? '*'
156
+ : ' ',
140
157
  formatFsAzimuth(shot.frontsightAzimuth, azimuthUnit, isRecorded),
141
158
  formatBsAzimuth(shot.backsightAzimuth, azimuthUnit, isRecorded),
142
- shot.kind === FrcsShotKind.Normal
143
- ? formatFsInclination(
144
- shot.frontsightInclination,
145
- inclinationUnit,
146
- isRecorded
147
- )
148
- : formatVerticalDistance(
159
+ shot.specialKind
160
+ ? formatVerticalDistance(
149
161
  shot.verticalDistance,
150
162
  distanceUnit,
151
163
  isRecorded
164
+ )
165
+ : formatFsInclination(
166
+ shot.frontsightInclination,
167
+ inclinationUnit,
168
+ isRecorded
152
169
  ),
153
- shot.kind === FrcsShotKind.Normal
154
- ? formatBsInclination(
170
+ shot.specialKind
171
+ ? EMPTY_BS_INCLINATION
172
+ : formatBsInclination(
155
173
  shot.backsightInclination,
156
174
  inclinationUnit,
157
175
  isRecorded
158
- )
159
- : EMPTY_BS_INCLINATION,
176
+ ),
160
177
  formatLeft(shot.toLruds?.left, distanceUnit, isRecorded),
161
178
  formatRight(shot.toLruds?.right, distanceUnit, isRecorded),
162
179
  formatUp(shot.toLruds?.up, distanceUnit, isRecorded),
@@ -1,6 +1,5 @@
1
1
  import { Angle, Length, Unit } from '@speleotica/unitized'
2
- import { FrcsSurveyFile } from './FrcsSurveyFile'
3
- import { FrcsUnits } from './FrcsTrip'
2
+ import type { FrcsSurveyFile, FrcsUnits } from './FrcsSurveyFile'
4
3
  import { makeFormatFrcsShot } from './formatFrcsShot'
5
4
 
6
5
  export async function* formatFrcsSurveyFile(
@@ -12,7 +11,7 @@ export async function* formatFrcsSurveyFile(
12
11
  }
13
12
  for (let tripIndex = 0; tripIndex < file.trips.length; tripIndex++) {
14
13
  const trip = file.trips[tripIndex]
15
- const { shots, header } = trip
14
+ const { shots, header, units } = trip
16
15
  const { name, team, date, comment } = header
17
16
  if (tripIndex > 0) yield ' *\n'
18
17
  yield name.replace(/\n?$/, '\n')
@@ -23,7 +22,7 @@ export async function* formatFrcsSurveyFile(
23
22
  if (line2) yield `${line2}\n`
24
23
  if (comment) yield comment.replace(/\n?$/, '\n')
25
24
  yield ' *\n'
26
- yield formatUnits(header)
25
+ yield formatUnits(units)
27
26
 
28
27
  let alternateUnits: FrcsUnits | undefined
29
28
 
@@ -44,7 +43,7 @@ export async function* formatFrcsSurveyFile(
44
43
  }
45
44
  yield formatFrcsShot(
46
45
  shot.recorded || shot,
47
- alternateUnits || header
46
+ alternateUnits || units
48
47
  ).replace(/\n?$/, '\n')
49
48
  }
50
49
  }
@@ -0,0 +1,82 @@
1
+ import type { FrcsShotColumnConfig } from './FrcsSurveyFile'
2
+
3
+ type ColumnRanges = {
4
+ toStation: [number, number]
5
+ fromStation: [number, number]
6
+ distance: [number, number]
7
+ distanceFeet: [number, number]
8
+ distanceInches: [number, number]
9
+ kind: [number, number]
10
+ exclude: [number, number]
11
+ frontsightAzimuth: [number, number]
12
+ backsightAzimuth: [number, number]
13
+ frontsightInclination: [number, number]
14
+ backsightInclination: [number, number]
15
+ left: [number, number]
16
+ right: [number, number]
17
+ up: [number, number]
18
+ down: [number, number]
19
+ }
20
+
21
+ export function getColumnRanges(config: FrcsShotColumnConfig): {
22
+ decimal: ColumnRanges
23
+ feetAndInches: ColumnRanges
24
+ } {
25
+ const decimal: ColumnRanges = {
26
+ toStation: [0, 0],
27
+ fromStation: [0, 0],
28
+ distance: [0, 0],
29
+ distanceFeet: [0, 0],
30
+ distanceInches: [0, 0],
31
+ kind: [0, 0],
32
+ exclude: [0, 0],
33
+ frontsightAzimuth: [0, 0],
34
+ backsightAzimuth: [0, 0],
35
+ frontsightInclination: [0, 0],
36
+ backsightInclination: [0, 0],
37
+ left: [0, 0],
38
+ right: [0, 0],
39
+ up: [0, 0],
40
+ down: [0, 0],
41
+ }
42
+ const feetAndInches: ColumnRanges = {
43
+ toStation: [0, 0],
44
+ fromStation: [0, 0],
45
+ distance: [0, 0],
46
+ distanceFeet: [0, 0],
47
+ distanceInches: [0, 0],
48
+ kind: [0, 0],
49
+ exclude: [0, 0],
50
+ frontsightAzimuth: [0, 0],
51
+ backsightAzimuth: [0, 0],
52
+ frontsightInclination: [0, 0],
53
+ backsightInclination: [0, 0],
54
+ left: [0, 0],
55
+ right: [0, 0],
56
+ up: [0, 0],
57
+ down: [0, 0],
58
+ }
59
+
60
+ let c = 0
61
+ for (const [key, value] of Object.entries(config) as [
62
+ keyof FrcsShotColumnConfig,
63
+ FrcsShotColumnConfig[keyof FrcsShotColumnConfig]
64
+ ][]) {
65
+ if (key === 'distanceFeet' || key === 'distanceInches') continue
66
+ decimal[key][0] = c
67
+ decimal[key][1] = c + value
68
+ c += value
69
+ }
70
+ c = 0
71
+ for (const [key, value] of Object.entries(config) as [
72
+ keyof FrcsShotColumnConfig,
73
+ FrcsShotColumnConfig[keyof FrcsShotColumnConfig]
74
+ ][]) {
75
+ if (key === 'distance') continue
76
+ const width = key === 'frontsightAzimuth' ? value - 1 : value
77
+ feetAndInches[key][0] = c
78
+ feetAndInches[key][1] = c + width
79
+ c += width
80
+ }
81
+ return { decimal, feetAndInches }
82
+ }
@@ -0,0 +1,10 @@
1
+ export function normalizeTeamMemberName(name: string) {
2
+ if (name.toUpperCase() === name) {
3
+ name = name.replace(
4
+ /(\S)(\S*)/g,
5
+ (match, head, tail) => `${head}${tail.toLowerCase()}`
6
+ )
7
+ }
8
+ name = name.replace(/_/g, ' ')
9
+ return name
10
+ }