├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── dist └── json-knife.bundle.js ├── gulpfile.babel.js ├── license.txt ├── package-lock.json ├── package.json ├── public ├── index.html └── sample.js ├── src ├── controller.js ├── entry.js ├── pattern.js ├── service.js └── util.js ├── test ├── answer.js ├── sample.js └── test.js └── webpack.config.babel.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | target 3 | !/node_modules/ 4 | /node_modules/ 5 | .idea/inspectionProfiles/ 6 | /.idea 7 | /.npmignore 8 | /public/root_domain_process.html 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '10' 4 | script: npm run test -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Andrew-Kang-G 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # json-knife [![Build Status](https://travis-ci.org/Andrew-Kang-G/json-knife.svg?branch=master)](https://travis-ci.org/Andrew-Kang-G/json-knife) [![NPM version](https://img.shields.io/npm/v/json-knife.svg)](https://www.npmjs.com/package/json-knife) [![](https://data.jsdelivr.com/v1/package/gh/Andrew-Kang-G/json-knife/badge)](https://www.jsdelivr.com/package/gh/Andrew-Kang-G/json-knife) 2 | ## Overview 3 | Mass replace specific properties value with a new value recursively in huge, complex and deep JSON string 4 | with a robust regular expression based engine. 5 | 6 | Zero dependency, 7KB 7 | 8 | LIVE DEMO 9 | 10 | 11 | ## Installation 12 | 13 | For ES5 users, 14 | 15 | ``` html 16 | 17 | 18 | 19 | 22 | 23 | 24 | ``` 25 | 26 | For ES6 npm users, run 'npm install --save json-knife' on console. 27 | 28 | ``` html 29 | import Pattern from 'json-knife'; 30 | ``` 31 | 32 | ## Syntax & Usage 33 | Very simple to use. Now we are going to set all 'Mike{[Gentleman]}' to null in the sample JSON string. 34 | 35 | ```javascript 36 | 37 | /** 38 | * @brief 39 | * Mass Update certain key-values recursively in huge, complex JSON string trees 40 | * @author Andrew Kang 41 | * @param original string required (must be JSON string) 42 | * @param key string required 43 | * @param value string or boolean or number or null required 44 | * @return string 45 | */ 46 | 47 | // IMPORTANT : the variable 'original' should be valid JSON. 48 | // You can test your JSON string source like here. 49 | // https://jsonformatter.curiousconcept.com/ 50 | 51 | var result = Pattern.sculptJson(original, 'Mike{[Gentleman]}', null); 52 | 53 | // You can convert the result string to an object type. 54 | var resultObj = JSON.parse(result); 55 | 56 | ``` 57 | **[Original source]** 58 | 59 | var original = 60 | ```json 61 | { 62 | "prob\"lems": [{ 63 | "classes": [{ 64 | "medications": [{ 65 | "medicationsClasses": [{ 66 | "Mike {[Gentleman]}": [{ 67 | "associatedDrug": [{ 68 | "name": "asprin", 69 | "dose": 35.3, 70 | "strength": "500 mg", 71 | "className" : false 72 | }], 73 | "Mike {[Gentleman]}": [{ 74 | "name": "somethingElse", 75 | "dose": "", 76 | "strength": "500 mg", 77 | "friends": { 78 | "self": { 79 | "Mike {[Gentleman]}": "33", 80 | "names": ["aa"] 81 | } 82 | } 83 | }] 84 | }], 85 | "Judy": [{ 86 | "associatedDrug": [{ 87 | "name": "asprin", 88 | "dose": "", 89 | "strength": "500 mg", 90 | "friends": ["Mike {[Gentleman]}"] 91 | }], 92 | "associatedDrug#2": [{ 93 | "name": "somethingElse", 94 | "dose": "", 95 | "strength": "500 mg" 96 | }], 97 | "friends": [{"Mike {[Gentleman]}": null}, {"Mike {[Gentleman]}": [["c[ 3\"5ool", 35], ["ca],[1\"3lm"], 53]}, "Jackson", "Mike {[Gentleman]}"] 98 | }] 99 | }] 100 | }], 101 | "classNameMissed": [{ 102 | "Mike {[Gentleman]}": "missing_value" 103 | }] 104 | }], 105 | "className": [{}] 106 | }] 107 | } 108 | ``` 109 | **[Result]** - string type 110 | 111 | ```json 112 | { 113 | "prob\"lems": [{ 114 | "classes": [{ 115 | "medications": [{ 116 | "medicationsClasses": [{ 117 | "Mike {[Gentleman]}": null, 118 | "Judy": [{ 119 | "associatedDrug": [{ 120 | "name": "asprin", 121 | "dose": "", 122 | "strength": "500 mg", 123 | "friends": ["Mike {[Gentleman]}"] 124 | }], 125 | "associatedDrug#2": [{ 126 | "name": "somethingElse", 127 | "dose": "", 128 | "strength": "500 mg" 129 | }], 130 | "friends": [{"Mike {[Gentleman]}": null}, {"Mike {[Gentleman]}": null}, "Jackson", "Mike {[Gentleman]}"] 131 | }] 132 | }] 133 | }], 134 | "classNameMissed": [{ 135 | "Mike {[Gentleman]}": null 136 | }] 137 | }], 138 | "className": [{}] 139 | }] 140 | } 141 | ``` 142 | 143 | Please inform me of the source related things by leaving issues on Github or emailing me at studypurpose@naver.com. -------------------------------------------------------------------------------- /dist/json-knife.bundle.js: -------------------------------------------------------------------------------- 1 | var Pattern=function(e){function t(r){if(n[r])return n[r].exports;var u=n[r]={exports:{},id:r,loaded:!1};return e[r].call(u.exports,u,u.exports,t),u.loaded=!0,u.exports}var n={};return t.m=e,t.c=n,t.p="../dist/",t(0)}([function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var u=n(1),l=r(u);t.default=l.default,e.exports=t.default},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function u(e,t,n){if(!e||"string"!=typeof e)throw new Error('the variable "original" must be a string type and not be null.');if(!t||"string"!=typeof t)throw new Error('the variable "key" must be a string type and not be null.');if(/"/.test(t))throw new Error('the variable "key" must not contain double quotes, but this can be allowed in the next version.');if(!(n&&("string"==typeof n||"number"==typeof n||"boolean"==typeof n)||"object"==typeof n&&null==n))throw new Error('the variable "value" must be a string or number or boolean or null.');return n&&"string"==typeof n&&(n=n.replace(/([^\u005C])"/g,'$1\\"')),e=e.trim(),a.default.sculpt(e,a.default.getMaterials(e,t,n))}Object.defineProperty(t,"__esModule",{value:!0});var l=n(2),a=r(l);t.default={sculptJson:u},e.exports=t.default},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function u(e){if(Array.isArray(e)){for(var t=0,n=Array(e.length);t0?n[u-1].step:0;if(o[4]){o[5]&&(p+=(o[5].match(new RegExp(y.default.steps.asc,"g"))||[]).length,p-=(o[5].match(new RegExp(y.default.steps.desc,"g"))||[]).length);var c=null;if(o[6]){var i=o[6],f=i.length;c=o.index+f,s>=p&&(s===p?(r.push(c),s=null):(r.push(a(c,i,s-p)),s=null))}n.push({step:p,previousLastIndex:c,key:null,noKey:o[0],debugInfo:o}),u+=1}else{if(o[3]){var d=null;t===n[n.length-1].key&&(d=o.index+o[3].length,r.push(a(d,o[3],n[n.length-1].step)),s=null),null!==s&&(d=o.index+o[3].length,r.push(a(d,o[3],s)),s=null);var h=p-(o[0].match(new RegExp(y.default.steps.desc,"g"))||[]).length;if(n.push({step:h,previousLastIndex:d,key:null,noKey:null}),0!==h)throw new Error("The final step should be 0.");break}var g=o[1].match(new RegExp("^"+y.default.commons.spaceOrEndBracketOrNot,"g"))[0],v=(o[1].match(new RegExp(y.default.steps.desc,"g"))||[]).length,O=(o[1].match(new RegExp(y.default.steps.asc,"g"))||[]).length;p+=O,p-=v;var x=o.index+g.length;s>=p&&(s===p?(r.push(x),s=null):(r.push(a(x,g,s-p+O)),s=null)),t===o[2]&&null==s&&(s=p),n.push({step:p,previousLastIndex:x,key:o[2],noKey:null}),u+=1}}}catch(e){throw console.log("The error has occurred at idx : "+u),console.log(n),console.log(r),e}finally{}return r}function o(e,t,n){"string"==typeof n&&(n='"'+n+'"');for(var r=[],u=new RegExp(y.default.jsonOutput(v.default.Text.escapeRegex(t)),"g"),a={},o=!1,p=[],c=0,i=function(){var u=a[0],i=l(a),f=u.replace(new RegExp(v.default.Text.escapeRegex(a[i])+"$"),n),d=a.index,h=a.index+a[0].length;return r.find(function(e){return e.startIndexd})?"continue":(5!==i&&6!==i||(o||(p=s(e,t),o=!0),h=p[c]),r.push({value:n,matchedKeyValue:u,newMatchedKeyValue:f,startIndex:d,lastIndex:h}),void(c+=1))};null!==(a=u.exec(e));){i()}return r}function p(e,t){return t.reverse().forEach(function(t,n){e=v.default.Text.replaceBetween(e,t.startIndex,t.lastIndex,t.newMatchedKeyValue)}),e}function c(e){var t=[],n=0;try{!function(){var r=new RegExp("(?:"+y.default.jsonOutput2()+")|("+y.default.commons.spaceOrEndBracketOrNot+"$)|(?:"+y.default.steps.withNoKey(!0)+")","g"),l={},a=[],s=null,o=0,p=[],c=null,i=0,f=null;a.push({key:"ORIGIN",step:i});for(var d=function(){var r=o;if(l[5]){var d=null;l[6]&&(r+=(l[6].match(new RegExp(y.default.steps.asc,"g"))||[]).length,r-=(l[6].match(new RegExp(y.default.steps.desc,"g"))||[]).length,/,/.test(l[6])&&(p.push(a[a.length-1].step),d=p.filter(function(e){return e===a[a.length-1].step}).length,0===d&&(d=null)),/\[/.test(l[6])&&(i=r&&(a=a.filter(function(e){return e.step=r&&(a=a.filter(function(e){return e.stept?1:-1}function d(e,t){var n=c(e).map(function(e){return JSON.stringify(e)}).sort(f),r=c(t).map(function(e){return JSON.stringify(e)}).sort(f);return i(n,r)}Object.defineProperty(t,"__esModule",{value:!0});var h=n(3),y=r(h),g=n(4),v=r(g);t.default={getMaterials:o,sculpt:p,deepCompare:d},e.exports=t.default},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function u(e){return o.key(e)+"(?:"+o.valueType.string+"|"+o.valueType.number+"|"+o.valueType.boolean+"|"+o.valueType.object+"|"+o.valueType.array+"|"+o.valueType.empty+")"}function l(){return p.withKey+"("+o.valueType2.string+"|"+o.valueType2.number+"|"+o.valueType2.boolean+"|"+o.valueType2.empty+"|)"}Object.defineProperty(t,"__esModule",{value:!0});var a=n(4),s=(r(a),{spaceOrNot:"[\\n\\r\\t\\s]*",spaceOrNotOrComma:"[,\\n\\r\\t\\s]*",spaceOrBigStartBracketOrNot:"[\\[\\n\\r\\t\\s]*",spaceOrStartBracketOrNot:"[\\[{\\n\\r\\t\\s]*",spaceOrEndBracketOrNot:"[}\\]\\n\\r\\t\\s]*",everything:"(?:.|[\\n\\r\\t\\s])"}),o={key:function(){var e=arguments.length<=0||void 0===arguments[0]?null:arguments[0];return e?"[,{]"+s.spaceOrNot+'"('+e+')"'+s.spaceOrNot+":"+s.spaceOrNot:"[,{]"+s.spaceOrNot+o.keyType+s.spaceOrNot+":"+s.spaceOrNot},keyType:'"((?:[^"]*?[^\\u005C])|(?:(?=[^"]*[\\u005C]").*?[^\\u005C]))"',valueType:{string:'(""|".*?[^\\u005C]")',number:"(-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?)",boolean:"(true|false)",object:"({)",array:"(\\[)",empty:"(null|undefined)",emptyObject:"{"+s.spaceOrNot+"}"},valueType2:{string:'(?:""|".*?[^\\u005C]")',number:"(?:-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?)",boolean:"(?:true|false)",empty:"(?:null|undefined)",emptyObject:"{"+s.spaceOrNot+"}",emptyArray:"\\["+s.spaceOrNot+"\\]"}},p={withKey:"("+s.spaceOrEndBracketOrNot+",(?:[\\[\\n\\r\\t\\s]*{[\\[\\n\\r\\t\\s]*)+|"+s.spaceOrEndBracketOrNot+",|(?:[\\[\\n\\r\\t\\s]*{[\\[\\n\\r\\t\\s]*)+)"+s.spaceOrNot+o.keyType+s.spaceOrNot+":"+s.spaceOrNot,withNoKey:function(){var e=arguments.length<=0||void 0===arguments[0]||arguments[0],t=e?"|":"";return"((((?:"+s.spaceOrNot+"[\\]}]"+s.spaceOrNot+")+"+t+"),"+s.spaceOrStartBracketOrNot+"|(?:"+s.spaceOrNot+"\\["+s.spaceOrNot+")+)("+o.valueType2.string+"|"+o.valueType2.number+"|"+o.valueType2.boolean+"|"+o.valueType2.empty+"|"+o.valueType2.emptyObject+"|"+o.valueType2.emptyArray+")|("+o.valueType2.emptyObject+"|"+o.valueType2.emptyArray+"))"},asc:"[\\[{]",desc:"[\\]}]",toNumberOfGap:function(e){return"(?:"+s.spaceOrNot+"[\\]},]"+s.spaceOrNot+"){"+e+"}$"}};t.default={commons:s,jsonBase:o,jsonOutput:u,jsonOutput2:l,steps:p},e.exports=t.default},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var u=n(3),l=(r(u),{replaceBetween:function(e,t,n,r){return e.substring(0,t)+r+e.substring(n)},escapeRegex:function(e){return e.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}});t.default={Text:l},e.exports=t.default}]); -------------------------------------------------------------------------------- /gulpfile.babel.js: -------------------------------------------------------------------------------- 1 | import gulp from 'gulp'; 2 | import babel from 'gulp-babel'; 3 | import mocha from 'gulp-mocha'; 4 | import gutil from 'gulp-util'; 5 | import webpack from 'webpack'; 6 | import webpackConfig from './webpack.config.babel'; 7 | import WebpackDevServer from 'webpack-dev-server'; 8 | 9 | gulp.task('default', ['webpack']); 10 | 11 | gulp.task('babel', () => { 12 | return gulp.src('src/*.js') 13 | .pipe(babel()) 14 | .pipe(gulp.dest('target')); 15 | }); 16 | 17 | gulp.task('test', ['babel'], () => { 18 | return gulp.src('test/*.js') 19 | .pipe(mocha({reporter: 'list'})) 20 | .on('error', () => { 21 | gulp.emit('end'); 22 | }); 23 | }); 24 | 25 | gulp.task('watch-test', () => { 26 | return gulp.watch(['src/**', 'test/**'], ['test']); 27 | }); 28 | 29 | gulp.task('webpack', ['test'], function(callback) { 30 | var myConfig = Object.create(webpackConfig); 31 | myConfig.plugins = [ 32 | new webpack.optimize.DedupePlugin(), 33 | new webpack.optimize.UglifyJsPlugin() 34 | ]; 35 | 36 | // run webpack 37 | webpack(myConfig, function(err, stats) { 38 | if (err) throw new gutil.PluginError('webpack', err); 39 | gutil.log('[webpack]', stats.toString({ 40 | colors: true, 41 | progress: true 42 | })); 43 | callback(); 44 | }); 45 | }); 46 | 47 | gulp.task('server', ['webpack'], function(callback) { 48 | // modify some webpack config options 49 | var myConfig = Object.create(webpackConfig); 50 | myConfig.devtool = 'eval'; 51 | myConfig.debug = true; 52 | 53 | // Start a webpack-dev-server 54 | new WebpackDevServer(webpack(myConfig), { 55 | publicPath: '/' + myConfig.output.publicPath, 56 | stats: { 57 | colors: true 58 | }, 59 | hot: true 60 | }).listen(8080, 'localhost', function(err) { 61 | if(err) throw new gutil.PluginError('webpack-dev-server', err); 62 | gutil.log('[webpack-dev-server]', 'http://localhost:8080/webpack-dev-server/index.html'); 63 | }); 64 | }); -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | json-knife 2 | https://github.com/Andrew-Kang-G/json-knife 3 | 4 | The MIT License (MIT) 5 | 6 | Copyright (c) 2019 Andrew-Kang-G 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in all 16 | copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "json-knife", 3 | "version": "1.3.1", 4 | "description": "Bulk set properties recursively in huge, complex and deep JSON string with a robust regular expression based engine", 5 | "main": "src/entry.js", 6 | "scripts": { 7 | "build": "gulp", 8 | "test": "gulp test" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/Andrew-Kang-G/json-knife.git" 13 | }, 14 | "keywords": [ 15 | "json", 16 | "parser", 17 | "recursive", 18 | "update", 19 | "remove" 20 | ], 21 | "author": "Andrew Kang", 22 | "license": "MIT", 23 | "bugs": { 24 | "url": "https://github.com/Andrew-Kang-G/json-knife/issues" 25 | }, 26 | "homepage": "https://github.com/Andrew-Kang-G/json-knife#readme", 27 | "devDependencies": { 28 | "chai": "^3.3.0", 29 | "gulp": "^3.9.0", 30 | "gulp-babel": "^5.3.0", 31 | "gulp-mocha": "^2.1.3", 32 | "gulp-util": "^3.0.7", 33 | "mocha": "^2.3.3", 34 | "webpack": "^1.12.2", 35 | "lodash": "^4.17.11", 36 | "growl": "^1.10.0", 37 | "minimatch": "^3.0.2", 38 | "webpack-dev-server": "^3.1.11", 39 | "babel-core": "^5.8.25", 40 | "babel-plugin-syntax-dynamic-import": "^6.18.0", 41 | "babel-loader": "^8.0.4", 42 | "babel-plugin-transform-object-rest-spread": "^6.26.0", 43 | "babel-plugin-transform-runtime": "^6.23.0", 44 | "babel-preset-env": "^1.7.0", 45 | "babel-preset-stage-0": "^6.24.1" 46 | }, 47 | "dependencies": {} 48 | } 49 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 |
11 | 12 |
13 |
Test codes. Check console.
14 |
15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 176 | 177 | -------------------------------------------------------------------------------- /public/sample.js: -------------------------------------------------------------------------------- 1 | var original = '{\n' + 2 | ' "prob\\"lems": [{\n' + 3 | ' "classes": [{\n' + 4 | ' "medications": [{\n' + 5 | ' "medicationsClasses": [{\n' + 6 | ' "Mike {[Gentleman]}": [{\n' + 7 | ' "associatedDrug": [{\n' + 8 | ' "name": "asprin",\n' + 9 | ' "dose": "a",\n' + 10 | ' "strength": "500 mg"\n' + 11 | ' }],\n' + 12 | ' "Mike {[Gentleman]}": [{\n' + 13 | ' "name": "somethingElse",\n' + 14 | ' "dose": "",\n' + 15 | ' "strength": "500 mg",\n' + 16 | ' "friends": {\n' + 17 | ' "self": {\n' + 18 | ' "Mike {[Gentleman]}": "33",\n' + 19 | ' "names": ["aa"]\n' + 20 | ' }\n' + 21 | ' }\n' + 22 | ' }]\n' + 23 | ' }],\n' + 24 | ' "Judy": [{\n' + 25 | ' "associatedDrug": [{\n' + 26 | ' "name": "asprin",\n' + 27 | ' "dose": "",\n' + 28 | ' "strength": "500 mg",\n' + 29 | ' "friends": ["Mike {[Gentleman]}"]\n' + 30 | ' }],\n' + 31 | ' "associatedDrug#2": [{\n' + 32 | ' "name": "somethingElse",\n' + 33 | ' "dose": "",\n' + 34 | ' "strength": "500 mg"\n' + 35 | ' }],\n' + 36 | ' "friends": [{"Mike {[Gentleman]}": null}, {"Mike {[Gentleman]}": [["c[ 3\\"5ool", 35], ["ca],[1\\"3lm"], 53]}, "Jackson", "Mike {[Gentleman]}"]\n' + 37 | ' }]\n' + 38 | ' }]\n' + 39 | ' }],\n' + 40 | ' "classNameMissed": [{\n' + 41 | ' "Mike {[Gentleman]}": "missing_value"\n' + 42 | ' }]\n' + 43 | ' }],\n' + 44 | ' "className": [{}]\n' + 45 | ' }]\n' + 46 | ' }'; 47 | 48 | var original2 ={ 49 | "problems": [ 50 | { 51 | "classes": [ 52 | { 53 | "medications": [ 54 | { 55 | "medicationsClasses": [ 56 | { 57 | "Mike {[Gentleman]}": [ 58 | { 59 | "associatedDrug": [ 60 | { 61 | "name": "asprin", 62 | "dose": {"a":[[],3, [{}]],"B":{},"c":[{}]}, 63 | "strength": "500 mg" 64 | }, 65 | [{ 66 | "name15": "asprin", 67 | "dose15": 5, 68 | "strength15": "500 mg" 69 | },22,[true, false]], 70 | [33,{ 71 | "name16": "asprin", 72 | "dose16": 6, 73 | "strength16": "500 mg" 74 | }], 75 | { 76 | "name2": "asprin", 77 | "dose2": "a", 78 | "strength2": "500 mg" 79 | }, 80 | { 81 | "name3": "asprin", 82 | "dose3": "a", 83 | "strength3": "500 mg" 84 | } 85 | ], 86 | "Mike {[Gentleman]}": [ 87 | { 88 | "name": "somethingElse", 89 | "dose": "", 90 | "strength": "500 mg", 91 | "friends": { 92 | "self": { 93 | "Mike {[Gentleman]}": "33", 94 | "names": [ 95 | "aa", 96 | true, 97 | {"xxx" : ["zd", 5, 3]} 98 | ] 99 | } 100 | } 101 | } 102 | ] 103 | }, 104 | { 105 | "dassociatedDrug": [ 106 | { 107 | "dose": "a", 108 | "name": "asprin", 109 | "strength": "500 mg" 110 | } 111 | ], 112 | "Mike {[Gentleman]}": [ 113 | { 114 | "name": "somethingElse", 115 | "dose": "", 116 | "strength": "500 mg", 117 | "friends": { 118 | "self": { 119 | "Mike {[Gentleman]}": "33", 120 | "names": [ 121 | "aa" 122 | ] 123 | } 124 | } 125 | } 126 | ] 127 | } 128 | ], 129 | "Judy": [ 130 | { 131 | "associatedDrug": [ 132 | { 133 | "name": "asprin", 134 | "dose": "", 135 | "strength": "500 mg", 136 | "friends": [ 137 | "Mike {[Gentleman]}" 138 | ] 139 | } 140 | ], 141 | "associatedDrug#2": [ 142 | { 143 | "name": "somethingElse", 144 | "dose": "", 145 | "strength": "500 mg" 146 | } 147 | ], 148 | "friends": [ 149 | { 150 | "Mike {[Gentleman]}": null 151 | }, 152 | { 153 | "Mike {[Gentleman]}": [ 154 | [ 155 | "c[ 3\"5ool", 156 | [3,5], 157 | 49 158 | ], 159 | [ 160 | "ca],[1\"3lm" 161 | ], 162 | 53 163 | ] 164 | }, 165 | "Jackson", 166 | "Mike {[Gentleman]}", 167 | { 168 | "problems": [ 169 | { 170 | "aclasses": [ 171 | { 172 | "medications": [ 173 | { 174 | "medicationsClasses": [ 175 | { 176 | "Mike {[Gentleman]}": [ 177 | { 178 | "associatedDrug": [ 179 | { 180 | "name": "asprin", 181 | "dose": "a", 182 | "strength": "500 mg" 183 | } 184 | ], 185 | "Mike {[Gentleman]}": [ 186 | { 187 | "name": "somethingElse", 188 | "dose": "", 189 | "strength": "500 mg", 190 | "friends": { 191 | "self": { 192 | "Mike {[Gentleman]}": "33", 193 | "names": [ 194 | "aa" 195 | ] 196 | } 197 | } 198 | }, 199 | { 200 | "problems": [ 201 | { 202 | "xxclasses": [ 203 | { 204 | "yyclassNameMissed": [ 205 | { 206 | "medicationsClasses": [ 207 | { 208 | "Mike {[Gentleman]}": [ 209 | { 210 | "associatedDrug": [ 211 | { 212 | "name": "asprin", 213 | "dose": "a", 214 | "strength": "500 mg" 215 | } 216 | ], 217 | "Mike {[Gentleman]}": [ 218 | { 219 | "name": "somethingElse", 220 | "dose": "", 221 | "strength": "500 mg", 222 | "friends": { 223 | "self": { 224 | "Mike {[Gentleman]}": "33", 225 | "names": [ 226 | "aa" 227 | ] 228 | } 229 | } 230 | } 231 | ] 232 | } 233 | ], 234 | "Judy": [ 235 | { 236 | "associatedDrug": [ 237 | { 238 | "name": "asprin", 239 | "dose": "", 240 | "strength": "500 mg", 241 | "friends": [ 242 | "Mike {[Gentleman]}" 243 | ] 244 | } 245 | ], 246 | "associatedDrug#2": [ 247 | { 248 | "name": "somethingElse", 249 | "dose": "", 250 | "strength": "500 mg" 251 | } 252 | ], 253 | "friends": [ 254 | { 255 | "Mike {[Gentleman]}": null 256 | }, 257 | { 258 | "Mike {[Gentleman]}": [ 259 | [ 260 | "c[ 3\"5ool", 261 | 35 262 | ], 263 | [ 264 | "ca],[1\"3lm" 265 | ], 266 | 53 267 | ] 268 | }, 269 | "Jackson", 270 | "Mike {[Gentleman]}", 271 | { 272 | "problems": [ 273 | { 274 | "classes": [ 275 | { 276 | "medications": [ 277 | { 278 | "medicationsClasses": [ 279 | { 280 | "Mike {[Gentleman]}": [ 281 | { 282 | "associatedDrug": [ 283 | { 284 | "name": "asprin", 285 | "dose": "a", 286 | "strength": "500 mg" 287 | } 288 | ], 289 | "Mike {[Gentleman]}": [ 290 | { 291 | "name": "somethingElse", 292 | "dose": "", 293 | "strength": "500 mg", 294 | "friends": { 295 | "self": { 296 | "Mike {[Gentleman]}": "33", 297 | "names": [ 298 | "aa" 299 | ] 300 | } 301 | } 302 | } 303 | ] 304 | } 305 | ], 306 | "Judy": [ 307 | { 308 | "associatedDrug": [ 309 | { 310 | "name": "asprin", 311 | "dose": "", 312 | "strength": "500 mg", 313 | "friends": [ 314 | "Mike {[Gentleman]}" 315 | ] 316 | } 317 | ], 318 | "associatedDrug#2": [ 319 | { 320 | "name": "somethingElse", 321 | "dose": "", 322 | "strength": "500 mg" 323 | } 324 | ], 325 | "friends": [ 326 | { 327 | "Mike {[Gentleman]}": null 328 | }, 329 | { 330 | "Mike {[Gentleman]}": [ 331 | [ 332 | "c[ 3\"5ool", 333 | 35 334 | ], 335 | [ 336 | "ca],[1\"3lm" 337 | ], 338 | 53 339 | ] 340 | }, 341 | "Jackson", 342 | "Mike {[Gentleman]}" 343 | ] 344 | } 345 | ] 346 | } 347 | ] 348 | } 349 | ], 350 | "classNameMissed": [ 351 | { 352 | "Mike {[Gentleman]}": "missing_value" 353 | } 354 | ] 355 | } 356 | ], 357 | "className": [ 358 | {} 359 | ] 360 | } 361 | ] 362 | } 363 | ] 364 | } 365 | ] 366 | } 367 | ] 368 | } 369 | ], 370 | "yyclassNameMissed2": [ 371 | { 372 | "Mike {[Gentleman]}": "missing_value" 373 | } 374 | ] 375 | } 376 | ], 377 | "xxclasses2": [ 378 | {} 379 | ] 380 | } 381 | ] 382 | } 383 | ] 384 | } 385 | ], 386 | "Judy": [ 387 | { 388 | "associatedDrug": [ 389 | { 390 | "name": "asprin", 391 | "dose": "", 392 | "strength": "500 mg", 393 | "friends": [ 394 | "Mike {[Gentleman]}" 395 | ] 396 | } 397 | ], 398 | "associatedDrug#2": [ 399 | { 400 | "name": "somethingElse", 401 | "dose": "", 402 | "strength": "500 mg" 403 | } 404 | ], 405 | "friends": [ 406 | { 407 | "Mike {[Gentleman]}": null 408 | }, 409 | { 410 | "Mike {[Gentleman]}": [ 411 | [ 412 | "c[ 3\"5ool", 413 | 35 414 | ], 415 | [ 416 | "ca],[1\"3lm" 417 | ], 418 | 53 419 | ] 420 | }, 421 | "Jackson", 422 | "Mike {[Gentleman]}" 423 | ] 424 | } 425 | ] 426 | } 427 | ] 428 | } 429 | ], 430 | "classNameMissed": [ 431 | { 432 | "Mike {[Gentleman]}": "missing_value" 433 | } 434 | ] 435 | } 436 | ], 437 | "className": [ 438 | {} 439 | ] 440 | } 441 | ] 442 | } 443 | ] 444 | } 445 | ] 446 | } 447 | ] 448 | } 449 | ], 450 | "classNameMissed": [ 451 | { 452 | "Mike {[Gentleman]}": "missing_value" 453 | } 454 | ] 455 | } 456 | ], 457 | "className": [ 458 | {} 459 | ] 460 | } 461 | ] 462 | }; 463 | 464 | var original3 ={ 465 | "problems": [ 466 | { 467 | "classes": [ 468 | { 469 | "medications": [ 470 | { 471 | "medicationsClasses": [ 472 | { 473 | "Mike {[Gentleman]}": [ 474 | { 475 | "associatedDrug": [ 476 | { 477 | "name": "asprin", 478 | "dose": {"a":[[],3, [{}]],"B":{},"c":[{}]}, 479 | "strength": "500 mg" 480 | }, 481 | [{ 482 | "name15": "asprin", 483 | "dose15": 5, 484 | "strength15": "500 mg" 485 | },22,[true, false]], 486 | [33,{ 487 | "name16": "asprin", 488 | "dose16": 6, 489 | "strength16": "500 mg" 490 | }], 491 | { 492 | "name2": "asprin", 493 | "dose2": "a", 494 | "strength2": "500 mg" 495 | }, 496 | { 497 | "name3": "asprin", 498 | "dose3": "a", 499 | "strength3": "500 mg" 500 | } 501 | ], 502 | "Mike {[Gentleman]}": [ 503 | { 504 | "name": "somethingElse", 505 | "dose": "", 506 | "strength": "500 mg", 507 | "friends": { 508 | "self": { 509 | "Mike {[Gentleman]}": "33", 510 | "names": [ 511 | "aa", 512 | true, 513 | {"xxx" : ["zd", 3, 5]} 514 | ] 515 | } 516 | } 517 | } 518 | ] 519 | }, 520 | { 521 | "dassociatedDrug": [ 522 | { 523 | "name": "asprin", 524 | "dose": "a", 525 | "strength": "500 mg" 526 | } 527 | ], 528 | "Mike {[Gentleman]}": [ 529 | { 530 | "name": "somethingElse", 531 | "dose": "", 532 | "strength": "500 mg", 533 | "friends": { 534 | "self": { 535 | "Mike {[Gentleman]}": "33", 536 | "names": [ 537 | "aa" 538 | ] 539 | } 540 | } 541 | } 542 | ] 543 | } 544 | ], 545 | "Judy": [ 546 | { 547 | "associatedDrug": [ 548 | { 549 | "name": "asprin", 550 | "dose": "", 551 | "strength": "500 mg", 552 | "friends": [ 553 | "Mike {[Gentleman]}" 554 | ] 555 | } 556 | ], 557 | "associatedDrug#2": [ 558 | { 559 | "name": "somethingElse", 560 | "dose": "", 561 | "strength": "500 mg" 562 | } 563 | ], 564 | "friends": [ 565 | { 566 | "Mike {[Gentleman]}": null 567 | }, 568 | { 569 | "Mike {[Gentleman]}": [ 570 | [ 571 | "c[ 3\"5ool", 572 | [3,5], 573 | 49 574 | ], 575 | [ 576 | "ca],[1\"3lm" 577 | ], 578 | 53 579 | ] 580 | }, 581 | "Jackson", 582 | "Mike {[Gentleman]}", 583 | { 584 | "problems": [ 585 | { 586 | "aclasses": [ 587 | { 588 | "medications": [ 589 | { 590 | "medicationsClasses": [ 591 | { 592 | "Mike {[Gentleman]}": [ 593 | { 594 | "associatedDrug": [ 595 | { 596 | "name": "asprin", 597 | "dose": "a", 598 | "strength": "500 mg" 599 | } 600 | ], 601 | "Mike {[Gentleman]}": [ 602 | { 603 | "name": "somethingElse", 604 | "dose": "", 605 | "strength": "500 mg", 606 | "friends": { 607 | "self": { 608 | "Mike {[Gentleman]}": "33", 609 | "names": [ 610 | "aa" 611 | ] 612 | } 613 | } 614 | }, 615 | { 616 | "problems": [ 617 | { 618 | "xxclasses": [ 619 | { 620 | "yyclassNameMissed": [ 621 | { 622 | "medicationsClasses": [ 623 | { 624 | "Mike {[Gentleman]}": [ 625 | { 626 | "associatedDrug": [ 627 | { 628 | "name": "asprin", 629 | "dose": "a", 630 | "strength": "500 mg" 631 | } 632 | ], 633 | "Mike {[Gentleman]}": [ 634 | { 635 | "name": "somethingElse", 636 | "dose": "", 637 | "strength": "500 mg", 638 | "friends": { 639 | "self": { 640 | "Mike {[Gentleman]}": "33", 641 | "names": [ 642 | "aa" 643 | ] 644 | } 645 | } 646 | } 647 | ] 648 | } 649 | ], 650 | "Judy": [ 651 | { 652 | "associatedDrug": [ 653 | { 654 | "name": "asprin", 655 | "dose": "", 656 | "strength": "500 mg", 657 | "friends": [ 658 | "Mike {[Gentleman]}" 659 | ] 660 | } 661 | ], 662 | "associatedDrug#2": [ 663 | { 664 | "name": "somethingElse", 665 | "dose": "", 666 | "strength": "500 mg" 667 | } 668 | ], 669 | "friends": [ 670 | { 671 | "Mike {[Gentleman]}": null 672 | }, 673 | { 674 | "Mike {[Gentleman]}": [ 675 | [ 676 | "c[ 3\"5ool", 677 | 35 678 | ], 679 | [ 680 | "ca],[1\"3lm" 681 | ], 682 | 53 683 | ] 684 | }, 685 | "Jackson", 686 | "Mike {[Gentleman]}", 687 | { 688 | "problems": [ 689 | { 690 | "classes": [ 691 | { 692 | "medications": [ 693 | { 694 | "medicationsClasses": [ 695 | { 696 | "Mike {[Gentleman]}": [ 697 | { 698 | "associatedDrug": [ 699 | { 700 | "name": "asprin", 701 | "dose": "a", 702 | "strength": "500 mg" 703 | } 704 | ], 705 | "Mike {[Gentleman]}": [ 706 | { 707 | "name": "somethingElse", 708 | "dose": "", 709 | "strength": "500 mg", 710 | "friends": { 711 | "self": { 712 | "Mike {[Gentleman]}": "33", 713 | "names": [ 714 | "aa" 715 | ] 716 | } 717 | } 718 | } 719 | ] 720 | } 721 | ], 722 | "Judy": [ 723 | { 724 | "associatedDrug": [ 725 | { 726 | "name": "asprin", 727 | "dose": "", 728 | "strength": "500 mg", 729 | "friends": [ 730 | "Mike {[Gentleman]}" 731 | ] 732 | } 733 | ], 734 | "associatedDrug#2": [ 735 | { 736 | "name": "somethingElse", 737 | "dose": "", 738 | "strength": "500 mg" 739 | } 740 | ], 741 | "friends": [ 742 | { 743 | "Mike {[Gentleman]}": null 744 | }, 745 | { 746 | "Mike {[Gentleman]}": [ 747 | [ 748 | "c[ 3\"5ool", 749 | 35 750 | ], 751 | [ 752 | "ca],[1\"3lm" 753 | ], 754 | 53 755 | ] 756 | }, 757 | "Jackson", 758 | "Mike {[Gentleman]}" 759 | ] 760 | } 761 | ] 762 | } 763 | ] 764 | } 765 | ], 766 | "classNameMissed": [ 767 | { 768 | "Mike {[Gentleman]}": "missing_value" 769 | } 770 | ] 771 | } 772 | ], 773 | "className": [ 774 | {} 775 | ] 776 | } 777 | ] 778 | } 779 | ] 780 | } 781 | ] 782 | } 783 | ] 784 | } 785 | ], 786 | "yyclassNameMissed2": [ 787 | { 788 | "Mike {[Gentleman]}": "missing_value" 789 | } 790 | ] 791 | } 792 | ], 793 | "xxclasses2": [ 794 | {} 795 | ] 796 | } 797 | ] 798 | } 799 | ] 800 | } 801 | ], 802 | "Judy": [ 803 | { 804 | "associatedDrug": [ 805 | { 806 | "name": "asprin", 807 | "dose": "", 808 | "strength": "500 mg", 809 | "friends": [ 810 | "Mike {[Gentleman]}" 811 | ] 812 | } 813 | ], 814 | "associatedDrug#2": [ 815 | { 816 | "name": "somethingElse", 817 | "dose": "", 818 | "strength": "500 mg" 819 | } 820 | ], 821 | "friends": [ 822 | { 823 | "Mike {[Gentleman]}": null 824 | }, 825 | { 826 | "Mike {[Gentleman]}": [ 827 | [ 828 | "c[ 3\"5ool", 829 | 35 830 | ], 831 | [ 832 | "ca],[1\"3lm" 833 | ], 834 | 53 835 | ] 836 | }, 837 | "Jackson", 838 | "Mike {[Gentleman]}" 839 | ] 840 | } 841 | ] 842 | } 843 | ] 844 | } 845 | ], 846 | "classNameMissed": [ 847 | { 848 | "Mike {[Gentleman]}": "missing_value" 849 | } 850 | ] 851 | } 852 | ], 853 | "className": [ 854 | {} 855 | ] 856 | } 857 | ] 858 | } 859 | ] 860 | } 861 | ] 862 | } 863 | ] 864 | } 865 | ], 866 | "classNameMissed": [ 867 | { 868 | "Mike {[Gentleman]}": "missing_value" 869 | } 870 | ] 871 | } 872 | ], 873 | "className": [ 874 | {} 875 | ] 876 | } 877 | ] 878 | }; 879 | -------------------------------------------------------------------------------- /src/controller.js: -------------------------------------------------------------------------------- 1 | import Service from './service'; 2 | 3 | /** 4 | * @brief 5 | * Mass Update certain key-values recursively in huge, complex JSON string trees 6 | * @author Andrew Kang 7 | * @param original string required (must be JSON string) 8 | * @param key string required 9 | * @param value string or boolean or number required 10 | * @return string 11 | */ 12 | function sculptJson(original, key, value){ 13 | 14 | if (!(original && typeof original === 'string')) { 15 | throw new Error('the variable "original" must be a string type and not be null.'); 16 | }else if (!(key && typeof key === 'string')) { 17 | throw new Error('the variable "key" must be a string type and not be null.'); 18 | }else if (/"/.test(key)) { 19 | throw new Error('the variable "key" must not contain double quotes, but this can be allowed in the next version.'); 20 | }else if (! ((value && (typeof value === 'string' || typeof value === 'number'|| typeof value === 'boolean')) || (typeof value == 'object' && value == null))) { 21 | throw new Error('the variable "value" must be a string or number or boolean or null.'); 22 | } 23 | 24 | if(value && typeof value === 'string') { 25 | value = value.replace(/([^\u005C])"/g, '$1\\"'); 26 | } 27 | original = original.trim(); 28 | 29 | return Service.sculpt(original, Service.getMaterials(original, key, value)); 30 | } 31 | 32 | /** 33 | * @brief 34 | * [Research] Deep-compare two JSONs regardless of positions of every 'key' in objects but considering positions of elements in arrays. 35 | * @author Andrew Kang 36 | * @param original string required (must be JSON string) 37 | * @param original2 string required (must be JSON string) 38 | * @return string 39 | */ 40 | function deepCompare(original, original2){ 41 | 42 | if (!(original && typeof original === 'string')) { 43 | throw new Error('the variable "original" must be a string type and not be null.'); 44 | }else if (!(original2 && typeof original2 === 'string')) { 45 | throw new Error('the variable "original2" must be a string type and not be null.'); 46 | } 47 | 48 | original = original.trim(); 49 | original2 = original2.trim(); 50 | 51 | return Service.deepCompare(original, original2); 52 | } 53 | 54 | 55 | export default { 56 | 57 | sculptJson 58 | 59 | }; -------------------------------------------------------------------------------- /src/entry.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 4 | * -- Url-knife -- 5 | * 6 | * Copyright (c) 2019 Andrew Kang 7 | * 8 | * The MIT License (MIT) 9 | 10 | Copyright (c) 2011-2018 Twitter, Inc. 11 | Copyright (c) 2011-2018 The Bootstrap Authors 12 | 13 | Permission is hereby granted, free of charge, to any person obtaining a copy 14 | of this software and associated documentation files (the "Software"), to deal 15 | in the Software without restriction, including without limitation the rights 16 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | copies of the Software, and to permit persons to whom the Software is 18 | furnished to do so, subject to the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be included in 21 | all copies or substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | THE SOFTWARE. 30 | 31 | 32 | * */ 33 | 34 | import Pattern from './controller'; 35 | 36 | export default Pattern; 37 | -------------------------------------------------------------------------------- /src/pattern.js: -------------------------------------------------------------------------------- 1 | import Util from './util'; 2 | 3 | const commons = { 4 | 5 | spaceOrNot: '[\\n\\r\\t\\s]*', 6 | spaceOrNotOrComma: '[,\\n\\r\\t\\s]*', 7 | spaceOrBigStartBracketOrNot: '[\\[\\n\\r\\t\\s]*', 8 | spaceOrStartBracketOrNot: '[\\[{\\n\\r\\t\\s]*', 9 | spaceOrEndBracketOrNot: '[}\\]\\n\\r\\t\\s]*', 10 | everything: '(?:.|[\\n\\r\\t\\s])' 11 | 12 | } 13 | 14 | const jsonBase = { 15 | 16 | // key starts with two patterns (1) {"key": (2) ,"key" : 17 | key(k = null) { 18 | if (k) { 19 | return '[,{]' + 20 | commons.spaceOrNot + 21 | '"(' + k + ')"' + 22 | commons.spaceOrNot + 23 | ':' + 24 | commons.spaceOrNot; 25 | } else { 26 | return '[,{]' + 27 | commons.spaceOrNot + 28 | jsonBase.keyType + 29 | commons.spaceOrNot + 30 | ':' + 31 | commons.spaceOrNot; 32 | } 33 | }, 34 | 35 | 36 | //keyType : '"((?:[^"\\\\]|\\\\"|\\\\[^"])*)"', 37 | keyType: '"((?:[^"]*?[^\\u005C])|(?:(?=[^"]*[\\u005C]").*?[^\\u005C]))"', 38 | 39 | valueType: { 40 | // 2 41 | string: '(""|".*?[^\\u005C]")', 42 | // 3 43 | //number: '([-+]?(?:\\d+\\.?\\d*|\\d*\.?\\d+)(?:[Ee][-+]?[0-2]?\\d{1,2})?)', 44 | number : '(-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?)', 45 | // 4 46 | boolean: '(true|false)', 47 | // 5 48 | object: '({)', 49 | // 6 50 | array: '(\\[)', 51 | // 7 52 | empty: '(null|undefined)', 53 | // 7 54 | emptyObject: '{' + commons.spaceOrNot + '}', 55 | 56 | /* // 2 57 | 58 | astring: '(?:".*?[^\\u005C\\u0022]"|"")', 59 | // 3 60 | anumber: '(?:[-+]?(?:\\d+\\.?\\d*|\\d*\.?\\d+)(?:[Ee][-+]?[0-2]?\\d{1,2})?)', 61 | // 4 62 | aboolean: '(?:true|false)', 63 | // 5 64 | aobject: '(?:{)', 65 | // 6 66 | aarray: '(?:\\[)', 67 | // 7 68 | aempty: '(?:null)',*/ 69 | }, 70 | 71 | valueType2: { 72 | 73 | string: '(?:""|".*?[^\\u005C]")', 74 | 75 | number : '(?:-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?)', 76 | 77 | boolean: '(?:true|false)', 78 | 79 | empty: '(?:null|undefined)', 80 | 81 | emptyObject: '{' + commons.spaceOrNot + '}', 82 | 83 | // 7 84 | emptyArray: '\\[' + commons.spaceOrNot + '\\]', 85 | } 86 | 87 | } 88 | 89 | // This is for service.js -> calculateSteps 90 | const steps = { 91 | 92 | // withKey is areas where JSON sets up hierarchies(steps). 93 | withKey: '(' + 94 | // }],[[{ 95 | commons.spaceOrEndBracketOrNot + 96 | ',' + 97 | '(?:' + 98 | '[\\[\\n\\r\\t\\s]*{[\\[\\n\\r\\t\\s]*)+' + 99 | '|' + 100 | // }], 101 | commons.spaceOrEndBracketOrNot + 102 | ',' + 103 | '|' + 104 | // [[{ 105 | '(?:[\\[\\n\\r\\t\\s]*{[\\[\\n\\r\\t\\s]*)+' + 106 | ')' + 107 | 108 | commons.spaceOrNot + 109 | jsonBase.keyType + 110 | commons.spaceOrNot + 111 | ':' + 112 | commons.spaceOrNot, 113 | 114 | 115 | // withNoKey is areas where JSON sets up hierarchies(steps). 116 | withNoKey(includeNoStepAreas = true) { 117 | 118 | const token = includeNoStepAreas ? '|' : ''; 119 | 120 | return '(' + 121 | 122 | '(' + 123 | 124 | /* 1. -> }]},{, }]},[ */ 125 | 126 | // catch desc symbols 127 | '(' + 128 | '(?:' + commons.spaceOrNot + '[\\]}]' + commons.spaceOrNot + ')+' + 129 | token + ')' + 130 | 131 | ',' + 132 | 133 | commons.spaceOrStartBracketOrNot + 134 | 135 | '|' + 136 | 137 | /* 2. -> [ */ 138 | // don't need to catch asc symbols 139 | '(?:' + commons.spaceOrNot + '\\[' + commons.spaceOrNot + ')+' + 140 | 141 | ')' + 142 | 143 | '(' + 144 | jsonBase.valueType2.string + '|' 145 | + jsonBase.valueType2.number + '|' 146 | + jsonBase.valueType2.boolean + '|' 147 | + jsonBase.valueType2.empty + '|' 148 | + jsonBase.valueType2.emptyObject + '|' 149 | + jsonBase.valueType2.emptyArray + 150 | ')' + 151 | 152 | '|(' + jsonBase.valueType2.emptyObject + '|' + jsonBase.valueType2.emptyArray +'))' 153 | 154 | }, 155 | 156 | 157 | asc: '[\\[{]', 158 | desc: '[\\]}]', 159 | toNumberOfGap(number) { 160 | return '(?:' + commons.spaceOrNot + '[\\]},]' + commons.spaceOrNot + ')' + '{' + number + '}$'; 161 | } 162 | 163 | } 164 | 165 | // This is for service.js -> getMaterials 166 | function jsonOutput(k) { 167 | 168 | return jsonBase.key(k) + '(?:' + jsonBase.valueType.string + '|' 169 | + jsonBase.valueType.number + '|' 170 | + jsonBase.valueType.boolean + '|' 171 | + jsonBase.valueType.object + '|' 172 | + jsonBase.valueType.array + '|' 173 | + jsonBase.valueType.empty + ')' 174 | 175 | } 176 | 177 | 178 | function jsonOutput2() { 179 | 180 | return steps.withKey + '(' + jsonBase.valueType2.string + '|' 181 | + jsonBase.valueType2.number + '|' 182 | + jsonBase.valueType2.boolean + '|' 183 | + jsonBase.valueType2.empty + '|' 184 | + ')' 185 | 186 | } 187 | 188 | export default { 189 | commons, jsonBase, jsonOutput, jsonOutput2, steps 190 | } -------------------------------------------------------------------------------- /src/service.js: -------------------------------------------------------------------------------- 1 | import Pattern from './pattern'; 2 | import Util from './util'; 3 | 4 | 5 | function getMatchedGroupNumber(match) { 6 | for (let a = 2; a < 8; a++) { 7 | if (match[a] !== undefined) { 8 | return a; 9 | } 10 | } 11 | } 12 | 13 | function adjustPreviousLastIndex(previousLastIndex, downArea, stepGapCnt) { 14 | 15 | let stepGapLength = 0; 16 | 17 | let rx = new RegExp(Pattern.steps.toNumberOfGap(stepGapCnt), ''); 18 | let match = {}; 19 | if ((match = rx.exec(downArea)) !== null) { 20 | stepGapLength = match[0].length; 21 | /* console.log('previousLastIndex : ' + previousLastIndex); 22 | console.log('downArea : ' + downArea); 23 | console.log('stepGapCnt : ' + stepGapCnt); 24 | console.log('stepgapLEN : ' + stepGapLength);*/ 25 | } 26 | 27 | 28 | return previousLastIndex - stepGapLength; 29 | } 30 | 31 | 32 | 33 | 34 | 35 | /* 36 | * match information 37 | * 38 | * 0 : as you are aware, match[0] is just the whole match 39 | * 40 | * 1~2 : withKey 41 | * 1 : front of key 42 | * 2 : only key 43 | * 44 | * 3 : final area (the very end of json, the final of the loop below, whole match) 45 | * 46 | * 4~7 : withNoKey 47 | * 4 : whole match 48 | * 5 : front of 'one value of array' - [[ 49 | * 6 : only down front of 'one value of array' - }] 50 | * 7 : one value - "aaa", 5, true... 51 | * 8 : {}, [] (empty object or array) 52 | 53 | * */ 54 | 55 | 56 | function calculateSteps(original, key) { 57 | 58 | let stepAreas = []; 59 | let keySteps = []; 60 | 61 | let idx = 0; 62 | 63 | try { 64 | 65 | let rx = new RegExp('(?:' + Pattern.steps.withKey + ')|' + 66 | '(' + Pattern.commons.spaceOrEndBracketOrNot + '$)|' + 67 | '(?:' + Pattern.steps.withNoKey(true) + ')', 'g'); 68 | 69 | let stepMilestone = null; 70 | let match = {}; 71 | 72 | while ((match = rx.exec(original)) !== null) { 73 | 74 | let step = idx > 0 ? stepAreas[idx - 1]['step'] : 0; 75 | 76 | /* one value of array */ 77 | if (match[4]) { 78 | 79 | //console.log('4 : '); 80 | //console.log(match); 81 | if (match[5]) { 82 | step += (match[5].match(new RegExp(Pattern.steps.asc, "g")) || []).length; 83 | step -= (match[5].match(new RegExp(Pattern.steps.desc, "g")) || []).length; 84 | } 85 | 86 | let previousLastIndex = null; 87 | 88 | if (match[6]) { 89 | const downArea = match[6]; 90 | const downAreaLength = downArea.length; 91 | 92 | previousLastIndex = match.index + downAreaLength; 93 | 94 | if (stepMilestone >= step) { 95 | 96 | if (stepMilestone === step) { 97 | 98 | keySteps.push(previousLastIndex); 99 | stepMilestone = null; 100 | 101 | } else { 102 | 103 | keySteps.push(adjustPreviousLastIndex(previousLastIndex, downArea, stepMilestone - step)); 104 | stepMilestone = null; 105 | } 106 | } 107 | } 108 | 109 | stepAreas.push({ 110 | step: step, 111 | previousLastIndex: previousLastIndex, 112 | key: null, 113 | noKey: match[0], 114 | debugInfo: match 115 | }); 116 | 117 | idx += 1; 118 | 119 | continue; 120 | } 121 | 122 | /* final area : all JSONs end at this point with the command 'break' */ 123 | if (match[3]) { 124 | 125 | //console.log('3 : '); 126 | //console.log(match); 127 | let previousLastIndex = null; 128 | 129 | if (key === stepAreas[stepAreas.length - 1].key) { 130 | 131 | previousLastIndex = match.index + match[3].length; 132 | 133 | keySteps.push(adjustPreviousLastIndex(previousLastIndex, match[3], stepAreas[stepAreas.length - 1].step)); 134 | stepMilestone = null; 135 | } 136 | 137 | if (stepMilestone !== null) { 138 | 139 | previousLastIndex = match.index + match[3].length; 140 | 141 | keySteps.push(adjustPreviousLastIndex(previousLastIndex, match[3], stepMilestone)); 142 | stepMilestone = null; 143 | } 144 | 145 | const finalStep = step - (match[0].match(new RegExp(Pattern.steps.desc, "g")) || []).length; 146 | 147 | stepAreas.push({ 148 | step: finalStep, 149 | previousLastIndex: previousLastIndex, 150 | key: null, 151 | noKey: null, 152 | //debugInfo: match, 153 | }); 154 | 155 | // Fail to calculate steps 156 | if (finalStep !== 0) { 157 | throw new Error('The final step should be 0.') 158 | } 159 | 160 | break; 161 | 162 | } 163 | 164 | /* Key area */ 165 | 166 | //console.log('normal : '); 167 | //console.log(match); 168 | 169 | let downArea = match[1].match(new RegExp('^' + Pattern.commons.spaceOrEndBracketOrNot, "g"))[0]; 170 | let descCnt = (match[1].match(new RegExp(Pattern.steps.desc, "g")) || []).length; 171 | let ascCnt = (match[1].match(new RegExp(Pattern.steps.asc, "g")) || []).length; 172 | 173 | 174 | step += ascCnt; 175 | step -= descCnt; 176 | 177 | 178 | let previousLastIndex = match.index + downArea.length; 179 | let stepGapLength = 0; 180 | 181 | if (stepMilestone >= step) { 182 | 183 | if (stepMilestone === step) { 184 | 185 | keySteps.push(previousLastIndex); 186 | stepMilestone = null; 187 | 188 | } else { 189 | 190 | keySteps.push(adjustPreviousLastIndex(previousLastIndex, downArea, stepMilestone - step + ascCnt)); 191 | stepMilestone = null; 192 | } 193 | } 194 | 195 | if (key === match[2] && stepMilestone == null) { 196 | stepMilestone = step; 197 | } 198 | 199 | stepAreas.push({ 200 | step: step, 201 | previousLastIndex: previousLastIndex, 202 | key: match[2], 203 | noKey: null, 204 | //debugInfo: match 205 | }); 206 | 207 | idx += 1; 208 | } 209 | 210 | }catch (e) { 211 | console.log('The error has occurred at idx : ' + idx) 212 | console.log(stepAreas) 213 | console.log(keySteps) 214 | throw e; 215 | }finally { 216 | /* console.log(stepAreas) 217 | console.log(keySteps)*/ 218 | } 219 | 220 | 221 | return keySteps; 222 | } 223 | 224 | 225 | function getMaterials(original, key, value) { 226 | 227 | if (typeof value == "string") { 228 | value = '"' + value + '"'; 229 | } 230 | 231 | let extractedAreas = []; 232 | 233 | let rx = new RegExp(Pattern.jsonOutput(Util.Text.escapeRegex(key)), 'g'); 234 | 235 | let matches = []; 236 | let match = {}; 237 | 238 | let calculateStepsDone = false; 239 | let keySteps = []; 240 | 241 | let idx = 0; 242 | while ((match = rx.exec(original)) !== null) { 243 | 244 | //console.log(match) 245 | 246 | const matchedKeyValue = match[0]; 247 | 248 | const matchedGroupNumber = getMatchedGroupNumber(match); 249 | 250 | const newMatchedKeyValue = matchedKeyValue.replace(new RegExp(Util.Text.escapeRegex(match[matchedGroupNumber]) + '$'), value); 251 | 252 | const startIndex = match.index; 253 | let lastIndex = match.index + match[0].length; 254 | 255 | 256 | if (extractedAreas.find(x => x.startIndex < startIndex && x.lastIndex > startIndex)) { 257 | continue; 258 | } 259 | 260 | if (matchedGroupNumber === 5 || matchedGroupNumber === 6) { 261 | 262 | if (!calculateStepsDone) { 263 | 264 | keySteps = calculateSteps(original, key); 265 | calculateStepsDone = true; 266 | 267 | } 268 | lastIndex = keySteps[idx]; 269 | 270 | } 271 | 272 | extractedAreas.push({ 273 | value: value, 274 | //aaa : match[matchedGroupNumber], 275 | matchedKeyValue: matchedKeyValue, 276 | newMatchedKeyValue: newMatchedKeyValue, 277 | startIndex: startIndex, 278 | lastIndex: lastIndex, 279 | }); 280 | 281 | idx += 1; 282 | } 283 | 284 | //console.log('※ getMaterials'); 285 | //console.log(keySteps); 286 | //console.log(extractedAreas); 287 | 288 | return extractedAreas; 289 | } 290 | 291 | function sculpt(original, materials) { 292 | 293 | materials.reverse().forEach(function (val, idx) { 294 | original = Util.Text.replaceBetween(original, val.startIndex, val.lastIndex, val.newMatchedKeyValue); 295 | }); 296 | 297 | return original; 298 | 299 | } 300 | 301 | /* 302 | * match information 303 | * 304 | * 0 : as you are aware, match[0] is just the whole match 305 | * 306 | * 1~3 : withKey 307 | * 1 : front of key 308 | * 2 : only key 309 | * 3 : only value 310 | * 311 | * 4 : final area (the very end of json, the final of the loop below, whole match) 312 | * 313 | * 5~8 : withNoKey 314 | * 5 : whole match 315 | * 6 : front of 'one value of array' - [[ 316 | * 7 : only down front of 'one value of array' - }] 317 | * 8 : one value - "aaa", 5, true... 318 | * 9 : {}, [] (empty object or array) 319 | * 320 | * */ 321 | 322 | /** 323 | * Extract every single key and value and their meta data, which consists of 'step', 'order' and 'ancestors'. 324 | * 325 | * @param {string} original JSON string to parse. 326 | * @return {array} True if the DOM is a valid DOM node. 327 | * @internal 328 | */ 329 | 330 | function getAbsoluteKeyValueMetaData(original) { 331 | 332 | let stepAreas = []; 333 | let idx = 0; 334 | 335 | try { 336 | 337 | let rx = new RegExp('(?:' + Pattern.jsonOutput2() + ')|' + 338 | '(' + Pattern.commons.spaceOrEndBracketOrNot + '$)|' + 339 | '(?:' + Pattern.steps.withNoKey(true) + ')', 'g'); 340 | 341 | let match = {}; 342 | 343 | let ancestors = []; 344 | 345 | let previousKey = null; 346 | let previousStep = 0; 347 | 348 | // To get an order in an array, we use steps of array. 349 | // arrayStepStore.push(ancestors[ancestors.length - 1]['step']) means that the param below 'order' has been +1 increased, and the step value itself is used to remove ancestors of the current key or value's own. 350 | let arrayStepStore = []; 351 | 352 | let ancestorCandidateKey = null; 353 | let ancestorCandidateStep = 0; 354 | let ancestorCandidateValue = null; 355 | 356 | ancestors.push({key: 'ORIGIN', step: ancestorCandidateStep}); 357 | 358 | while ((match = rx.exec(original)) !== null) { 359 | 360 | let step = previousStep; 361 | 362 | /* withNoKey */ 363 | if (match[5]) { 364 | 365 | let order = null; 366 | 367 | if (match[6]) { 368 | step += (match[6].match(new RegExp(Pattern.steps.asc, "g")) || []).length; 369 | step -= (match[6].match(new RegExp(Pattern.steps.desc, "g")) || []).length; 370 | 371 | 372 | //if (ancestors.length > 1) { 373 | if (/,/.test(match[6])) { 374 | // console.log('idx : ' + idx + ' / step : ' + ancestors[ancestors.length - 1]['step']) 375 | arrayStepStore.push(ancestors[ancestors.length - 1]['step']); 376 | 377 | order = arrayStepStore.filter(x => x === ancestors[ancestors.length - 1]['step']).length; 378 | if (order === 0) { 379 | order = null; 380 | } 381 | } 382 | if (/\[/.test(match[6])) { 383 | 384 | if (ancestorCandidateStep < step) { 385 | // the previous ancestor is not fake, which means they had array or object values. If they had one string or number thing, they are fake ancestors. 386 | if (ancestorCandidateValue == '') { 387 | ancestors.push({key: ancestorCandidateKey, step: ancestorCandidateStep}); 388 | } 389 | } else if (ancestorCandidateStep >= step) { 390 | ancestors = ancestors.filter((x) => x.step < step); 391 | } 392 | 393 | arrayStepStore = arrayStepStore.filter(x => x !== ancestors[ancestors.length - 1]['step']); 394 | arrayStepStore.push(ancestors[ancestors.length - 1]['step']); 395 | 396 | order = 1; 397 | } 398 | } 399 | 400 | stepAreas.push({ 401 | // type: 'withNoKey', 402 | step: step, 403 | order: order, 404 | key: null, 405 | // match[9] : empty object or array 406 | value: match[9] ? match[9] : match[8], 407 | ancestors: [...ancestors], 408 | //debugInfo: match 409 | }); 410 | 411 | previousStep = step; 412 | previousKey = null; 413 | 414 | 415 | /* final area : all JSONs end at this point with the command 'break' */ 416 | } else if (match[4]) { 417 | 418 | if (idx === 0) { 419 | stepAreas.push({ 420 | step: null, 421 | order: null, 422 | key: null, 423 | value: null, 424 | ancestors: null, 425 | etc: original, 426 | //debugInfo: match 427 | }); 428 | 429 | break; 430 | } 431 | 432 | const finalStep = step - (match[0].match(new RegExp(Pattern.steps.desc, "g")) || []).length; 433 | 434 | stepAreas.push({ 435 | // type: 'final', 436 | step: finalStep, 437 | order: null, 438 | key: null, 439 | value: null, 440 | ancestors: null, 441 | etc: match[4] 442 | //debugInfo: match 443 | }); 444 | 445 | // Fail to calculate steps 446 | if (finalStep !== 0) { 447 | throw new Error('The final step should be 0.') 448 | } 449 | 450 | break; 451 | 452 | /* withKey */ 453 | } else { 454 | 455 | let order = null; 456 | 457 | step += (match[1].match(new RegExp(Pattern.steps.asc, "g")) || []).length; 458 | step -= (match[1].match(new RegExp(Pattern.steps.desc, "g")) || []).length; 459 | 460 | if (ancestorCandidateStep < step) { 461 | // the previous ancestor is not fake, which means they had array or object values. If they had one string or number thing, they are fake ancestors. 462 | if (ancestorCandidateValue == '') { 463 | ancestors.push({ 464 | key: ancestorCandidateKey, 465 | step: ancestorCandidateStep 466 | }); 467 | } 468 | } else if (ancestorCandidateStep >= step) { 469 | ancestors = ancestors.filter((x) => x.step < step); 470 | } 471 | 472 | // if (ancestors.length > 0) { 473 | if (/,/.test(match[1])) { 474 | 475 | if (/{/.test(match[1])) { 476 | arrayStepStore.push(ancestors[ancestors.length - 1]['step']); 477 | } 478 | order = arrayStepStore.filter(x => x === ancestors[ancestors.length - 1]['step']).length; 479 | if (order === 0) { 480 | order = null; 481 | } 482 | } 483 | if (/\[/.test(match[1])) { 484 | 485 | arrayStepStore = arrayStepStore.filter(x => x !== ancestors[ancestors.length - 1]['step']); 486 | arrayStepStore.push(ancestors[ancestors.length - 1]['step']); 487 | 488 | if (/,/.test(match[1])) { 489 | arrayStepStore.push(ancestors[ancestors.length - 1]['step']); 490 | order = arrayStepStore.filter(x => x === ancestors[ancestors.length - 1]['step']).length; 491 | } else { 492 | order = 1; 493 | } 494 | 495 | } 496 | // } 497 | 498 | stepAreas.push({ 499 | // type: 'withKey', 500 | step: step, 501 | order: order, 502 | key: match[2], 503 | value: match[3], 504 | ancestors: [...ancestors], 505 | //debugInfo: match 506 | }); 507 | 508 | previousStep = step; 509 | previousKey = match[2]; 510 | 511 | ancestorCandidateStep = previousStep; 512 | ancestorCandidateKey = previousKey; 513 | ancestorCandidateValue = match[3]; 514 | } 515 | 516 | idx += 1; 517 | } 518 | }catch (e) { 519 | console.log('The error has occurred at idx : ' + idx) 520 | console.log(stepAreas); 521 | throw e; 522 | }finally { 523 | //console.log(stepAreas); 524 | } 525 | 526 | return stepAreas; 527 | } 528 | 529 | function arraysEqual(a, b) { 530 | a = Array.isArray(a) ? a : []; 531 | b = Array.isArray(b) ? b : []; 532 | return a.length === b.length && a.every((el, ix) => el === b[ix]); 533 | } 534 | 535 | function s(x, y) { 536 | var pre = ['string', 'number', 'bool'] 537 | if (typeof x !== typeof y) return pre.indexOf(typeof y) - pre.indexOf(typeof x); 538 | 539 | if (x === y) return 0; 540 | else return (x > y) ? 1 : -1; 541 | 542 | } 543 | 544 | function deepCompare(original, original2) { 545 | 546 | const keySteps = getAbsoluteKeyValueMetaData(original).map((x) => JSON.stringify(x)).sort(s); 547 | const keySteps2 = getAbsoluteKeyValueMetaData(original2).map((x) => JSON.stringify(x)).sort(s); 548 | 549 | return arraysEqual(keySteps, keySteps2) 550 | } 551 | 552 | 553 | export default { 554 | 555 | getMaterials, sculpt, deepCompare 556 | } -------------------------------------------------------------------------------- /src/util.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Private : Utils 3 | * */ 4 | import Pattern from './pattern'; 5 | 6 | const Text = { 7 | 8 | replaceBetween(from, start, end, what) { 9 | return from.substring(0, start) + what + from.substring(end); 10 | }, 11 | escapeRegex(v) { 12 | return v.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); 13 | }, 14 | 15 | 16 | }; 17 | 18 | export default { 19 | Text 20 | } -------------------------------------------------------------------------------- /test/answer.js: -------------------------------------------------------------------------------- 1 | const n1 = "{\"problems\":[{\"classes\":[{\"medications\":[{\"medicationsClasses\":[{\"Mike {[Gentleman]}\":[{\"associatedDrug\":[{\"name\":\"asprin\",\"dose\":\"a\",\"strength\":\"500 mg\"}],\"Mike {[Gentleman]}\":[{\"name\":\"somethingElse\",\"dose\":\"\",\"strength\":\"500 mg\",\"friends\":{\"self\":{\"Mike {[Gentleman]}\":\"33\",\"names\":[\"aa\"]}}}]}],\"Judy\":[{\"associatedDrug\":[{\"name\":\"asprin\",\"dose\":\"\",\"strength\":\"500 mg\",\"friends\":[\"Mike {[Gentleman]}\"]}],\"associatedDrug#2\":[{\"name\":\"somethingElse\",\"dose\":\"\",\"strength\":\"500 mg\"}],\"friends\":[{\"Mike {[Gentleman]}\":null},{\"Mike {[Gentleman]}\":[[\"c[ 3\\\"5ool\",35],[\"ca],[1\\\"3lm\"],53]},\"Jackson\",\"Mike {[Gentleman]}\",{\"problems\":[{\"aclasses\":[{\"medications\":[{\"medicationsClasses\":[{\"Mike {[Gentleman]}\":[{\"associatedDrug\":[{\"name\":\"asprin\",\"dose\":\"a\",\"strength\":\"500 mg\"}],\"Mike {[Gentleman]}\":[{\"name\":\"somethingElse\",\"dose\":\"\",\"strength\":\"500 mg\",\"friends\":{\"self\":{\"Mike {[Gentleman]}\":\"33\",\"names\":[\"aa\"]}}},{\"problems\":[{\"xxclasses\":[{\"yyclassNameMissed\":[{\"medicationsClasses\":[{\"Mike {[Gentleman]}\":[{\"associatedDrug\":[{\"name\":\"asprin\",\"dose\":\"a\",\"strength\":\"500 mg\"}],\"Mike {[Gentleman]}\":[{\"name\":\"somethingElse\",\"dose\":\"\",\"strength\":\"500 mg\",\"friends\":{\"self\":{\"Mike {[Gentleman]}\":\"33\",\"names\":[\"aa\"]}}}]}],\"Judy\":[{\"associatedDrug\":[{\"name\":\"asprin\",\"dose\":\"\",\"strength\":\"500 mg\",\"friends\":[\"Mike {[Gentleman]}\"]}],\"associatedDrug#2\":[{\"name\":\"somethingElse\",\"dose\":\"\",\"strength\":\"500 mg\"}],\"friends\":[{\"Mike {[Gentleman]}\":null},{\"Mike {[Gentleman]}\":[[\"c[ 3\\\"5ool\",35],[\"ca],[1\\\"3lm\"],53]},\"Jackson\",\"Mike {[Gentleman]}\",{\"problems\":[{\"classes\":[{\"medications\":[{\"medicationsClasses\":[{\"Mike {[Gentleman]}\":[{\"associatedDrug\":[{\"name\":\"asprin\",\"dose\":\"a\",\"strength\":\"500 mg\"}],\"Mike {[Gentleman]}\":[{\"name\":\"somethingElse\",\"dose\":\"\",\"strength\":\"500 mg\",\"friends\":{\"self\":{\"Mike {[Gentleman]}\":\"33\",\"names\":[\"aa\"]}}}]}],\"Judy\":[{\"associatedDrug\":[{\"name\":\"asprin\",\"dose\":\"\",\"strength\":\"500 mg\",\"friends\":[\"Mike {[Gentleman]}\"]}],\"associatedDrug#2\":[{\"name\":\"somethingElse\",\"dose\":\"\",\"strength\":\"500 mg\"}],\"friends\":[{\"Mike {[Gentleman]}\":null},{\"Mike {[Gentleman]}\":[[\"c[ 3\\\"5ool\",35],[\"ca],[1\\\"3lm\"],53]},\"Jackson\",\"Mike {[Gentleman]}\"]}]}]}],\"classNameMissed\":[{\"Mike {[Gentleman]}\":\"missing_value\"}]}],\"className\":[{}]}]}]}]}]}],\"yyclassNameMissed2\":[{\"Mike {[Gentleman]}\":\"missing_value\"}]}],\"xxclasses2\":[{}]}]}]}],\"Judy\":[{\"associatedDrug\":[{\"name\":\"asprin\",\"dose\":\"\",\"strength\":\"500 mg\",\"friends\":[\"Mike {[Gentleman]}\"]}],\"associatedDrug#2\":[{\"name\":\"somethingElse\",\"dose\":\"\",\"strength\":\"500 mg\"}],\"friends\":[{\"Mike {[Gentleman]}\":null},{\"Mike {[Gentleman]}\":[[\"c[ 3\\\"5ool\",35],[\"ca],[1\\\"3lm\"],53]},\"Jackson\",\"Mike {[Gentleman]}\"]}]}]}],\"classNameMissed\":[{\"Mike {[Gentleman]}\":\"missing_value\"}]}],\"className\":[{}]}]}]}]}]}],\"classNameMissed\":[{\"Mike {[Gentleman]}\":\"missing_value\"}]}],\"className\":[{}]}]}" 2 | 3 | const n2 = "{\"problems\":[{\"classes\":[{\"medications\":[{\"medicationsClasses\":[{\"Mike {[Gentleman]}\":[{\"associatedDrug\":[{\"name\":\"asprin\",\"dose\":\"a\",\"strength\":\"500 mg\"}],\"Mike {[Gentleman]}\":[{\"name\":\"somethingElse\",\"dose\":\"\",\"strength\":\"500 mg\",\"friends\":{\"self\":null}}]}],\"Judy\":[{\"associatedDrug\":[{\"name\":\"asprin\",\"dose\":\"\",\"strength\":\"500 mg\",\"friends\":[\"Mike {[Gentleman]}\"]}],\"associatedDrug#2\":[{\"name\":\"somethingElse\",\"dose\":\"\",\"strength\":\"500 mg\"}],\"friends\":[{\"Mike {[Gentleman]}\":null},{\"Mike {[Gentleman]}\":[[\"c[ 3\\\"5ool\",35],[\"ca],[1\\\"3lm\"],53]},\"Jackson\",\"Mike {[Gentleman]}\",{\"problems\":[{\"aclasses\":[{\"medications\":[{\"medicationsClasses\":[{\"Mike {[Gentleman]}\":[{\"associatedDrug\":[{\"name\":\"asprin\",\"dose\":\"a\",\"strength\":\"500 mg\"}],\"Mike {[Gentleman]}\":[{\"name\":\"somethingElse\",\"dose\":\"\",\"strength\":\"500 mg\",\"friends\":{\"self\":null}},{\"problems\":[{\"xxclasses\":[{\"yyclassNameMissed\":[{\"medicationsClasses\":[{\"Mike {[Gentleman]}\":[{\"associatedDrug\":[{\"name\":\"asprin\",\"dose\":\"a\",\"strength\":\"500 mg\"}],\"Mike {[Gentleman]}\":[{\"name\":\"somethingElse\",\"dose\":\"\",\"strength\":\"500 mg\",\"friends\":{\"self\":null}}]}],\"Judy\":[{\"associatedDrug\":[{\"name\":\"asprin\",\"dose\":\"\",\"strength\":\"500 mg\",\"friends\":[\"Mike {[Gentleman]}\"]}],\"associatedDrug#2\":[{\"name\":\"somethingElse\",\"dose\":\"\",\"strength\":\"500 mg\"}],\"friends\":[{\"Mike {[Gentleman]}\":null},{\"Mike {[Gentleman]}\":[[\"c[ 3\\\"5ool\",35],[\"ca],[1\\\"3lm\"],53]},\"Jackson\",\"Mike {[Gentleman]}\",{\"problems\":[{\"classes\":[{\"medications\":[{\"medicationsClasses\":[{\"Mike {[Gentleman]}\":[{\"associatedDrug\":[{\"name\":\"asprin\",\"dose\":\"a\",\"strength\":\"500 mg\"}],\"Mike {[Gentleman]}\":[{\"name\":\"somethingElse\",\"dose\":\"\",\"strength\":\"500 mg\",\"friends\":{\"self\":null}}]}],\"Judy\":[{\"associatedDrug\":[{\"name\":\"asprin\",\"dose\":\"\",\"strength\":\"500 mg\",\"friends\":[\"Mike {[Gentleman]}\"]}],\"associatedDrug#2\":[{\"name\":\"somethingElse\",\"dose\":\"\",\"strength\":\"500 mg\"}],\"friends\":[{\"Mike {[Gentleman]}\":null},{\"Mike {[Gentleman]}\":[[\"c[ 3\\\"5ool\",35],[\"ca],[1\\\"3lm\"],53]},\"Jackson\",\"Mike {[Gentleman]}\"]}]}]}],\"classNameMissed\":[{\"Mike {[Gentleman]}\":\"missing_value\"}]}],\"className\":[{}]}]}]}]}]}],\"yyclassNameMissed2\":[{\"Mike {[Gentleman]}\":\"missing_value\"}]}],\"xxclasses2\":[{}]}]}]}],\"Judy\":[{\"associatedDrug\":[{\"name\":\"asprin\",\"dose\":\"\",\"strength\":\"500 mg\",\"friends\":[\"Mike {[Gentleman]}\"]}],\"associatedDrug#2\":[{\"name\":\"somethingElse\",\"dose\":\"\",\"strength\":\"500 mg\"}],\"friends\":[{\"Mike {[Gentleman]}\":null},{\"Mike {[Gentleman]}\":[[\"c[ 3\\\"5ool\",35],[\"ca],[1\\\"3lm\"],53]},\"Jackson\",\"Mike {[Gentleman]}\"]}]}]}],\"classNameMissed\":[{\"Mike {[Gentleman]}\":\"missing_value\"}]}],\"className\":[{}]}]}]}]}]}],\"classNameMissed\":[{\"Mike {[Gentleman]}\":\"missing_value\"}]}],\"className\":[{}]}]}"; 4 | 5 | const n3 = "{\"problems\":[{\"classes\":[{\"medications\":[{\"medicationsClasses\":[{\"Mike {[Gentleman]}\":null,\"Judy\":[{\"associatedDrug\":[{\"name\":\"asprin\",\"dose\":\"\",\"strength\":\"500 mg\",\"friends\":[\"Mike {[Gentleman]}\"]}],\"associatedDrug#2\":[{\"name\":\"somethingElse\",\"dose\":\"\",\"strength\":\"500 mg\"}],\"friends\":[{\"Mike {[Gentleman]}\":null},{\"Mike {[Gentleman]}\":null},\"Jackson\",\"Mike {[Gentleman]}\",{\"problems\":[{\"aclasses\":[{\"medications\":[{\"medicationsClasses\":[{\"Mike {[Gentleman]}\":null,\"Judy\":[{\"associatedDrug\":[{\"name\":\"asprin\",\"dose\":\"\",\"strength\":\"500 mg\",\"friends\":[\"Mike {[Gentleman]}\"]}],\"associatedDrug#2\":[{\"name\":\"somethingElse\",\"dose\":\"\",\"strength\":\"500 mg\"}],\"friends\":[{\"Mike {[Gentleman]}\":null},{\"Mike {[Gentleman]}\":null},\"Jackson\",\"Mike {[Gentleman]}\"]}]}]}],\"classNameMissed\":[{\"Mike {[Gentleman]}\":null}]}],\"className\":[{}]}]}]}]}]}],\"classNameMissed\":[{\"Mike {[Gentleman]}\":null}]}],\"className\":[{}]}]}"; 6 | 7 | const n4 = "{\"problems\":[{\"classes\":[{\"medications\":[{\"medicationsClasses\":[{\"Mike {[Gentleman]}\":[{\"associatedDrug\":[{\"name\":\"asprin\",\"dose\":\"a\",\"strength\":\"500 mg\"}],\"Mike {[Gentleman]}\":[{\"name\":\"somethingElse\",\"dose\":\"\",\"strength\":\"500 mg\",\"friends\":{\"self\":{\"Mike {[Gentleman]}\":\"33\",\"names\":[\"aa\"]}}}]}],\"Judy\":[{\"associatedDrug\":[{\"name\":\"asprin\",\"dose\":\"\",\"strength\":\"500 mg\",\"friends\":[\"Mike {[Gentleman]}\"]}],\"associatedDrug#2\":[{\"name\":\"somethingElse\",\"dose\":\"\",\"strength\":\"500 mg\"}],\"friends\":[{\"Mike {[Gentleman]}\":null},{\"Mike {[Gentleman]}\":[[\"c[ 3\\\"5ool\",35],[\"ca],[1\\\"3lm\"],53]},\"Jackson\",\"Mike {[Gentleman]}\",{\"problems\":[{\"aclasses\":[{\"medications\":[{\"medicationsClasses\":[{\"Mike {[Gentleman]}\":[{\"associatedDrug\":[{\"name\":\"asprin\",\"dose\":\"a\",\"strength\":\"500 mg\"}],\"Mike {[Gentleman]}\":[{\"name\":\"somethingElse\",\"dose\":\"\",\"strength\":\"500 mg\",\"friends\":{\"self\":{\"Mike {[Gentleman]}\":\"33\",\"names\":[\"aa\"]}}},{\"problems\":[{\"xxclasses\":[{\"yyclassNameMissed\":[{\"medicationsClasses\":[{\"Mike {[Gentleman]}\":[{\"associatedDrug\":[{\"name\":\"asprin\",\"dose\":\"a\",\"strength\":\"500 mg\"}],\"Mike {[Gentleman]}\":[{\"name\":\"somethingElse\",\"dose\":\"\",\"strength\":\"500 mg\",\"friends\":{\"self\":{\"Mike {[Gentleman]}\":\"33\",\"names\":[\"aa\"]}}}]}],\"Judy\":[{\"associatedDrug\":[{\"name\":\"asprin\",\"dose\":\"\",\"strength\":\"500 mg\",\"friends\":[\"Mike {[Gentleman]}\"]}],\"associatedDrug#2\":[{\"name\":\"somethingElse\",\"dose\":\"\",\"strength\":\"500 mg\"}],\"friends\":[{\"Mike {[Gentleman]}\":null},{\"Mike {[Gentleman]}\":[[\"c[ 3\\\"5ool\",35],[\"ca],[1\\\"3lm\"],53]},\"Jackson\",\"Mike {[Gentleman]}\",{\"problems\":[{\"classes\":[{\"medications\":[{\"medicationsClasses\":[{\"Mike {[Gentleman]}\":[{\"associatedDrug\":[{\"name\":\"asprin\",\"dose\":\"a\",\"strength\":\"500 mg\"}],\"Mike {[Gentleman]}\":[{\"name\":\"somethingElse\",\"dose\":\"\",\"strength\":\"500 mg\",\"friends\":{\"self\":{\"Mike {[Gentleman]}\":\"33\",\"names\":[\"aa\"]}}}]}],\"Judy\":[{\"associatedDrug\":[{\"name\":\"asprin\",\"dose\":\"\",\"strength\":\"500 mg\",\"friends\":[\"Mike {[Gentleman]}\"]}],\"associatedDrug#2\":[{\"name\":\"somethingElse\",\"dose\":\"\",\"strength\":\"500 mg\"}],\"friends\":[{\"Mike {[Gentleman]}\":null},{\"Mike {[Gentleman]}\":[[\"c[ 3\\\"5ool\",35],[\"ca],[1\\\"3lm\"],53]},\"Jackson\",\"Mike {[Gentleman]}\"]}]}]}],\"classNameMissed\":[{\"Mike {[Gentleman]}\":\"missing_value\"}]}],\"className\":true}]}]}]}]}],\"yyclassNameMissed2\":[{\"Mike {[Gentleman]}\":\"missing_value\"}]}],\"xxclasses2\":[{}]}]}]}],\"Judy\":[{\"associatedDrug\":[{\"name\":\"asprin\",\"dose\":\"\",\"strength\":\"500 mg\",\"friends\":[\"Mike {[Gentleman]}\"]}],\"associatedDrug#2\":[{\"name\":\"somethingElse\",\"dose\":\"\",\"strength\":\"500 mg\"}],\"friends\":[{\"Mike {[Gentleman]}\":null},{\"Mike {[Gentleman]}\":[[\"c[ 3\\\"5ool\",35],[\"ca],[1\\\"3lm\"],53]},\"Jackson\",\"Mike {[Gentleman]}\"]}]}]}],\"classNameMissed\":[{\"Mike {[Gentleman]}\":\"missing_value\"}]}],\"className\":true}]}]}]}]}],\"classNameMissed\":[{\"Mike {[Gentleman]}\":\"missing_value\"}]}],\"className\":true}]}"; 8 | 9 | export default { 10 | n1, n2, n3, n4 11 | } -------------------------------------------------------------------------------- /test/sample.js: -------------------------------------------------------------------------------- 1 | const str_1 = '{\n' + 2 | ' "prob\\"lems": [{\n' + 3 | ' "classes": [{\n' + 4 | ' "medications": [{\n' + 5 | ' "medicationsClasses": [{\n' + 6 | ' "Mike {[Gentleman]}": [{\n' + 7 | ' "associatedDrug": [{\n' + 8 | ' "name": "asprin",\n' + 9 | ' "dose": "a",\n' + 10 | ' "strength": "500 mg"\n' + 11 | ' }],\n' + 12 | ' "Mike {[Gentleman]}": [{\n' + 13 | ' "name": "somethingElse",\n' + 14 | ' "dose": "",\n' + 15 | ' "strength": "500 mg",\n' + 16 | ' "friends": {\n' + 17 | ' "self": {\n' + 18 | ' "Mike {[Gentleman]}": "33",\n' + 19 | ' "names": ["aa"]\n' + 20 | ' }\n' + 21 | ' }\n' + 22 | ' }]\n' + 23 | ' }],\n' + 24 | ' "Judy": [{\n' + 25 | ' "associatedDrug": [{\n' + 26 | ' "name": "asprin",\n' + 27 | ' "dose": "",\n' + 28 | ' "strength": "500 mg",\n' + 29 | ' "friends": ["Mike {[Gentleman]}"]\n' + 30 | ' }],\n' + 31 | ' "associatedDrug#2": [{\n' + 32 | ' "name": "somethingElse",\n' + 33 | ' "dose": "",\n' + 34 | ' "strength": "500 mg"\n' + 35 | ' }],\n' + 36 | ' "friends": [{"Mike {[Gentleman]}": null}, {"Mike {[Gentleman]}": [["c[ 3\\"5ool", 35], ["ca],[1\\"3lm"], 53]}, "Jackson", "Mike {[Gentleman]}"]\n' + 37 | ' }]\n' + 38 | ' }]\n' + 39 | ' }],\n' + 40 | ' "classNameMissed": [{\n' + 41 | ' "Mike {[Gentleman]}": "missing_value"\n' + 42 | ' }]\n' + 43 | ' }],\n' + 44 | ' "className": [{}]\n' + 45 | ' }]\n' + 46 | ' }'; 47 | 48 | const obj_1 ={ 49 | "problems": [ 50 | { 51 | "classes": [ 52 | { 53 | "medications": [ 54 | { 55 | "medicationsClasses": [ 56 | { 57 | "Mike {[Gentleman]}": [ 58 | { 59 | "associatedDrug": [ 60 | { 61 | "name": "asprin", 62 | "dose": "a", 63 | "strength": "500 mg" 64 | } 65 | ], 66 | "Mike {[Gentleman]}": [ 67 | { 68 | "name": "somethingElse", 69 | "dose": "", 70 | "strength": "500 mg", 71 | "friends": { 72 | "self": { 73 | "Mike {[Gentleman]}": "33", 74 | "names": [ 75 | "aa" 76 | ] 77 | } 78 | } 79 | } 80 | ] 81 | } 82 | ], 83 | "Judy": [ 84 | { 85 | "associatedDrug": [ 86 | { 87 | "name": "asprin", 88 | "dose": "", 89 | "strength": "500 mg", 90 | "friends": [ 91 | "Mike {[Gentleman]}" 92 | ] 93 | } 94 | ], 95 | "associatedDrug#2": [ 96 | { 97 | "name": "somethingElse", 98 | "dose": "", 99 | "strength": "500 mg" 100 | } 101 | ], 102 | "friends": [ 103 | { 104 | "Mike {[Gentleman]}": null 105 | }, 106 | { 107 | "Mike {[Gentleman]}": [ 108 | [ 109 | "c[ 3\"5ool", 110 | 35 111 | ], 112 | [ 113 | "ca],[1\"3lm" 114 | ], 115 | 53 116 | ] 117 | }, 118 | "Jackson", 119 | "Mike {[Gentleman]}", 120 | { 121 | "problems": [ 122 | { 123 | "aclasses": [ 124 | { 125 | "medications": [ 126 | { 127 | "medicationsClasses": [ 128 | { 129 | "Mike {[Gentleman]}": [ 130 | { 131 | "associatedDrug": [ 132 | { 133 | "name": "asprin", 134 | "dose": "a", 135 | "strength": "500 mg" 136 | } 137 | ], 138 | "Mike {[Gentleman]}": [ 139 | { 140 | "name": "somethingElse", 141 | "dose": "", 142 | "strength": "500 mg", 143 | "friends": { 144 | "self": { 145 | "Mike {[Gentleman]}": "33", 146 | "names": [ 147 | "aa" 148 | ] 149 | } 150 | } 151 | }, 152 | { 153 | "problems": [ 154 | { 155 | "xxclasses": [ 156 | { 157 | "yyclassNameMissed": [ 158 | { 159 | "medicationsClasses": [ 160 | { 161 | "Mike {[Gentleman]}": [ 162 | { 163 | "associatedDrug": [ 164 | { 165 | "name": "asprin", 166 | "dose": "a", 167 | "strength": "500 mg" 168 | } 169 | ], 170 | "Mike {[Gentleman]}": [ 171 | { 172 | "name": "somethingElse", 173 | "dose": "", 174 | "strength": "500 mg", 175 | "friends": { 176 | "self": { 177 | "Mike {[Gentleman]}": "33", 178 | "names": [ 179 | "aa" 180 | ] 181 | } 182 | } 183 | } 184 | ] 185 | } 186 | ], 187 | "Judy": [ 188 | { 189 | "associatedDrug": [ 190 | { 191 | "name": "asprin", 192 | "dose": "", 193 | "strength": "500 mg", 194 | "friends": [ 195 | "Mike {[Gentleman]}" 196 | ] 197 | } 198 | ], 199 | "associatedDrug#2": [ 200 | { 201 | "name": "somethingElse", 202 | "dose": "", 203 | "strength": "500 mg" 204 | } 205 | ], 206 | "friends": [ 207 | { 208 | "Mike {[Gentleman]}": null 209 | }, 210 | { 211 | "Mike {[Gentleman]}": [ 212 | [ 213 | "c[ 3\"5ool", 214 | 35 215 | ], 216 | [ 217 | "ca],[1\"3lm" 218 | ], 219 | 53 220 | ] 221 | }, 222 | "Jackson", 223 | "Mike {[Gentleman]}", 224 | { 225 | "problems": [ 226 | { 227 | "classes": [ 228 | { 229 | "medications": [ 230 | { 231 | "medicationsClasses": [ 232 | { 233 | "Mike {[Gentleman]}": [ 234 | { 235 | "associatedDrug": [ 236 | { 237 | "name": "asprin", 238 | "dose": "a", 239 | "strength": "500 mg" 240 | } 241 | ], 242 | "Mike {[Gentleman]}": [ 243 | { 244 | "name": "somethingElse", 245 | "dose": "", 246 | "strength": "500 mg", 247 | "friends": { 248 | "self": { 249 | "Mike {[Gentleman]}": "33", 250 | "names": [ 251 | "aa" 252 | ] 253 | } 254 | } 255 | } 256 | ] 257 | } 258 | ], 259 | "Judy": [ 260 | { 261 | "associatedDrug": [ 262 | { 263 | "name": "asprin", 264 | "dose": "", 265 | "strength": "500 mg", 266 | "friends": [ 267 | "Mike {[Gentleman]}" 268 | ] 269 | } 270 | ], 271 | "associatedDrug#2": [ 272 | { 273 | "name": "somethingElse", 274 | "dose": "", 275 | "strength": "500 mg" 276 | } 277 | ], 278 | "friends": [ 279 | { 280 | "Mike {[Gentleman]}": null 281 | }, 282 | { 283 | "Mike {[Gentleman]}": [ 284 | [ 285 | "c[ 3\"5ool", 286 | 35 287 | ], 288 | [ 289 | "ca],[1\"3lm" 290 | ], 291 | 53 292 | ] 293 | }, 294 | "Jackson", 295 | "Mike {[Gentleman]}" 296 | ] 297 | } 298 | ] 299 | } 300 | ] 301 | } 302 | ], 303 | "classNameMissed": [ 304 | { 305 | "Mike {[Gentleman]}": "missing_value" 306 | } 307 | ] 308 | } 309 | ], 310 | "className": [ 311 | {} 312 | ] 313 | } 314 | ] 315 | } 316 | ] 317 | } 318 | ] 319 | } 320 | ] 321 | } 322 | ], 323 | "yyclassNameMissed2": [ 324 | { 325 | "Mike {[Gentleman]}": "missing_value" 326 | } 327 | ] 328 | } 329 | ], 330 | "xxclasses2": [ 331 | {} 332 | ] 333 | } 334 | ] 335 | } 336 | ] 337 | } 338 | ], 339 | "Judy": [ 340 | { 341 | "associatedDrug": [ 342 | { 343 | "name": "asprin", 344 | "dose": "", 345 | "strength": "500 mg", 346 | "friends": [ 347 | "Mike {[Gentleman]}" 348 | ] 349 | } 350 | ], 351 | "associatedDrug#2": [ 352 | { 353 | "name": "somethingElse", 354 | "dose": "", 355 | "strength": "500 mg" 356 | } 357 | ], 358 | "friends": [ 359 | { 360 | "Mike {[Gentleman]}": null 361 | }, 362 | { 363 | "Mike {[Gentleman]}": [ 364 | [ 365 | "c[ 3\"5ool", 366 | 35 367 | ], 368 | [ 369 | "ca],[1\"3lm" 370 | ], 371 | 53 372 | ] 373 | }, 374 | "Jackson", 375 | "Mike {[Gentleman]}" 376 | ] 377 | } 378 | ] 379 | } 380 | ] 381 | } 382 | ], 383 | "classNameMissed": [ 384 | { 385 | "Mike {[Gentleman]}": "missing_value" 386 | } 387 | ] 388 | } 389 | ], 390 | "className": [ 391 | {} 392 | ] 393 | } 394 | ] 395 | } 396 | ] 397 | } 398 | ] 399 | } 400 | ] 401 | } 402 | ], 403 | "classNameMissed": [ 404 | { 405 | "Mike {[Gentleman]}": "missing_value" 406 | } 407 | ] 408 | } 409 | ], 410 | "className": [ 411 | {} 412 | ] 413 | } 414 | ] 415 | }; 416 | 417 | export default { 418 | str_1, obj_1 419 | } -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | import Pattern from '../src/controller' 2 | import Sample from './sample' 3 | import Answer from './answer' 4 | 5 | //const assert = require('assert'); 6 | var assert = require('chai').assert; 7 | 8 | function expect(result) { 9 | return { 10 | toBe: function(expected) { 11 | if (result !== expected) { 12 | throw new Error(result + ' is not equal to ' + expected); 13 | } 14 | } 15 | } 16 | } 17 | 18 | function checkProperties(doc, key, value) { 19 | for (var propertyName in doc) { 20 | if (typeof doc[propertyName] == "object") { 21 | checkProperties(doc[propertyName]); 22 | } else { 23 | if (propertyName == key) { 24 | doc[propertyName] = value; 25 | //print(doc[propertyName]); 26 | } 27 | } 28 | } 29 | } 30 | 31 | function getObjects(obj, key, newVal) { 32 | var newValue = newVal; 33 | var objects = []; 34 | for (var i in obj) { 35 | if (!obj.hasOwnProperty(i)) continue; 36 | if (typeof obj[i] == 'object') { 37 | objects = objects.concat(getObjects(obj[i], key, newValue)); 38 | } else if (i == key) { 39 | obj[key] = newValue; 40 | } 41 | } 42 | return obj; 43 | } 44 | 45 | 46 | describe('BDD style', function() { 47 | 48 | before(function(){ 49 | 50 | }); 51 | //... 52 | 53 | after(function(){ 54 | 55 | }); 56 | 57 | beforeEach(function() { 58 | 59 | }); 60 | 61 | afterEach(function() { 62 | 63 | }); 64 | 65 | describe('Sample file checker', function() { 66 | 67 | it('Check if a sample is a correct JSON', function() { 68 | expect(JSON.stringify(JSON.parse(JSON.stringify(Sample.obj_1)))) 69 | .toBe(Answer.n1); 70 | }); 71 | }); 72 | 73 | describe('Bulk update', function() { 74 | 75 | it('self : null', function() { 76 | expect(Pattern.sculptJson(Answer.n1, 'self', null)) 77 | .toBe(Answer.n2); 78 | }); 79 | 80 | it('Mike {[Gentleman]} : null', function() { 81 | expect(Pattern.sculptJson(Answer.n1, 'Mike {[Gentleman]}', null)) 82 | .toBe(Answer.n3); 83 | }); 84 | 85 | it('className : true', function() { 86 | expect(Pattern.sculptJson(Answer.n1, 'className', true)) 87 | .toBe(Answer.n4); 88 | }); 89 | 90 | /* it('Normal way - Mike {[Gentleman]} : null', function() { 91 | expect(getObjects(JSON.parse(Answer.n1), 'Mike {[Gentleman]}', null)) 92 | .toBe(JSON.parse(Answer.n3)); 93 | });*/ 94 | }); 95 | 96 | 97 | }); -------------------------------------------------------------------------------- /webpack.config.babel.js: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | 3 | module.exports = { 4 | entry: { 5 | preload: './target/entry.js' 6 | }, 7 | output: { 8 | path: path.join(__dirname, 'dist'), 9 | publicPath: '../dist/', 10 | filename: 'json-knife.bundle.js', 11 | chunkFilename: '[id].bundle.js', 12 | libraryTarget: 'var', 13 | library: 'Pattern' 14 | } 15 | }; --------------------------------------------------------------------------------