milsymbol-sidc 0.3.0 → 0.4.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
@@ -1,5 +1,6 @@
1
1
  # milsymbol-sidc
2
2
 
3
+ [![CI](https://github.com/psylsph/milsymbol-sidc/actions/workflows/ci.yml/badge.svg)](https://github.com/psylsph/milsymbol-sidc/actions/workflows/ci.yml)
3
4
  [![npm version](https://img.shields.io/npm/v/milsymbol-sidc.svg)](https://www.npmjs.com/package/milsymbol-sidc)
4
5
  [![npm downloads](https://img.shields.io/npm/dm/milsymbol-sidc.svg)](https://www.npmjs.com/package/milsymbol-sidc)
5
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
@@ -35,8 +36,8 @@ new ms.Symbol(sidc).asSVG(); // friendly land unit icon
35
36
 
36
37
  > **Coverage:** complete structural encoding for positions 1–20 of the numeric
37
38
  > SIDC. Positions 8–10 have named universal codes; positions 11–20 accept
38
- > validated raw entity and modifier codes. Symbol-set-specific entity and
39
- > modifier catalogs remain future work.
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.
40
41
 
41
42
  ## Installation
42
43
 
@@ -142,6 +143,7 @@ Present. This remains the default for backward compatibility; configure
142
143
  | ------ | ---- | ------- | ----------- |
143
144
  | `strict` | `boolean` | `false` | Throw on invalid field combinations during `toString()` instead of warning. Invalid values always throw immediately regardless of this flag. |
144
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. |
145
147
 
146
148
  ### Methods
147
149
 
@@ -161,6 +163,14 @@ All setters validate their argument and return a new immutable `Sidc`.
161
163
  | `modifier1(v)` | Positions 17–18 | Any two-digit string; symbol-set-specific catalogs are not included |
162
164
  | `modifier2(v)` | Positions 19–20 | Any two-digit string; symbol-set-specific catalogs are not included |
163
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` |
164
174
 
165
175
  ### Enum reference
166
176
 
@@ -390,6 +400,72 @@ try {
390
400
  Error classes: `SidcError` (base) → `SidcValidationError`,
391
401
  `SidcCombinationError`.
392
402
 
403
+ ### Reading and reporting problems
404
+
405
+ `console.warn` is only the default. Inspect problems without side effects with
406
+ `problems()` and `isValid()`, or route them anywhere with `onWarning`:
407
+
408
+ ```ts
409
+ import { Sidc, SymbolSet, Status } from "milsymbol-sidc";
410
+
411
+ const sidc = new Sidc()
412
+ .symbolSet(SymbolSet.ControlMeasure)
413
+ .status(Status.Destroyed);
414
+
415
+ sidc.problems();
416
+ // [{ code: "condition-status-control-measure", message: "…" }]
417
+ sidc.isValid(); // false
418
+
419
+ new Sidc({ onWarning: (problem) => log.warn(problem.code) })
420
+ .symbolSet(SymbolSet.ControlMeasure)
421
+ .status(Status.Destroyed)
422
+ .toString(); // no console output; onWarning is called once
423
+ ```
424
+
425
+ Every problem carries a stable `code` and the exact legacy warning `message`.
426
+ `problems()` never throws, even for builders created with `{ strict: true }`;
427
+ `toString()` still throws `SidcCombinationError` in strict mode.
428
+
429
+ ## Parsing a SIDC
430
+
431
+ `Sidc.parse()` turns a 20-character numeric SIDC back into a builder so you can
432
+ validate, edit, and re-render existing codes. `Sidc.tryParse()` returns
433
+ `undefined` instead of throwing.
434
+
435
+ ```ts
436
+ import { Sidc } from "milsymbol-sidc";
437
+
438
+ const sidc = Sidc.parse("14031002161234560109");
439
+ sidc.toObject().entity; // "123456"
440
+
441
+ sidc.with({ modifier1: "02" }).toString(); // "14031002161234560209"
442
+ Sidc.tryParse("not-a-sidc"); // undefined
443
+ ```
444
+
445
+ 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.
448
+
449
+ ## Catalogs (optional)
450
+
451
+ The `milsymbol-sidc/catalogs` subpath exposes a membership catalog generated from
452
+ milsymbol's numeric symbol data: which entity and modifier codes milsymbol
453
+ registers for each symbol set. It is a separate entry point, so the core builder
454
+ stays data-free unless you import it.
455
+
456
+ ```ts
457
+ import { entityCodes, isKnownEntityCode } from "milsymbol-sidc/catalogs";
458
+
459
+ isKnownEntityCode("10", "121100"); // true — a registered land-unit entity
460
+ isKnownEntityCode("10", "999999"); // false
461
+ entityCodes("10").length; // number of registered land-unit codes
462
+ ```
463
+
464
+ The catalog is **membership only**: it carries no semantic names and is never
465
+ consulted by `toString()`, so raw entity and modifier values still encode
466
+ without recognition warnings. Regenerate it with `npm run generate:catalogs`;
467
+ the milsymbol version it was derived from is exported as `CATALOG_SOURCE`.
468
+
393
469
  ## Using with milsymbol
394
470
 
395
471
  milsymbol routes any SIDC whose first two characters are digits to its numeric
@@ -524,10 +600,16 @@ new Sidc({ standard: Standard.App6, strict: true })
524
600
 
525
601
  ```bash
526
602
  npm install
527
- npm test # compiles with tsc, then runs node --test against dist/
603
+ npm test # compiles with tsc, then runs node --test against dist/
528
604
  npm run build
605
+ npm run lint # eslint
606
+ npm run format:check # prettier
607
+ npm run generate:catalogs # regenerate src/catalogs.generated.ts from milsymbol
529
608
  ```
530
609
 
610
+ CI runs the test suite on Node 18/20/22/24, plus lint, formatting, markdownlint,
611
+ coverage, and a check that the generated catalog is current.
612
+
531
613
  Test coverage includes per-field offset encoding for every enum member,
532
614
  defaults, immutability, setter validation errors, extended-field offsets,
533
615
  all combination rules in both warn and strict modes, raw-code escape hatches,
@@ -535,10 +617,8 @@ and error class hierarchy.
535
617
 
536
618
  ## Roadmap
537
619
 
538
- - Symbol-set-specific named entity and modifier catalogs with semantic
539
- validation.
620
+ - Semantic entity and modifier names, layered on the membership catalog.
540
621
  - Official positions 21–30 / Set C extension data.
541
- - Parsing/decoding SIDC strings back into structured fields.
542
622
 
543
623
  ## License
544
624
 
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Optional membership catalogs derived from milsymbol's numeric symbol data.
3
+ *
4
+ * Import from the `milsymbol-sidc/catalogs` subpath. This module is deliberately
5
+ * **not** part of the main entry point, so bundlers that only use the builder
6
+ * never include the catalog data.
7
+ *
8
+ * These catalogs answer "which codes does milsymbol register for this symbol
9
+ * set?". They intentionally carry no semantic names, and they are never
10
+ * consulted by `Sidc.toString()` - raw entity and modifier values continue to
11
+ * encode without recognition warnings.
12
+ *
13
+ * ```ts
14
+ * import { isKnownEntityCode } from "milsymbol-sidc/catalogs";
15
+ *
16
+ * isKnownEntityCode("10", "121100"); // true for land units
17
+ * isKnownEntityCode("10", "999999"); // false
18
+ * ```
19
+ */
20
+ import { CATALOG_SOURCE } from "./catalogs.generated.js";
21
+ export { CATALOG_SOURCE };
22
+ export type CatalogSource = typeof CATALOG_SOURCE;
23
+ /** Every symbol set the catalog covers, sorted ascending. */
24
+ export declare function catalogSymbolSets(): readonly string[];
25
+ /** `true` when any catalog data exists for the symbol set. */
26
+ export declare function hasCatalog(symbolSet: string): boolean;
27
+ /** Six-digit entity codes milsymbol registers for a symbol set. */
28
+ export declare function entityCodes(symbolSet: string): readonly string[];
29
+ /** `true` when the entity code is registered for the symbol set. */
30
+ export declare function isKnownEntityCode(symbolSet: string, entity: string): boolean;
31
+ /** Two-digit modifier 1 codes milsymbol registers for a symbol set. */
32
+ export declare function modifier1Codes(symbolSet: string): readonly string[];
33
+ /** `true` when modifier 1 is registered for the symbol set. */
34
+ export declare function isKnownModifier1Code(symbolSet: string, modifier: string): boolean;
35
+ /** Two-digit modifier 2 codes milsymbol registers for a symbol set. */
36
+ export declare function modifier2Codes(symbolSet: string): readonly string[];
37
+ /** `true` when modifier 2 is registered for the symbol set. */
38
+ export declare function isKnownModifier2Code(symbolSet: string, modifier: string): boolean;
39
+ //# sourceMappingURL=catalog.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Optional membership catalogs derived from milsymbol's numeric symbol data.
3
+ *
4
+ * Import from the `milsymbol-sidc/catalogs` subpath. This module is deliberately
5
+ * **not** part of the main entry point, so bundlers that only use the builder
6
+ * never include the catalog data.
7
+ *
8
+ * These catalogs answer "which codes does milsymbol register for this symbol
9
+ * set?". They intentionally carry no semantic names, and they are never
10
+ * consulted by `Sidc.toString()` - raw entity and modifier values continue to
11
+ * encode without recognition warnings.
12
+ *
13
+ * ```ts
14
+ * import { isKnownEntityCode } from "milsymbol-sidc/catalogs";
15
+ *
16
+ * isKnownEntityCode("10", "121100"); // true for land units
17
+ * isKnownEntityCode("10", "999999"); // false
18
+ * ```
19
+ */
20
+ import { CATALOG_SOURCE, ENTITY_CODES, MODIFIER_1_CODES, MODIFIER_2_CODES, } from "./catalogs.generated.js";
21
+ export { CATALOG_SOURCE };
22
+ const EMPTY = Object.freeze([]);
23
+ const SYMBOL_SETS = new Set([
24
+ ...Object.keys(ENTITY_CODES),
25
+ ...Object.keys(MODIFIER_1_CODES),
26
+ ...Object.keys(MODIFIER_2_CODES),
27
+ ]);
28
+ function codesFor(table, symbolSet) {
29
+ return table[symbolSet] ?? EMPTY;
30
+ }
31
+ /** Every symbol set the catalog covers, sorted ascending. */
32
+ export function catalogSymbolSets() {
33
+ return Object.freeze([...SYMBOL_SETS].sort());
34
+ }
35
+ /** `true` when any catalog data exists for the symbol set. */
36
+ export function hasCatalog(symbolSet) {
37
+ return SYMBOL_SETS.has(symbolSet);
38
+ }
39
+ /** Six-digit entity codes milsymbol registers for a symbol set. */
40
+ export function entityCodes(symbolSet) {
41
+ return codesFor(ENTITY_CODES, symbolSet);
42
+ }
43
+ /** `true` when the entity code is registered for the symbol set. */
44
+ export function isKnownEntityCode(symbolSet, entity) {
45
+ return entityCodes(symbolSet).includes(entity);
46
+ }
47
+ /** Two-digit modifier 1 codes milsymbol registers for a symbol set. */
48
+ export function modifier1Codes(symbolSet) {
49
+ return codesFor(MODIFIER_1_CODES, symbolSet);
50
+ }
51
+ /** `true` when modifier 1 is registered for the symbol set. */
52
+ export function isKnownModifier1Code(symbolSet, modifier) {
53
+ return modifier1Codes(symbolSet).includes(modifier);
54
+ }
55
+ /** Two-digit modifier 2 codes milsymbol registers for a symbol set. */
56
+ export function modifier2Codes(symbolSet) {
57
+ return codesFor(MODIFIER_2_CODES, symbolSet);
58
+ }
59
+ /** `true` when modifier 2 is registered for the symbol set. */
60
+ export function isKnownModifier2Code(symbolSet, modifier) {
61
+ return modifier2Codes(symbolSet).includes(modifier);
62
+ }
63
+ //# sourceMappingURL=catalog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../src/catalog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EACL,cAAc,EACd,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,cAAc,EAAE,CAAC;AAG1B,MAAM,KAAK,GAAsB,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AAEnD,MAAM,WAAW,GAAwB,IAAI,GAAG,CAAC;IAC/C,GAAG,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC;IAC5B,GAAG,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC;IAChC,GAAG,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC;CACjC,CAAC,CAAC;AAEH,SAAS,QAAQ,CACf,KAAkD,EAClD,SAAiB;IAEjB,OAAO,KAAK,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC;AACnC,CAAC;AAED,6DAA6D;AAC7D,MAAM,UAAU,iBAAiB;IAC/B,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;AAChD,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,UAAU,CAAC,SAAiB;IAC1C,OAAO,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;AACpC,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,WAAW,CAAC,SAAiB;IAC3C,OAAO,QAAQ,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;AAC3C,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,iBAAiB,CAAC,SAAiB,EAAE,MAAc;IACjE,OAAO,WAAW,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AACjD,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,cAAc,CAAC,SAAiB;IAC9C,OAAO,QAAQ,CAAC,gBAAgB,EAAE,SAAS,CAAC,CAAC;AAC/C,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,oBAAoB,CAClC,SAAiB,EACjB,QAAgB;IAEhB,OAAO,cAAc,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AACtD,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,cAAc,CAAC,SAAiB;IAC9C,OAAO,QAAQ,CAAC,gBAAgB,EAAE,SAAS,CAAC,CAAC;AAC/C,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,oBAAoB,CAClC,SAAiB,EACjB,QAAgB;IAEhB,OAAO,cAAc,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AACtD,CAAC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * GENERATED FILE - do not edit by hand.
3
+ *
4
+ * Membership catalog derived from milsymbol 3.0.4 (MIT),
5
+ * Copyright (c) 2017 Måns Beckman - https://www.spatialillusions.com
6
+ *
7
+ * Regenerate with `npm run generate:catalogs`.
8
+ */
9
+ /** Package and version the catalog was generated from. */
10
+ export declare const CATALOG_SOURCE: {
11
+ readonly name: "milsymbol";
12
+ readonly version: "3.0.4";
13
+ };
14
+ /** Six-digit entity codes milsymbol registers, keyed by symbol set. */
15
+ export declare const ENTITY_CODES: Readonly<Record<string, readonly string[]>>;
16
+ /** Two-digit modifier 1 codes milsymbol registers, keyed by symbol set. */
17
+ export declare const MODIFIER_1_CODES: Readonly<Record<string, readonly string[]>>;
18
+ /** Two-digit modifier 2 codes milsymbol registers, keyed by symbol set. */
19
+ export declare const MODIFIER_2_CODES: Readonly<Record<string, readonly string[]>>;
20
+ //# sourceMappingURL=catalogs.generated.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalogs.generated.d.ts","sourceRoot":"","sources":["../../src/catalogs.generated.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,0DAA0D;AAC1D,eAAO,MAAM,cAAc;;;CAGjB,CAAC;AAEX,uEAAuE;AACvE,eAAO,MAAM,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CA0sCjE,CAAC;AAEL,2EAA2E;AAC3E,eAAO,MAAM,gBAAgB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CA0uBrE,CAAC;AAEL,2EAA2E;AAC3E,eAAO,MAAM,gBAAgB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CA4PrE,CAAC"}