@mattwca/little-parser-lib 1.0.1 → 1.0.3

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
@@ -9,7 +9,7 @@ A lightweight, flexible TypeScript library for building parsers using parser com
9
9
  - 📝 **TypeScript First**: Full type safety and IntelliSense support
10
10
  - 🎯 **Backtracking Support**: Automatic position restoration on parse failures
11
11
  - 📦 **Zero Dependencies**: Lightweight with no external runtime dependencies
12
- - ✨ Packaged with [tsdown](https://tsdown.dev)
12
+ - ✨ **Widely Compatible**: Packaged with [tsdown](https://tsdown.dev)
13
13
 
14
14
  ## Installation
15
15
 
@@ -199,6 +199,46 @@ Convenience method to tokenize and parse in one step.
199
199
  const result = runParserOnString(myParser, 'input string', tokenizer);
200
200
  ```
201
201
 
202
+ ## Utilities
203
+
204
+ The library provides utility functions to help with common parser result manipulation tasks.
205
+
206
+ ### `unwrapResult(items)`
207
+
208
+ Flattens nested arrays that result from combining parsers like `and` and `many`. This is particularly useful when you have deeply nested parser structures and need a flat array of results.
209
+
210
+ ```typescript
211
+ import { unwrapResult } from '@mattwca/little-parser-lib';
212
+
213
+ // Parser results can be nested
214
+ const parser = and(
215
+ many(anyOf('letter')),
216
+ many(anyOf('digit'))
217
+ );
218
+
219
+ const result = runParser(parser, stream);
220
+ // result.result might be: [[token1, token2], [token3, token4]]
221
+
222
+ const flattened = unwrapResult(result.result);
223
+ // flattened is: [token1, token2, token3, token4]
224
+ ```
225
+
226
+ **Parameters:**
227
+ - `items: (T | T[])[]` - An array that may contain nested arrays
228
+
229
+ **Returns:**
230
+ - `T[]` - A flattened array with all nested items extracted
231
+
232
+ **Example Use Cases:**
233
+
234
+ ```typescript
235
+ // Use with map to process flattened results
236
+ const tokenParser = map(
237
+ and(many(anyOf('letter')), many(anyOf('digit'))),
238
+ (results) => unwrapResult(results).map(t => t.value).join('')
239
+ );
240
+ ```
241
+
202
242
  ## Example: Simple Expression Parser
203
243
 
204
244
  ```typescript
@@ -301,6 +341,7 @@ try {
301
341
  - `runParserOnString(parser, input, tokenizer)`: Execute parser on string
302
342
  - `isSuccessfulResult(result)`: Type guard for successful results
303
343
  - `isFailedResult(result)`: Type guard for failed results
344
+ - `unwrapResult(results)`: Unwrap nested parser results
304
345
 
305
346
  ## License
306
347
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mattwca/little-parser-lib",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",
@@ -42,6 +42,7 @@
42
42
  "node": ">=14"
43
43
  },
44
44
  "repository": {
45
+ "type": "git",
45
46
  "url": "https://github.com/mattwca/little-parser-lib"
46
47
  }
47
48
  }
package/src/index.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export * from './tokenizer';
2
- export * from './parser';
2
+ export * from './parsers';
3
+ export * from './utils';
@@ -0,0 +1,3 @@
1
+ export * from './parsers';
2
+ export * from './ParsingError';
3
+ export * from './types';
@@ -92,8 +92,8 @@ export function or<T>(...parsers: ParseFn<T>[]): ParseFn<T> {
92
92
  }
93
93
 
94
94
  /**
95
- * Applies a parser repeatedly until it fails, collecting all successful results into an array.
96
- * If the parser fails on the first attempt, returns a failure.
95
+ * Applies a parser repeatedly until it fails or doesn't make progress (move the position), collecting
96
+ * all successful results into an array. If the parser fails on the first attempt, returns a failure.
97
97
  */
98
98
  export function many(parser: ParseFn<any>): ParseFn<any> {
99
99
  return (tokenStream: TokenStream) => {
@@ -102,10 +102,20 @@ export function many(parser: ParseFn<any>): ParseFn<any> {
102
102
  let parseFailure = null;
103
103
 
104
104
  while (true) {
105
+ const positionBefore = tokenStream.position;
105
106
  tokenStream.storePosition();
106
107
 
107
108
  const result = parser(tokenStream);
109
+
108
110
  if (isSuccessfulResult(result)) {
111
+ const positionAfter = tokenStream.position;
112
+
113
+ // Check if the parser made any progress - if it didn't, we break out to avoid infinite loops.
114
+ if (positionAfter === positionBefore) {
115
+ tokenStream.restorePosition();
116
+ break;
117
+ }
118
+
109
119
  results.push(result.result);
110
120
  tokenStream.clearPosition();
111
121
  } else {
@@ -197,24 +207,11 @@ export function endOfInput(): ParseFn {
197
207
  };
198
208
  }
199
209
 
200
- export function parseName(): ParseFn<any> {
201
- return (tokenStream: TokenStream) => {
202
- const validTokenTypes: TokenType[] = ['letter', 'digit', 'minus', 'underscore'];
203
- const parseValidToken = anyOf(...validTokenTypes);
204
-
205
- const parser = and(anyOf('letter'), many(parseValidToken));
206
- const result = parser(tokenStream);
207
-
208
- if (isSuccessfulResult(result)) {
209
- console.log(result);
210
- }
211
-
212
- return result;
213
- }
214
- }
215
-
216
210
  /**
217
211
  * Transforms the result of a parser using a given mapping function.
212
+ * @param parser The parser whose result is to be transformed.
213
+ * @param mapFn A function that takes the parser's result and returns a new value.
214
+ * @returns A new parser that applies the mapping function to the result of the original parser.
218
215
  */
219
216
  export function map<T, U>(parser: ParseFn<T>, mapFn: (value: T) => U): ParseFn<U> {
220
217
  return (tokenStream: TokenStream) => {
package/src/utils.ts ADDED
@@ -0,0 +1,17 @@
1
+ /**
2
+ * A method which unwraps a given generic array, taking each element and accumulating them, if the given item is a nested array, it is flattened into the result.
3
+ * Useful for flattening parser results built with the `and` and `many` combinators, which can produce nested arrays.
4
+ * @param items - An array of items or nested arrays of items to be unwrapped.
5
+ * @returns A flattened array containing all individual items.
6
+ */
7
+ export const unwrapResult = <T>(items: (T | T[])[]): T[] => {
8
+ const result: T[] = [];
9
+ for (const item of items) {
10
+ if (Array.isArray(item)) {
11
+ result.push(...unwrapResult(item));
12
+ } else {
13
+ result.push(item);
14
+ }
15
+ }
16
+ return result;
17
+ };
@@ -1,3 +0,0 @@
1
- export * from './parser';
2
- export * from './ParsingError';
3
- export * from './types';
File without changes
File without changes