string-array 2.1.7 → 2.1.8

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,7 +1,16 @@
1
- [![NPM version][npm-image]][npm-url]
2
-
3
1
  # String Array
4
2
 
3
+ [![License][license-image]][license-url]
4
+ [![build][build-image]][build-url]
5
+
6
+ [![Downloads][downloads-image]][downloads-url]
7
+
8
+ [![npm badge][npm-badge-png]][package-url]
9
+
10
+ - [API reference](https://fynjs.pages.dev/api/modules/string-array) - TypeDoc
11
+ - [Markdown reference](docs/reference.md) - the full API and runtime behavior in one file. Also ships in the package.
12
+ - [GitHub](https://github.com/jchip/fynjs/tree/main/packages/string-array)
13
+
5
14
  Parse string into array of string elements.
6
15
 
7
16
  `"[ hello, world, [ 1, [2, [ 3 ]]]]"` :arrow_right: `[ "hello", "world", [ "1", [ "2", [ "3" ]]]]`
@@ -84,6 +93,13 @@ const r2 = stringArray.parse("test[1,2,3]");
84
93
 
85
94
  Licensed under the [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0)
86
95
 
87
- [npm-image]: https://badge.fury.io/js/string-array.svg
88
- [npm-url]: https://npmjs.org/package/string-array
89
96
  [npm scripts]: https://docs.npmjs.com/misc/scripts
97
+
98
+ [license-image]: https://img.shields.io/npm/l/string-array.svg
99
+ [license-url]: LICENSE
100
+ [build-image]: https://github.com/jchip/fynjs/actions/workflows/ci.yml/badge.svg
101
+ [build-url]: https://github.com/jchip/fynjs/actions/workflows/ci.yml
102
+ [downloads-image]: https://img.shields.io/npm/dm/string-array.svg
103
+ [downloads-url]: https://npm-stat.com/charts.html?package=string-array
104
+ [npm-badge-png]: https://nodei.co/npm/string-array.png?downloads=true&stars=true
105
+ [package-url]: https://npmjs.com/package/string-array
@@ -0,0 +1,140 @@
1
+ # string-array reference
2
+
3
+ `string-array` parses a bracketed, comma separated string such as `"[a, b, [c]]"` into a nested array of strings. It has no runtime dependencies. ESM only (`"type": "module"`).
4
+
5
+ ## Imports
6
+
7
+ ```js
8
+ import { parse } from "string-array";
9
+ import type { ParseResult, StringArray } from "string-array";
10
+ ```
11
+
12
+ Everything is a named export from the package root. There is no default export and there are no subpaths (only `string-array/package.json`). The `exports` map has a single `default` condition pointing at an ESM file.
13
+
14
+ Runtime exports: `parse`.
15
+
16
+ Type-only exports: `StringArray`, `ParseResult`.
17
+
18
+ ## `StringArray`
19
+
20
+ ```ts
21
+ type StringArray = string | StringArray[];
22
+ ```
23
+
24
+ An element is either a string or a nested array of elements. Leaves are always strings. Quote characters are never interpreted, and no numbers or booleans are produced.
25
+
26
+ ## `ParseResult`
27
+
28
+ ```ts
29
+ interface ParseResult {
30
+ prefix: string;
31
+ array: StringArray[];
32
+ remain: string;
33
+ }
34
+ ```
35
+
36
+ | Field | Type | Behavior |
37
+ | --- | --- | --- |
38
+ | `prefix` | `string` | Trimmed text before the first `[`. `""` when there is none, when `noPrefix` is `true`, or when the input is empty. |
39
+ | `array` | `StringArray[]` | The outermost parsed array. Its items are strings or nested arrays. `[]` for empty input. |
40
+ | `remain` | `string` | Text left after the first complete top-level array, with leading whitespace and one separating `,` removed. The input is trimmed up front, so `remain` has no outer whitespace. `""` when nothing is left. |
41
+
42
+ ## `parse(str, noPrefix?, noExtra?)`
43
+
44
+ ```ts
45
+ function parse(str: string, noPrefix?: boolean, noExtra?: boolean): ParseResult
46
+ ```
47
+
48
+ Parses one array from the start of `str` (after an optional prefix) and returns it with the prefix and the unparsed rest.
49
+
50
+ | Parameter | Type | Default | Behavior |
51
+ | --- | --- | --- | --- |
52
+ | `str` | `string` | none | Input text. Trimmed first. A non-string throws `TypeError`. |
53
+ | `noPrefix` | `boolean` | `undefined` | Only the exact value `true` disables prefix detection. Any other value, including truthy ones such as `1`, keeps it enabled. |
54
+ | `noExtra` | `boolean` | `undefined` | Only the exact value `true` makes text after the top-level array an error. Any other value allows it and returns it in `remain`. |
55
+
56
+ ### Grammar
57
+
58
+ Informal, as implemented:
59
+
60
+ ```
61
+ input := ws* [ prefix ] array rest
62
+ prefix := text before the first "[", trimmed; only when that "[" is not at index 0
63
+ array := "[" ws* items "]"
64
+ items := (element | array) separated by ","
65
+ element := any characters up to the next "," or "]", trimmed
66
+ rest := ws* [ "," ws* ] remain
67
+ ```
68
+
69
+ - Brackets: `[` opens an array and `]` closes it. Consecutive openers such as `[[[a]]]` nest.
70
+ - Nesting: unbounded depth. The parser is iterative, with no recursion.
71
+ - Separator: `,`. Whitespace around elements, brackets and separators is trimmed (`String.prototype.trim` semantics).
72
+ - Elements: raw text, trimmed. Quotes (`'`, `"`, backtick) stay part of the element. There is no escape character and no way to put `,` or `]` inside an element. A `[` in the middle of an element is accepted as plain text (see edge cases).
73
+ - The comma after a nested array is optional. If present directly after its `]`, it is consumed.
74
+ - Only the first top-level array is parsed. Later text is not parsed, it is returned in `remain`.
75
+
76
+ ### Algorithm
77
+
78
+ 1. `str` is trimmed. If the result is empty, return `{ prefix: "", array: [], remain: "" }`. This happens before any other check, so `noPrefix` and `noExtra` do not matter for empty input.
79
+ 2. Unless `noPrefix === true`, find the first `[`. If its index is greater than 0, `prefix` is the text before it (trimmed) and parsing starts at that `[`. If the index is 0 or there is no `[`, `prefix` is `""` and the text is parsed as is.
80
+ 3. The parse loop: if the remaining text starts with `[`, a new array opens (leading whitespace after it is skipped). Otherwise, if no array is open, it throws `array missing [`.
81
+ 4. In an open array, the next element runs up to the next `,` or `]`. If neither exists it throws `array missing ]`.
82
+ 5. The element is trimmed. A non-empty element is pushed. An empty element is pushed as `""` only when it ends at `,`. An empty element ending at `]` is dropped.
83
+ 6. On `]`, the array closes. A single `,` that follows is consumed.
84
+ 7. When the outermost array closes, the loop stops. If text remains and `noExtra === true`, it throws `extra data at end of array`. Otherwise the text is returned as `remain`.
85
+
86
+ `array` is the outermost array itself. `"[a, [b]]"` gives `array: ["a", ["b"]]`. Each call returns fresh objects.
87
+
88
+ ### Non-array and unusual input
89
+
90
+ | Input | Result |
91
+ | --- | --- |
92
+ | `""` or whitespace only | `{ prefix: "", array: [], remain: "" }`. No error, with any flags. |
93
+ | No `[` (`"abc"`) | Throws `array missing [`. |
94
+ | Text then `[`, with `noPrefix: true` (`"pre[a]"`) | Throws `array missing [`. |
95
+ | `"]"` | Throws `array missing [`. |
96
+ | `"[a"`, `"[[a]"` | Throws `array missing ]`. |
97
+ | `null`, `undefined`, number, array | Throws `TypeError` from `str.trim`. Not guarded. |
98
+
99
+ ### Errors
100
+
101
+ All thrown errors are plain `Error` instances (not `AssertionError`) except the `TypeError` for non-string input.
102
+
103
+ | Message | When |
104
+ | --- | --- |
105
+ | `array missing [` | Input is non-empty and the parser needs an opening `[` but finds none: no `[` in the input, text before `[` with `noPrefix: true`, or input starting with `]`. |
106
+ | `array missing ]` | An array is still open and there is no further `,` or `]`, or the input ends while an array is open. |
107
+ | `extra data at end of array` | The top-level array closed, text remains, and `noExtra === true`. |
108
+
109
+ An unmatched `]` after a complete array is not an error. It lands in `remain`, or throws `extra data at end of array` with `noExtra`.
110
+
111
+ ### Edge cases
112
+
113
+ | Input | Result |
114
+ | --- | --- |
115
+ | `"[]"`, `"[ ]"` | `array: []` |
116
+ | `"[a,]"` | `["a"]`. A trailing comma adds nothing. |
117
+ | `"[,]"` | `[""]` |
118
+ | `"[a,,b]"` | `["a", "", "b"]` |
119
+ | `"[a,,]"` | `["a", ""]` |
120
+ | `"[[a],]"` | `[["a"]]` |
121
+ | `"[[a] b]"` | `[["a"], "b"]`. The comma after a nested array is optional. |
122
+ | `"[[],[]]"`, `"[a,[]]"` | `[[], []]`, `["a", []]` |
123
+ | `"[ 'x,y' ]"` | `["'x", "y'"]`. Quotes do not protect the comma. |
124
+ | `"[a [b]]"` | `array: ["a [b"]`, `remain: "]"`. The inner `[` is plain text, so the first `]` closes the outer array. |
125
+ | `"pre [a] post"` | `prefix: "pre"`, `array: ["a"]`, `remain: "post"` |
126
+ | `"x]y[a]"` | `prefix: "x]y"`, `array: ["a"]` |
127
+ | `"[a], x"` | `remain: "x"`. The comma after `]` is consumed. |
128
+ | `"[a] x [b]"` | `remain: "x [b]"`. The second array is not parsed. |
129
+ | `"[a]]"` | `remain: "]"` |
130
+ | `"[a]["` | `remain: "["` |
131
+ | `"[a],"`, `"[a] , "` | `remain: ""`, even with `noExtra: true`. The comma is consumed and nothing is left. |
132
+ | `"[a] ,x"` with `noExtra` | Throws `extra data at end of array`. |
133
+ | `"pre[a]"` with `noExtra` | Fine. A prefix is not extra data. |
134
+
135
+ ```js
136
+ parse("tag[ hello, world, [ 1, [2] ] ] rest");
137
+ // { prefix: "tag", array: ["hello", "world", ["1", ["2"]]], remain: "rest" }
138
+
139
+ parse("[a, b] more", false, true); // throws Error("extra data at end of array")
140
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "string-array",
3
- "version": "2.1.7",
3
+ "version": "2.1.8",
4
4
  "description": "Parse string into array of string elements",
5
5
  "type": "module",
6
6
  "types": "./dist/index.d.ts",
@@ -23,7 +23,7 @@
23
23
  "prepublishOnly": "xrun build",
24
24
  "postpack": "publish-util-postpack"
25
25
  },
26
- "homepage": "https://github.com/jchip/fynjs/tree/main/packages/string-array",
26
+ "homepage": "https://fynjs.pages.dev/api/modules/string-array",
27
27
  "bugs": {
28
28
  "url": "https://github.com/jchip/fynjs/issues"
29
29
  },
@@ -39,7 +39,8 @@
39
39
  "parser"
40
40
  ],
41
41
  "files": [
42
- "dist"
42
+ "dist",
43
+ "docs/reference.md"
43
44
  ],
44
45
  "author": "Joel Chen",
45
46
  "license": "Apache-2.0",
@@ -48,7 +49,7 @@
48
49
  "@types/node": "^26.4.1",
49
50
  "@vitest/coverage-v8": "^5.0.0",
50
51
  "prettier": "^3.5.3",
51
- "publish-util": "^3.1.7",
52
+ "publish-util": "^3.1.8",
52
53
  "typescript": "^7.0.2",
53
54
  "vite": "^8.2.2",
54
55
  "vitest": "^5.0.0"