@speleotica/frcsdata 4.3.1 → 5.0.0-beta.2

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 (172) 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 +37 -0
  12. package/chunksToLines.js.map +1 -0
  13. package/cli/check-survey-correspondence.d.ts +2 -0
  14. package/cli/check-survey-correspondence.d.ts.map +1 -0
  15. package/cli/check-survey-correspondence.js +44 -0
  16. package/cli/check-survey-correspondence.js.map +1 -0
  17. package/cli/check-survey.d.ts +2 -0
  18. package/cli/check-survey.d.ts.map +1 -0
  19. package/cli/check-survey.js +27 -0
  20. package/cli/check-survey.js.map +1 -0
  21. package/cli/parse-survey.d.ts +2 -0
  22. package/cli/parse-survey.d.ts.map +1 -0
  23. package/cli/parse-survey.js +15 -0
  24. package/cli/parse-survey.js.map +1 -0
  25. package/cli/summarize-survey.d.ts +2 -0
  26. package/cli/summarize-survey.d.ts.map +1 -0
  27. package/cli/summarize-survey.js +33 -0
  28. package/cli/summarize-survey.js.map +1 -0
  29. package/cli.d.ts +2 -0
  30. package/cli.d.ts.map +1 -0
  31. package/cli.js +72 -0
  32. package/cli.js.map +1 -0
  33. package/formatFrcsTripSummaryFile.d.ts +3 -0
  34. package/formatFrcsTripSummaryFile.d.ts.map +1 -0
  35. package/formatFrcsTripSummaryFile.js +33 -0
  36. package/formatFrcsTripSummaryFile.js.map +1 -0
  37. package/formatIssues.d.ts +10 -0
  38. package/formatIssues.d.ts.map +1 -0
  39. package/formatIssues.js +52 -0
  40. package/formatIssues.js.map +1 -0
  41. package/index.d.ts +5 -7
  42. package/index.d.ts.map +1 -1
  43. package/index.js +16 -49
  44. package/index.js.map +1 -1
  45. package/node/index.d.ts +4 -2
  46. package/node/index.d.ts.map +1 -1
  47. package/node/index.js +6 -12
  48. package/node/index.js.map +1 -1
  49. package/package.json +8 -6
  50. package/parseFrcsPlotFile.js +112 -245
  51. package/parseFrcsPlotFile.js.map +1 -1
  52. package/parseFrcsTripSummaryFile.d.ts +3 -1
  53. package/parseFrcsTripSummaryFile.d.ts.map +1 -1
  54. package/parseFrcsTripSummaryFile.js +53 -119
  55. package/parseFrcsTripSummaryFile.js.map +1 -1
  56. package/src/ParseIssue.ts +19 -0
  57. package/src/SourceLoc.ts +13 -0
  58. package/src/chunksToLines.ts +26 -0
  59. package/src/cli/check-survey-correspondence.ts +49 -0
  60. package/src/cli/check-survey.ts +23 -0
  61. package/src/cli/parse-survey.ts +10 -0
  62. package/src/cli/summarize-survey.ts +28 -0
  63. package/src/cli.ts +63 -0
  64. package/src/formatFrcsTripSummaryFile.ts +45 -0
  65. package/src/formatIssues.ts +97 -0
  66. package/src/index.ts +9 -7
  67. package/src/node/index.ts +18 -5
  68. package/src/parseFrcsTripSummaryFile.ts +8 -2
  69. package/src/string/index.ts +18 -5
  70. package/src/survey/FrcsSurveyFile.ts +217 -0
  71. package/src/survey/FrcsSurveyFileJson.ts +46 -0
  72. package/src/survey/ZodFrcsSurveyFileJson.ts +260 -0
  73. package/src/survey/ZodFrcsSurveyFileToJson.ts +297 -0
  74. package/src/{formatFrcsShot.ts → survey/formatFrcsShot.ts} +39 -22
  75. package/src/{formatFrcsSurveyFile.ts → survey/formatFrcsSurveyFile.ts} +4 -5
  76. package/src/survey/getColumnRanges.ts +82 -0
  77. package/src/survey/normalizeTeamMemberName.ts +7 -0
  78. package/src/survey/parseFrcsSurveyFile.ts +848 -0
  79. package/src/survey/parsers.ts +128 -0
  80. package/src/survey/summarizeSurvey.ts +51 -0
  81. package/src/survey/validators.ts +24 -0
  82. package/src/underlineSource.ts +34 -0
  83. package/src/unwrapInvalid.ts +3 -0
  84. package/src/web/index.ts +27 -21
  85. package/string/index.d.ts +4 -2
  86. package/string/index.d.ts.map +1 -1
  87. package/string/index.js +8 -34
  88. package/string/index.js.map +1 -1
  89. package/survey/FrcsSurveyFile.d.ts +172 -0
  90. package/survey/FrcsSurveyFile.d.ts.map +1 -0
  91. package/{FrcsSurveyFile.js → survey/FrcsSurveyFile.js} +3 -1
  92. package/survey/FrcsSurveyFile.js.map +1 -0
  93. package/survey/FrcsSurveyFileJson.d.ts +15 -0
  94. package/survey/FrcsSurveyFileJson.d.ts.map +1 -0
  95. package/{FrcsTrip.js → survey/FrcsSurveyFileJson.js} +1 -1
  96. package/survey/FrcsSurveyFileJson.js.map +1 -0
  97. package/survey/ZodFrcsSurveyFileJson.d.ts +60549 -0
  98. package/survey/ZodFrcsSurveyFileJson.d.ts.map +1 -0
  99. package/survey/ZodFrcsSurveyFileJson.js +186 -0
  100. package/survey/ZodFrcsSurveyFileJson.js.map +1 -0
  101. package/survey/ZodFrcsSurveyFileToJson.d.ts +60390 -0
  102. package/survey/ZodFrcsSurveyFileToJson.d.ts.map +1 -0
  103. package/survey/ZodFrcsSurveyFileToJson.js +209 -0
  104. package/survey/ZodFrcsSurveyFileToJson.js.map +1 -0
  105. package/{formatFrcsShot.d.ts → survey/formatFrcsShot.d.ts} +2 -3
  106. package/survey/formatFrcsShot.d.ts.map +1 -0
  107. package/survey/formatFrcsShot.js +107 -0
  108. package/survey/formatFrcsShot.js.map +1 -0
  109. package/survey/formatFrcsSurveyFile.d.ts +3 -0
  110. package/survey/formatFrcsSurveyFile.d.ts.map +1 -0
  111. package/survey/formatFrcsSurveyFile.js +87 -0
  112. package/survey/formatFrcsSurveyFile.js.map +1 -0
  113. package/survey/getColumnRanges.d.ts +24 -0
  114. package/survey/getColumnRanges.d.ts.map +1 -0
  115. package/survey/getColumnRanges.js +62 -0
  116. package/survey/getColumnRanges.js.map +1 -0
  117. package/survey/normalizeTeamMemberName.d.ts +2 -0
  118. package/survey/normalizeTeamMemberName.d.ts.map +1 -0
  119. package/survey/normalizeTeamMemberName.js +12 -0
  120. package/survey/normalizeTeamMemberName.js.map +1 -0
  121. package/{parseFrcsSurveyFile.d.ts → survey/parseFrcsSurveyFile.d.ts} +2 -5
  122. package/survey/parseFrcsSurveyFile.d.ts.map +1 -0
  123. package/survey/parseFrcsSurveyFile.js +626 -0
  124. package/survey/parseFrcsSurveyFile.js.map +1 -0
  125. package/survey/parsers.d.ts +11 -0
  126. package/survey/parsers.d.ts.map +1 -0
  127. package/survey/parsers.js +119 -0
  128. package/survey/parsers.js.map +1 -0
  129. package/survey/summarizeSurvey.d.ts +6 -0
  130. package/survey/summarizeSurvey.d.ts.map +1 -0
  131. package/survey/summarizeSurvey.js +58 -0
  132. package/survey/summarizeSurvey.js.map +1 -0
  133. package/survey/validators.d.ts +7 -0
  134. package/survey/validators.d.ts.map +1 -0
  135. package/survey/validators.js +36 -0
  136. package/survey/validators.js.map +1 -0
  137. package/underlineSource.d.ts +6 -0
  138. package/underlineSource.d.ts.map +1 -0
  139. package/underlineSource.js +22 -0
  140. package/underlineSource.js.map +1 -0
  141. package/unwrapInvalid.d.ts +4 -0
  142. package/unwrapInvalid.d.ts.map +1 -0
  143. package/unwrapInvalid.js +10 -0
  144. package/unwrapInvalid.js.map +1 -0
  145. package/web/index.d.ts +6 -6
  146. package/web/index.d.ts.map +1 -1
  147. package/web/index.js +60 -118
  148. package/web/index.js.map +1 -1
  149. package/FrcsShot.d.ts +0 -57
  150. package/FrcsShot.d.ts.map +0 -1
  151. package/FrcsShot.js +0 -13
  152. package/FrcsShot.js.map +0 -1
  153. package/FrcsSurveyFile.d.ts +0 -29
  154. package/FrcsSurveyFile.d.ts.map +0 -1
  155. package/FrcsSurveyFile.js.map +0 -1
  156. package/FrcsTrip.d.ts +0 -23
  157. package/FrcsTrip.d.ts.map +0 -1
  158. package/FrcsTrip.js.map +0 -1
  159. package/formatFrcsShot.d.ts.map +0 -1
  160. package/formatFrcsShot.js +0 -96
  161. package/formatFrcsShot.js.map +0 -1
  162. package/formatFrcsSurveyFile.d.ts +0 -3
  163. package/formatFrcsSurveyFile.d.ts.map +0 -1
  164. package/formatFrcsSurveyFile.js +0 -165
  165. package/formatFrcsSurveyFile.js.map +0 -1
  166. package/parseFrcsSurveyFile.d.ts.map +0 -1
  167. package/parseFrcsSurveyFile.js +0 -812
  168. package/parseFrcsSurveyFile.js.map +0 -1
  169. package/src/FrcsShot.ts +0 -56
  170. package/src/FrcsSurveyFile.ts +0 -47
  171. package/src/FrcsTrip.ts +0 -25
  172. package/src/parseFrcsSurveyFile.ts +0 -788
