@atmosx/event-product-parser 3.0.62 → 3.0.75

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 (179) hide show
  1. package/.github/docs/docs-functions.md +1 -1
  2. package/.github/docs/docs-general-configurations.md +1 -11
  3. package/.github/docs/docs-integrations.md +3 -2
  4. package/README.md +10 -8
  5. package/dist/cjs/index.cjs +24482 -7207
  6. package/dist/esm/index.mjs +24275 -7003
  7. package/package.json +56 -47
  8. package/pnpm-workspace.yaml +4 -0
  9. package/src/bootstrap.ts +65 -48
  10. package/src/{@building → building}/CreateEvent.ts +22 -24
  11. package/src/{@building → building}/GetCleanedEvent.ts +2 -2
  12. package/src/{@building → building}/GetEventAttachments.ts +14 -12
  13. package/src/building/GetEventDirection.ts +28 -0
  14. package/src/{@building → building}/GetEventEnhancedName.ts +5 -8
  15. package/src/{@building → building}/GetEventGeometry.ts +19 -13
  16. package/src/{@building → building}/GetEventHeader.ts +13 -13
  17. package/src/{@building → building}/GetEventNodes.ts +22 -20
  18. package/src/{@building → building}/GetEventOffice.ts +13 -13
  19. package/src/building/GetEventPopulation.ts +58 -0
  20. package/src/building/GetEventProperties.ts +106 -0
  21. package/src/{@building → building}/GetEventSignature.ts +9 -9
  22. package/src/{@building → building}/GetEventTags.ts +3 -3
  23. package/src/building/GetEventTheme.ts +26 -0
  24. package/src/building/GetEventTracking.ts +64 -0
  25. package/src/components/audio/GenerateAudioMessage.ts +149 -0
  26. package/src/{@modules/@eas → components/audio/components}/GetCleanDescription.ts +2 -2
  27. package/src/{@modules/@eas → components/audio/components}/GetFloatPCM16.ts +2 -2
  28. package/src/{@modules/@eas → components/audio/components}/GetMergedPCM16.ts +2 -2
  29. package/src/{@modules/@eas → components/audio/components}/GetPCM16.ts +13 -8
  30. package/src/{@modules/@eas → components/audio/components}/GetPCMToFloat.ts +2 -2
  31. package/src/{@modules/@eas → components/audio/components}/GetSampledPCM16.ts +14 -8
  32. package/src/{@modules/@eas → components/audio/components}/GetTTS.ts +17 -10
  33. package/src/{@modules/@eas → components/audio/components}/GetWavPCM16.ts +7 -7
  34. package/src/{@modules/@eas → components/audio/components}/SetAFSK.ts +13 -8
  35. package/src/{@modules/@eas → components/audio/components}/SetAsciiToBits.ts +2 -2
  36. package/src/{@modules/@eas → components/audio/components}/SetAttentionTone.ts +11 -6
  37. package/src/{@modules/@eas → components/audio/components}/SetNoise.ts +12 -7
  38. package/src/{@modules/@eas → components/audio/components}/SetRadioEffect.ts +12 -7
  39. package/src/{@modules/@eas → components/audio/components}/SetSameHeader.ts +22 -14
  40. package/src/{@modules/@utilities/SetWarning.ts → components/database/CreateQuery.ts} +18 -13
  41. package/src/{@modules/@database → components/database}/GetCachedEvents.ts +18 -15
  42. package/src/components/database/ImportBoundaries.ts +168 -0
  43. package/src/{@modules/@database → components/database}/ImportBroadcastify.ts +14 -24
  44. package/src/components/database/ImportCities.ts +87 -0
  45. package/src/{@modules/@database → components/database}/ImportShapefiles.ts +23 -26
  46. package/src/{@modules/@database → components/database}/ImportStanza.ts +15 -19
  47. package/src/components/database/InitializeDatabase.ts +71 -0
  48. package/src/components/images/GenerateGraphic.ts +242 -0
  49. package/src/components/images/components/CreateRectangle.ts +22 -0
  50. package/src/components/images/components/CreateText.ts +22 -0
  51. package/src/components/images/modules/CreateSVG.ts +37 -0
  52. package/src/components/images/modules/GetGeographicalBoundaries.ts +72 -0
  53. package/src/components/images/modules/GetGeographicalCities.ts +58 -0
  54. package/src/components/images/modules/GetGeographicalEvents.ts +48 -0
  55. package/src/components/images/modules/GetGeometryBounds.ts +82 -0
  56. package/src/components/images/modules/GetParsedBoundary.ts +58 -0
  57. package/src/components/images/modules/GetSVGPath.ts +53 -0
  58. package/src/components/images/modules/NormalizePolygon.ts +57 -0
  59. package/src/{@modules/@stanza → components/stanza}/GetAwipsType.ts +16 -17
  60. package/src/{@modules/@stanza → components/stanza}/ValidateStanza.ts +27 -15
  61. package/src/{@modules/@utilities → components/utilities}/CreateHttp.ts +26 -26
  62. package/src/{@parsers/@text → components/utilities}/GetEmbededText.ts +8 -6
  63. package/src/{@modules/@utilities → components/utilities}/GetFormattedTime.ts +2 -2
  64. package/src/{@modules/@utilities → components/utilities}/GetLatestIssuance.ts +2 -2
  65. package/src/{@modules/@utilities → components/utilities}/GetMatched.ts +10 -5
  66. package/src/{@modules/@utilities → components/utilities}/GetShapeNearestPoint.ts +24 -19
  67. package/src/{@parsers/@text → components/utilities}/GetStringText.ts +9 -9
  68. package/src/components/utilities/GetUnionPolygon.ts +36 -0
  69. package/src/components/utilities/QueueManager.ts +70 -0
  70. package/src/components/utilities/SetCronSchedule.ts +106 -0
  71. package/src/{@modules/@utilities → components/utilities}/SetDebug.ts +12 -12
  72. package/src/components/utilities/SetEventEmit.ts +42 -0
  73. package/src/{@modules/@utilities → components/utilities}/SetSettings.ts +7 -7
  74. package/src/{@modules/@utilities → components/utilities}/SetSleep.ts +5 -5
  75. package/src/components/utilities/SetTimeoutAction.ts +64 -0
  76. package/src/components/utilities/SetWarning.ts +47 -0
  77. package/src/{@modules/@xmpp → components/xmpp}/DeployXMPP.ts +20 -20
  78. package/src/{@core/CreateListener.ts → components/xmpp/ErrorXMPP.ts} +8 -5
  79. package/src/{@modules/@xmpp → components/xmpp}/OfflineXMPP.ts +13 -13
  80. package/src/{@modules/@xmpp → components/xmpp}/OnlineXMPP.ts +18 -18
  81. package/src/components/xmpp/ReconnectXMPP.ts +64 -0
  82. package/src/{@modules/@xmpp → components/xmpp}/StanzaXMPP.ts +25 -25
  83. package/src/{@core → core}/ClearEvents.ts +9 -9
  84. package/src/{@core → core}/GetEvents.ts +4 -4
  85. package/src/{@core → core}/GetNodes.ts +4 -4
  86. package/src/{@core → core}/GetRandomEvent.ts +4 -4
  87. package/src/{@core → core}/GetVersion.ts +4 -4
  88. package/src/{@core → core}/ManualEvent.ts +23 -24
  89. package/src/{@core → core}/QueryStanza.ts +12 -11
  90. package/src/core/SetNode.ts +87 -0
  91. package/src/{@core → core}/StartService.ts +21 -20
  92. package/src/{@core → core}/StopService.ts +10 -10
  93. package/src/{@enums → enums}/AWIPS.ts +2 -2
  94. package/src/{@enums → enums}/Actions.ts +2 -2
  95. package/src/{@enums → enums}/Cancellation.ts +2 -2
  96. package/src/{@enums → enums}/Causes.ts +2 -2
  97. package/src/{@enums → enums}/Correlations.ts +2 -2
  98. package/src/{@enums → enums}/Enhanced.ts +4 -3
  99. package/src/{@enums → enums}/Events.ts +2 -2
  100. package/src/{@enums → enums}/Expressions.ts +3 -3
  101. package/src/{@enums → enums}/GlobalFilter.ts +2 -2
  102. package/src/{@enums → enums}/Hail.ts +2 -2
  103. package/src/{@enums → enums}/ICAO.ts +2 -2
  104. package/src/{@enums → enums}/Matches.ts +8 -3
  105. package/src/{@enums → enums}/Products.ts +2 -2
  106. package/src/{@enums → enums}/Records.ts +2 -2
  107. package/src/{@enums → enums}/Severity.ts +2 -2
  108. package/src/{@enums → enums}/Shapefiles.ts +2 -2
  109. package/src/{@enums → enums}/States.ts +68 -4
  110. package/src/{@enums → enums}/Status.ts +2 -2
  111. package/src/{@enums → enums}/Strings.ts +2 -2
  112. package/src/{@enums → enums}/Tags.ts +9 -4
  113. package/src/{@enums → enums}/Testing.ts +2 -2
  114. package/src/enums/Themes.ts +70 -0
  115. package/src/events/ParseAPI.ts +133 -0
  116. package/src/{@events → events}/ParseText.ts +24 -22
  117. package/src/{@events → events}/ParseUGC.ts +27 -26
  118. package/src/{@events → events}/ParseVTEC.ts +38 -37
  119. package/src/index.ts +57 -37
  120. package/src/{@manager → manager}/MakeEvents.ts +38 -47
  121. package/src/manager/RemoveEvent.ts +74 -0
  122. package/src/{@manager → manager}/SetHash.ts +18 -13
  123. package/src/{@manager → manager}/UpdateEvents.ts +12 -12
  124. package/src/{@manager → manager}/UpdateNode.ts +14 -14
  125. package/src/{@manager → manager}/ValidateEvents.ts +55 -45
  126. package/src/{@parsers/@hvtec → parsers/hvtec}/HVExtract.ts +11 -11
  127. package/src/{@parsers/@text → parsers/text}/GetDescriptionFromProduct.ts +20 -21
  128. package/src/parsers/text/GetPolygonFromProduct.ts +71 -0
  129. package/src/{@parsers/@text → parsers/text}/GetTextFromProduct.ts +12 -12
  130. package/src/parsers/ugc/GetCache.ts +24 -0
  131. package/src/{@parsers/@ugc → parsers/ugc}/GetExpiry.ts +2 -2
  132. package/src/{@parsers/@ugc/GetUGCHeader.ts → parsers/ugc/GetHeader.ts} +4 -4
  133. package/src/{@parsers/@ugc → parsers/ugc}/GetLocations.ts +10 -10
  134. package/src/parsers/ugc/GetZonePolygon.ts +73 -0
  135. package/src/{@parsers/@ugc → parsers/ugc}/GetZones.ts +3 -3
  136. package/src/{@parsers/@ugc → parsers/ugc}/SetCache.ts +13 -8
  137. package/src/{@parsers/@ugc → parsers/ugc}/UGCExtract.ts +14 -14
  138. package/src/{@parsers/@pvtec → parsers/vtec}/GetExpiry.ts +2 -2
  139. package/src/parsers/vtec/VTECExtract.ts +49 -0
  140. package/src/{@types → static}/Attributes.ts +2 -3
  141. package/src/{@types → static}/Event.ts +8 -7
  142. package/src/{@types → static}/Properties.ts +17 -3
  143. package/src/{@types → static}/Stanza.ts +2 -2
  144. package/src/tasks/CreateTasks.ts +116 -0
  145. package/src/tasks/TaskGenerateJSON.ts +34 -0
  146. package/src/tasks/TaskGenerateText.ts +34 -0
  147. package/src/tasks/TaskSendNTFY.ts +95 -0
  148. package/src/tasks/TaskSendWebhook.ts +107 -0
  149. package/src/{@types → types}/Actions.ts +3 -3
  150. package/src/{@types → types}/HVTEC.ts +6 -6
  151. package/src/{@types → types}/Hash.ts +5 -5
  152. package/src/types/Nodes.ts +29 -0
  153. package/src/{@types → types}/Settings.ts +17 -8
  154. package/src/{@types → types}/StanzaCompiled.ts +15 -15
  155. package/src/{@types → types}/UGC.ts +5 -5
  156. package/src/{@modules/@utilities/GetSettings.ts → types/VTEC.ts} +12 -7
  157. package/tools/build.js +47 -0
  158. package/tsconfig.json +28 -1
  159. package/src/@building/GetEventProperties.ts +0 -96
  160. package/src/@building/GetEventTracking.ts +0 -68
  161. package/src/@core/SetNode.ts +0 -81
  162. package/src/@events/ParseAPI.ts +0 -117
  163. package/src/@manager/RemoveEvent.ts +0 -70
  164. package/src/@manager/Tasks.ts +0 -246
  165. package/src/@modules/@database/InitializeDatabase.ts +0 -59
  166. package/src/@modules/@eas/GenerateEASMessage.ts +0 -144
  167. package/src/@modules/@utilities/SetCronSchedule.ts +0 -94
  168. package/src/@modules/@utilities/SetEventEmit.ts +0 -41
  169. package/src/@modules/@utilities/SetListener.ts +0 -30
  170. package/src/@modules/@utilities/SetTimeoutAction.ts +0 -64
  171. package/src/@modules/@xmpp/ErrorXMPP.ts +0 -27
  172. package/src/@modules/@xmpp/ReconnectXMPP.ts +0 -64
  173. package/src/@parsers/@pvtec/VTECExtract.ts +0 -49
  174. package/src/@parsers/@text/GetPolygonFromProduct.ts +0 -53
  175. package/src/@parsers/@text/GetXML.ts +0 -61
  176. package/src/@parsers/@ugc/GetCache.ts +0 -24
  177. package/src/@parsers/@ugc/GetZonePolygon.ts +0 -111
  178. package/src/@types/VTEC.ts +0 -30
  179. package/tsup.config.ts +0 -16
