milsymbol-sidc 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,10 +6,11 @@
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
7
7
  [![TypeScript](https://img.shields.io/badge/TypeScript-%E2%89%A55.7-blue?logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
8
8
 
9
- A fluent TypeScript builder for **20-character numeric SIDC strings** — the
10
- symbol identification code format used by [MIL-STD-2525E](https://en.wikipedia.org/wiki/MIL-STD-2525)
11
- and [APP-6](https://en.wikipedia.org/wiki/NATO_Joint_Military_Symbology) — made
12
- for constructing symbols with the
9
+ A fluent TypeScript builder for **numeric SIDC strings** — 20 characters by
10
+ default, with opt-in positions 21–23 (extended modifiers and frame shape) for
11
+ [MIL-STD-2525E](https://en.wikipedia.org/wiki/MIL-STD-2525) and
12
+ [APP-6](https://en.wikipedia.org/wiki/NATO_Joint_Military_Symbology) symbols —
13
+ made for constructing symbols with the
13
14
  [milsymbol](https://github.com/spatialillusions/milsymbol) library.
14
15
 
15
16
  ```ts
@@ -30,14 +31,16 @@ new ms.Symbol(sidc).asSVG(); // friendly land unit icon
30
31
  - **Validated output** — invalid values throw; inconsistent combinations warn
31
32
  (or throw in `strict` mode), using the same rules milsymbol applies when it
32
33
  parses a SIDC.
33
- - **milsymbol-ready** — every generated 20-character string is accepted by
34
+ - **milsymbol-ready** — every generated string is accepted by
34
35
  milsymbol's numeric parser. Full rendering depends on the entity and
35
36
  modifier codes you supply, exactly as it does for any raw SIDC.
36
37
 
37
38
  > **Coverage:** complete structural encoding for positions 1–20 of the numeric
38
- > SIDC. Positions 8–10 have named universal codes; positions 11–20 accept
39
- > validated raw entity and modifier codes. A membership-only code catalog ships
40
- > behind the `milsymbol-sidc/catalogs` subpath; semantic names remain future work.
39
+ > SIDC, plus opt-in positions 21–23 (extended modifiers and frame shape) that
40
+ > milsymbol consumes for 2525E/APP-6 E symbols. Positions 8–10 have named
41
+ > universal codes; positions 11–20 accept validated raw entity and modifier
42
+ > codes. A membership-only code catalog ships behind the `milsymbol-sidc/catalogs`
43
+ > subpath; semantic names remain future work.
41
44
 
42
45
  ## Installation
43
46
 
@@ -78,11 +81,11 @@ import {
78
81
 
79
82
  // A hostile planned air missile track under MIL-STD-2525E:
80
83
  const sidc = new Sidc()
81
- .version(Version.MilStd2525E) // pos 1-2 → "13"
82
- .context(Context.Reality) // pos 3 → "0"
84
+ .version(Version.MilStd2525E) // pos 1-2 → "13"
85
+ .context(Context.Reality) // pos 3 → "0"
83
86
  .identity(StandardIdentity.SuspectJoker) // pos 4 → "5"
84
- .symbolSet(SymbolSet.AirMissile) // pos 5-6 → "02"
85
- .status(Status.Planned) // pos 7 → "1"
87
+ .symbolSet(SymbolSet.AirMissile) // pos 5-6 → "02"
88
+ .status(Status.Planned) // pos 7 → "1"
86
89
  .toString();
87
90
 
88
91
  console.log(sidc); // "13050210000000000000"
@@ -104,32 +107,43 @@ const hostile = base.identity(StandardIdentity.SuspectJoker).toString();
104
107
  ## Anatomy of the generated SIDC
105
108
 
106
109
  ```text
107
- 13 0 3 10 0 2 16 123456 78 90
108
- │ │ │ │ │ │ │ │ │ │
109
- │ │ │ │ │ │ │ │ │ └ modifier 2 (19–20)
110
- │ │ │ │ │ │ │ │ └ │ modifier 1 (17–18)
111
- │ │ │ │ │ │ │ └ │ │ entity code (11–16)
112
- │ │ │ │ │ │ └ │ │ │ amplifier (9–10)
113
- │ │ │ │ │ └ │ │ │ │ HQ/task force/feint-dummy (8)
114
- │ │ │ │ └ │ │ │ │ │ status (7)
115
- │ │ │ └ │ │ │ │ │ │ symbol set (5–6)
116
- │ │ └ │ │ │ │ │ │ │ standard identity (4)
117
- │ └ │ │ │ │ │ │ │ │ context (3)
118
- └ │ │ │ │ │ │ │ │ │ version / edition (1–2)
110
+ 13 0 3 10 0 2 16 123456 78 90 0 0 A
111
+ │ │ │ │ │ │ │ │ │ │ │ │ │
112
+ │ │ │ │ │ │ │ │ │ │ │ │ └ frame shape (23) — `A` = no frame
113
+ │ │ │ │ │ │ │ │ │ │ │ └ │ modifier 2 extension (22)
114
+ │ │ │ │ │ │ │ │ │ │ └ │ │ modifier 1 extension (21)
115
+ │ │ │ │ │ │ │ │ │ └ │ │ │ modifier 2 (19–20)
116
+ │ │ │ │ │ │ │ │ └ │ │ │ │ modifier 1 (17–18)
117
+ │ │ │ │ │ │ │ └ │ │ │ │ │ entity code (11–16)
118
+ │ │ │ │ │ │ └ │ │ │ │ │ │ amplifier (9–10)
119
+ │ │ │ │ │ └ │ │ │ │ │ │ │ HQ/task force/feint-dummy (8)
120
+ │ │ │ │ └ │ │ │ │ │ │ │ │ status (7)
121
+ │ │ │ └ │ │ │ │ │ │ │ │ │ symbol set (5–6)
122
+ │ │ └ │ │ │ │ │ │ │ │ │ │ standard identity (4)
123
+ │ └ │ │ │ │ │ │ │ │ │ │ │ context (3)
124
+ └ │ │ │ │ │ │ │ │ │ │ │ │ version / edition (1–2)
119
125
  ```
120
126
 
121
- | Position | Field | API |
122
- | -------- | ------------------ | ----------------- |
123
- | 1–2 | Version / edition | `Version`, `version()` |
124
- | 3 | Context | `Context`, `context()` |
125
- | 4 | Standard identity | `StandardIdentity`, `identity()` |
126
- | 5–6 | Symbol set | `SymbolSet`, `symbolSet()` |
127
- | 7 | Status / condition | `Status`, `status()` |
128
- | 8 | HQ/task force/feint-dummy | `HqTaskForceDummy`, `hqTaskForceDummy()` |
129
- | 9–10 | Amplifier | `Amplifier`, `amplifier()` |
130
- | 11–16 | Entity code | `entity()` — six raw digits |
131
- | 17–18 | Modifier 1 | `modifier1()` — two raw digits |
132
- | 19–20 | Modifier 2 | `modifier2()` — two raw digits |
127
+ Positions 21–23 are emitted only when an extension field is set explicitly;
128
+ otherwise `toString()` produces the classic 20-character SIDC.
129
+
130
+ | Position | Field | API |
131
+ | -------- | ------------------------- | ------------------------------------------------------------ |
132
+ | 1–2 | Version / edition | `Version`, `version()` |
133
+ | 3 | Context | `Context`, `context()` |
134
+ | 4 | Standard identity | `StandardIdentity`, `identity()` |
135
+ | 5–6 | Symbol set | `SymbolSet`, `symbolSet()` |
136
+ | 7 | Status / condition | `Status`, `status()` |
137
+ | 8 | HQ/task force/feint-dummy | `HqTaskForceDummy`, `hqTaskForceDummy()` |
138
+ | 9–10 | Amplifier | `Amplifier`, `amplifier()` |
139
+ | 11–16 | Entity code | `entity()` — six raw digits |
140
+ | 17–18 | Modifier 1 | `modifier1()` — two raw digits, or `extendedModifier1()` |
141
+ | 19–20 | Modifier 2 | `modifier2()` — two raw digits, or `extendedModifier2()` |
142
+ | 21 | Modifier 1 extension | `extendedModifier1()` — hundreds digit of a three-digit code |
143
+ | 22 | Modifier 2 extension | `extendedModifier2()` — hundreds digit of a three-digit code |
144
+ | 23 | Frame shape | `frameShape()` — `0`–`9`, or `A` (no frame) |
145
+ | 17–18 | Modifier 1 | `modifier1()` — two raw digits |
146
+ | 19–20 | Modifier 2 | `modifier2()` — two raw digits |
133
147
 
134
148
  ## API
135
149
 
@@ -139,38 +153,42 @@ Creates a builder preconfigured to 2525E / Reality / Unknown / Unknown set /
139
153
  Present. This remains the default for backward compatibility; configure
140
154
  `Standard.App6` to default to APP-6 E instead.
141
155
 
142
- | Option | Type | Default | Description |
143
- | ------ | ---- | ------- | ----------- |
144
- | `strict` | `boolean` | `false` | Throw on invalid field combinations during `toString()` instead of warning. Invalid values always throw immediately regardless of this flag. |
145
- | `standard` | `Standard` | Not configured (2525E behavior) | Select a standard family. `App6` defaults the version to APP-6 E (`"14"`); `MilStd2525` defaults it to MIL-STD-2525E (`"13"`). Explicit configuration also checks that later version choices belong to the selected family. |
146
- | `onWarning` | `(problem: SidcProblem) => void` | `console.warn` | Receive non-fatal problems instead of writing to the console. `strict: true` still throws instead of reporting. |
156
+ | Option | Type | Default | Description |
157
+ | ----------- | -------------------------------- | ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
158
+ | `strict` | `boolean` | `false` | Throw on invalid field combinations during `toString()` instead of warning. Invalid values always throw immediately regardless of this flag. |
159
+ | `standard` | `Standard` | Not configured (2525E behavior) | Select a standard family. `App6` defaults the version to APP-6 E (`"14"`); `MilStd2525` defaults it to MIL-STD-2525E (`"13"`). Explicit configuration also checks that later version choices belong to the selected family. |
160
+ | `onWarning` | `(problem: SidcProblem) => void` | `console.warn` | Receive non-fatal problems instead of writing to the console. `strict: true` still throws instead of reporting. |
147
161
 
148
162
  ### Methods
149
163
 
150
164
  All setters validate their argument and return a new immutable `Sidc`.
151
165
 
152
- | Method | Field | Accepts |
153
- | ------ | ----- | ------- |
154
- | `standard(s)` | Version default + validation rules | A `Standard` constant. It retains a compatible current version; otherwise it selects that family's latest edition. |
155
- | `version(v)` | Positions 1–2 | A `Version` constant or any two-digit string (escape hatch for future editions) |
156
- | `context(c)` | Position 3 | A `Context` constant |
157
- | `identity(i)` | Position 4 | A `StandardIdentity` constant |
158
- | `symbolSet(s)` | Positions 5–6 | A `SymbolSet` constant or any two-digit string |
159
- | `status(s)` | Position 7 | A `Status` constant |
160
- | `hqTaskForceDummy(v)` | Position 8 | An `HqTaskForceDummy` constant |
161
- | `amplifier(v)` | Positions 9–10 | An `Amplifier` constant |
162
- | `entity(v)` | Positions 11–16 | Any six-digit string; symbol-set-specific catalogs are not included |
163
- | `modifier1(v)` | Positions 17–18 | Any two-digit string; symbol-set-specific catalogs are not included |
164
- | `modifier2(v)` | Positions 19–20 | Any two-digit string; symbol-set-specific catalogs are not included |
165
- | `toString()` | — | Validates combinations and renders the 20-character SIDC |
166
- | `problems()` | — | Structured list of non-fatal problems; never throws |
167
- | `isValid()` | — | `true` when `problems()` is empty |
168
- | `with(fields)` | — | Applies a partial field record immutably; validates like the setters |
169
- | `clone()` | — | Copies the fields into an independent builder |
170
- | `equals(other)` | — | Compares encoded fields, ignoring `strict` and `standard` |
171
- | `toObject()` / `toJSON()` | — | Plain, serializable snapshot of every encoded field |
172
- | `Sidc.parse(s, options?)` | — | Parses a 20-character numeric SIDC; throws when invalid |
173
- | `Sidc.tryParse(s, options?)` | — | Parses a SIDC or returns `undefined` |
166
+ | Method | Field | Accepts |
167
+ | ---------------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
168
+ | `standard(s)` | Version default + validation rules | A `Standard` constant. It retains a compatible current version; otherwise it selects that family's latest edition. |
169
+ | `version(v)` | Positions 1–2 | A `Version` constant or any two-digit string (escape hatch for future editions) |
170
+ | `context(c)` | Position 3 | A `Context` constant |
171
+ | `identity(i)` | Position 4 | A `StandardIdentity` constant |
172
+ | `symbolSet(s)` | Positions 5–6 | A `SymbolSet` constant or any two-digit string |
173
+ | `status(s)` | Position 7 | A `Status` constant |
174
+ | `hqTaskForceDummy(v)` | Position 8 | An `HqTaskForceDummy` constant |
175
+ | `amplifier(v)` | Positions 9–10 | An `Amplifier` constant |
176
+ | `entity(v)` | Positions 11–16 | Any six-digit string; symbol-set-specific catalogs are not included |
177
+ | `modifier1(v)` | Positions 17–18 | Any two-digit string; resets the modifier-1 extension digit to `0` when a tail exists |
178
+ | `modifier2(v)` | Positions 19–20 | Any two-digit string; resets the modifier-2 extension digit to `0` when a tail exists |
179
+ | `extendedModifier1(v)` | Positions 17–18 + 21 | Any three-digit string; hundreds digit lands at position 21 |
180
+ | `extendedModifier2(v)` | Positions 19–20 + 22 | Any three-digit string; hundreds digit lands at position 22 |
181
+ | `frameShape(v)` | Position 23 | A `FrameShape` constant |
182
+ | `withoutExtension()` | Positions 21–23 | Drops the tail, keeping the two-digit modifier slots (may change rendering) |
183
+ | `toString()` | — | Validates combinations and renders the 20- or 23-character SIDC |
184
+ | `problems()` | — | Structured list of non-fatal problems; never throws |
185
+ | `isValid()` | — | `true` when `problems()` is empty |
186
+ | `with(fields)` | — | Applies a partial field record immutably; validates like the setters |
187
+ | `clone()` | — | Copies the fields into an independent builder |
188
+ | `equals(other)` | — | Compares encoded fields, ignoring `strict` and `standard` |
189
+ | `toObject()` / `toJSON()` | — | Plain, serializable snapshot of every encoded field |
190
+ | `Sidc.parse(s, options?)` | — | Parses a 20- or 23-character numeric SIDC; throws when invalid |
191
+ | `Sidc.tryParse(s, options?)` | — | Parses a SIDC or returns `undefined` |
174
192
 
175
193
  ### Enum reference
176
194
 
@@ -179,24 +197,24 @@ All setters validate their argument and return a new immutable `Sidc`.
179
197
  Values match milsymbol's `standard` option and `ms.setStandard()` API, so the
180
198
  same constant can configure both libraries.
181
199
 
182
- | Constant | Value | Standard family |
183
- | -------- | ----- | --------------- |
200
+ | Constant | Value | Standard family |
201
+ | ------------ | -------- | --------------------------------------------------- |
184
202
  | `MilStd2525` | `"2525"` | US MIL-STD-2525 (**default behavior when omitted**) |
185
- | `App6` | `"APP6"` | NATO APP-6 |
203
+ | `App6` | `"APP6"` | NATO APP-6 |
186
204
 
187
205
  #### `HqTaskForceDummy`
188
206
 
189
207
  Position 8 values identify headquarters, task force, and feint/dummy variants.
190
208
 
191
- | Constant | Code | Meaning |
192
- | -------- | ---- | ------- |
193
- | `None` | `"0"` | None / not applicable |
194
- | `FeintDummy` | `"1"` | Feint/dummy |
195
- | `Headquarters` | `"2"` | Headquarters |
196
- | `FeintDummyHeadquarters` | `"3"` | Feint/dummy headquarters |
197
- | `TaskForce` | `"4"` | Task force |
198
- | `FeintDummyTaskForce` | `"5"` | Feint/dummy task force |
199
- | `TaskForceHeadquarters` | `"6"` | Task-force headquarters |
209
+ | Constant | Code | Meaning |
210
+ | --------------------------------- | ----- | ----------------------------------- |
211
+ | `None` | `"0"` | None / not applicable |
212
+ | `FeintDummy` | `"1"` | Feint/dummy |
213
+ | `Headquarters` | `"2"` | Headquarters |
214
+ | `FeintDummyHeadquarters` | `"3"` | Feint/dummy headquarters |
215
+ | `TaskForce` | `"4"` | Task force |
216
+ | `FeintDummyTaskForce` | `"5"` | Feint/dummy task force |
217
+ | `TaskForceHeadquarters` | `"6"` | Task-force headquarters |
200
218
  | `FeintDummyTaskForceHeadquarters` | `"7"` | Feint/dummy task-force headquarters |
201
219
 
202
220
  #### `Amplifier`
@@ -204,113 +222,134 @@ Position 8 values identify headquarters, task force, and feint/dummy variants.
204
222
  Position 9–10 values identify echelon, mobility, leadership, or auxiliary
205
223
  amplifiers. `None` writes the zero/no-amplifier code `"00"`.
206
224
 
207
- | Constant | Code | Meaning |
208
- | -------- | ---- | ------- |
209
- | `None` | `"00"` | None / not specified |
210
- | `TeamCrew` | `"11"` | Team/crew |
211
- | `Squad` | `"12"` | Squad |
212
- | `Section` | `"13"` | Section |
213
- | `PlatoonDetachment` | `"14"` | Platoon/detachment |
214
- | `CompanyBatteryTroop` | `"15"` | Company/battery/troop |
215
- | `BattalionSquadron` | `"16"` | Battalion/squadron |
216
- | `RegimentGroup` | `"17"` | Regiment/group |
217
- | `Brigade` | `"18"` | Brigade |
218
- | `Division` | `"21"` | Division |
219
- | `CorpsMef` | `"22"` | Corps/MEF |
220
- | `Army` | `"23"` | Army |
221
- | `ArmyGroupFront` | `"24"` | Army group/front |
222
- | `RegionTheater` | `"25"` | Region/theater |
223
- | `Command` | `"26"` | Command |
224
- | `WheeledLimitedCrossCountry` | `"31"` | Wheeled, limited cross-country |
225
- | `WheeledCrossCountry` | `"32"` | Wheeled, cross-country |
226
- | `Tracked` | `"33"` | Tracked |
227
- | `WheeledTrackedCombination` | `"34"` | Wheeled and tracked combination |
228
- | `Towed` | `"35"` | Towed |
229
- | `Rail` | `"36"` | Rail |
230
- | `PackAnimals` | `"37"` | Pack animals |
231
- | `OverSnowPrimeMover` | `"41"` | Over snow, prime mover |
232
- | `Sled` | `"42"` | Sled |
233
- | `Barge` | `"51"` | Barge |
234
- | `Amphibious` | `"52"` | Amphibious |
235
- | `ShortTowedArray` | `"61"` | Short towed array |
236
- | `LongTowedArray` | `"62"` | Long towed array |
237
- | `LeaderIndividual` | `"71"` | Leader individual |
238
- | `DeputyIndividual` | `"72"` | Deputy individual |
225
+ | Constant | Code | Meaning |
226
+ | ---------------------------- | ------ | ------------------------------- |
227
+ | `None` | `"00"` | None / not specified |
228
+ | `TeamCrew` | `"11"` | Team/crew |
229
+ | `Squad` | `"12"` | Squad |
230
+ | `Section` | `"13"` | Section |
231
+ | `PlatoonDetachment` | `"14"` | Platoon/detachment |
232
+ | `CompanyBatteryTroop` | `"15"` | Company/battery/troop |
233
+ | `BattalionSquadron` | `"16"` | Battalion/squadron |
234
+ | `RegimentGroup` | `"17"` | Regiment/group |
235
+ | `Brigade` | `"18"` | Brigade |
236
+ | `Division` | `"21"` | Division |
237
+ | `CorpsMef` | `"22"` | Corps/MEF |
238
+ | `Army` | `"23"` | Army |
239
+ | `ArmyGroupFront` | `"24"` | Army group/front |
240
+ | `RegionTheater` | `"25"` | Region/theater |
241
+ | `Command` | `"26"` | Command |
242
+ | `WheeledLimitedCrossCountry` | `"31"` | Wheeled, limited cross-country |
243
+ | `WheeledCrossCountry` | `"32"` | Wheeled, cross-country |
244
+ | `Tracked` | `"33"` | Tracked |
245
+ | `WheeledTrackedCombination` | `"34"` | Wheeled and tracked combination |
246
+ | `Towed` | `"35"` | Towed |
247
+ | `Rail` | `"36"` | Rail |
248
+ | `PackAnimals` | `"37"` | Pack animals |
249
+ | `OverSnowPrimeMover` | `"41"` | Over snow, prime mover |
250
+ | `Sled` | `"42"` | Sled |
251
+ | `Barge` | `"51"` | Barge |
252
+ | `Amphibious` | `"52"` | Amphibious |
253
+ | `ShortTowedArray` | `"61"` | Short towed array |
254
+ | `LongTowedArray` | `"62"` | Long towed array |
255
+ | `LeaderIndividual` | `"71"` | Leader individual |
256
+ | `DeputyIndividual` | `"72"` | Deputy individual |
239
257
 
240
258
  Entity and modifier setters intentionally accept raw digit strings so callers
241
259
  can use codes specific to their symbol set and edition. They validate width and
242
260
  ASCII digits but do not validate catalog membership.
243
261
 
262
+ #### `FrameShape`
263
+
264
+ Position 23, consumed by milsymbol for E-edition shape overrides (`1`–`9` are
265
+ ignored upstream unless the version is E; `A` applies on any edition).
266
+ Selectors are named after the frame they select; `NoFrame` (`A`) is the only
267
+ letter-valued code in the SIDC.
268
+
269
+ | Constant | Code | Meaning |
270
+ | -------------------------- | ----- | -------------------------------------------------- |
271
+ | `Default` | `"0"` | No override (**implied when no extension is set**) |
272
+ | `Space` | `"1"` | Space frame |
273
+ | `Air` | `"2"` | Air frame |
274
+ | `LandUnit` | `"3"` | Land unit frame |
275
+ | `LandEquipmentSeaSurface` | `"4"` | Land equipment / sea surface frame |
276
+ | `Installation` | `"5"` | Installation frame |
277
+ | `LandDismountedIndividual` | `"6"` | Dismounted individual frame |
278
+ | `SeaSubsurface` | `"7"` | Sea subsurface frame |
279
+ | `ActivityEvent` | `"8"` | Activity / event frame |
280
+ | `Cyberspace` | `"9"` | Cyberspace frame |
281
+ | `NoFrame` | `"A"` | Suppress the frame entirely |
282
+
244
283
  #### `Version`
245
284
 
246
- | Constant | Code | Standard |
247
- | -------- | ---- | -------- |
248
- | `MilStd2525D` | `"10"` | MIL-STD-2525D |
249
- | `App6D` | `"11"` | APP-6 D |
285
+ | Constant | Code | Standard |
286
+ | ------------- | ------ | --------------------------- |
287
+ | `MilStd2525D` | `"10"` | MIL-STD-2525D |
288
+ | `App6D` | `"11"` | APP-6 D |
250
289
  | `MilStd2525E` | `"13"` | MIL-STD-2525E (**default**) |
251
- | `App6E` | `"14"` | APP-6 E |
290
+ | `App6E` | `"14"` | APP-6 E |
252
291
 
253
292
  #### `Context`
254
293
 
255
- | Constant | Code | Meaning |
256
- | -------- | ---- | ------- |
257
- | `Reality` | `"0"` | Real-world operation (**default**) |
258
- | `Exercise` | `"1"` | Training/exercise |
259
- | `Simulation` | `"2"` | Simulation |
294
+ | Constant | Code | Meaning |
295
+ | ------------ | ----- | ---------------------------------- |
296
+ | `Reality` | `"0"` | Real-world operation (**default**) |
297
+ | `Exercise` | `"1"` | Training/exercise |
298
+ | `Simulation` | `"2"` | Simulation |
260
299
 
261
300
  #### `StandardIdentity`
262
301
 
263
- | Constant | Code | Frame drawn |
264
- | -------- | ---- | ----------- |
265
- | `Pending` | `"0"` | Unknown shape, dashed |
266
- | `Unknown` | `"1"` | Yellow octagonal frame (**default**) |
267
- | `AssumedFriend` | `"2"` | Blue frame, dashed |
268
- | `Friend` | `"3"` | Blue frame |
269
- | `Neutral` | `"4"` | Green frame |
270
- | `SuspectJoker` | `"5"` | Red frame, dashed — **Suspect** in reality, **Joker** in exercises |
271
- | `HostileFaker` | `"6"` | Red frame — **Hostile** in reality, **Faker** in exercises |
302
+ | Constant | Code | Frame drawn |
303
+ | --------------- | ----- | ------------------------------------------------------------------ |
304
+ | `Pending` | `"0"` | Unknown shape, dashed |
305
+ | `Unknown` | `"1"` | Yellow octagonal frame (**default**) |
306
+ | `AssumedFriend` | `"2"` | Blue frame, dashed |
307
+ | `Friend` | `"3"` | Blue frame |
308
+ | `Neutral` | `"4"` | Green frame |
309
+ | `SuspectJoker` | `"5"` | Red frame, dashed — **Suspect** in reality, **Joker** in exercises |
310
+ | `HostileFaker` | `"6"` | Red frame — **Hostile** in reality, **Faker** in exercises |
272
311
 
273
312
  #### `SymbolSet`
274
313
 
275
314
  Only sets that milsymbol can render are listed.
276
315
 
277
- | Constant | Code | Domain |
278
- | -------- | ---- | ------ |
279
- | `Unknown` | `"00"` | Unknown |
280
- | `Air` | `"01"` | Air tracks |
281
- | `AirMissile` | `"02"` | Air missiles |
282
- | `Space` | `"05"` | Space |
283
- | `SpaceMissile` | `"06"` | Space missiles |
284
- | `LandUnit` | `"10"` | Land units |
285
- | `LandCivilianUnit` | `"11"` | Land civilian units |
286
- | `LandEquipment` | `"15"` | Land equipment |
287
- | `Installation` | `"20"` | Installations |
288
- | `ControlMeasure` | `"25"` | Tactical graphics / control measures |
289
- | `LandDismountedIndividual` | `"27"` | Dismounted individuals |
290
- | `SeaSurface` | `"30"` | Sea surface tracks |
291
- | `SeaSubsurface` | `"35"` | Subsurface tracks |
292
- | `MineWarfare` | `"36"` | Sea mines |
293
- | `Activity` | `"40"` | Activities/events |
294
- | `SignalsIntelligenceSpace` | `"50"` | SIGINT space |
295
- | `SignalsIntelligenceAir` | `"51"` | SIGINT air |
296
- | `SignalsIntelligenceLand` | `"52"` | SIGINT land |
297
- | `SignalsIntelligenceSeaSurface` | `"53"` | SIGINT sea surface |
298
- | `SignalsIntelligenceSubsurface` | `"54"` | SIGINT subsurface |
299
- | `Cyberspace` | `"60"` | Cyberspace |
316
+ | Constant | Code | Domain |
317
+ | ------------------------------- | ------ | ------------------------------------ |
318
+ | `Unknown` | `"00"` | Unknown |
319
+ | `Air` | `"01"` | Air tracks |
320
+ | `AirMissile` | `"02"` | Air missiles |
321
+ | `Space` | `"05"` | Space |
322
+ | `SpaceMissile` | `"06"` | Space missiles |
323
+ | `LandUnit` | `"10"` | Land units |
324
+ | `LandCivilianUnit` | `"11"` | Land civilian units |
325
+ | `LandEquipment` | `"15"` | Land equipment |
326
+ | `Installation` | `"20"` | Installations |
327
+ | `ControlMeasure` | `"25"` | Tactical graphics / control measures |
328
+ | `LandDismountedIndividual` | `"27"` | Dismounted individuals |
329
+ | `SeaSurface` | `"30"` | Sea surface tracks |
330
+ | `SeaSubsurface` | `"35"` | Subsurface tracks |
331
+ | `MineWarfare` | `"36"` | Sea mines |
332
+ | `Activity` | `"40"` | Activities/events |
333
+ | `SignalsIntelligenceSpace` | `"50"` | SIGINT space |
334
+ | `SignalsIntelligenceAir` | `"51"` | SIGINT air |
335
+ | `SignalsIntelligenceLand` | `"52"` | SIGINT land |
336
+ | `SignalsIntelligenceSeaSurface` | `"53"` | SIGINT sea surface |
337
+ | `SignalsIntelligenceSubsurface` | `"54"` | SIGINT subsurface |
338
+ | `Cyberspace` | `"60"` | Cyberspace |
300
339
 
301
340
  Codes `"12"` and `"39"` have no named constant but are recognized via the raw
302
341
  string escape hatch.
303
342
 
304
343
  #### `Status`
305
344
 
306
- | Constant | Code | Meaning |
307
- | -------- | ---- | ------- |
308
- | `Present` | `"0"` | Present / actual (**default**) |
309
- | `Planned` | `"1"` | Planned / anticipated (dashed frame) |
310
- | `FullyCapable` | `"2"` | Condition bar: fully capable |
311
- | `Damaged` | `"3"` | Condition bar: damaged |
312
- | `Destroyed` | `"4"` | Condition bar: destroyed |
313
- | `FullToCapacity` | `"5"` | Condition bar: full to capacity |
345
+ | Constant | Code | Meaning |
346
+ | ---------------- | ----- | ------------------------------------ |
347
+ | `Present` | `"0"` | Present / actual (**default**) |
348
+ | `Planned` | `"1"` | Planned / anticipated (dashed frame) |
349
+ | `FullyCapable` | `"2"` | Condition bar: fully capable |
350
+ | `Damaged` | `"3"` | Condition bar: damaged |
351
+ | `Destroyed` | `"4"` | Condition bar: destroyed |
352
+ | `FullToCapacity` | `"5"` | Condition bar: full to capacity |
314
353
 
315
354
  ## Validation and error handling
316
355
 
@@ -333,6 +372,12 @@ Active combination rules:
333
372
  identity is pending/unknown.
334
373
  - Symbol set 27 is unsupported in MIL-STD-2525D; symbol set 60 is unsupported
335
374
  in APP-6 D.
375
+ - Non-default extension values (nonzero modifier extension digits or a frame
376
+ shape other than `Default`) are reported for D-edition versions `"10"`,
377
+ `"11"`, and `"12"`. This is the library's support policy, not a milsymbol
378
+ restriction: upstream consumes positions 21–22 and `A` on any edition, while
379
+ shape selectors `1`–`9` only take effect for E editions. Explicit all-zero
380
+ tails never warn.
336
381
  - When a `Standard` is explicitly configured, official version codes from the
337
382
  other standard family are reported.
338
383
  - Raw version/symbol-set codes outside milsymbol's known tables are reported.
@@ -428,7 +473,8 @@ Every problem carries a stable `code` and the exact legacy warning `message`.
428
473
 
429
474
  ## Parsing a SIDC
430
475
 
431
- `Sidc.parse()` turns a 20-character numeric SIDC back into a builder so you can
476
+ `Sidc.parse()` turns a 20- or 23-character numeric SIDC back into a builder so
477
+ you can
432
478
  validate, edit, and re-render existing codes. `Sidc.tryParse()` returns
433
479
  `undefined` instead of throwing.
434
480
 
@@ -443,8 +489,12 @@ Sidc.tryParse("not-a-sidc"); // undefined
443
489
  ```
444
490
 
445
491
  Round-tripping is guaranteed: `Sidc.parse(s).toString() === s` for any string
446
- this library produces. Only the 20-character numeric form is supported today;
447
- letter-based SIDCs and the 21–30 character extension are not.
492
+ this library produces, including explicit zero tails (`…000` stays 23
493
+ characters, because tail presence is data). A 20-character SIDC and the same
494
+ code padded with a zero tail render identically in milsymbol but compare as
495
+ unequal builders, mirroring the different strings. Only the 20- and
496
+ 23-character numeric forms are supported; letter-based SIDCs, 21/22-character
497
+ input, and positions 24–30 are not.
448
498
 
449
499
  ## Catalogs (optional)
450
500
 
@@ -459,6 +509,16 @@ import { entityCodes, isKnownEntityCode } from "milsymbol-sidc/catalogs";
459
509
  isKnownEntityCode("10", "121100"); // true — a registered land-unit entity
460
510
  isKnownEntityCode("10", "999999"); // false
461
511
  entityCodes("10").length; // number of registered land-unit codes
512
+
513
+ // Three-digit (extended) modifiers are exposed separately:
514
+ import {
515
+ extendedModifier1Codes,
516
+ isKnownExtendedModifier1Code,
517
+ } from "milsymbol-sidc/catalogs";
518
+
519
+ isKnownExtendedModifier1Code("10", "100"); // true — the common UAV modifier
520
+ isKnownExtendedModifier1Code("10", "199"); // false
521
+ extendedModifier1Codes("10").length; // registered three-digit modifier 1 codes
462
522
  ```
463
523
 
464
524
  The catalog is **membership only**: it carries no semantic names and is never
@@ -502,9 +562,8 @@ const svg = symbol.asSVG();
502
562
  const ms = require("milsymbol");
503
563
 
504
564
  async function render() {
505
- const { Sidc, Standard, StandardIdentity, SymbolSet } = await import(
506
- "milsymbol-sidc"
507
- );
565
+ const { Sidc, Standard, StandardIdentity, SymbolSet } =
566
+ await import("milsymbol-sidc");
508
567
 
509
568
  const sidc = new Sidc({ standard: Standard.App6 })
510
569
  .identity(StandardIdentity.Friend)
@@ -523,7 +582,12 @@ Node.js 20.19+ and 22.12+ can also `require("milsymbol-sidc")` directly via
523
582
  ```html
524
583
  <script src="https://unpkg.com/milsymbol@3/dist/milsymbol.js"></script>
525
584
  <script type="module">
526
- import { Sidc, Standard, StandardIdentity, SymbolSet } from "https://unpkg.com/milsymbol-sidc/dist/src/index.js";
585
+ import {
586
+ Sidc,
587
+ Standard,
588
+ StandardIdentity,
589
+ SymbolSet,
590
+ } from "https://unpkg.com/milsymbol-sidc/dist/src/index.js";
527
591
 
528
592
  const sidc = new Sidc({ standard: Standard.App6 })
529
593
  .identity(StandardIdentity.Neutral)
@@ -542,6 +606,7 @@ Node.js 20.19+ and 22.12+ can also `require("milsymbol-sidc")` directly via
542
606
  import {
543
607
  Amplifier,
544
608
  Context,
609
+ FrameShape,
545
610
  HqTaskForceDummy,
546
611
  Sidc,
547
612
  Standard,
@@ -588,6 +653,22 @@ new Sidc({ standard: Standard.App6, strict: true })
588
653
  .modifier2("09")
589
654
  .toString(); // "14031000001234560109"
590
655
 
656
+ // 2525E UAV modifier (extended modifier 1 "100") plus the airborne modifier
657
+ new Sidc({ strict: true })
658
+ .identity(StandardIdentity.Friend)
659
+ .symbolSet(SymbolSet.LandUnit)
660
+ .entity("110000")
661
+ .extendedModifier1("100")
662
+ .extendedModifier2("100")
663
+ .toString(); // "13031000001100000000110"
664
+
665
+ // Frame shape "A" suppresses the frame for E-edition symbols
666
+ new Sidc({ strict: true })
667
+ .identity(StandardIdentity.Friend)
668
+ .symbolSet(SymbolSet.LandUnit)
669
+ .frameShape(FrameShape.NoFrame)
670
+ .toString(); // "1303100000000000000000A"
671
+
591
672
  // APP-6 D configuration retains an explicitly selected compatible edition
592
673
  new Sidc({ standard: Standard.App6, strict: true })
593
674
  .version(Version.App6D)
@@ -618,7 +699,9 @@ and error class hierarchy.
618
699
  ## Roadmap
619
700
 
620
701
  - Semantic entity and modifier names, layered on the membership catalog.
621
- - Official positions 21–30 / Set C extension data.
702
+ - Official positions 24–30 / Set C extension data (country codes and beyond).
703
+ Positions 21–23 shipped: see `extendedModifier1()`, `extendedModifier2()`,
704
+ and `frameShape()`.
622
705
 
623
706
  ## License
624
707
 
@@ -36,4 +36,12 @@ export declare function isKnownModifier1Code(symbolSet: string, modifier: string
36
36
  export declare function modifier2Codes(symbolSet: string): readonly string[];
37
37
  /** `true` when modifier 2 is registered for the symbol set. */
38
38
  export declare function isKnownModifier2Code(symbolSet: string, modifier: string): boolean;
39
+ /** Registered three-digit modifier 1 codes, not zero-prefixed two-digit aliases. */
40
+ export declare function extendedModifier1Codes(symbolSet: string): readonly string[];
41
+ /** Membership only: neither edition validation nor a rendering guarantee. */
42
+ export declare function isKnownExtendedModifier1Code(symbolSet: string, modifier: string): boolean;
43
+ /** Registered three-digit modifier 2 codes, not zero-prefixed two-digit aliases. */
44
+ export declare function extendedModifier2Codes(symbolSet: string): readonly string[];
45
+ /** Membership only: neither edition validation nor a rendering guarantee. */
46
+ export declare function isKnownExtendedModifier2Code(symbolSet: string, modifier: string): boolean;
39
47
  //# sourceMappingURL=catalog.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../src/catalog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EACL,cAAc,EAIf,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,cAAc,EAAE,CAAC;AAC1B,MAAM,MAAM,aAAa,GAAG,OAAO,cAAc,CAAC;AAiBlD,6DAA6D;AAC7D,wBAAgB,iBAAiB,IAAI,SAAS,MAAM,EAAE,CAErD;AAED,8DAA8D;AAC9D,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAErD;AAED,mEAAmE;AACnE,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAEhE;AAED,oEAAoE;AACpE,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAE5E;AAED,uEAAuE;AACvE,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAEnE;AAED,+DAA+D;AAC/D,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACf,OAAO,CAET;AAED,uEAAuE;AACvE,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAEnE;AAED,+DAA+D;AAC/D,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACf,OAAO,CAET"}
1
+ {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../src/catalog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EACL,cAAc,EAMf,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,cAAc,EAAE,CAAC;AAC1B,MAAM,MAAM,aAAa,GAAG,OAAO,cAAc,CAAC;AAmBlD,6DAA6D;AAC7D,wBAAgB,iBAAiB,IAAI,SAAS,MAAM,EAAE,CAErD;AAED,8DAA8D;AAC9D,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAErD;AAED,mEAAmE;AACnE,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAEhE;AAED,oEAAoE;AACpE,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAE5E;AAED,uEAAuE;AACvE,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAEnE;AAED,+DAA+D;AAC/D,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACf,OAAO,CAET;AAED,uEAAuE;AACvE,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAEnE;AAED,+DAA+D;AAC/D,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACf,OAAO,CAET;AAED,oFAAoF;AACpF,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAE3E;AAED,6EAA6E;AAC7E,wBAAgB,4BAA4B,CAC1C,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACf,OAAO,CAET;AAED,oFAAoF;AACpF,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAE3E;AAED,6EAA6E;AAC7E,wBAAgB,4BAA4B,CAC1C,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACf,OAAO,CAET"}