@@ -1 +1 @@
1
- {"version":3,"file":"parseFrcsTripSummaryFile.js","names":["_unitized","require","_asyncIterator","r","n","t","o","e","Symbol","asyncIterator","iterator","call","AsyncFromSyncIterator","TypeError","AsyncFromSyncIteratorContinuation","Object","Promise","reject","done","resolve","value","then","s","next","prototype","apply","arguments","_return","_throw","tripSummaryRegex","parseFrcsTripSummaryFile","_x","_x2","_parseFrcsTripSummaryFile","_asyncToGenerator2","_regenerator","mark","_callee","file","lines","errors","tripSummaries","tripStartLine","lineNumber","team","shots","_iteratorAbruptCompletion","_didIteratorError","_iteratorError","_iterator","_step","line","match","tripNumber","tripIndex","year","date","totalLength","numShots","name","excludedLength","numExcludedShots","_team","_shots","trimmed","wrap","_callee$","_context","prev","sent","exec","parseInt","Date","Unitize","feet","parseFloat","trim","abrupt","push","_toConsumableArray2","split","t0","finish","stop","module","exports","default"],"sources":["src/parseFrcsTripSummaryFile.ts"],"sourcesContent":["import { FrcsTripSummary } from './FrcsTripSummary'\nimport { FrcsTripSummaryFile } from './FrcsTripSummaryFile'\nimport { SegmentParseError } from 'parse-segment'\nimport { Unitize } from '@speleotica/unitized'\n\nconst tripSummaryRegex =\n /^\\s*(\\d+)\\s+(\\d{1,2})\\/(\\s\\d|\\d\\d)\\/(\\d{2,4})\\s+(\\d+(?:\\.\\d*)?)\\s+(\\d+)\\s+(\\S.*)EXCLUDED:\\s*(\\d+(?:\\.\\d{2})?)\\s*(\\d+)/\n/**\n * Parses data from a STAT_sum.txt file. Here is an excerpt of the format:\n<pre> 1 2/15/81 258.60 17 ENTRANCE DROPS, JOE'S \"I LOVE MY WIFE TRAVERSE\", TRICKY TRAVERSE EXCLUDED: 0.00 0\n Peter Quick Keith Ortiz\n A1 AD1-AD3 AE1 AE1 SIDE\n AE9 SIDE AE10-AE9 AE13 SIDE AE15 SIDE\n AE20-AE11\n\n 3 3/ 6/81 2371.20 61 DOUG'S DEMISE (50 FT DROP), CHRIS CROSS, CRAWL ABOVE DROP EXCLUDED: 0.00 0\n Peter Quick Chris Gerace Phil Oden Chip Hopper\n A13 SIDE B1-B5 B2 SIDE B3 SIDE\n B6-B18 B17 SIDE B19-B38 B32 SIDE\n BS1-BS5 C1-C18 </pre>\n */\nexport default async function parseFrcsTripSummaryFile(\n file: string,\n lines: AsyncIterable<string>\n): Promise<FrcsTripSummaryFile> {\n const errors: Array<SegmentParseError> = []\n const tripSummaries: Array<FrcsTripSummary | undefined> = []\n\n let tripStartLine = -2\n let lineNumber = 0\n\n let team: Array<string> = []\n let shots: Array<string> = []\n\n for await (const line of lines) {\n lineNumber++\n\n const match = tripSummaryRegex.exec(line)\n if (match) {\n tripStartLine = lineNumber\n const tripNumber = parseInt(match[1])\n const tripIndex = tripNumber - 1\n let year = parseInt(match[4])\n if (year < 1000) year += 1900\n const date = new Date(year, parseInt(match[2]) - 1, parseInt(match[3]))\n const totalLength = Unitize.feet(parseFloat(match[5]))\n const numShots = parseInt(match[6])\n const name = match[7].trim()\n const excludedLength = Unitize.feet(parseFloat(match[8]))\n const numExcludedShots = parseInt(match[9])\n team = []\n shots = []\n tripSummaries[tripIndex] = {\n tripNumber,\n tripIndex,\n date,\n totalLength,\n numShots,\n name,\n excludedLength,\n numExcludedShots,\n team,\n shots,\n }\n continue\n }\n if (lineNumber === tripStartLine + 1) {\n team.push(...line.trim().split(/\\s\\s+|\\t+/g))\n } else {\n const trimmed = line.trim()\n if (trimmed) shots.push(...trimmed.split(/\\s\\s+|\\t+/))\n }\n }\n\n return { errors, tripSummaries }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"parseFrcsTripSummaryFile.js","names":["_unitized","require","tripSummaryRegex","parseFrcsTripSummaryFile","file","lines","indexBy","errors","tripSummaries","tripStartLine","lineNumber","team","shots","line","match","exec","tripNumber","parseInt","tripIndex","length","year","date","Date","totalLength","Unitize","feet","parseFloat","numShots","name","trim","excludedLength","numExcludedShots","push","split","trimmed","module","exports","default"],"sources":["src/parseFrcsTripSummaryFile.ts"],"sourcesContent":["import { FrcsTripSummary } from './FrcsTripSummary'\nimport { FrcsTripSummaryFile } from './FrcsTripSummaryFile'\nimport { SegmentParseError } from 'parse-segment'\nimport { Unitize } from '@speleotica/unitized'\n\nconst tripSummaryRegex =\n /^\\s*(\\d+)\\s+(\\d{1,2})\\/(\\s\\d|\\d\\d)\\/(\\d{2,4})\\s+(\\d+(?:\\.\\d*)?)\\s+(\\d+)\\s+(\\S.*)EXCLUDED:\\s*(\\d+(?:\\.\\d{2})?)\\s*(\\d+)/\n/**\n * Parses data from a STAT_sum.txt file. Here is an excerpt of the format:\n<pre> 1 2/15/81 258.60 17 ENTRANCE DROPS, JOE'S \"I LOVE MY WIFE TRAVERSE\", TRICKY TRAVERSE EXCLUDED: 0.00 0\n Peter Quick Keith Ortiz\n A1 AD1-AD3 AE1 AE1 SIDE\n AE9 SIDE AE10-AE9 AE13 SIDE AE15 SIDE\n AE20-AE11\n\n 3 3/ 6/81 2371.20 61 DOUG'S DEMISE (50 FT DROP), CHRIS CROSS, CRAWL ABOVE DROP EXCLUDED: 0.00 0\n Peter Quick Chris Gerace Phil Oden Chip Hopper\n A13 SIDE B1-B5 B2 SIDE B3 SIDE\n B6-B18 B17 SIDE B19-B38 B32 SIDE\n BS1-BS5 C1-C18 </pre>\n */\nexport default async function parseFrcsTripSummaryFile(\n file: string,\n lines: AsyncIterable<string>,\n {\n indexBy = 'tripNumber',\n }: {\n indexBy?: 'tripNumber' | 'occurrence'\n } = {}\n): Promise<FrcsTripSummaryFile> {\n const errors: Array<SegmentParseError> = []\n const tripSummaries: Array<FrcsTripSummary | undefined> = []\n\n let tripStartLine = -2\n let lineNumber = 0\n\n let team: Array<string> = []\n let shots: Array<string> = []\n\n for await (const line of lines) {\n lineNumber++\n\n const match = tripSummaryRegex.exec(line)\n if (match) {\n tripStartLine = lineNumber\n const tripNumber = parseInt(match[1])\n const tripIndex =\n indexBy === 'tripNumber' ? tripNumber - 1 : tripSummaries.length\n let year = parseInt(match[4])\n if (year < 1000) year += 1900\n const date = new Date(year, parseInt(match[2]) - 1, parseInt(match[3]))\n const totalLength = Unitize.feet(parseFloat(match[5]))\n const numShots = parseInt(match[6])\n const name = match[7].trim()\n const excludedLength = Unitize.feet(parseFloat(match[8]))\n const numExcludedShots = parseInt(match[9])\n team = []\n shots = []\n tripSummaries[tripIndex] = {\n tripNumber,\n tripIndex,\n date,\n totalLength,\n numShots,\n name,\n excludedLength,\n numExcludedShots,\n team,\n shots,\n }\n continue\n }\n if (lineNumber === tripStartLine + 1) {\n team.push(...line.trim().split(/\\s\\s+|\\t+/g))\n } else {\n const trimmed = line.trim()\n if (trimmed) shots.push(...trimmed.split(/\\s\\s+|\\t+/))\n }\n }\n\n return { errors, tripSummaries }\n}\n"],"mappings":";;;;;;AAGA,IAAAA,SAAA,GAAAC,OAAA;AAEA,MAAMC,gBAAgB,GACpB,uHAAuH;AACzH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACe,eAAeC,wBAAwBA,CACpDC,IAAY,EACZC,KAA4B,EAC5B;EACEC,OAAO,GAAG;AAGZ,CAAC,GAAG,CAAC,CAAC,EACwB;EAC9B,MAAMC,MAAgC,GAAG,EAAE;EAC3C,MAAMC,aAAiD,GAAG,EAAE;EAE5D,IAAIC,aAAa,GAAG,CAAC,CAAC;EACtB,IAAIC,UAAU,GAAG,CAAC;EAElB,IAAIC,IAAmB,GAAG,EAAE;EAC5B,IAAIC,KAAoB,GAAG,EAAE;EAE7B,WAAW,MAAMC,IAAI,IAAIR,KAAK,EAAE;IAC9BK,UAAU,EAAE;IAEZ,MAAMI,KAAK,GAAGZ,gBAAgB,CAACa,IAAI,CAACF,IAAI,CAAC;IACzC,IAAIC,KAAK,EAAE;MACTL,aAAa,GAAGC,UAAU;MAC1B,MAAMM,UAAU,GAAGC,QAAQ,CAACH,KAAK,CAAC,CAAC,CAAC,CAAC;MACrC,MAAMI,SAAS,GACbZ,OAAO,KAAK,YAAY,GAAGU,UAAU,GAAG,CAAC,GAAGR,aAAa,CAACW,MAAM;MAClE,IAAIC,IAAI,GAAGH,QAAQ,CAACH,KAAK,CAAC,CAAC,CAAC,CAAC;MAC7B,IAAIM,IAAI,GAAG,IAAI,EAAEA,IAAI,IAAI,IAAI;MAC7B,MAAMC,IAAI,GAAG,IAAIC,IAAI,CAACF,IAAI,EAAEH,QAAQ,CAACH,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAEG,QAAQ,CAACH,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;MACvE,MAAMS,WAAW,GAAGC,iBAAO,CAACC,IAAI,CAACC,UAAU,CAACZ,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;MACtD,MAAMa,QAAQ,GAAGV,QAAQ,CAACH,KAAK,CAAC,CAAC,CAAC,CAAC;MACnC,MAAMc,IAAI,GAAGd,KAAK,CAAC,CAAC,CAAC,CAACe,IAAI,CAAC,CAAC;MAC5B,MAAMC,cAAc,GAAGN,iBAAO,CAACC,IAAI,CAACC,UAAU,CAACZ,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;MACzD,MAAMiB,gBAAgB,GAAGd,QAAQ,CAACH,KAAK,CAAC,CAAC,CAAC,CAAC;MAC3CH,IAAI,GAAG,EAAE;MACTC,KAAK,GAAG,EAAE;MACVJ,aAAa,CAACU,SAAS,CAAC,GAAG;QACzBF,UAAU;QACVE,SAAS;QACTG,IAAI;QACJE,WAAW;QACXI,QAAQ;QACRC,IAAI;QACJE,cAAc;QACdC,gBAAgB;QAChBpB,IAAI;QACJC;MACF,CAAC;MACD;IACF;IACA,IAAIF,UAAU,KAAKD,aAAa,GAAG,CAAC,EAAE;MACpCE,IAAI,CAACqB,IAAI,CAAC,GAAGnB,IAAI,CAACgB,IAAI,CAAC,CAAC,CAACI,KAAK,CAAC,YAAY,CAAC,CAAC;IAC/C,CAAC,MAAM;MACL,MAAMC,OAAO,GAAGrB,IAAI,CAACgB,IAAI,CAAC,CAAC;MAC3B,IAAIK,OAAO,EAAEtB,KAAK,CAACoB,IAAI,CAAC,GAAGE,OAAO,CAACD,KAAK,CAAC,WAAW,CAAC,CAAC;IACxD;EACF;EAEA,OAAO;IAAE1B,MAAM;IAAEC;EAAc,CAAC;AAClC;AAAC2B,MAAA,CAAAC,OAAA,GAAAA,OAAA,CAAAC,OAAA","ignoreList":[]}
@@ -0,0 +1,19 @@
1
+ import { SourceLoc } from './SourceLoc'
2
+ import z from 'zod'
3
+
4
+ export const ParseIssueSeverity = z.enum(['error', 'warning'])
5
+ export type ParseIssueSeverity = z.output<typeof ParseIssueSeverity>
6
+
7
+ export const ParseIssue = z.strictObject({
8
+ type: ParseIssueSeverity,
9
+ code: z.string().nonempty(),
10
+ message: z.string().optional(),
11
+ loc: SourceLoc.optional(),
12
+ })
13
+
14
+ export type ParseIssue = {
15
+ type: ParseIssueSeverity
16
+ code: string
17
+ message?: string
18
+ loc?: SourceLoc
19
+ }
@@ -0,0 +1,13 @@
1
+ import z from 'zod'
2
+
3
+ export const SourcePos = z.object({
4
+ line: z.number().int().nonnegative(),
5
+ column: z.number().int().nonnegative(),
6
+ index: z.number().int().nonnegative(),
7
+ })
8
+
9
+ export type SourcePos = z.output<typeof SourcePos>
10
+
11
+ export const SourceLoc = z.object({ start: SourcePos, end: SourcePos })
12
+
13
+ export type SourceLoc = z.output<typeof SourceLoc>
@@ -0,0 +1,26 @@
1
+ export async function* chunksToLines(
2
+ chunks: Iterable<string> | AsyncIterable<string>
3
+ ) {
4
+ let chunkStartIndex = 0
5
+ let remainder = ''
6
+ let prevChunkEndedWithCarriageReturn = false
7
+ for await (let chunk of chunks) {
8
+ if (!chunk.length) continue
9
+ if (remainder) {
10
+ chunk = remainder + chunk
11
+ remainder = ''
12
+ }
13
+ let end = prevChunkEndedWithCarriageReturn && chunk[0] === '\n' ? 1 : 0
14
+ const rx = /\r\n?|\n/gm
15
+ rx.lastIndex = end
16
+ for (const match of chunk.matchAll(rx)) {
17
+ const line = chunk.substring(end, match.index)
18
+ yield { line, startIndex: chunkStartIndex + end }
19
+ end = match.index + match[0].length
20
+ }
21
+ if (end < chunk.length) remainder = chunk.substring(end)
22
+ chunkStartIndex += end
23
+ prevChunkEndedWithCarriageReturn = chunk[chunk.length - 1] === '\r'
24
+ }
25
+ if (remainder) yield { line: remainder, startIndex: chunkStartIndex }
26
+ }
@@ -0,0 +1,49 @@
1
+ /* eslint-disable no-console */
2
+ import chalk from 'chalk'
3
+ import { parseFrcsSurveyFile } from '../string/index'
4
+ import fs from 'fs/promises'
5
+ import { summarizeSurvey } from '../survey/summarizeSurvey'
6
+ import { parseFrcsTripSummaryFile } from '../node/index.js'
7
+ import { formatFrcsTripSummaryFile } from '../formatFrcsTripSummaryFile.js'
8
+ import { isDeepStrictEqual } from 'util'
9
+
10
+ export async function checkSurveyCorrespondence(
11
+ surveyFile: string,
12
+ summaryFile: string
13
+ ) {
14
+ const source = await fs.readFile(surveyFile, 'utf8')
15
+ const parsedSurvey = await parseFrcsSurveyFile(surveyFile, source)
16
+ const parsedSummaries = (
17
+ await parseFrcsTripSummaryFile(summaryFile, { indexBy: 'occurrence' })
18
+ ).tripSummaries.sort((a, b) => (a?.tripNumber ?? 0) - (b?.tripNumber ?? 0))
19
+ const convertedSummaries = summarizeSurvey(parsedSurvey, {
20
+ ignoreVerticalOfHShots: true,
21
+ }).tripSummaries.sort((a, b) => (a?.tripNumber ?? 0) - (b?.tripNumber ?? 0))
22
+
23
+ let errored = false
24
+
25
+ for (
26
+ let i = 0;
27
+ i < Math.max(parsedSummaries.length, convertedSummaries.length);
28
+ i++
29
+ ) {
30
+ const parsed = parsedSummaries[i]
31
+ const converted = convertedSummaries[i]
32
+
33
+ const parsedLines = [
34
+ ...formatFrcsTripSummaryFile({ tripSummaries: [parsed] }),
35
+ ].slice(0, 2)
36
+ const convertedLines = [
37
+ ...formatFrcsTripSummaryFile({ tripSummaries: [converted] }),
38
+ ].slice(0, 2)
39
+
40
+ if (!isDeepStrictEqual(parsedLines, convertedLines)) {
41
+ errored = true
42
+ console.log(
43
+ convertedLines.map((line) => chalk.green('+' + line)).join('\n')
44
+ )
45
+ console.log(parsedLines.map((line) => chalk.red('-' + line)).join('\n'))
46
+ }
47
+ }
48
+ process.exit(errored ? 1 : 0)
49
+ }
@@ -0,0 +1,23 @@
1
+ /* eslint-disable no-console */
2
+ import fs from 'fs/promises'
3
+ import parseFrcsSurveyFile from '../survey/parseFrcsSurveyFile'
4
+ import chalk from 'chalk'
5
+ import { formatIssues } from '../formatIssues.js'
6
+
7
+ export async function checkSurvey(file: string) {
8
+ const source = await fs.readFile(file, 'utf8')
9
+ const parsed = await parseFrcsSurveyFile(file, [source])
10
+
11
+ const issues = parsed.issues || []
12
+ console.log(
13
+ formatIssues({
14
+ file,
15
+ source,
16
+ parsed,
17
+ errorStyle: chalk.red,
18
+ warningStyle: chalk.yellow,
19
+ })
20
+ )
21
+
22
+ process.exit(issues.some((i) => i.type === 'error') ? 1 : 0)
23
+ }
@@ -0,0 +1,10 @@
1
+ /* eslint-disable no-console */
2
+ import { parseFrcsSurveyFile } from '../node/index'
3
+ import { ZodValidOrInvalidFrcsSurveyFileToJson } from '../survey/ZodFrcsSurveyFileToJson'
4
+
5
+ export async function parseSurvey(file: string) {
6
+ const parsed = ZodValidOrInvalidFrcsSurveyFileToJson.parse(
7
+ await parseFrcsSurveyFile(file)
8
+ )
9
+ console.log(JSON.stringify(parsed))
10
+ }
@@ -0,0 +1,28 @@
1
+ /* eslint-disable no-console */
2
+ import chalk from 'chalk'
3
+ import { formatIssues } from '../formatIssues'
4
+ import { parseFrcsSurveyFile } from '../string/index'
5
+ import fs from 'fs/promises'
6
+ import { formatFrcsTripSummaryFile } from '../formatFrcsTripSummaryFile'
7
+ import { summarizeSurvey as baseSummarizeSurvey } from '../survey/summarizeSurvey'
8
+
9
+ export async function summarizeSurvey(file: string) {
10
+ const source = await fs.readFile(file, 'utf8')
11
+ const parsed = await parseFrcsSurveyFile(file, source)
12
+ if ('INVALID' in parsed) {
13
+ console.log(
14
+ formatIssues({
15
+ file,
16
+ source,
17
+ parsed,
18
+ errorStyle: chalk.red,
19
+ warningStyle: chalk.yellow,
20
+ })
21
+ )
22
+ process.exit(1)
23
+ }
24
+
25
+ for (const line of formatFrcsTripSummaryFile(baseSummarizeSurvey(parsed))) {
26
+ console.log(line)
27
+ }
28
+ }
package/src/cli.ts ADDED
@@ -0,0 +1,63 @@
1
+ import yargs from 'yargs/yargs'
2
+
3
+ void yargs(process.argv.slice(2))
4
+ .command({
5
+ command: 'check-survey <file>',
6
+ describe: 'check survey file for errors or warnings',
7
+ builder: (yargs) =>
8
+ yargs.positional('file', {
9
+ type: 'string',
10
+ demandOption: true,
11
+ }),
12
+ handler: async ({ file }) => {
13
+ const { checkSurvey } = await import('./cli/check-survey')
14
+ await checkSurvey(file)
15
+ },
16
+ })
17
+ .command({
18
+ command: 'parse-survey <file>',
19
+ describe: 'parse survey file and output JSON parse tree',
20
+ builder: (yargs) =>
21
+ yargs.positional('file', {
22
+ type: 'string',
23
+ demandOption: true,
24
+ }),
25
+ handler: async ({ file }) => {
26
+ const { parseSurvey } = await import('./cli/parse-survey')
27
+ await parseSurvey(file)
28
+ },
29
+ })
30
+ .command({
31
+ command: 'summarize-survey <file>',
32
+ describe: 'parse survey file and output trip summaries',
33
+ builder: (yargs) =>
34
+ yargs.positional('file', {
35
+ type: 'string',
36
+ demandOption: true,
37
+ }),
38
+ handler: async ({ file }) => {
39
+ const { summarizeSurvey } = await import('./cli/summarize-survey')
40
+ await summarizeSurvey(file)
41
+ },
42
+ })
43
+ .command({
44
+ command: 'check-survey-correspondence <surveyFile> <summaryFile>',
45
+ describe: 'parse survey file and output trip summaries',
46
+ builder: (yargs) =>
47
+ yargs
48
+ .positional('surveyFile', {
49
+ type: 'string',
50
+ demandOption: true,
51
+ })
52
+ .positional('summaryFile', {
53
+ type: 'string',
54
+ demandOption: true,
55
+ }),
56
+ handler: async ({ surveyFile, summaryFile }) => {
57
+ const { checkSurveyCorrespondence } = await import(
58
+ './cli/check-survey-correspondence'
59
+ )
60
+ await checkSurveyCorrespondence(surveyFile, summaryFile)
61
+ },
62
+ })
63
+ .demandCommand().argv
@@ -0,0 +1,45 @@
1
+ import { Length } from '@speleotica/unitized'
2
+ import { FrcsTripSummaryFile } from './FrcsTripSummaryFile.js'
3
+
4
+ const nameLength = 78
5
+
6
+ export function* formatFrcsTripSummaryFile(
7
+ file: FrcsTripSummaryFile
8
+ ): Iterable<string> {
9
+ for (const summary of file.tripSummaries) {
10
+ if (!summary) continue
11
+ const {
12
+ tripNumber,
13
+ date,
14
+ totalLength,
15
+ numShots,
16
+ name,
17
+ excludedLength,
18
+ numExcludedShots,
19
+ team,
20
+ shots,
21
+ } = summary
22
+ const month = (date.getMonth() + 1).toFixed()
23
+ const day = date.getDate().toFixed()
24
+ const year = date.getFullYear().toFixed()
25
+ yield `${tripNumber.toFixed().padStart(3)} ${month.padStart(
26
+ 2
27
+ )}/${day.padStart(2)}/${year.padStart(4)}${totalLength
28
+ .get(Length.feet)
29
+ .toFixed(2)
30
+ .padStart(10)}${numShots.toFixed().padStart(5)} ${name
31
+ .slice(0, nameLength)
32
+ .padEnd(nameLength)} EXCLUDED:${excludedLength
33
+ .get(Length.feet)
34
+ .toFixed(2)
35
+ .padStart(7)}${numExcludedShots.toFixed().padStart(3)}`
36
+ yield ' '.repeat(tripNumber >= 1000 ? 34 : 33) + team.join(' ')
37
+ for (let i = 0; i < shots.length; i += 4) {
38
+ yield ' '.repeat(tripNumber >= 1000 ? 36 : 35) +
39
+ shots
40
+ .slice(i, i + 4)
41
+ .map((s) => s.padEnd(14))
42
+ .join('')
43
+ }
44
+ }
45
+ }
@@ -0,0 +1,97 @@
1
+ import { FrcsSurveyFile, InvalidFrcsSurveyFile } from './survey/FrcsSurveyFile'
2
+ import {
3
+ FrcsSurveyFileJson,
4
+ InvalidFrcsSurveyFileJson,
5
+ } from './survey/FrcsSurveyFileJson.js'
6
+ import { underlineSource } from './underlineSource'
7
+ import { unwrapInvalid } from './unwrapInvalid.js'
8
+
9
+ export function formatIssues({
10
+ parsed,
11
+ source,
12
+ file,
13
+ errorStyle = (s) => s,
14
+ warningStyle = (s) => s,
15
+ }: {
16
+ parsed:
17
+ | FrcsSurveyFile
18
+ | InvalidFrcsSurveyFile
19
+ | FrcsSurveyFileJson
20
+ | InvalidFrcsSurveyFileJson
21
+ source: string
22
+ file: string
23
+ errorStyle?: (s: string) => string
24
+ warningStyle?: (s: string) => string
25
+ }) {
26
+ const issues = parsed.issues || []
27
+ const lines: string[] = []
28
+ for (const issue of issues) {
29
+ const { type, loc, message } = issue
30
+ const style = type === 'error' ? errorStyle : warningStyle
31
+ lines.push(
32
+ `${style(
33
+ `${
34
+ type === 'error' ? errorStyle('✘') : warningStyle('⚠')
35
+ } ${`${type[0].toUpperCase()}${type.substring(1)}:`.padEnd(
36
+ 8
37
+ )} ${message?.padEnd(40)}`
38
+ )} (${file}:${loc?.start?.line}:${loc?.start?.column})`
39
+ )
40
+ if (loc) {
41
+ lines.push(underlineSource(source, loc, { underlineStyle: style }))
42
+ }
43
+ }
44
+
45
+ const errorCount = issues.reduce(
46
+ (count, i) => (i.type === 'error' ? count + 1 : count),
47
+ 0
48
+ )
49
+ const warningCount = issues.reduce(
50
+ (count, i) => (i.type === 'warning' ? count + 1 : count),
51
+ 0
52
+ )
53
+ const trips = unwrapInvalid(parsed).trips
54
+ const tripCount = trips.length
55
+ const shotCount = trips.reduce(
56
+ (count, trip) => count + unwrapInvalid(trip).shots.length,
57
+ 0
58
+ )
59
+
60
+ const fmtErrorCount = `✘ ${errorCount}`
61
+ const fmtWarningCount = `⚠ ${warningCount}`
62
+ const fmtTripCount = `${tripCount}`
63
+ const fmtShotCount = `${shotCount}`
64
+
65
+ const countWidth = Math.max(
66
+ fmtErrorCount.length,
67
+ fmtWarningCount.length,
68
+ fmtTripCount.length,
69
+ fmtShotCount.length
70
+ )
71
+
72
+ if (errorCount) {
73
+ lines.push(
74
+ errorStyle(
75
+ `${fmtErrorCount.padStart(countWidth)} error${
76
+ errorCount === 1 ? '' : 's'
77
+ }`
78
+ )
79
+ )
80
+ }
81
+ if (warningCount) {
82
+ lines.push(
83
+ warningStyle(
84
+ `${fmtWarningCount.padStart(countWidth)} warning${
85
+ warningCount === 1 ? '' : 's'
86
+ }`
87
+ )
88
+ )
89
+ }
90
+ lines.push(
91
+ `${fmtTripCount.padStart(countWidth)} trip${tripCount === 1 ? '' : 's'}`
92
+ )
93
+ lines.push(
94
+ `${fmtShotCount.padStart(countWidth)} shot${shotCount === 1 ? '' : 's'}`
95
+ )
96
+ return lines.join('\n')
97
+ }
package/src/index.ts CHANGED
@@ -1,19 +1,21 @@
1
- import { FrcsTrip, FrcsTripHeader } from './FrcsTrip'
2
- import { FrcsShot, FrcsShotKind } from './FrcsShot'
3
- import { FrcsSurveyFile } from './FrcsSurveyFile'
4
- import parseFrcsSurveyFile from './parseFrcsSurveyFile'
1
+ import type {
2
+ FrcsShot,
3
+ FrcsSurveyFile,
4
+ FrcsTrip,
5
+ FrcsTripHeader,
6
+ } from './survey/FrcsSurveyFile'
7
+ import parseFrcsSurveyFile from './survey/parseFrcsSurveyFile'
5
8
  import { FrcsPlotShot } from './FrcsPlotShot'
6
9
  import { FrcsPlotFile } from './FrcsPlotFile'
7
10
  import parseFrcsPlotFile from './parseFrcsPlotFile'
8
11
  import { FrcsTripSummary } from './FrcsTripSummary'
9
12
  import { FrcsTripSummaryFile } from './FrcsTripSummaryFile'
10
13
  import parseFrcsTripSummaryFile from './parseFrcsTripSummaryFile'
11
- import formatFrcsShot from './formatFrcsShot'
12
- import { formatFrcsSurveyFile } from './formatFrcsSurveyFile'
14
+ import formatFrcsShot from './survey/formatFrcsShot'
15
+ import { formatFrcsSurveyFile } from './survey/formatFrcsSurveyFile'
13
16
 
14
17
  export {
15
18
  FrcsShot,
16
- FrcsShotKind,
17
19
  FrcsSurveyFile,
18
20
  FrcsTrip,
19
21
  FrcsTripHeader,
package/src/node/index.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  import fs from 'fs'
2
2
  import readline from 'readline'
3
- import _parseFrcsSurveyFile from '../parseFrcsSurveyFile'
3
+ import _parseFrcsSurveyFile from '../survey/parseFrcsSurveyFile'
4
4
  import _parseFrcsPlotFile from '../parseFrcsPlotFile'
5
5
  import _parseFrcsTripSummaryFile from '../parseFrcsTripSummaryFile'
6
6
 
7
- const convert =
7
+ const convertLineBased =
8
8
  <T, Rest extends any[]>(
9
9
  fn: (
10
10
  file: string,
@@ -15,6 +15,19 @@ const convert =
15
15
  (file: string, ...rest: Rest): Promise<T> =>
16
16
  fn(file, readline.createInterface(fs.createReadStream(file)), ...rest)
17
17
 
18
- export const parseFrcsSurveyFile = convert(_parseFrcsSurveyFile)
19
- export const parseFrcsPlotFile = convert(_parseFrcsPlotFile)
20
- export const parseFrcsTripSummaryFile = convert(_parseFrcsTripSummaryFile)
18
+ const convertChunkBased =
19
+ <T, Rest extends any[]>(
20
+ fn: (
21
+ file: string,
22
+ lines: AsyncIterable<string>,
23
+ ...rest: Rest
24
+ ) => Promise<T>
25
+ ) =>
26
+ (file: string, ...rest: Rest): Promise<T> =>
27
+ fn(file, fs.createReadStream(file, 'utf8'), ...rest)
28
+
29
+ export const parseFrcsSurveyFile = convertChunkBased(_parseFrcsSurveyFile)
30
+ export const parseFrcsPlotFile = convertLineBased(_parseFrcsPlotFile)
31
+ export const parseFrcsTripSummaryFile = convertLineBased(
32
+ _parseFrcsTripSummaryFile
33
+ )
@@ -21,7 +21,12 @@ const tripSummaryRegex =
21
21
  */
22
22
  export default async function parseFrcsTripSummaryFile(
23
23
  file: string,
24
- lines: AsyncIterable<string>
24
+ lines: AsyncIterable<string>,
25
+ {
26
+ indexBy = 'tripNumber',
27
+ }: {
28
+ indexBy?: 'tripNumber' | 'occurrence'
29
+ } = {}
25
30
  ): Promise<FrcsTripSummaryFile> {
26
31
  const errors: Array<SegmentParseError> = []
27
32
  const tripSummaries: Array<FrcsTripSummary | undefined> = []
@@ -39,7 +44,8 @@ export default async function parseFrcsTripSummaryFile(
39
44
  if (match) {
40
45
  tripStartLine = lineNumber
41
46
  const tripNumber = parseInt(match[1])
42
- const tripIndex = tripNumber - 1
47
+ const tripIndex =
48
+ indexBy === 'tripNumber' ? tripNumber - 1 : tripSummaries.length
43
49
  let year = parseInt(match[4])
44
50
  if (year < 1000) year += 1900
45
51
  const date = new Date(year, parseInt(match[2]) - 1, parseInt(match[3]))
@@ -1,11 +1,11 @@
1
- import _parseFrcsSurveyFile from '../parseFrcsSurveyFile'
1
+ import _parseFrcsSurveyFile from '../survey/parseFrcsSurveyFile'
2
2
  import _parseFrcsPlotFile from '../parseFrcsPlotFile'
3
3
  import _parseFrcsTripSummaryFile from '../parseFrcsTripSummaryFile'
4
4
 
5
5
  async function* linesOf(s: string): AsyncIterable<string> {
6
6
  yield* s.split(/\r\n?|\n/gm)
7
7
  }
8
- const convert =
8
+ const convertLineBased =
9
9
  <T, Rest extends any[]>(
10
10
  fn: (
11
11
  file: string,
@@ -16,6 +16,19 @@ const convert =
16
16
  (file: string, str: string, ...rest: Rest): Promise<T> =>
17
17
  fn(file, linesOf(str), ...rest)
18
18
 
19
- export const parseFrcsSurveyFile = convert(_parseFrcsSurveyFile)
20
- export const parseFrcsPlotFile = convert(_parseFrcsPlotFile)
21
- export const parseFrcsTripSummaryFile = convert(_parseFrcsTripSummaryFile)
19
+ const convertChunkBased =
20
+ <T, Rest extends any[]>(
21
+ fn: (
22
+ file: string,
23
+ lines: Iterable<string> | AsyncIterable<string>,
24
+ ...rest: Rest
25
+ ) => Promise<T>
26
+ ) =>
27
+ (file: string, str: string, ...rest: Rest): Promise<T> =>
28
+ fn(file, [str], ...rest)
29
+
30
+ export const parseFrcsSurveyFile = convertChunkBased(_parseFrcsSurveyFile)
31
+ export const parseFrcsPlotFile = convertLineBased(_parseFrcsPlotFile)
32
+ export const parseFrcsTripSummaryFile = convertLineBased(
33
+ _parseFrcsTripSummaryFile
34
+ )