@@ -11,58 +11,62 @@
11
11
  Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, & CJ Ziegler)
12
12
  Discord: https://atmosphericx-discord.scriptkitty.cafe
13
13
  Ko-Fi: https://ko-fi.com/k3yomi
14
- Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
14
+ Documentation: https://atmosphericx.scriptkitty.cafe/documentation
15
15
 
16
- Internal Package: @atmosx/event-product-parser
16
+ Independent Package: @atmosx/event-product-parser
17
17
 
18
18
  */
19
19
 
20
- import { TypeEvent } from "../@types/Event";
21
- import { TypeSettings } from "../@types/Settings";
22
- import { bootstrap } from "../bootstrap"
23
- import { GetEventEnhancedName } from "../@building/GetEventEnhancedName";
24
- import { GetEventSignature } from "../@building/GetEventSignature"
25
- import { MakeEvents } from "./MakeEvents";
26
- import { RemoveEvent } from "./RemoveEvent";
27
- import { GetEventAttachments } from "../@building/GetEventAttachments";
28
- import { SetEventEmit } from "../@modules/@utilities/SetEventEmit";
29
- import { SetDebug } from "../@modules/@utilities/SetDebug";
30
- import { GetMatched } from "../@modules/@utilities/GetMatched";
31
- import { GetEventGeometry } from "../@building/GetEventGeometry";
20
+ import { TypeEvent } from "StaticTypes/Event"
21
+ import { TypeSettings } from "Types/Settings"
22
+ import { Bootstrap } from "@Bootstrap"
23
+ import { GetEventEnhancedName } from "@Building/GetEventEnhancedName"
24
+ import { GetEventSignature } from "@Building/GetEventSignature"
25
+ import { MakeEvents } from "@Manager/MakeEvents"
26
+ import { RemoveEvent } from "@Manager/RemoveEvent"
27
+ import { GetEventAttachments } from "@Building/GetEventAttachments"
28
+ import { SetEventEmit } from "@Utilities/SetEventEmit"
29
+ import { SetDebug } from "@Utilities/SetDebug"
30
+ import { GetMatched } from "@Utilities/GetMatched"
31
+ import { GetEventPopulation } from "@Building/GetEventPopulation"
32
+ import { GetEventGeometry } from "@Building/GetEventGeometry"
32
33
  import { createHash } from "crypto"
