• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..21-May-2021-

LICENSEH A D21-May-20211 KiB2016

README.mdH A D21-May-20216.3 KiB178113

package.jsonH A D21-May-2021823 3333

README.md

1# character-parser
2
3Parse JavaScript one character at a time to look for snippets in Templates.  This is not a validator, it's just designed to allow you to have sections of JavaScript delimited by brackets robustly.
4
5[![Build Status](https://img.shields.io/travis/ForbesLindesay/character-parser/master.svg)](https://travis-ci.org/ForbesLindesay/character-parser)
6
7## Installation
8
9    npm install character-parser
10
11## Usage
12
13### Parsing
14
15Work out how much depth changes:
16
17```js
18var state = parse('foo(arg1, arg2, {\n  foo: [a, b\n');
19assert.deepEqual(state.stack, [')', '}', ']']);
20
21parse('    c, d]\n  })', state);
22assert.deepEqual(state.stack, []);
23```
24
25### Custom Delimited Expressions
26
27Find code up to a custom delimiter:
28
29```js
30// EJS-style
31var section = parser.parseUntil('foo.bar("%>").baz%> bing bong', '%>');
32assert(section.start === 0);
33assert(section.end === 17); // exclusive end of string
34assert(section.src = 'foo.bar("%>").baz');
35
36var section = parser.parseUntil('<%foo.bar("%>").baz%> bing bong', '%>', {start: 2});
37assert(section.start === 2);
38assert(section.end === 19); // exclusive end of string
39assert(section.src = 'foo.bar("%>").baz');
40
41// Jade-style
42var section = parser.parseUntil('#[p= [1, 2][i]]', ']', {start: 2})
43assert(section.start === 2);
44assert(section.end === 14); // exclusive end of string
45assert(section.src === 'p= [1, 2][i]')
46
47// Dumb parsing
48// Stop at first delimiter encountered, doesn't matter if it's nested or not
49// This is the character-parser@1 default behavior.
50var section = parser.parseUntil('#[p= [1, 2][i]]', '}', {start: 2, ignoreNesting: true})
51assert(section.start === 2);
52assert(section.end === 10); // exclusive end of string
53assert(section.src === 'p= [1, 2')
54''
55```
56
57Delimiters are ignored if they are inside strings or comments.
58
59## API
60
61All methods may throw an exception in the case of syntax errors. The exception contains an additional `code` property that always starts with `CHARACTER_PARSER:` that is unique for the error.
62
63### parse(str, state = defaultState(), options = {start: 0, end: src.length})
64
65Parse a string starting at the index start, and return the state after parsing that string.
66
67If you want to parse one string in multiple sections you should keep passing the resulting state to the next parse operation.
68
69Returns a `State` object.
70
71### parseUntil(src, delimiter, options = {start: 0, ignoreLineComment: false, ignoreNesting: false})
72
73Parses the source until the first occurence of `delimiter` which is not in a string or a comment.
74
75If `ignoreLineComment` is `true`, it will still count if the delimiter occurs in a line comment.
76
77If `ignoreNesting` is `true`, it will stop at the first bracket, not taking into account if the bracket part of nesting or not. See example above.
78
79It returns an object with the structure:
80
81```js
82{
83  start: 0,//index of first character of string
84  end: 13,//index of first character after the end of string
85  src: 'source string'
86}
87```
88
89### parseChar(character, state = defaultState())
90
91Parses the single character and returns the state.  See `parse` for the structure of the returned state object.  N.B. character must be a single character not a multi character string.
92
93### defaultState()
94
95Get a default starting state.
96
97### isPunctuator(character)
98
99Returns `true` if `character` represents punctuation in JavaScript.
100
101### isKeyword(name)
102
103Returns `true` if `name` is a keyword in JavaScript.
104
105### TOKEN_TYPES & BRACKETS
106
107Objects whose values can be a frame in the `stack` property of a State (documented below).
108
109## State
110
111A state is an object with the following structure
112
113```js
114{
115  stack: [],          // stack of detected brackets; the outermost is [0]
116  regexpStart: false, // true if a slash is just encountered and a REGEXP state has just been added to the stack
117
118  escaped: false,     // true if in a string and the last character was an escape character
119  hasDollar: false,   // true if in a template string and the last character was a dollar sign
120
121  src: '',            // the concatenated source string
122  history: '',        // reversed `src`
123  lastChar: ''        // last parsed character
124}
125```
126
127`stack` property can contain any of the following:
128
129- Any of the property values of `characterParser.TOKEN_TYPES`
130- Any of the property values of `characterParser.BRACKETS` (the end bracket, not the starting bracket)
131
132It also has the following useful methods:
133
134- `.current()` returns the innermost bracket (i.e. the last stack frame).
135- `.isString()` returns `true` if the current location is inside a string.
136- `.isComment()` returns `true` if the current location is inside a comment.
137- `.isNesting([opts])` returns `true` if the current location is not at the top level, i.e. if the stack is not empty. If `opts.ignoreLineComment` is `true`, line comments are not counted as a level, so for `// a` it will still return false.
138
139### Errors
140
141All errors thrown by character-parser has a `code` property attached to it that allows one to identify what sort of error is thrown. For errors thrown from `parse` and `parseUntil`, an additional `index` property is available.
142
143## Transition from v1
144
145In character-parser@2, we have changed the APIs quite a bit. These are some notes that will help you transition to the new version.
146
147### State Object Changes
148
149Instead of keeping depths of different brackets, we are now keeping a stack. We also removed some properties:
150
151```js
152state.lineCommentstate.current() === parser.TOKEN_TYPES.LINE_COMMENT
153state.blockCommentstate.current() === parser.TOKEN_TYPES.BLOCK_COMMENT
154state.singleQuotestate.current() === parser.TOKEN_TYPES.SINGLE_QUOTE
155state.doubleQuotestate.current() === parser.TOKEN_TYPES.DOUBLE_QUOTE
156state.regexpstate.current() === parser.TOKEN_TYPES.REGEXP
157```
158
159### `parseMax`
160
161This function has been removed since the usefulness of this function has been questioned. You should find that `parseUntil` is a better choice for your task.
162
163### `parseUntil`
164
165The default behavior when the delimiter is a bracket has been changed so that nesting is taken into account to determine if the end is reached.
166
167To preserve the original behavior, pass `ignoreNesting: true` as an option.
168
169To see the difference between the new and old behaviors, see the "Usage" section earlier.
170
171### `parseMaxBracket`
172
173This function has been merged into `parseUntil`. You can directly rename the function call without any repercussions.
174
175## License
176
177MIT
178