Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
; EditorConfig file: https://EditorConfig.org
; Install the "EditorConfig" plugin into your editor to use

root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 2
trim_trailing_whitespace = true

[*.md]
indent_size = 4
4 changes: 4 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
dist
node_modules
test/js
docs/index.html
80 changes: 80 additions & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
'use strict';

module.exports = {
extends: [
'ash-nazg/sauron-node-overrides'
],
parser: '@babel/eslint-parser',
parserOptions: {
requireConfigFile: false,
ecmaVersion: 2020
},
env: {
es6: true
},
settings: {
polyfills: [
'Math.trunc',
'Number.parseFloat',
'Symbol.iterator'
]
},
overrides: [{
files: '*.cjs',
extends: ['ash-nazg/sauron-node-script-overrides'],
rules: {
// Internal use
'node/shebang': 'off'
}
}, {
files: 'test/index.js',
parser: '@babel/eslint-parser',
parserOptions: {
requireConfigFile: false,
ecmaVersion: 2020,
sourceType: 'module'
},
rules: {
'no-shadow': ['error', {allow: ['assert']}],
'node/no-unsupported-features/es-syntax': ['error', {
ignores: ['dynamicImport', 'modules']
}],
'no-console': 0
}
}, {
files: '*.html',
env: {
browser: true
},
globals: {
JSONPullParser: true
},
rules: {
'import/unambiguous': 0
}
}, {
files: ['*.md/*.js'],
globals: {
json: true,
require: true,
JSONPullParser: true
},
rules: {
'import/no-commonjs': 0,
'import/unambiguous': 0,
'no-shadow': ['error', {
allow: ['JSONPullParser']
}],
'no-unused-vars': ['error', {
varsIgnorePattern: 'token|JSONPullParser'
}],
'node/no-missing-require': ['error', {
allowModules: ['json-pull-parser']
}]
}
}],
rules: {
'no-bitwise': 0,
'unicorn/consistent-destructuring': 0
}
};
111 changes: 58 additions & 53 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
JSONPullParser
--------------
# JSONPullParser

**Introduction**
## Introduction

`JSONPullParser` is a dropin replacement for `JSON.parse` and also provides a
pull based api.
A dropin replacement for `JSON.parse` and also provides a pull based api.

**Usage**
## Usage

```javascript
let parser = new JSONPullParser(json);
let builder = new JSONPullParser.ObjectBuilder();
```js
const parser = new JSONPullParser(json);
const builder = new JSONPullParser.ObjectBuilder();

for (let token of parser) builder.handle(token);
for (const token of parser) {
builder.handle(token);
}
```

See live [demo](http://www.susi.se/json-pull-parser/demo.html)!
Expand All @@ -26,23 +26,25 @@ If your *JavaScript* engine supports [Symbol.iterator](https://developer.mozilla
then your parser is *iterable*.

```javascript
let parser = new JSONPullParser(json);
const parser = new JSONPullParser(json);