33
34
 
34
35
  export const ValidateEvents = async (events: TypeEvent[]): Promise<void> => {
35
36
  const tick = performance.now();
36
37
  if (events.length === 0) return
37
- const configurations = bootstrap.settings as TypeSettings
38
+ const configurations = Bootstrap.Settings as TypeSettings
38
39
  const sets = {} as Record<string, Set<string>>;
39
40
  const bools = {} as Record<string, boolean>;
40
41
  const megered = {...configurations.GlobalSettings, ...configurations.GlobalSettings.EventFiltering}
41
42
  for (const key in megered) {
42
- const setting = megered[key];
43
- if (Array.isArray(setting)) { sets[key] = new Set(setting.map(item => item.toLowerCase())); }
44
- if (typeof setting === 'boolean') { bools[key] = setting; }
43
+ const setting = megered[key as keyof typeof megered]
44
+ if (Array.isArray(setting)) {
45
+ (sets as Record<string, any>)[key] = new Set(setting.map(item => String(item).toLowerCase()));
46
+ }
47
+ if (typeof setting === 'boolean') {
48
+ (bools as Record<string, any>)[key] = setting;
49
+ }
45
50
  }
46
-
47
51
  const isFiltered = (define: TypeEvent): boolean => {
48
52
  const properties = define.properties;
49
53
  const zones = properties.geocode.ugc;
50
54
  const icao = properties.geocode.office.office
51
55
 
52
56
  if (properties.status_metadata.is_test) {
53
- SetEventEmit({ event: `onTestProduct`, metadata: define })
57
+ SetEventEmit({ Event: `onTestProduct`, Metadata: define })
54
58
  if (bools?.IgnoreTestProducts) return true;
55
59
  }
56
60
 
57
61
  if (properties.status_metadata.is_expired) {
58
- SetEventEmit({ event: `onExpiredProduct`, metadata: define })
59
- RemoveEvent(define, false)
62
+ SetEventEmit({ Event: `onExpiredProduct`, Metadata: define })
63
+ RemoveEvent({ Event: define, IsTimeBasedExpiration: false })
60
64
  return true;
61
65
  }
62
66
 
63
- if (properties.metadata?.vtec?.is_watch && properties.metadata.source != `events.api`) {
64
- const isSPC = properties.metadata?.vtec?.prediction_center;
65
- SetEventEmit({ event: isSPC ? `onStormPredictionWatch` : `onNonStormPredictionWatch`, metadata: define })
67
+ if (properties.metadata?.vtec?.Watch && properties.metadata.source != `events.api`) {
68
+ const isSPC = properties.metadata?.vtec?.PredictionCenter;
69
+ SetEventEmit({ Event: isSPC ? `onStormPredictionWatch` : `onNonStormPredictionWatch`, Metadata: define })
66
70
  if (bools?.SPCWatchesOnly && !isSPC) {
67
71
  return true;
68
72
  }
@@ -74,45 +78,45 @@ export const ValidateEvents = async (events: TypeEvent[]): Promise<void> => {
74
78
  for (const key in sets) {
75
79
  const setting = sets[key]
76
80
  const values = [...setting];
77
- if (key === 'ListeningEvents' && setting.size > 0 && !GetMatched(values, define.properties.event)) {
81
+ if (key === 'ListeningEvents' && setting.size > 0 && !GetMatched({ Strings: values, String: define.properties.event })) {
78
82
  SetEventEmit({
79
- event: `onFilteredEvent`,
80
- metadata: define
83
+ Event: `onFilteredEvent`,
84
+ Metadata: define
81
85
  });
82
86
  return true
83
87
  }
84
- if (key === 'IgnoredEvents' && setting.size > 0 && GetMatched(values, define.properties.event)) {
88
+ if (key === 'IgnoredEvents' && setting.size > 0 && GetMatched({ Strings: values, String: define.properties.event })) {
85
89
  SetEventEmit({
86
- event: `onIgnoredEvent`,
87
- metadata: define
90
+ Event: `onIgnoredEvent`,
91
+ Metadata: define
88
92
  });
89
93
  return true
90
94
  }
91
95
  if (key === 'ListeningICAO' && setting.size > 0 && icao != null && !setting.has(icao.toLowerCase())) {
92
96
  SetEventEmit({
93
- event: `onFilteredICAO`,
94
- metadata: define
97
+ Event: `onFilteredICAO`,
98
+ Metadata: define
95
99
  });
96
100
  return true
97
101
  }
98
102
  if (key === 'IgnoredICAO' && setting.size > 0 && icao != null && setting.has(icao.toLowerCase())) {
99
103
  SetEventEmit({
100
- event: `onIgnoredICAO`,
101
- metadata: define
104
+ Event: `onIgnoredICAO`,
105
+ Metadata: define
102
106
  });
103
107
  return true
104
108
  }
105
109
  if (key === 'ListeningUGC' && setting.size > 0 && zones.length > 0 && !zones.some((ugc: string) => setting.has(ugc.toLowerCase()))) {
106
110
  SetEventEmit({
107
- event: `onFilteredUGC`,
108
- metadata: define
111
+ Event: `onFilteredUGC`,
112
+ Metadata: define
109
113
  });
110
114
  return true
111
115
  }
112
116
  if (key === 'ListeningStates' && setting.size > 0 && zones.length > 0 && !zones.some((ugc: string) => setting.has(ugc.substring(0, 2).toLowerCase()))) {
113
117
  SetEventEmit({
114
- event: `onFilteredState`,
115
- metadata: define
118
+ Event: `onFilteredState`,
119
+ Metadata: define
116
120
  });
117
121
  return true
118
122
  }
@@ -121,22 +125,28 @@ export const ValidateEvents = async (events: TypeEvent[]): Promise<void> => {
121
125
  }
122
126
 
123
127
  const filtering = events.filter((event: TypeEvent) => {
124
- bootstrap.cache.processed = bootstrap.cache.processed.filter((e) => e !== event);
128
+ Bootstrap.Cache.Parsed = Bootstrap.Cache.Parsed.filter((e) => e !== event);
125
129
  const define = GetEventSignature(event) as TypeEvent;
126
130
  const pre = {...define,properties: {...define.properties, metadata: {...define.properties.metadata }}};
127
131
  const properties = define.properties; delete pre.properties.metadata.ms; delete pre.properties.metadata.header;
128
132
  const enhanced = properties.event = GetEventEnhancedName(event)
129
133
  const filtered = isFiltered(define)
130
134
  if (!filtered) {
131
- event.geometry = !bools?.DisableGeometryParsing ? GetEventGeometry(event) : null;
132
- properties.metadata.attachments = GetEventAttachments(event)
135
+ const tick2 = performance.now();
136
+ const geometry = !bools?.DisableGeometryParsing ? GetEventGeometry({ Event: event }) : null;
137
+ const population = GetEventPopulation(geometry)
138
+ const attachments = GetEventAttachments(event)
139
+ event.geometry = geometry;
140
+ event.properties.geocode.census.population = population.population;
141
+ event.properties.geocode.census.cities = population.cities;
142
+ properties.metadata.attachments = attachments;
143
+ SetDebug({ Title: `Filtered`, Message: `${Math.round(performance.now() - tick2)}ms` })
133
144
  }
134
145
  properties.metadata.hash = createHash("sha256").update(JSON.stringify(pre)).digest("hex")
135
- SetEventEmit({ event: `onProductType${enhanced.replace(/\s+/g, '')}`, metadata: define });
146
+ SetEventEmit({ Event: `onProductType${enhanced.replace(/\s+/g, '')}`, Metadata: define });
136
147
  return !filtered
137
148
  })
138
149
 
139
- SetDebug({ title: `ValidateEvents (PRE) (${filtering.length}/${events.length})`, message: `${Math.round(performance.now() - tick)}ms` })
150
+ SetDebug({ Title: `ValidateEvents (${filtering.length}/${events.length})`, Message: `${Math.round(performance.now() - tick)}ms` })
140
151
  await MakeEvents(filtering)
141
- SetDebug({ title: `MakeEvents (${filtering.length}/${events.length})`, message: `${Math.round(performance.now() - tick)}ms` })
142
152
  }
@@ -11,17 +11,17 @@
11
11
  Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, & CJ Ziegler)
12
12
  Discord: https://atmosphericx-discord.scriptkitty.cafe
13
13
  Ko-Fi: https://ko-fi.com/k3yomi
14
- Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
14
+ Documentation: https://atmosphericx.scriptkitty.cafe/documentation
15
15
 
16
- Internal Package: @atmosx/event-product-parser
16
+ Independent Package: @atmosx/event-product-parser
17
17
 
18
18
  */
19
19
 
20
- import { TypeHVTEC } from "../../@types/HVTEC";
21
- import { EnumCauses } from "../../@enums/Causes";
22
- import { EnumRecords } from "../../@enums/Records";
23
- import { EnumExpressions } from "../../@enums/Expressions";
24
- import { EnumSeverity } from "../../@enums/Severity";
20
+ import { TypeHVTEC } from "Types/HVTEC"
21
+ import { EnumCauses } from "@Enums/Causes"
22
+ import { EnumRecords } from "@Enums/Records"
23
+ import { EnumExpressions } from "@Enums/Expressions"
24
+ import { EnumSeverity } from "@Enums/Severity"
25
25
 
26
26
  export const HVExtract = (message: string): TypeHVTEC[] | null => {
27
27
  const getHVTECs = message.match(EnumExpressions.hvtec) ?? [];
@@ -30,10 +30,10 @@ export const HVExtract = (message: string): TypeHVTEC[] | null => {
30
30
  const sub = vtec.split(`.`);
31
31
  if (sub.length < 7) continue;
32
32
  vtecs.push({
33
- hvtec: vtec,
34
- severity: EnumSeverity[sub[1]],
35
- cause: EnumCauses[sub[2]],
36
- record: EnumRecords[sub[6]]
33
+ HVTEC: vtec,
34
+ Severity: EnumSeverity[sub[1]],
35
+ Cause: EnumCauses[sub[2]],
36
+ Record: EnumRecords[sub[6]]
37
37
  })
38
38
  }
39
39
  return vtecs.length > 0 ? vtecs : null;
@@ -11,21 +11,20 @@
11
11
  Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, & CJ Ziegler)
12
12
  Discord: https://atmosphericx-discord.scriptkitty.cafe
13
13
  Ko-Fi: https://ko-fi.com/k3yomi
14
- Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
14
+ Documentation: https://atmosphericx.scriptkitty.cafe/documentation
15
15
 
16
- Internal Package: @atmosx/event-product-parser
16
+ Independent Package: @atmosx/event-product-parser
17
17
 
18
18
  */
19
19
 
20
- import { EnumExpressions } from "../../@enums/Expressions";
20
+ import { EnumExpressions } from "@Enums/Expressions"
21
21
 
22
22
  interface GetDescriptionFromProductOptions {
23
- message: string
24
- handle?: string
23
+ Message: string
24
+ Handle?: string
25
25
  }
26
26
 
27
- export const GetDescriptionFromProduct = (options: GetDescriptionFromProductOptions): string => {
28
- let message = options.message;
27
+ export const GetDescriptionFromProduct = ({ Message, Handle }: GetDescriptionFromProductOptions): string => {
29
28
  const predefinedEndMarkers = ['&&', 'LAT...'];
30
29
  const getEndIndex = (text: string, fromIndex = 0): number => {
31
30
  const indices = predefinedEndMarkers
@@ -33,28 +32,28 @@ export const GetDescriptionFromProduct = (options: GetDescriptionFromProductOpti
33
32
  .filter((idx) => idx !== -1);
34
33
  return indices.length ? Math.min(...indices) : -1;
35
34
  };
36
- const dates = Array.from(message.matchAll(EnumExpressions.dateline));
35
+ const dates = Array.from(Message.matchAll(EnumExpressions.dateline));
37
36
  if (dates.length) {
38
37
  const lastMatch = dates[dates.length - 1][0];
39
- const sIndx = message.lastIndexOf(lastMatch);
38
+ const sIndx = Message.lastIndexOf(lastMatch);
40
39
  if (sIndx !== -1) {
41
- const endIndx = getEndIndex(message, sIndx);
42
- message = message.substring(sIndx + lastMatch.length, endIndx !== -1 ? endIndx : undefined).trimStart();
43
- if (message.startsWith('/')) message = message.slice(1).trimStart();
44
- if (options.handle && message.includes(options.handle)) {
45
- const handleIdx = message.indexOf(options.handle);
46
- message = message.substring(handleIdx + options.handle.length).trimStart();
47
- if (message.startsWith('/')) message = message.slice(1).trimStart();
40
+ const endIndx = getEndIndex(Message, sIndx);
41
+ Message = Message.substring(sIndx + lastMatch.length, endIndx !== -1 ? endIndx : undefined).trimStart();
42
+ if (Message.startsWith('/')) Message = Message.slice(1).trimStart();
43
+ if (Handle && Message.includes(Handle)) {
44
+ const handleIdx = Message.indexOf(Handle);
45
+ Message = Message.substring(handleIdx + Handle.length).trimStart();
46
+ if (Message.startsWith('/')) Message = Message.slice(1).trimStart();
48
47
  }
49
48
  }
50
- } else if (options.handle) {
51
- const handleIndx = message.indexOf(options.handle);
49
+ } else if (Handle) {
50
+ const handleIndx = Message.indexOf(Handle);
52
51
  if (handleIndx !== -1) {
53
- let afterHandle = message.substring(handleIndx + options.handle.length).trimStart();
52
+ let afterHandle = Message.substring(handleIndx + Handle.length).trimStart();
54
53
  if (afterHandle.startsWith('/')) afterHandle = afterHandle.slice(1).trimStart();
55
54
  const latEnd = getEndIndex(afterHandle);
56
- message = latEnd !== -1 ? afterHandle.substring(0, latEnd).trim() : afterHandle.trim();
55
+ Message = latEnd !== -1 ? afterHandle.substring(0, latEnd).trim() : afterHandle.trim();
57
56
  }
58
57
  }
59
- return message.trim();
58
+ return Message.trim();
60
59
  }
@@ -0,0 +1,71 @@
1
+ /*
2
+ _ _ _ __ __
3
+ /\ | | | | (_) \ \ / /
4
+ / \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
5
+ / /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
6
+ / ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
7
+ /_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
8
+ | |
9
+ |_|
10
+
11
+ Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, & CJ Ziegler)
12
+ Discord: https://atmosphericx-discord.scriptkitty.cafe
13
+ Ko-Fi: https://ko-fi.com/k3yomi
14
+ Documentation: https://atmosphericx.scriptkitty.cafe/documentation
15
+
16
+ Independent Package: @atmosx/event-product-parser
17
+
18
+ */
19
+
20
+ export const GetPolygonFromProduct = (message: string): number[][] => {
21
+ const coordinates: number[][] = [];
22
+ const match = message.match(
23
+ /LAT\.\.\.LON\s+([\s\S]*?)(?=\n\s*(?:TIME\.\.\.MOT\.\.\.LOC|\$\$|[A-Za-z]|$))/i
24
+ );
25
+ if (!match) return coordinates;
26
+ const text = match[1]
27
+ .split(/\r?\n/).map(l => l.trim())
28
+ .filter(l => l && !/[A-Za-z]/.test(l))
29
+ .join(' ').trim();
30
+ if (!text) return coordinates;
31
+ const values = text.match(/\d{4,8}/g);
32
+ if (!values || values.length === 0) return coordinates;
33
+ const points: { lat: number; lon: number }[] = [];
34
+ if (values.every(v => v.length === 8)) {
35
+ for (const value of values) {
36
+ const lat = parseInt(value.slice(0, 4), 10) / 100;
37
+ let lon = parseInt(value.slice(4, 8), 10) / 100;
38
+ if (lon < 20) lon += 100;
39
+ points.push({ lat, lon });
40
+ }
41
+ } else if (values.every(v => v.length === 4)) {
42
+ for (let i = 0; i + 1 < values.length; i += 2) {
43
+ const lat = parseInt(values[i], 10) / 100;
44
+ const lon = parseInt(values[i + 1], 10) / 100;
45
+ points.push({ lat, lon });
46
+ }
47
+ } else {
48
+ for (let i = 0; i + 1 < values.length; i += 2) {
49
+ const latStr = values[i];
50
+ const lonStr = values[i + 1];
51
+ if (latStr.length !== 4) continue;
52
+ if (lonStr.length < 4 || lonStr.length > 5) continue;
53
+ const lat = parseInt(latStr, 10) / 100;
54
+ let lon = parseInt(lonStr, 10) / 100;
55
+ points.push({ lat, lon });
56
+ }
57
+ }
58
+ if (points.length === 0) return coordinates;
59
+ const isEast = points.some(p => p.lon > 130 && p.lon < 180);
60
+ for (const p of points) {
61
+ const lon = isEast ? p.lon : -p.lon;
62
+ if (Number.isFinite(p.lat) && Number.isFinite(lon) && p.lat >= -90 && p.lat <= 90 && lon >= -180 && lon <= 180) {
63
+ coordinates.push([lon, p.lat]);
64
+ }
65
+ }
66
+ if (coordinates.length > 2 && (coordinates[0][0] !== coordinates[coordinates.length - 1][0] || coordinates[0][1] !== coordinates[coordinates.length - 1][1])) {
67
+ coordinates.push([...coordinates[0]]);
68
+ }
69
+
70
+ return coordinates;
71
+ };
@@ -11,32 +11,32 @@
11
11
  Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, & CJ Ziegler)
12
12
  Discord: https://atmosphericx-discord.scriptkitty.cafe
13
13
  Ko-Fi: https://ko-fi.com/k3yomi
14
- Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
14
+ Documentation: https://atmosphericx.scriptkitty.cafe/documentation
15
15
 
16
- Internal Package: @atmosx/event-product-parser
16
+ Independent Package: @atmosx/event-product-parser
17
17
 
18
18
  */
19
19
 
20
20
  interface GetTextFromProductOptions {
21
- message: string
22
- find: string[]
23
- append?: string
24
- removal?: string[]
21
+ Message: string
22
+ Find: string[]
23
+ Append?: string
24
+ Removal?: string[]
25
25
  }
26
26
 
27
- export const GetTextFromProduct = (options: GetTextFromProductOptions): string => {
28
- const lines = options.message.split(`\n`);
27
+ export const GetTextFromProduct = ({ Message, Find, Append, Removal }: GetTextFromProductOptions): string => {
28
+ const lines = Message.split(`\n`);
29
29
  for (const line of lines) {
30
- const matchedFind = options.find.find((find) => line.includes(find));
30
+ const matchedFind = Find.find((find) => line.includes(find));
31
31
  if (matchedFind) {
32
32
  let result = line.slice(line.indexOf(matchedFind) + matchedFind.length).trim();
33
- if (options.removal) {
34
- for (const str of options.removal) {
33
+ if (Removal) {
34
+ for (const str of Removal) {
35
35
  result = result.toLowerCase().split(str.toLowerCase()).join('');
36
36
  }
37
37
  result = result.replace(matchedFind, '').replace('<', '').trim();
38
38
  }
39
- return result.toUpperCase() + (options?.append ?? ``);
39
+ return result.toUpperCase() + (Append ?? ``);
40
40
  }
41
41
  }
42
42
  return null;
@@ -0,0 +1,24 @@
1
+ /*
2
+ _ _ _ __ __
3
+ /\ | | | | (_) \ \ / /
4
+ / \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
5
+ / /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
6
+ / ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
7
+ /_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
8
+ | |
9
+ |_|
10
+
11
+ Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, & CJ Ziegler)
12
+ Discord: https://atmosphericx-discord.scriptkitty.cafe
13
+ Ko-Fi: https://ko-fi.com/k3yomi
14
+ Documentation: https://atmosphericx.scriptkitty.cafe/documentation
15
+
16
+ Independent Package: @atmosx/event-product-parser
17
+
18
+ */
19
+
20
+ import { Bootstrap } from "@Bootstrap"
21
+
22
+ export const GetCache = (key: string) => {
23
+ return Bootstrap.Cache.UGC.get(key);
24
+ };
@@ -11,9 +11,9 @@
11
11
  Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, & CJ Ziegler)
12
12
  Discord: https://atmosphericx-discord.scriptkitty.cafe
13
13
  Ko-Fi: https://ko-fi.com/k3yomi
14
- Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
14
+ Documentation: https://atmosphericx.scriptkitty.cafe/documentation
15
15
 
16
- Internal Package: @atmosx/event-product-parser
16
+ Independent Package: @atmosx/event-product-parser
17
17
 
18
18
  */
19
19
 
@@ -11,15 +11,15 @@
11
11
  Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, & CJ Ziegler)
12
12
  Discord: https://atmosphericx-discord.scriptkitty.cafe
13
13
  Ko-Fi: https://ko-fi.com/k3yomi
14
- Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
14
+ Documentation: https://atmosphericx.scriptkitty.cafe/documentation
15
15
 
16
- Internal Package: @atmosx/event-product-parser
16
+ Independent Package: @atmosx/event-product-parser
17
17
 
18
18
  */
19
19
 
20
- import { EnumExpressions } from "../../@enums/Expressions"
20
+ import { EnumExpressions } from "@Enums/Expressions"
21
21
 
22
- export const getUGCHeader = (message: string): string | null => {
22
+ export const GetHeader = (message: string): string | null => {
23
23
  const start = message.search(EnumExpressions.ugc1)
24
24
  const sub = message.substring(start)
25
25
  const end = sub.search(EnumExpressions.ugc2)
@@ -11,17 +11,17 @@
11
11
  Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, & CJ Ziegler)
12
12
  Discord: https://atmosphericx-discord.scriptkitty.cafe
13
13
  Ko-Fi: https://ko-fi.com/k3yomi
14
- Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
14
+ Documentation: https://atmosphericx.scriptkitty.cafe/documentation
15
15
 
16
- Internal Package: @atmosx/event-product-parser
16
+ Independent Package: @atmosx/event-product-parser
17
17
 
18
18
  */
19
19
 
20
- import { bootstrap } from "../../bootstrap";
21
- import { getCache } from "./GetCache";
22
- import { setCache } from "./SetCache";
20
+ import { Bootstrap } from "@Bootstrap"
21
+ import { GetCache } from "@ParsingUGC/GetCache"
22
+ import { SetCache } from "@ParsingUGC/SetCache"
23
23
 
24
- export const getLocations = async (zones: string[]): Promise<string[]> => {
24
+ export const GetLocations = async (zones: string[]): Promise<string[]> => {
25
25
  const uniqueZones = Array.from(new Set(zones));
26
26
 
27
27
  const results: string[] = [];
@@ -29,7 +29,7 @@ export const getLocations = async (zones: string[]): Promise<string[]> => {
29
29
 
30
30
  for (let i = 0; i < uniqueZones.length; i++) {
31
31
  const zone = uniqueZones[i];
32
- const cached = getCache(zone);
32
+ const cached = GetCache(zone);
33
33
 
34
34
  if (cached) {
35
35
  for (let j = 0; j < cached.length; j++) {
@@ -41,7 +41,7 @@ export const getLocations = async (zones: string[]): Promise<string[]> => {
41
41
  }
42
42
 
43
43
  if (missing.length > 0) {
44
- const rows = await bootstrap.database
44
+ const rows = await Bootstrap.Database
45
45
  .prepare(
46
46
  `SELECT id, location FROM shapefiles WHERE id IN (${missing.map(() => '?').join(',')})`
47
47
  )
@@ -49,9 +49,9 @@ export const getLocations = async (zones: string[]): Promise<string[]> => {
49
49
 
50
50
  for (let i = 0; i < rows.length; i++) {
51
51
  const r = rows[i] as any;
52
- setCache(r.id, [r.location]);
52
+ SetCache({ Key: r.id, Value: [r.location] });
53
53
  results.push(r.location);
54
54
  }
55
55
  }
56
- return results;
56
+ return Array.from(new Set(results));
57
57
  };
@@ -0,0 +1,73 @@
1
+ /*
2
+ _ _ _ __ __
3
+ /\ | | | | (_) \ \ / /
4
+ / \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
5
+ / /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
6
+ / ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
7
+ /_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
8
+ | |
9
+ |_|
10
+
11
+ Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, & CJ Ziegler)
12
+ Discord: https://atmosphericx-discord.scriptkitty.cafe
13
+ Ko-Fi: https://ko-fi.com/k3yomi
14
+ Documentation: https://atmosphericx.scriptkitty.cafe/documentation
15
+
16
+ Independent Package: @atmosx/event-product-parser
17
+
18
+ */
19
+
20
+ import { CreateQuery } from "@Database/CreateQuery"
21
+ import { GetUnionPolygon } from "@Utilities/GetUnionPolygon"
22
+ import { createHash } from "crypto";
23
+
24
+ interface CoordinatesOptions {
25
+ Zones: string[]
26
+ Union: boolean
27
+ }
28
+
29
+ interface CoordinatesResponse {
30
+ type: `Polygon` | `MultiPolygon`
31
+ coordinates: any[]
32
+ }
33
+
34
+ export const GetZonePolygon = ({ Zones, Union }: CoordinatesOptions): CoordinatesResponse | null => {
35
+ const list = [...new Set(Zones.map(z => z.trim()))].filter(z => z === 'XX000' ? false : true);
36
+ if (list.length === 0) return null;
37
+
38
+ const placeholders = list.map(() => "?").join(",");
39
+ const rows = CreateQuery({
40
+ Query: `SELECT geometry FROM shapefiles WHERE id IN (${placeholders})`,
41
+ Parameters: list
42
+ });
43
+ const polygons: any[] = [];
44
+ const geometryHashes = new Set<string>();
45
+ for (const row of rows) {
46
+ if (!row?.geometry) continue;
47
+ const geometryHash = createHash("sha256").update(row.geometry).digest("hex");
48
+ if (geometryHashes.has(geometryHash)) continue;
49
+ geometryHashes.add(geometryHash);
50
+ const geom = JSON.parse(row.geometry);
51
+ if (geom?.type === "Polygon") {
52
+ polygons.push(geom.coordinates);
53
+ }
54
+ if (geom?.type === "MultiPolygon") {
55
+ for (const poly of geom.coordinates) {
56
+ polygons.push(poly);
57
+ }
58
+ }
59
+ }
60
+ if (polygons.length === 0) return null;
61
+ if (Union) {
62
+ return GetUnionPolygon({ Polygons: polygons });
63
+ } else {
64
+ const multi: any[] = [];
65
+ for (const polyCoords of polygons) {
66
+ if (Array.isArray(polyCoords) && Array.isArray(polyCoords[0])) {
67
+ multi.push(polyCoords);
68
+ }
69
+ }
70
+ if (multi.length === 0) return null;
71
+ return {type: "MultiPolygon", coordinates: multi};
72
+ }
73
+ }
@@ -11,13 +11,13 @@
11
11
  Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, & CJ Ziegler)
12
12
  Discord: https://atmosphericx-discord.scriptkitty.cafe
13
13
  Ko-Fi: https://ko-fi.com/k3yomi
14
- Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
14
+ Documentation: https://atmosphericx.scriptkitty.cafe/documentation
15
15
 
16
- Internal Package: @atmosx/event-product-parser
16
+ Independent Package: @atmosx/event-product-parser
17
17
 
18
18
  */
19
19
 
20
- export const getZones = (header: string): string[] => {
20
+ export const GetZones = (header: string): string[] => {
21
21
  const splits = header.split('-');
22
22
  const zones: string[] = [];
23
23
  let state = splits[0].substring(0, 2);