@ham2k/lib-operation-data 0.9.0 → 0.10.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.
- package/jest.config.js +21 -0
- package/package.json +19 -7
- package/src/{index.js → index.ts} +1 -0
- package/src/lib/{bands.js → bands.ts} +55 -11
- package/src/lib/{modes.spec.js → modes.spec.ts} +1 -0
- package/src/lib/{modes.js → modes.ts} +44 -29
- package/src/types.ts +40 -0
- package/tsconfig.json +21 -0
package/jest.config.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
preset: 'ts-jest/presets/default-esm',
|
|
3
|
+
extensionsToTreatAsEsm: ['.ts'],
|
|
4
|
+
testEnvironment: 'node',
|
|
5
|
+
transform: {
|
|
6
|
+
'^.+\\.ts$': ['ts-jest', {
|
|
7
|
+
useESM: true,
|
|
8
|
+
tsconfig: {
|
|
9
|
+
module: 'ES2020',
|
|
10
|
+
moduleResolution: 'node'
|
|
11
|
+
}
|
|
12
|
+
}]
|
|
13
|
+
},
|
|
14
|
+
moduleNameMapper: {
|
|
15
|
+
'^(\\.{1,2}/.*)\\.js$': '$1',
|
|
16
|
+
'^(\\.{1,2}/.*)\\.json$': '$1'
|
|
17
|
+
},
|
|
18
|
+
testMatch: ['**/*.spec.ts', '**/*.test.ts'],
|
|
19
|
+
transformIgnorePatterns: []
|
|
20
|
+
}
|
|
21
|
+
|
package/package.json
CHANGED
|
@@ -1,19 +1,31 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ham2k/lib-operation-data",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.1",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"main": "./
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
6
7
|
"exports": {
|
|
7
|
-
".":
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js"
|
|
11
|
+
}
|
|
8
12
|
},
|
|
9
13
|
"devDependencies": {
|
|
10
|
-
"jest": "
|
|
11
|
-
"
|
|
14
|
+
"@types/jest": "^30.0.0",
|
|
15
|
+
"@types/node": "^24.10.1",
|
|
16
|
+
"jest": "~30",
|
|
17
|
+
"standard": "^17.1.2",
|
|
18
|
+
"ts-jest": "^29.1.0",
|
|
19
|
+
"typescript": "^5.0.0"
|
|
12
20
|
},
|
|
13
21
|
"scripts": {
|
|
14
|
-
"
|
|
22
|
+
"build": "tsc",
|
|
23
|
+
"test": "node --experimental-vm-modules ./node_modules/.bin/jest",
|
|
24
|
+
"prepublishOnly": "npm run build"
|
|
15
25
|
},
|
|
16
26
|
"standard": {
|
|
17
|
-
"env": [
|
|
27
|
+
"env": [
|
|
28
|
+
"jest"
|
|
29
|
+
]
|
|
18
30
|
}
|
|
19
31
|
}
|
|
@@ -1,3 +1,40 @@
|
|
|
1
|
+
export const EXTENDED_BANDS = [ // Includes 11m
|
|
2
|
+
'2190m',
|
|
3
|
+
'630m',
|
|
4
|
+
'560m',
|
|
5
|
+
'160m',
|
|
6
|
+
'80m',
|
|
7
|
+
'60m',
|
|
8
|
+
'40m',
|
|
9
|
+
'30m',
|
|
10
|
+
'20m',
|
|
11
|
+
'17m',
|
|
12
|
+
'15m',
|
|
13
|
+
'12m',
|
|
14
|
+
'11m',
|
|
15
|
+
'10m',
|
|
16
|
+
'6m',
|
|
17
|
+
'5m',
|
|
18
|
+
'4m',
|
|
19
|
+
'2m',
|
|
20
|
+
'1.25m',
|
|
21
|
+
'70cm',
|
|
22
|
+
'33cm',
|
|
23
|
+
'23cm',
|
|
24
|
+
'13cm',
|
|
25
|
+
'9cm',
|
|
26
|
+
'6cm',
|
|
27
|
+
'3cm',
|
|
28
|
+
'1.25cm',
|
|
29
|
+
'6mm',
|
|
30
|
+
'4mm',
|
|
31
|
+
'2.5mm',
|
|
32
|
+
'2mm',
|
|
33
|
+
'1mm',
|
|
34
|
+
'submm',
|
|
35
|
+
'other'
|
|
36
|
+
] as const
|
|
37
|
+
|
|
1
38
|
export const BANDS = [
|
|
2
39
|
'2190m',
|
|
3
40
|
'630m',
|
|
@@ -32,22 +69,24 @@ export const BANDS = [
|
|
|
32
69
|
'1mm',
|
|
33
70
|
'submm',
|
|
34
71
|
'other'
|
|
35
|
-
]
|
|
72
|
+
] as const
|
|
73
|
+
|
|
74
|
+
export type Band = typeof EXTENDED_BANDS[number]
|
|
36
75
|
|
|
37
|
-
export const HF_BANDS = ['160m', '80m', '60m', '40m', '30m', '20m', '17m', '15m', '12m', '10m']
|
|
38
|
-
export const VHF_BANDS = ['6m', '5m', '4m', '2m', '1.25m']
|
|
39
|
-
export const UHF_BANDS = ['70cm', '33cm', '23cm', '13cm']
|
|
40
|
-
export const SHF_BANDS = ['9cm', '6cm', '3cm', '1.25cm']
|
|
41
|
-
export const EHF_BANDS = ['6mm', '4mm', '2mm', '2.5mm', '1mm', 'submm']
|
|
76
|
+
export const HF_BANDS = ['160m', '80m', '60m', '40m', '30m', '20m', '17m', '15m', '12m', '10m'] as const
|
|
77
|
+
export const VHF_BANDS = ['6m', '5m', '4m', '2m', '1.25m'] as const
|
|
78
|
+
export const UHF_BANDS = ['70cm', '33cm', '23cm', '13cm'] as const
|
|
79
|
+
export const SHF_BANDS = ['9cm', '6cm', '3cm', '1.25cm'] as const
|
|
80
|
+
export const EHF_BANDS = ['6mm', '4mm', '2mm', '2.5mm', '1mm', 'submm'] as const
|
|
42
81
|
|
|
43
|
-
export const POPULAR_BANDS = ['160m', '80m', '60m', '40m', '30m', '20m', '17m', '15m', '12m', '10m', '6m', '2m', '70cm']
|
|
44
|
-
export const CONTEST_BANDS = ['160m', '80m', '40m', '20m', '15m', '10m']
|
|
82
|
+
export const POPULAR_BANDS = ['160m', '80m', '60m', '40m', '30m', '20m', '17m', '15m', '12m', '10m', '6m', '2m', '70cm'] as const
|
|
83
|
+
export const CONTEST_BANDS = ['160m', '80m', '40m', '20m', '15m', '10m'] as const
|
|
45
84
|
|
|
46
|
-
export function bandForFrequency
|
|
85
|
+
export function bandForFrequency(freq: number): Band {
|
|
47
86
|
return bandForExactFrequencyInMHz(freq) ?? bandForExactFrequencyInMHz(freq * 1000) ?? 'other'
|
|
48
87
|
}
|
|
49
88
|
|
|
50
|
-
function bandForExactFrequencyInMHz
|
|
89
|
+
function bandForExactFrequencyInMHz(freq: number): Band | undefined {
|
|
51
90
|
if (freq >= 130 && freq <= 140) return '2190m'
|
|
52
91
|
else if (freq >= 450 && freq <= 499) return '630m'
|
|
53
92
|
else if (freq >= 500 && freq <= 505) return '560m'
|
|
@@ -60,6 +99,7 @@ function bandForExactFrequencyInMHz (freq) {
|
|
|
60
99
|
else if (freq >= 18000 && freq <= 18200) return '17m'
|
|
61
100
|
else if (freq >= 20900 && freq <= 21600) return '15m'
|
|
62
101
|
else if (freq >= 24500 && freq <= 25200) return '12m'
|
|
102
|
+
else if (freq >= 26000 && freq <= 27500) return '11m'
|
|
63
103
|
else if (freq >= 27900 && freq <= 30000) return '10m'
|
|
64
104
|
else if (freq >= 50000 && freq <= 54000) return '6m'
|
|
65
105
|
else if (freq >= 54001 && freq <= 69999) return '5m'
|
|
@@ -83,7 +123,7 @@ function bandForExactFrequencyInMHz (freq) {
|
|
|
83
123
|
else return undefined
|
|
84
124
|
}
|
|
85
125
|
|
|
86
|
-
export function frequencyForBand(band, mode) {
|
|
126
|
+
export function frequencyForBand(band: Band, mode?: string): number | undefined {
|
|
87
127
|
if (band === '2190m') return 135.7
|
|
88
128
|
else if (band === '630m') return 472
|
|
89
129
|
else if (band === '560m') return 501
|
|
@@ -136,6 +176,9 @@ export function frequencyForBand(band, mode) {
|
|
|
136
176
|
else if (mode === 'FT4') return 24919
|
|
137
177
|
else return 24890
|
|
138
178
|
}
|
|
179
|
+
else if (band === '11m') {
|
|
180
|
+
return 26965
|
|
181
|
+
}
|
|
139
182
|
else if (band === '10m') {
|
|
140
183
|
if (mode === 'SSB' || mode === 'USB') return 28300
|
|
141
184
|
else if (mode === 'FM' || mode === 'AM') return 28500
|
|
@@ -169,3 +212,4 @@ export function frequencyForBand(band, mode) {
|
|
|
169
212
|
else if (band === 'submm') return 300000000
|
|
170
213
|
else return undefined
|
|
171
214
|
}
|
|
215
|
+
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import BandPlans from '../data/bandPlans.json'
|
|
2
|
+
import type { BandPlansData, SegmentWithMetadata, ModeForFrequencyOptions } from '../types'
|
|
2
3
|
|
|
3
|
-
export const SUPER_MODES = [
|
|
4
|
+
export const SUPER_MODES: readonly string[] = [
|
|
4
5
|
'CW',
|
|
5
6
|
'PHONE',
|
|
6
7
|
'DATA'
|
|
7
|
-
]
|
|
8
|
+
] as const
|
|
8
9
|
|
|
9
|
-
export
|
|
10
|
+
export type SuperMode = 'CW' | 'PHONE' | 'DATA'
|
|
11
|
+
|
|
12
|
+
export const MAIN_MODES: readonly string[] = [
|
|
10
13
|
'CW',
|
|
11
14
|
'SSB',
|
|
12
15
|
'AM',
|
|
@@ -14,9 +17,9 @@ export const MAIN_MODES = [
|
|
|
14
17
|
'FT8',
|
|
15
18
|
'FT4',
|
|
16
19
|
'RTTY'
|
|
17
|
-
]
|
|
20
|
+
] as const
|
|
18
21
|
|
|
19
|
-
export const POPULAR_MODES = [
|
|
22
|
+
export const POPULAR_MODES: readonly string[] = [
|
|
20
23
|
'CW',
|
|
21
24
|
'SSB',
|
|
22
25
|
'USB',
|
|
@@ -42,9 +45,9 @@ export const POPULAR_MODES = [
|
|
|
42
45
|
'PSK',
|
|
43
46
|
'SSTV',
|
|
44
47
|
'WSPR',
|
|
45
|
-
]
|
|
48
|
+
] as const
|
|
46
49
|
|
|
47
|
-
export const ADIF_MODES = [
|
|
50
|
+
export const ADIF_MODES: readonly string[] = [
|
|
48
51
|
'AM',
|
|
49
52
|
'ARDOP',
|
|
50
53
|
'ATV',
|
|
@@ -91,9 +94,9 @@ export const ADIF_MODES = [
|
|
|
91
94
|
'VOI',
|
|
92
95
|
'WINMOR',
|
|
93
96
|
'WSPR'
|
|
94
|
-
]
|
|
97
|
+
] as const
|
|
95
98
|
|
|
96
|
-
export const ADIF_SUBMODES = {
|
|
99
|
+
export const ADIF_SUBMODES: Record<string, readonly string[]> = {
|
|
97
100
|
'CHIP': ['CHIP64', 'CHIP128'],
|
|
98
101
|
'DIGITALVOICE': ['C4FM', 'DMR', 'DSTAR', 'FREEDV', 'M17'],
|
|
99
102
|
'DOMINO': ['DOM-M', 'DOM4', 'DOM5', 'DOM8', 'DOM11', 'DOM16', 'DOM22', 'DOM44', 'DOM88', 'DOMINOEX', 'DOMINOF'],
|
|
@@ -116,18 +119,18 @@ export const ADIF_SUBMODES = {
|
|
|
116
119
|
'THOR': ['THOR-M', 'THOR4', 'THOR5', 'THOR8', 'THOR11', 'THOR16', 'THOR22', 'THOR25X4', 'THOR50X1', 'THOR50X2', 'THOR100'],
|
|
117
120
|
'THRB': ['THRBX', 'THRBX1', 'THRBX2', 'THRBX4', 'THROB1', 'THROB2', 'THROB4'],
|
|
118
121
|
'TOR': ['AMTORFEC', 'GTOR', 'NAVTEX', 'SITORB']
|
|
119
|
-
}
|
|
122
|
+
} as const
|
|
120
123
|
|
|
121
|
-
export const ADIF_MODE_FOR_SUBMODE = {}
|
|
124
|
+
export const ADIF_MODE_FOR_SUBMODE: Record<string, string> = {}
|
|
122
125
|
Object.keys(ADIF_SUBMODES).forEach(mode => {
|
|
123
126
|
ADIF_SUBMODES[mode].forEach(submode => {
|
|
124
127
|
ADIF_MODE_FOR_SUBMODE[submode] = mode
|
|
125
128
|
})
|
|
126
129
|
})
|
|
127
130
|
|
|
128
|
-
export const ADIF_MODES_AND_SUBMODES = [...
|
|
131
|
+
export const ADIF_MODES_AND_SUBMODES: readonly string[] = [...new Set([...ADIF_MODES, ...Object.values(ADIF_SUBMODES).flat()])].sort()
|
|
129
132
|
|
|
130
|
-
export function adifModeAndSubmodeForMode(mode) {
|
|
133
|
+
export function adifModeAndSubmodeForMode(mode: string): string[] {
|
|
131
134
|
if (ADIF_MODE_FOR_SUBMODE[mode]) {
|
|
132
135
|
return [ADIF_MODE_FOR_SUBMODE[mode], mode]
|
|
133
136
|
} else {
|
|
@@ -135,7 +138,7 @@ export function adifModeAndSubmodeForMode(mode) {
|
|
|
135
138
|
}
|
|
136
139
|
}
|
|
137
140
|
|
|
138
|
-
export function superModeForMode(mode) {
|
|
141
|
+
export function superModeForMode(mode: string): SuperMode {
|
|
139
142
|
if (ADIF_MODE_FOR_SUBMODE[mode]) mode = ADIF_MODE_FOR_SUBMODE[mode]
|
|
140
143
|
|
|
141
144
|
if (mode === 'CW') {
|
|
@@ -147,27 +150,38 @@ export function superModeForMode(mode) {
|
|
|
147
150
|
}
|
|
148
151
|
}
|
|
149
152
|
|
|
150
|
-
const
|
|
153
|
+
const bandPlansData = BandPlans as unknown as BandPlansData
|
|
154
|
+
|
|
155
|
+
const AllSegments: SegmentWithMetadata[] = Object.keys(bandPlansData.bands).reduce((segments, band) => {
|
|
151
156
|
return segments.concat(
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
157
|
+
bandPlansData.bands[band].segments.map(segment => {
|
|
158
|
+
const mhz = Array.isArray(segment.mhz) && segment.mhz.length >= 2
|
|
159
|
+
? [segment.mhz[0], segment.mhz[1]] as [number, number]
|
|
160
|
+
: [0, 0] as [number, number]
|
|
161
|
+
return {
|
|
162
|
+
name: segment.name,
|
|
163
|
+
mode: segment.mode,
|
|
164
|
+
submode: segment.submode,
|
|
165
|
+
priority: segment.priority,
|
|
166
|
+
mhz,
|
|
155
167
|
band,
|
|
156
|
-
width:
|
|
157
|
-
regions: (segment.regions || []).reduce((regions, region) => { regions[region] = true; return regions }, {}),
|
|
158
|
-
entities: (segment.entities || []).reduce((entities, entity) => { entities[entity] = true; return entities }, {}),
|
|
159
|
-
countries: (segment.countries || []).reduce((countries, country) => { countries[country] = true; return countries }, {}),
|
|
160
|
-
}
|
|
161
|
-
)
|
|
168
|
+
width: mhz[1] - mhz[0],
|
|
169
|
+
regions: (segment.regions || []).reduce((regions: Record<string, boolean>, region) => { regions[region.toString()] = true; return regions }, {}),
|
|
170
|
+
entities: (segment.entities || []).reduce((entities: Record<string, boolean>, entity) => { entities[entity] = true; return entities }, {}),
|
|
171
|
+
countries: (segment.countries || []).reduce((countries: Record<string, boolean>, country) => { countries[country] = true; return countries }, {}),
|
|
172
|
+
} as SegmentWithMetadata
|
|
173
|
+
})
|
|
162
174
|
)
|
|
163
|
-
}, [])
|
|
175
|
+
}, [] as SegmentWithMetadata[])
|
|
176
|
+
|
|
177
|
+
export function modeForFrequency(frequency: number, options: ModeForFrequencyOptions = {}): string | null | undefined {
|
|
178
|
+
const { ituRegion, countryCode, entityPrefix } = options
|
|
164
179
|
|
|
165
|
-
export function modeForFrequency(frequency, { ituRegion, countryCode, entityPrefix } = {}) {
|
|
166
180
|
const segments = AllSegments.filter(segment => (
|
|
167
181
|
(segment.mhz[0] <= frequency && segment.mhz[1] >= frequency) &&
|
|
168
182
|
(!entityPrefix || Object.keys(segment.entities).length === 0 || segment.entities[entityPrefix]) &&
|
|
169
183
|
(!countryCode || Object.keys(segment.countries).length === 0 || segment.countries[countryCode]) &&
|
|
170
|
-
(!ituRegion || Object.keys(segment.regions).length === 0 || segment.regions[ituRegion])
|
|
184
|
+
(!ituRegion || Object.keys(segment.regions).length === 0 || segment.regions[ituRegion.toString()])
|
|
171
185
|
))
|
|
172
186
|
|
|
173
187
|
const sortedSegments = segments.sort((a, b) => {
|
|
@@ -180,11 +194,12 @@ export function modeForFrequency(frequency, { ituRegion, countryCode, entityPref
|
|
|
180
194
|
if (countryCode && !a.countries[countryCode] && b.countries[countryCode]) return 1
|
|
181
195
|
if (countryCode && a.countries[countryCode] && !b.countries[countryCode]) return -1
|
|
182
196
|
|
|
183
|
-
if (ituRegion && !a.regions[ituRegion] && b.regions[ituRegion]) return 1
|
|
184
|
-
if (ituRegion && a.regions[ituRegion] && !b.regions[ituRegion]) return -1
|
|
197
|
+
if (ituRegion && !a.regions[ituRegion.toString()] && b.regions[ituRegion.toString()]) return 1
|
|
198
|
+
if (ituRegion && a.regions[ituRegion.toString()] && !b.regions[ituRegion.toString()]) return -1
|
|
185
199
|
|
|
186
200
|
return a.width - b.width
|
|
187
201
|
})
|
|
188
202
|
|
|
189
203
|
return sortedSegments[0]?.mode
|
|
190
204
|
}
|
|
205
|
+
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export interface BandPlanSegment {
|
|
2
|
+
name: string
|
|
3
|
+
mhz: [number, number] | number[]
|
|
4
|
+
mode?: string | null
|
|
5
|
+
submode?: string
|
|
6
|
+
priority?: number
|
|
7
|
+
regions?: number[]
|
|
8
|
+
entities?: string[]
|
|
9
|
+
countries?: string[]
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface BandPlan {
|
|
13
|
+
mhz: [number, number] | number[]
|
|
14
|
+
segments: BandPlanSegment[]
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface BandPlansData {
|
|
18
|
+
sources: Array<{ url: string }>
|
|
19
|
+
bands: Record<string, BandPlan>
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface SegmentWithMetadata {
|
|
23
|
+
name: string
|
|
24
|
+
mhz: [number, number]
|
|
25
|
+
mode?: string | null
|
|
26
|
+
submode?: string
|
|
27
|
+
priority?: number
|
|
28
|
+
band: string
|
|
29
|
+
width: number
|
|
30
|
+
regions: Record<string, boolean>
|
|
31
|
+
entities: Record<string, boolean>
|
|
32
|
+
countries: Record<string, boolean>
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface ModeForFrequencyOptions {
|
|
36
|
+
ituRegion?: number
|
|
37
|
+
countryCode?: string
|
|
38
|
+
entityPrefix?: string
|
|
39
|
+
}
|
|
40
|
+
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "ES2020",
|
|
5
|
+
"lib": ["ES2020"],
|
|
6
|
+
"moduleResolution": "node",
|
|
7
|
+
"outDir": "./dist",
|
|
8
|
+
"rootDir": "./src",
|
|
9
|
+
"strict": true,
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"forceConsistentCasingInFileNames": true,
|
|
13
|
+
"resolveJsonModule": true,
|
|
14
|
+
"declaration": true,
|
|
15
|
+
"declarationMap": true,
|
|
16
|
+
"sourceMap": true
|
|
17
|
+
},
|
|
18
|
+
"include": ["src/**/*"],
|
|
19
|
+
"exclude": ["node_modules", "dist"]
|
|
20
|
+
}
|
|
21
|
+
|