for (let token of parser) {
for (const token of parser) {
// use token
}
```

Otherwise you have to get an *iterator* from `parser.tokens()`
Otherwise you have to get an *iterator* from `parser.tokens()`:

```javascript
var parser = new JSONPullParser(json);
var it = parser.tokens();
const parser = new JSONPullParser(json);
const it = parser.tokens();

while (true) {
var step = it.next();
if (step.done) break;
var token = step.value;
const step = it.next();
if (step.done) {
break;
}
const token = step.value;
// use token
}
```
Expand All @@ -53,20 +55,20 @@ and `EndArray` at the correct depth.

## Installation

**Node (CommonJS)**
### Node (CommonJS)

```sh
$ npm install json-pull-parser
```

```javascript
const JSONPullParser = require('json-pull-parser')
```js
const JSONPullParser = require('json-pull-parser');
```

**Browser**
### Browser

```html
<script src="https://unpkg.com/json-pull-parser/dist/json-pull-parser.js"></script>
<script src="https://unpkg.com/json-pull-parser/dist/json-pull-parser.cjs"></script>
```

## ObjectBuilder
Expand All @@ -77,43 +79,46 @@ const JSONPullParser = require('json-pull-parser')
`JSON.parse` could be implemented by simply feeding all the tokens to
`ObjectBuilder`.

```javascript
JSON.parse = function (source)
{
let parser = new JSONPullParser(source);
let builder = new JSONPullParser.ObjectBuilder();
for (let token of parser) builder.handle(token);
```js
JSON.parse = function (source) {
const parser = new JSONPullParser(source);
const builder = new JSONPullParser.ObjectBuilder();
for (const token of parser) {
builder.handle(token);
}
return builder.value;
}
};
```

## Custom handling of events

```javascript
let parser = new JSONPullParser(json);
```js
const parser = new JSONPullParser(json);

for (let token of parser) {
for (const token of parser) {
switch (token.type) {
case JSONPullParser.StartObject:
break;
case JSONPullParser.EndObject:
break;
case JSONPullParser.StartArray:
break;
case JSONPullParser.EndArray:
break;
case JSONPullParser.String:
break;
case JSONPullParser.Number:
break;
case JSONPullParser.TrueLiteral:
break;
case JSONPullParser.FalseLiteral:
break;
case JSONPullParser.NullLiteral:
break;
case JSONPullParser.Error:
break;
case JSONPullParser.StartObject:
break;
case JSONPullParser.EndObject:
break;
case JSONPullParser.StartArray:
break;
case JSONPullParser.EndArray:
break;
case JSONPullParser.String:
break;
case JSONPullParser.Number:
break;
case JSONPullParser.TrueLiteral:
break;
case JSONPullParser.FalseLiteral:
break;
case JSONPullParser.NullLiteral:
break;
case JSONPullParser.Error:
break;
default:
throw new Error('Should not get here');
}
}

Expand Down
8 changes: 0 additions & 8 deletions bin/verify

This file was deleted.

13 changes: 13 additions & 0 deletions bin/verify.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/usr/bin/env node
'use strict';

const JSONPullParser = require('../');

let content = '';
process.stdin.resume();
process.stdin.on('data', (data) => {
content += data.toString();
});

// eslint-disable-next-line no-console -- CLI
process.stdin.on('end', () => console.log(JSONPullParser.parse(content)));
2 changes: 2 additions & 0 deletions dist/json-pull-parser.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).JSONPullParser=t()}(this,(function(){"use strict";class e{constructor(){this.handler={ref:this,add(e){return this.ref.value=e,e}}}startObject(){this.handler={old:this.handler,key:null,ref:this.handler.add({}),add(e){return null===this.key?this.key=e:(this.ref[this.key]=e,this.key=null),e}}}endObject(){this.handler=this.handler.old}startArray(){this.handler={old:this.handler,ref:this.handler.add([]),add(e){return this.ref.push(e),e}}}add(e){this.handler.add(e)}handle(e){switch(e.type){case"{":this.startObject();break;case"}":this.endObject();break;case"[":this.startArray();break;case"]":this.endArray();break;case"string":case"number":case"true":case"false":case"null":this.add(e.value);break;case"error":throw new SyntaxError(e.value.message)}}}e.prototype.endArray=e.prototype.endObject;const t=16;class r{constructor(e){this.text=e}[Symbol.iterator](){return n(this.text)}tokens(){return n(this.text)}}function*n(e){const t={s:e,d:!1,f:0,l:e.length,e:1,c:0,r:1,x:[]};for(;;){if(t.f===t.l){if(!t.e&&!t.x.length)return;yield a(t.s,t.l,t.l,"Unexpected end of JSON input")}const e=u(t);t.f=e.last,yield e}}function a(e,t,n,a,s=1){let i=t,o=e.charCodeAt(i);for(;10!==o&&i>0;)o=e.charCodeAt(--i);10===o&&++i;const c="undefined:"+s,u=e.slice(i,t+1);let l="";for(let e=i;e<t;++e)l+=" ";l+="^";const d=new SyntaxError(c+"\n"+u+"\n"+l+"\n\n"+a);return{type:r.Error,value:d,first:t,last:n}}function s(e,t,n){return{type:r.StartObject,value:"{",first:t,last:t+1}}function i(e,t,n){return{type:r.EndObject,value:"}",first:t,last:t+1}}function o(e,t,n){return{type:r.StartArray,value:"[",first:t,last:t+1}}function c(e,t,n){return{type:r.EndArray,value:"]",first:t,last:t+1}}function u(e){const{s:n,l:u}=e;let{f:f}=e;for(;f<u;)switch(e.c++,n.charCodeAt(f)){case 10:e.c=0,e.r++;case 9:case 13:case 32:++f;continue;case 123:return 1&e.e?(e.e=18,e.x.push(32),s(0,f)):a(n,f,u,"Unexpected token { in JSON at position "+f,e.r);case 125:return e.e&t&&32===e.x.pop()?(e.e=e.x.length>0?20:0,i(0,f)):a(n,f,u,"Unexpected token } in JSON at position "+f,e.r);case 91:return 1&e.e?(e.e=17,e.x.push(64),o(0,f)):a(n,f,u,"Unexpected token [ in JSON at position "+f,e.r);case 93:return e.e&t&&64===e.x.pop()?(e.e=e.x.length>0?20:0,c(0,f)):a(n,f,u,"Unexpected token ] in JSON at position "+f,e.r);case 58:if(!(8&e.e))return a(n,f,u,"Unexpected token : in JSON at position "+f,e.r);e.e=1,++f;continue;case 44:if(!(4&e.e))return a(n,f,u,"Unexpected token , in JSON at position "+f,e.r);e.x.length>0&&32===e.x[e.x.length-1]?e.e=2:e.e=1,++f;continue;case 45:case 48:case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:return 1&e.e?(e.e=e.x.length>0?20:0,l(n,f,u)):a(n,f,u,"Unexpected number in JSON at position "+f,e.r);case 34:return 2&e.e?(e.e=8,d(n,f,u)):1&e.e?(e.e=e.x.length>0?20:0,d(n,f,u)):a(n,f,u,"Unexpected string in JSON at position "+f,e.r);case 116:return 1&e.e?(e.e=e.x.length>0?20:0,h(n,f,u)):a(n,f,u,"Unexpected token t in JSON at position "+f,e.r);case 102:return 1&e.e?(e.e=e.x.length>0?20:0,p(n,f,u)):a(n,f,u,"Unexpected token f in JSON at position "+f,e.r);case 110:return 1&e.e?(e.e=e.x.length>0?20:0,x(n,f,u)):a(n,f,u,"Unexpected token n in JSON at position "+f,e.r);default:return a(n,f,u,"Unexpected token "+n[f]+" in JSON at position "+f,e.r)}return{type:r.EndDocument,first:u,last:u}}function l(e,t,n){let s=t,i=e.charCodeAt(s++);if(45===i&&(i=e.charCodeAt(s++)),48!==i)for(;i>=48&&i<=57;)i=e.charCodeAt(s++);else i=e.charCodeAt(s++);if(46===i)for(i=e.charCodeAt(s++);i>=48&&i<=57;)i=e.charCodeAt(s++);if(101===i||69===i){if(i=e.charCodeAt(s++),43!==i&&45!==i||(i=e.charCodeAt(s++)),i<48||i>57)return a(e,s-1,n,"Unexpected token "+e[s-1]+" in JSON at position "+(s-1));if(s>=n)return a(e,t,n,"Unexpected end of JSON input");for(;i>=48&&i<=57;)i=e.charCodeAt(s++)}return{type:r.Number,value:Number.parseFloat(e.slice(t,s-1)),first:t,last:s-1}}function d(e,t,n){let s=t+1;for(;s<n;){let t=e.charCodeAt(s++);if(34===t)break;if(92===t&&(t=e.charCodeAt(s++),117===t&&(s+=4,s>n)))return a(e,n,n,"Unexpected end of JSON input")}return{type:r.String,value:JSON.parse(e.slice(t,s)),source:e,first:t,last:s}}function f(e,t,r,n,s){if(t+n.length>r)return a(e,r,r,"Unexpected end of JSON input");for(const s of n){if(e.charCodeAt(t++)!==s)return a(e,t,r,"Unexpected token "+e[t-1]+" in JSON at position "+(t-1))}return s}function h(e,t,n){return f(e,t,n,[116,114,117,101],{type:r.TrueLiteral,value:!0,source:e,first:t,last:t+4})}function p(e,t,n){return f(e,t,n,[102,97,108,115,101],{type:r.FalseLiteral,value:!1,source:e,first:t,last:t+5})}function x(e,t,n){return f(e,t,n,[110,117,108,108],{type:r.NullLiteral,value:null,source:e,first:t,last:t+4})}return r.StartDocument="<",r.EndDocument=">",r.StartObject="{",r.EndObject="}",r.StartArray="[",r.EndArray="]",r.String="string",r.Number="number",r.TrueLiteral="true",r.FalseLiteral="false",r.NullLiteral="null",r.Whitespace="ws",r.Error="error",r.ObjectBuilder=e,r.parse=function(t,r){"string"!=typeof t&&(t=String(t));const a=new e;for(const e of n(t))a.handle(e);if(void 0===a.value)throw new SyntaxError("Unexpected end of JSON input");return a.value},r}));
//# sourceMappingURL=json-pull-parser.cjs.map
1 change: 1 addition & 0 deletions dist/json-pull-parser.cjs.map

Large diffs are not rendered by default.

Loading