@ya-modbus/cli 0.8.0 → 0.9.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.
Files changed (83) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +85 -0
  3. package/dist/cjs/bin/ya-modbus.js +0 -0
  4. package/dist/cjs/src/commands/discover.d.ts +2 -0
  5. package/dist/cjs/src/commands/discover.d.ts.map +1 -1
  6. package/dist/cjs/src/commands/discover.js +19 -11
  7. package/dist/cjs/src/commands/discover.js.map +1 -1
  8. package/dist/cjs/src/discovery/parameter-generator-utils.d.ts +5 -2
  9. package/dist/cjs/src/discovery/parameter-generator-utils.d.ts.map +1 -1
  10. package/dist/cjs/src/discovery/parameter-generator-utils.js +46 -25
  11. package/dist/cjs/src/discovery/parameter-generator-utils.js.map +1 -1
  12. package/dist/cjs/src/discovery/parameter-generator.d.ts +4 -0
  13. package/dist/cjs/src/discovery/parameter-generator.d.ts.map +1 -1
  14. package/dist/cjs/src/discovery/parameter-generator.js +20 -8
  15. package/dist/cjs/src/discovery/parameter-generator.js.map +1 -1
  16. package/dist/cjs/src/index.d.ts.map +1 -1
  17. package/dist/cjs/src/index.js +2 -0
  18. package/dist/cjs/src/index.js.map +1 -1
  19. package/dist/cjs/src/utils/merge-specs.d.ts +34 -0
  20. package/dist/cjs/src/utils/merge-specs.d.ts.map +1 -0
  21. package/dist/cjs/src/utils/merge-specs.js +53 -0
  22. package/dist/cjs/src/utils/merge-specs.js.map +1 -0
  23. package/dist/cjs/src/utils/parse-baud-rate.d.ts +14 -0
  24. package/dist/cjs/src/utils/parse-baud-rate.d.ts.map +1 -0
  25. package/dist/cjs/src/utils/parse-baud-rate.js +52 -0
  26. package/dist/cjs/src/utils/parse-baud-rate.js.map +1 -0
  27. package/dist/cjs/src/utils/parse-id-range.d.ts.map +1 -1
  28. package/dist/cjs/src/utils/parse-id-range.js +23 -48
  29. package/dist/cjs/src/utils/parse-id-range.js.map +1 -1
  30. package/dist/cjs/src/utils/parse-integer.d.ts +15 -0
  31. package/dist/cjs/src/utils/parse-integer.d.ts.map +1 -0
  32. package/dist/cjs/src/utils/parse-integer.js +27 -0
  33. package/dist/cjs/src/utils/parse-integer.js.map +1 -0
  34. package/dist/cjs/src/utils/parse-parity.d.ts +18 -0
  35. package/dist/cjs/src/utils/parse-parity.d.ts.map +1 -0
  36. package/dist/cjs/src/utils/parse-parity.js +46 -0
  37. package/dist/cjs/src/utils/parse-parity.js.map +1 -0
  38. package/dist/cjs/src/utils/parse-spec.d.ts +73 -0
  39. package/dist/cjs/src/utils/parse-spec.d.ts.map +1 -0
  40. package/dist/cjs/src/utils/parse-spec.js +47 -0
  41. package/dist/cjs/src/utils/parse-spec.js.map +1 -0
  42. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  43. package/dist/esm/bin/ya-modbus.js +0 -0
  44. package/dist/esm/src/commands/discover.d.ts +2 -0
  45. package/dist/esm/src/commands/discover.d.ts.map +1 -1
  46. package/dist/esm/src/commands/discover.js +19 -11
  47. package/dist/esm/src/commands/discover.js.map +1 -1
  48. package/dist/esm/src/discovery/parameter-generator-utils.d.ts +5 -2
  49. package/dist/esm/src/discovery/parameter-generator-utils.d.ts.map +1 -1
  50. package/dist/esm/src/discovery/parameter-generator-utils.js +46 -25
  51. package/dist/esm/src/discovery/parameter-generator-utils.js.map +1 -1
  52. package/dist/esm/src/discovery/parameter-generator.d.ts +4 -0
  53. package/dist/esm/src/discovery/parameter-generator.d.ts.map +1 -1
  54. package/dist/esm/src/discovery/parameter-generator.js +20 -8
  55. package/dist/esm/src/discovery/parameter-generator.js.map +1 -1
  56. package/dist/esm/src/index.d.ts.map +1 -1
  57. package/dist/esm/src/index.js +2 -0
  58. package/dist/esm/src/index.js.map +1 -1
  59. package/dist/esm/src/utils/merge-specs.d.ts +34 -0
  60. package/dist/esm/src/utils/merge-specs.d.ts.map +1 -0
  61. package/dist/esm/src/utils/merge-specs.js +50 -0
  62. package/dist/esm/src/utils/merge-specs.js.map +1 -0
  63. package/dist/esm/src/utils/parse-baud-rate.d.ts +14 -0
  64. package/dist/esm/src/utils/parse-baud-rate.d.ts.map +1 -0
  65. package/dist/esm/src/utils/parse-baud-rate.js +49 -0
  66. package/dist/esm/src/utils/parse-baud-rate.js.map +1 -0
  67. package/dist/esm/src/utils/parse-id-range.d.ts.map +1 -1
  68. package/dist/esm/src/utils/parse-id-range.js +23 -48
  69. package/dist/esm/src/utils/parse-id-range.js.map +1 -1
  70. package/dist/esm/src/utils/parse-integer.d.ts +15 -0
  71. package/dist/esm/src/utils/parse-integer.d.ts.map +1 -0
  72. package/dist/esm/src/utils/parse-integer.js +24 -0
  73. package/dist/esm/src/utils/parse-integer.js.map +1 -0
  74. package/dist/esm/src/utils/parse-parity.d.ts +18 -0
  75. package/dist/esm/src/utils/parse-parity.d.ts.map +1 -0
  76. package/dist/esm/src/utils/parse-parity.js +42 -0
  77. package/dist/esm/src/utils/parse-parity.js.map +1 -0
  78. package/dist/esm/src/utils/parse-spec.d.ts +73 -0
  79. package/dist/esm/src/utils/parse-spec.d.ts.map +1 -0
  80. package/dist/esm/src/utils/parse-spec.js +44 -0
  81. package/dist/esm/src/utils/parse-spec.js.map +1 -0
  82. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  83. package/package.json +3 -3
@@ -1,3 +1,5 @@
1
+ import { parseInteger } from './parse-integer.js';
2
+ import { parseSpec } from './parse-spec.js';
1
3
  /**
2
4
  * Parses a comma-separated list of IDs and ranges into a sorted array of unique IDs.
3
5
  *
@@ -10,41 +12,28 @@
10
12
  * parseIdRange("1-3,2-4") // [1, 2, 3, 4]
11
13
  */
12
14
  export function parseIdRange(spec) {
13
- const trimmed = spec.trim();
14
- if (!trimmed) {
15
- throw new Error('Invalid ID specification: empty string. Expected format: "1,2,3" or "1-5"');
16
- }
17
- const ids = new Set();
18
- const parts = trimmed.split(',');
19
- for (const part of parts) {
20
- const normalized = part.trim();
21
- if (!normalized)
22
- continue;
23
- // Check if it's a range (contains hyphen)
24
- if (normalized.includes('-')) {
25
- const rangeParts = normalized.split('-').map((s) => s.trim());
26
- if (rangeParts.length !== 2 || !rangeParts[0] || !rangeParts[1]) {
27
- throw new Error(`Invalid range format: "${part}". Expected format: "start-end"`);
28
- }
29
- const start = parseInteger(rangeParts[0], part);
30
- const end = parseInteger(rangeParts[1], part);
31
- if (start > end) {
32
- throw new Error(`Invalid range: "${part}". Start must be less than or equal to end`);
33
- }
34
- validateModbusAddress(start, part);
35
- validateModbusAddress(end, part);
36
- for (let i = start; i <= end; i++) {
37
- ids.add(i);
15
+ return parseSpec({
16
+ spec,
17
+ label: 'ID',
18
+ formatExamples: ['"1,2,3"', '"1-5"'],
19
+ skipEmptyParts: true,
20
+ parseSingle: (value, context) => {
21
+ const id = parseInteger(value, context, 'ID');
22
+ validateModbusAddress(id, context);
23
+ return id;
24
+ },
25
+ parseRange: (start, end, context) => {
26
+ const startId = parseInteger(start, context, 'ID');
27
+ const endId = parseInteger(end, context, 'ID');
28
+ if (startId > endId) {
29
+ throw new Error(`Invalid range: "${context}". Start must be less than or equal to end`);
38
30
  }
39
- }
40
- else {
41
- // Single ID
42
- const id = parseInteger(normalized, part);
43
- validateModbusAddress(id, part);
44
- ids.add(id);
45
- }
46
- }
47
- return Array.from(ids).sort((a, b) => a - b);
31
+ validateModbusAddress(startId, context);
32
+ validateModbusAddress(endId, context);
33
+ return Array.from({ length: endId - startId + 1 }, (_, i) => startId + i);
34
+ },
35
+ sortItems: (items) => items.sort((a, b) => a - b),
36
+ });
48
37
  }
49
38
  /**
50
39
  * Validates that a number is a valid Modbus slave address (1-247).
@@ -54,18 +43,4 @@ function validateModbusAddress(id, context) {
54
43
  throw new Error(`Invalid Modbus slave address: ${id} in "${context}". ` + `Valid addresses are 1-247`);
55
44
  }
56
45
  }
57
- /**
58
- * Parses a string to an integer with validation.
59
- * Rejects decimal numbers explicitly.
60
- */
61
- function parseInteger(str, context) {
62
- if (str.includes('.')) {
63
- throw new Error(`Invalid ID format: "${context}". Decimal numbers not allowed, expected whole numbers only`);
64
- }
65
- const num = parseInt(str, 10);
66
- if (isNaN(num)) {
67
- throw new Error(`Invalid ID format: "${context}". Expected a number`);
68
- }
69
- return num;
70
- }
71
46
  //# sourceMappingURL=parse-id-range.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"parse-id-range.js","sourceRoot":"","sources":["../../../../src/utils/parse-id-range.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"parse-id-range.js","sourceRoot":"","sources":["../../../../src/utils/parse-id-range.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAE3C;;;;;;;;;;GAUG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,OAAO,SAAS,CAAC;QACf,IAAI;QACJ,KAAK,EAAE,IAAI;QACX,cAAc,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC;QACpC,cAAc,EAAE,IAAI;QACpB,WAAW,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;YAC9B,MAAM,EAAE,GAAG,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,CAAA;YAC7C,qBAAqB,CAAC,EAAE,EAAE,OAAO,CAAC,CAAA;YAClC,OAAO,EAAE,CAAA;QACX,CAAC;QACD,UAAU,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE;YAClC,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,CAAA;YAClD,MAAM,KAAK,GAAG,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,CAAC,CAAA;YAE9C,IAAI,OAAO,GAAG,KAAK,EAAE,CAAC;gBACpB,MAAM,IAAI,KAAK,CAAC,mBAAmB,OAAO,4CAA4C,CAAC,CAAA;YACzF,CAAC;YAED,qBAAqB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;YACvC,qBAAqB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;YAErC,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,GAAG,OAAO,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,OAAO,GAAG,CAAC,CAAC,CAAA;QAC3E,CAAC;QACD,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;KAClD,CAAC,CAAA;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,qBAAqB,CAAC,EAAU,EAAE,OAAe;IACxD,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,GAAG,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CACb,iCAAiC,EAAE,QAAQ,OAAO,KAAK,GAAG,2BAA2B,CACtF,CAAA;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Parses a string to an integer with validation.
3
+ * Rejects decimal numbers explicitly.
4
+ *
5
+ * @param str - String to parse
6
+ * @param context - Context string for error messages
7
+ * @param label - Label for the value type (e.g., "ID", "baud rate")
8
+ * @returns Parsed integer
9
+ *
10
+ * @example
11
+ * parseInteger("123", "1-5", "ID") // 123
12
+ * parseInteger("12.5", "1-5", "ID") // throws Error
13
+ */
14
+ export declare function parseInteger(str: string, context: string, label: string): number;
15
+ //# sourceMappingURL=parse-integer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-integer.d.ts","sourceRoot":"","sources":["../../../../src/utils/parse-integer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAahF"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Parses a string to an integer with validation.
3
+ * Rejects decimal numbers explicitly.
4
+ *
5
+ * @param str - String to parse
6
+ * @param context - Context string for error messages
7
+ * @param label - Label for the value type (e.g., "ID", "baud rate")
8
+ * @returns Parsed integer
9
+ *
10
+ * @example
11
+ * parseInteger("123", "1-5", "ID") // 123
12
+ * parseInteger("12.5", "1-5", "ID") // throws Error
13
+ */
14
+ export function parseInteger(str, context, label) {
15
+ if (str.includes('.')) {
16
+ throw new Error(`Invalid ${label} format: "${context}". Decimal numbers not allowed, expected whole numbers only`);
17
+ }
18
+ const num = parseInt(str, 10);
19
+ if (isNaN(num)) {
20
+ throw new Error(`Invalid ${label} format: "${context}". Expected a number`);
21
+ }
22
+ return num;
23
+ }
24
+ //# sourceMappingURL=parse-integer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-integer.js","sourceRoot":"","sources":["../../../../src/utils/parse-integer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,YAAY,CAAC,GAAW,EAAE,OAAe,EAAE,KAAa;IACtE,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CACb,WAAW,KAAK,aAAa,OAAO,6DAA6D,CAClG,CAAA;IACH,CAAC;IAED,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,CAAA;IAC7B,IAAI,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,WAAW,KAAK,aAAa,OAAO,sBAAsB,CAAC,CAAA;IAC7E,CAAC;IAED,OAAO,GAAG,CAAA;AACZ,CAAC"}
@@ -0,0 +1,18 @@
1
+ import type { Parity } from '@ya-modbus/driver-types';
2
+ /**
3
+ * Parses a comma-separated list of parity values into a sorted array of unique parities.
4
+ *
5
+ * @param spec - Parity specification string (e.g., "none,even,odd")
6
+ * @returns Sorted array of unique parity values in standard order (none, even, odd)
7
+ *
8
+ * @example
9
+ * parseParity("none,even") // ["none", "even"]
10
+ * parseParity("odd,none") // ["none", "odd"]
11
+ * parseParity("even,even") // ["even"]
12
+ */
13
+ export declare function parseParity(spec: string): Parity[];
14
+ /**
15
+ * Sorts parities in standard order (none, even, odd)
16
+ */
17
+ export declare function sortParitiesInStandardOrder(parities: Parity[]): Parity[];
18
+ //# sourceMappingURL=parse-parity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-parity.d.ts","sourceRoot":"","sources":["../../../../src/utils/parse-parity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;AAMrD;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAmBlD;AAED;;GAEG;AACH,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAExE"}
@@ -0,0 +1,42 @@
1
+ import { STANDARD_PARITY } from '../discovery/constants.js';
2
+ import { parseSpec } from './parse-spec.js';
3
+ /**
4
+ * Parses a comma-separated list of parity values into a sorted array of unique parities.
5
+ *
6
+ * @param spec - Parity specification string (e.g., "none,even,odd")
7
+ * @returns Sorted array of unique parity values in standard order (none, even, odd)
8
+ *
9
+ * @example
10
+ * parseParity("none,even") // ["none", "even"]
11
+ * parseParity("odd,none") // ["none", "odd"]
12
+ * parseParity("even,even") // ["even"]
13
+ */
14
+ export function parseParity(spec) {
15
+ return parseSpec({
16
+ spec,
17
+ label: 'parity',
18
+ formatExamples: ['"none,even,odd"'],
19
+ skipEmptyParts: false, // Throw error on empty parts for explicit validation
20
+ parseSingle: (value, context) => {
21
+ const normalized = value.toLowerCase();
22
+ if (!isValidParity(normalized)) {
23
+ throw new Error(`Invalid parity value: "${value}" in "${context}". Valid values are: ${STANDARD_PARITY.join(', ')}`);
24
+ }
25
+ return normalized;
26
+ },
27
+ sortItems: (items) => sortParitiesInStandardOrder(items),
28
+ });
29
+ }
30
+ /**
31
+ * Sorts parities in standard order (none, even, odd)
32
+ */
33
+ export function sortParitiesInStandardOrder(parities) {
34
+ return STANDARD_PARITY.filter((p) => parities.includes(p));
35
+ }
36
+ /**
37
+ * Type guard to check if a string is a valid parity value.
38
+ */
39
+ function isValidParity(value) {
40
+ return STANDARD_PARITY.includes(value);
41
+ }
42
+ //# sourceMappingURL=parse-parity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-parity.js","sourceRoot":"","sources":["../../../../src/utils/parse-parity.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAA;AAE3D,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAE3C;;;;;;;;;;GAUG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,SAAS,CAAC;QACf,IAAI;QACJ,KAAK,EAAE,QAAQ;QACf,cAAc,EAAE,CAAC,iBAAiB,CAAC;QACnC,cAAc,EAAE,KAAK,EAAE,qDAAqD;QAC5E,WAAW,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;YAC9B,MAAM,UAAU,GAAG,KAAK,CAAC,WAAW,EAAE,CAAA;YAEtC,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC/B,MAAM,IAAI,KAAK,CACb,0BAA0B,KAAK,SAAS,OAAO,wBAAwB,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACpG,CAAA;YACH,CAAC;YAED,OAAO,UAAU,CAAA;QACnB,CAAC;QACD,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,2BAA2B,CAAC,KAAK,CAAC;KACzD,CAAC,CAAA;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,2BAA2B,CAAC,QAAkB;IAC5D,OAAO,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAA;AAC5D,CAAC;AAED;;GAEG;AACH,SAAS,aAAa,CAAC,KAAa;IAClC,OAAO,eAAe,CAAC,QAAQ,CAAC,KAAe,CAAC,CAAA;AAClD,CAAC"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Generic utility for parsing comma-separated specification strings
3
+ * with optional range support.
4
+ *
5
+ * Handles:
6
+ * - Empty string validation
7
+ * - Comma-separated list parsing
8
+ * - Optional range expansion (e.g., "1-5")
9
+ * - Deduplication via Set
10
+ * - Custom sorting/ordering
11
+ *
12
+ * @example
13
+ * const parseIds = (spec: string) => parseSpec({
14
+ * spec,
15
+ * label: 'ID',
16
+ * formatExamples: ['"1,2,3"', '"1-5"'],
17
+ * parseSingle: (value, context) => {
18
+ * const id = parseInteger(value, context, 'ID')
19
+ * if (id < 1 || id > 247) throw new Error(...)
20
+ * return id
21
+ * },
22
+ * parseRange: (start, end, context) => {
23
+ * const startId = parseInteger(start, context, 'ID')
24
+ * const endId = parseInteger(end, context, 'ID')
25
+ * return Array.from({length: endId - startId + 1}, (_, i) => startId + i)
26
+ * },
27
+ * sortItems: (items) => items.sort((a, b) => a - b)
28
+ * })
29
+ */
30
+ export interface ParseSpecOptions<T> {
31
+ /** The specification string to parse (e.g., "1,2,3" or "none,even") */
32
+ spec: string;
33
+ /** Label for the value type (e.g., "ID", "parity", "baud rate") */
34
+ label: string;
35
+ /** Example formats to show in error messages (e.g., ['"1,2,3"', '"1-5"']) */
36
+ formatExamples: string[];
37
+ /**
38
+ * Parse a single value from the spec
39
+ * @param value - The trimmed value to parse
40
+ * @param context - The original part for error context
41
+ * @returns The parsed value
42
+ */
43
+ parseSingle: (value: string, context: string) => T;
44
+ /**
45
+ * Optional: Parse a range (e.g., "1-5")
46
+ * @param start - The start value string
47
+ * @param end - The end value string
48
+ * @param context - The original range string for error context
49
+ * @returns Array of values in the range
50
+ */
51
+ parseRange?: (start: string, end: string, context: string) => T[];
52
+ /**
53
+ * Sort/order the final array of values
54
+ * @param items - Deduplicated array of items
55
+ * @returns Sorted array
56
+ */
57
+ sortItems: (items: T[]) => T[];
58
+ /**
59
+ * Optional: Skip empty parts in comma-separated list instead of throwing error
60
+ * Default: false (throw error on empty parts)
61
+ */
62
+ skipEmptyParts?: boolean;
63
+ }
64
+ /**
65
+ * Generic parser for comma-separated specification strings
66
+ *
67
+ * @param options - Parsing options
68
+ * @returns Sorted array of unique values
69
+ *
70
+ * @throws Error if spec is empty or contains invalid values
71
+ */
72
+ export declare function parseSpec<T>(options: ParseSpecOptions<T>): T[];
73
+ //# sourceMappingURL=parse-spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-spec.d.ts","sourceRoot":"","sources":["../../../../src/utils/parse-spec.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,WAAW,gBAAgB,CAAC,CAAC;IACjC,uEAAuE;IACvE,IAAI,EAAE,MAAM,CAAA;IAEZ,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAA;IAEb,6EAA6E;IAC7E,cAAc,EAAE,MAAM,EAAE,CAAA;IAExB;;;;;OAKG;IACH,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC,CAAA;IAElD;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC,EAAE,CAAA;IAEjE;;;;OAIG;IACH,SAAS,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,KAAK,CAAC,EAAE,CAAA;IAE9B;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAoD9D"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Generic parser for comma-separated specification strings
3
+ *
4
+ * @param options - Parsing options
5
+ * @returns Sorted array of unique values
6
+ *
7
+ * @throws Error if spec is empty or contains invalid values
8
+ */
9
+ export function parseSpec(options) {
10
+ const { spec, label, formatExamples, parseSingle, parseRange, sortItems, skipEmptyParts = false, } = options;
11
+ const trimmed = spec.trim();
12
+ if (!trimmed) {
13
+ throw new Error(`Invalid ${label} specification: empty string. Expected format: ${formatExamples.join(' or ')}`);
14
+ }
15
+ const items = new Set();
16
+ const parts = trimmed.split(',');
17
+ for (const part of parts) {
18
+ const normalized = part.trim();
19
+ if (!normalized) {
20
+ if (skipEmptyParts) {
21
+ continue;
22
+ }
23
+ else {
24
+ throw new Error(`Invalid ${label} specification: empty value in "${spec}". Expected format: ${formatExamples.join(' or ')}`);
25
+ }
26
+ }
27
+ // Check if it's a range (contains hyphen)
28
+ if (normalized.includes('-') && parseRange) {
29
+ const rangeParts = normalized.split('-').map((s) => s.trim());
30
+ if (rangeParts.length !== 2 || !rangeParts[0] || !rangeParts[1]) {
31
+ throw new Error(`Invalid range format: "${part}". Expected format: "start-end"`);
32
+ }
33
+ const rangeValues = parseRange(rangeParts[0], rangeParts[1], part);
34
+ rangeValues.forEach((value) => items.add(value));
35
+ }
36
+ else {
37
+ // Single value
38
+ const value = parseSingle(normalized, part);
39
+ items.add(value);
40
+ }
41
+ }
42
+ return sortItems(Array.from(items));
43
+ }
44
+ //# sourceMappingURL=parse-spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-spec.js","sourceRoot":"","sources":["../../../../src/utils/parse-spec.ts"],"names":[],"mappings":"AAsEA;;;;;;;GAOG;AACH,MAAM,UAAU,SAAS,CAAI,OAA4B;IACvD,MAAM,EACJ,IAAI,EACJ,KAAK,EACL,cAAc,EACd,WAAW,EACX,UAAU,EACV,SAAS,EACT,cAAc,GAAG,KAAK,GACvB,GAAG,OAAO,CAAA;IAEX,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;IAC3B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,WAAW,KAAK,kDAAkD,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAChG,CAAA;IACH,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,GAAG,EAAK,CAAA;IAC1B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IAEhC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;QAE9B,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,IAAI,cAAc,EAAE,CAAC;gBACnB,SAAQ;YACV,CAAC;iBAAM,CAAC;gBACN,MAAM,IAAI,KAAK,CACb,WAAW,KAAK,mCAAmC,IAAI,uBAAuB,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAC5G,CAAA;YACH,CAAC;QACH,CAAC;QAED,0CAA0C;QAC1C,IAAI,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,UAAU,EAAE,CAAC;YAC3C,MAAM,UAAU,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAA;YAE7D,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;gBAChE,MAAM,IAAI,KAAK,CAAC,0BAA0B,IAAI,iCAAiC,CAAC,CAAA;YAClF,CAAC;YAED,MAAM,WAAW,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAA;YAClE,WAAW,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAA;QAClD,CAAC;aAAM,CAAC;YACN,eAAe;YACf,MAAM,KAAK,GAAG,WAAW,CAAC,UAAU,EAAE,IAAI,CAAC,CAAA;YAC3C,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QAClB,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAA;AACrC,CAAC"}