├── example ├── webpack-project │ ├── .gitignore │ ├── babel.config.js │ ├── src │ │ ├── index.css │ │ ├── index.html │ │ ├── index.js │ │ └── sampledata.js │ ├── package.json │ └── webpack.config.js └── create-react-app-project │ ├── src │ ├── index.css │ ├── index.js │ ├── sampledata.js │ ├── logo.svg │ └── registerServiceWorker.js │ ├── public │ ├── favicon.ico │ ├── manifest.json │ └── index.html │ ├── .gitignore │ └── package.json ├── .gitignore ├── test ├── jest.transform.js ├── logic │ ├── index.js │ ├── locale.js │ ├── testSyntaxLogic.js │ └── syntax.js ├── test.js ├── jest.setup.js ├── sampleData.js ├── change │ └── index.js ├── render │ └── index.js └── err.js ├── .travis.yml ├── ISSUE_TEMPLATE.md ├── src ├── locale │ ├── index.js │ ├── zh-cn.js │ ├── pt.js │ ├── es.js │ ├── jpn.js │ ├── fr.js │ ├── de.js │ ├── en.js │ ├── id.js │ ├── ru.js │ ├── hin.js │ └── ta.js ├── themes.js ├── err.js └── mitsuketa │ └── index.js ├── LICENSE.md ├── babel.config.js ├── scripts └── copy-files.js ├── CODE_OF_CONDUCT.md ├── CHANGELOG.md ├── package.json ├── .all-contributorsrc ├── CONTRIBUTING.md └── README.md /example/webpack-project/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | public/ -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules/ 2 | /dist/ 3 | /test/__snapshots__/ 4 | /example/node_modules/ 5 | /example/dist/ 6 | *.tgz -------------------------------------------------------------------------------- /example/create-react-app-project/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | } 6 | -------------------------------------------------------------------------------- /example/webpack-project/babel.config.js: -------------------------------------------------------------------------------- 1 | const baseConfig = require("../../babel.config"); 2 | 3 | module.exports = baseConfig; 4 | -------------------------------------------------------------------------------- /test/jest.transform.js: -------------------------------------------------------------------------------- 1 | let babel = require('../babel.config'); 2 | 3 | module.exports = require('babel-jest').createTransformer(babel); -------------------------------------------------------------------------------- /example/create-react-app-project/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndrewRedican/react-json-editor-ajrm/HEAD/example/create-react-app-project/public/favicon.ico -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | cache: 4 | directories: 5 | - node_modules 6 | node_js: 12 7 | branches: 8 | only: 9 | - master 10 | notifications: 11 | email: false 12 | script: 13 | - npm run test -------------------------------------------------------------------------------- /test/logic/index.js: -------------------------------------------------------------------------------- 1 | import syntaxTest from "./syntax"; 2 | import localeTest from "./locale"; 3 | 4 | function run() { 5 | syntaxTest(); 6 | localeTest(); 7 | // ... Add more logic specifc tests once we need them in different files ... 8 | } 9 | 10 | export default run; 11 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 1. What version of RJEA are you using (react-json-editor-ajrm version)? *REQUIRED 2 | 2. What operating system and processor architecture are you using? *REQUIRED 3 | 3. What did you do? *REQUIRED 4 | 4. What did you expect to see? *REQUIRED 5 | 5. What did you see instead? *REQUIRED 6 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | import renderTest from './render'; 2 | import logicTest from './logic'; 3 | import changeTest from './change'; 4 | 5 | beforeAll(() => { 6 | const div = document.createElement('div'); 7 | window.domNode = div; 8 | document.body.appendChild(div); 9 | }); 10 | 11 | renderTest(); 12 | logicTest(); 13 | changeTest(); -------------------------------------------------------------------------------- /example/create-react-app-project/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /example/create-react-app-project/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /example/webpack-project/src/index.css: -------------------------------------------------------------------------------- 1 | /* ========================================== */ 2 | /* Scroll Bar 3 | */ 4 | ::-webkit-scrollbar { 5 | width: 4px; 6 | } 7 | 8 | ::-webkit-scrollbar-track { 9 | border-radius: 10px; 10 | background: #eee; 11 | } 12 | 13 | ::-webkit-scrollbar-thumb { 14 | border-radius: 10px; 15 | background: #888; 16 | } 17 | ::-webkit-scrollbar-thumb:window-inactive { 18 | background: rgba(100,100,100,0.4); 19 | } -------------------------------------------------------------------------------- /example/create-react-app-project/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "create-react-app-project", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "react": "^16.4.2", 7 | "react-dom": "^16.4.2", 8 | "react-json-editor-ajrm": "2.5.13", 9 | "react-scripts": "1.1.5" 10 | }, 11 | "scripts": { 12 | "start": "react-scripts start", 13 | "build": "react-scripts build", 14 | "test": "react-scripts test --env=jsdom", 15 | "eject": "react-scripts eject" 16 | } 17 | } -------------------------------------------------------------------------------- /src/locale/index.js: -------------------------------------------------------------------------------- 1 | // Allows us to pass arrays and numbers instead of just strings to the format function. 2 | const stringify = (arg) => Array.isArray(arg) ? arg.join(", ") : typeof arg === "string" ? arg : "" + arg; 3 | 4 | // Replaces a string with the values of an object. Google "format unicorn" on an explanation of how to use. 5 | const format = (str, args) => args ? Object.keys(args).reduce((str, arg) => str.replace(new RegExp(`\\{${arg}\\}`, 'gi'), stringify(args[arg])), str) : str; 6 | 7 | export { 8 | format 9 | }; -------------------------------------------------------------------------------- /test/jest.setup.js: -------------------------------------------------------------------------------- 1 | import Enzyme, { shallow, render, mount } from 'enzyme'; 2 | import Adapter from 'enzyme-adapter-react-16'; 3 | import { JSDOM } from 'jsdom'; 4 | 5 | 6 | Enzyme.configure({ adapter: new Adapter() }); 7 | 8 | const { window } = new JSDOM('
'); 9 | 10 | global.shallow = shallow; 11 | global.render = render; 12 | global.mount = mount; 13 | global.window = window; 14 | global.document = window.document; -------------------------------------------------------------------------------- /example/webpack-project/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | <%= htmlWebpackPlugin.options.title %> 8 | 9 | 10 | 11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /example/webpack-project/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-json-editor-ajrm-example", 3 | "version": "1.7.0", 4 | "description": "A simple website to showcase react-json-editor-ajrm component", 5 | "author": "andrew.redican.mejia@gmail.com", 6 | "scripts": { 7 | "start": "cross-env NODE_ENV=development BABEL_ENV=modules:commonjs webpack-dev-server", 8 | "build": "cross-env NODE_ENV=production BABEL_ENV=modules:commonjs webpack" 9 | }, 10 | "dependencies": { 11 | "react": "^16.14.0", 12 | "react-dom": "^16.14.0", 13 | "react-json-editor-ajrm": "2.5.13" 14 | }, 15 | "devDependencies": { 16 | "cross-env": "^5.2.0", 17 | "css-loader": "^1.0.0", 18 | "html-webpack-plugin": "^3.2.0", 19 | "style-loader": "^0.21.0", 20 | "webpack": "^4.16.3", 21 | "webpack-cli": "^3.1.0", 22 | "webpack-dev-server": "^3.11.0" 23 | } 24 | } -------------------------------------------------------------------------------- /src/themes.js: -------------------------------------------------------------------------------- 1 | const dark_vscode_tribute = { 2 | default : '#D4D4D4', 3 | background : '#1E1E1E', 4 | background_warning : '#1E1E1E', 5 | string : '#CE8453', 6 | number : '#B5CE9F', 7 | colon : '#49B8F7', 8 | keys : '#9CDCFE', 9 | keys_whiteSpace : '#AF74A5', 10 | primitive : '#6392C6' 11 | }; 12 | 13 | const light_mitsuketa_tribute = { 14 | default : '#D4D4D4', 15 | background : '#FCFDFD', 16 | background_warning : '#FEECEB', 17 | string : '#FA7921', 18 | number : '#70CE35', 19 | colon : '#49B8F7', 20 | keys : '#59A5D8', 21 | keys_whiteSpace : '#835FB6', 22 | primitive : '#386FA4' 23 | }; 24 | 25 | const themes = { 26 | dark_vscode_tribute : dark_vscode_tribute, 27 | light_mitsuketa_tribute : light_mitsuketa_tribute 28 | }; 29 | 30 | export default themes; -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Andrew Redican 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /example/webpack-project/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const webpack = require("webpack"); 3 | const package = require("./../../package.json"); 4 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 5 | 6 | const defines = { 7 | "process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV), 8 | "process.env.VERSION": JSON.stringify(package.version) 9 | }; 10 | 11 | const config = { 12 | target: "web", 13 | mode: process.env.NODE_ENV, 14 | entry: "./src/index.js", 15 | output: { 16 | path: path.resolve(__dirname, "dist"), 17 | filename: "bundle.js" 18 | }, 19 | module: { 20 | rules: [ 21 | { 22 | test: /\.css$/, 23 | use: [{ loader: "style-loader" }, { loader: "css-loader" }] 24 | }, 25 | { 26 | test: /\.jsx?$/, 27 | exclude: /node_modules/, 28 | use: { 29 | loader: "babel-loader" 30 | } 31 | } 32 | ] 33 | }, 34 | devtool: process.env.NODE_ENV === "development" ? "eval-source-map" : false, 35 | plugins: [ 36 | new webpack.DefinePlugin(defines), 37 | new HtmlWebpackPlugin({ 38 | title: package.name + " (version " + package.version + ")", 39 | template: "./src/index.html" 40 | }) 41 | ] 42 | }; 43 | 44 | module.exports = config; 45 | -------------------------------------------------------------------------------- /test/sampleData.js: -------------------------------------------------------------------------------- 1 | const sampleData = { 2 | basic : { 3 | hello : 'world', 4 | foo : 'bar' 5 | }, 6 | common : { 7 | strings : [ 8 | 'xyz', 9 | 'This is a test', 10 | '+_)(*&^%$#@!~/|}{:?/.,;][=-`', 11 | 'This is a test with a newline\n' 12 | ], 13 | numbers : [ 0, 1, -100, -7.5, 500, 1.823 ], 14 | primitives : [false,true], 15 | escape : ['\n', '\r'] 16 | }, 17 | uncommonKeys : { 18 | true : true, 19 | false : false, 20 | undefined : 'undefined', 21 | null : 'null', 22 | '' : 0, 23 | 'compound word' : ['*'], 24 | '~!@#$%' : 'non-alphanumeric', 25 | $ : 'dollar', 26 | _ : 'underscore', 27 | '{}' : 'curly brackets', 28 | '[]' : 'square brackets', 29 | 0 : 'number', 30 | '0' : 'number-like text', 31 | A423423 : 'letter-number', 32 | '0A' : 'number-letter', 33 | 'A 4' : 'letter-space-number', 34 | '0 A' : 'number-space-letter', 35 | '0 A,&' : 'number-space-letter-nonAlphanumeric' 36 | } 37 | }; 38 | 39 | export default sampleData; 40 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | const { BABEL_ENV } = process.env; 2 | 3 | console.log("Running Babel ...", { BABEL_ENV }); 4 | 5 | const moduleSystem = (BABEL_ENV && BABEL_ENV.startsWith('modules:')) ? BABEL_ENV.substring("modules:".length) : "es"; 6 | 7 | // For the ES configuration only transpile react to valid JavaScript. 8 | // For commonjs transpile to old JS versions. 9 | const presets = moduleSystem === "es" 10 | ? ['@babel/preset-react'] 11 | : [ 12 | ['@babel/preset-env', { 13 | targets: { 14 | ie: 11, 15 | edge: 14, 16 | firefox: 45, 17 | chrome: 49, 18 | safari: 10, 19 | node: '6.11', 20 | }, 21 | modules: moduleSystem, 22 | }], 23 | '@babel/preset-react' 24 | ]; 25 | 26 | // The ES system does not polyfill etc, while the others do. 27 | const transformOptions = moduleSystem === "es" 28 | ? { 29 | helpers: true, 30 | useESModules: true 31 | } 32 | : { 33 | helpers: true, 34 | useESModules: false 35 | }; 36 | 37 | module.exports = { 38 | presets, 39 | plugins: [ 40 | '@babel/plugin-transform-object-assign', 41 | '@babel/plugin-proposal-object-rest-spread', 42 | 'babel-plugin-extensible-destructuring', 43 | ['@babel/plugin-transform-runtime', transformOptions] 44 | ], 45 | env: { 46 | production: { 47 | plugins: [ 48 | // Optimize constant react elements in the production build. (Makes debugging harder, so skip this in development) 49 | 'transform-react-constant-elements', 50 | ], 51 | ignore: ['test/*'] 52 | } 53 | }, 54 | ignore: ['scripts/*.js'] 55 | }; 56 | -------------------------------------------------------------------------------- /test/change/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import JSONInput from '../../src'; 3 | import locale from '../../src/locale/en'; 4 | 5 | function run() { 6 | test(`Update placeholder property value`, () => { 7 | let wrapper = mount( 8 | , 13 | { attachTo: window.domNode } 14 | ); 15 | expect(wrapper).toMatchSnapshot(); 16 | 17 | function checkState(componentState){ 18 | Object.keys(componentState).forEach( keyName => { 19 | expect(wrapper.state()[keyName]).toEqual(componentState[keyName]); 20 | }); 21 | } 22 | 23 | // Note: markupText not evaluated 24 | 25 | // Behavior On Component Initial Mount 26 | const intialState = { 27 | error: undefined, 28 | jsObject: undefined, 29 | json: '', 30 | lines: 4, 31 | plainText: undefined, 32 | prevPlaceholder: { 33 | valueToChange : false 34 | } 35 | }; 36 | checkState(intialState); 37 | 38 | // Behavior On Component Update with New Property 39 | wrapper.setProps({ placeholder: { valueToChange : true }}); 40 | const stateAfterPlaceholderChange = { 41 | error: undefined, 42 | jsObject: undefined, 43 | json: '', 44 | lines: 4, 45 | plainText: undefined, 46 | prevPlaceholder: { 47 | valueToChange : true 48 | } 49 | }; 50 | checkState(stateAfterPlaceholderChange); 51 | 52 | }); 53 | 54 | } 55 | 56 | export default run; -------------------------------------------------------------------------------- /example/webpack-project/src/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import ReactDOM from "react-dom"; 3 | import "./index.css"; 4 | 5 | // todo: use the imported version in prod, source in dev. 6 | /** 7 | * Import RJEA component 8 | */ 9 | 10 | //Using distribution version in node_modules 11 | import JSONInput from 'react-json-editor-ajrm'; 12 | import locale from 'react-json-editor-ajrm/locale/en'; 13 | 14 | //Using distribution version from project 15 | // import JSONInput from '../../../dist'; 16 | // import locale from '../../../dist/locale/en'; 17 | 18 | //Using source code 19 | // import JSONInput from "../../../src"; 20 | // import locale from "../../../src/locale/en"; 21 | 22 | /** 23 | * Import some data. This is a sample object, which will be passed down to JSONInput placeholder properperties. 24 | * You can use placeholder to show data once, after component has mounted. 25 | */ 26 | import sampleData from "./sampledata"; 27 | 28 | class App extends Component { 29 | constructor(props) { 30 | super(props); 31 | } 32 | render() { 33 | /** 34 | * Rendering this JSONInput component with some properties 35 | */ 36 | return ( 37 |
38 | 47 |
48 | ); 49 | } 50 | } 51 | 52 | ReactDOM.render(, document.querySelector("#app")); 53 | -------------------------------------------------------------------------------- /example/create-react-app-project/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | React App 23 | 24 | 25 | 28 |
29 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /example/create-react-app-project/src/index.js: -------------------------------------------------------------------------------- 1 | // import React from 'react'; 2 | // import ReactDOM from 'react-dom'; 3 | // import './index.css'; 4 | // import App from './App'; 5 | // import registerServiceWorker from './registerServiceWorker'; 6 | 7 | // ReactDOM.render(, document.getElementById('root')); 8 | // registerServiceWorker(); 9 | 10 | import React, { Component } from "react"; 11 | import ReactDOM from "react-dom"; 12 | import "./index.css"; 13 | 14 | // todo: use the imported version in prod, source in dev. 15 | /** 16 | * Import RJEA component 17 | */ 18 | 19 | //Using distribution version in node_modules 20 | //import JSONInput from 'react-json-editor-ajrm'; 21 | //import locale from 'react-json-editor-ajrm/locale/en'; 22 | 23 | //Using distribution version from project 24 | //import JSONInput from '../../dist'; 25 | //import locale from '../../dist/locale/en'; 26 | 27 | //Using source code 28 | import JSONInput from "react-json-editor-ajrm/index"; 29 | import locale from "react-json-editor-ajrm/locale/en"; 30 | 31 | /** 32 | * Import some data. This is a sample object, which will be passed down to JSONInput placeholder properperties. 33 | * You can use placeholder to show data once, after component has mounted. 34 | */ 35 | import sampleData from "./sampledata"; 36 | 37 | class App extends Component { 38 | render() { 39 | /** 40 | * Rendering this JSONInput component with some properties 41 | */ 42 | return ( 43 |
44 | 53 |
54 | ); 55 | } 56 | } 57 | 58 | ReactDOM.render(, document.querySelector("#root")); 59 | -------------------------------------------------------------------------------- /test/logic/locale.js: -------------------------------------------------------------------------------- 1 | import * as localeSystem from "../../src/locale"; 2 | 3 | function run() { 4 | test('Formatting with all arguments present and used', () => { 5 | const string = 'The {adjective} {color} {animal} jumps over the lazy dog.'; 6 | const result = localeSystem.format(string, { 7 | adjective: 'smart', 8 | color: 'blue', 9 | animal: 'cat' 10 | }); 11 | expect(result).toEqual("The smart blue cat jumps over the lazy dog.") 12 | }); 13 | 14 | test('Formatting with some arguments used twice', () => { 15 | const string = 'The {adjective} {color} {animal} jumps over the {adjective} dog.'; 16 | const result = localeSystem.format(string, { 17 | adjective: 'smart', 18 | color: 'blue', 19 | animal: 'cat' 20 | }); 21 | expect(result).toEqual("The smart blue cat jumps over the smart dog.") 22 | }); 23 | 24 | test('Formatting with some arguments not used', () => { 25 | const string = 'The {adjective} brown {animal} jumps over the lazy dog.'; 26 | const result = localeSystem.format(string, { 27 | adjective: 'smart', 28 | color: 'blue', 29 | animal: 'cat' 30 | }); 31 | expect(result).toEqual("The smart brown cat jumps over the lazy dog.") 32 | }); 33 | 34 | test('Formatting with some arguments missing', () => { 35 | const string = 'The {adjective} {color} {animal} jumps over the lazy dog.'; 36 | const result = localeSystem.format(string, { 37 | adjective: 'smart', 38 | color: 'blue' 39 | }); 40 | expect(result).toEqual("The smart blue {animal} jumps over the lazy dog.") 41 | }); 42 | 43 | test('Formatting with some arguments having different casing', () => { 44 | const string = 'The {aDjecTIVe} {Color} {animal} jumps over the lazy dog.'; 45 | const result = localeSystem.format(string, { 46 | AdJECtivE: 'smart', 47 | color: 'blue', 48 | Animal: 'cat' 49 | }); 50 | expect(result).toEqual("The smart blue cat jumps over the lazy dog.") 51 | }); 52 | } 53 | 54 | export default run; -------------------------------------------------------------------------------- /example/create-react-app-project/src/sampledata.js: -------------------------------------------------------------------------------- 1 | const sampleData = { 2 | "example prop": null, 3 | nancy_mccarty: { 4 | A1: { 5 | userID: "nancy_mccarty", 6 | userName: "Nancy's McCarty", 7 | id: "A1", 8 | score: "0.75", 9 | date_created: 151208443563, 10 | date_signed: 151208448055, 11 | date_approved: 151208471190, 12 | answers: [ 13 | { 14 | Q1 : true, 15 | Q2 : false 16 | }, 17 | { 18 | Q34 : 'This is an answer', 19 | Q35 : false 20 | } 21 | ] 22 | }, 23 | A2: { 24 | userID: "nancy_mccarty", 25 | userName: "Nancy McCarty", 26 | id: "A2", 27 | score: 0.9, 28 | date_created: 151208450090, 29 | date_signed: false, 30 | date_approved: false, 31 | answers: ["No", "No", "No", "Yes", "Yes"] 32 | } 33 | }, 34 | george_richardson: { 35 | A2: { 36 | userID: "george_richardson", 37 | userName: "George Richardson", 38 | id: "A2", 39 | score: 0.35, 40 | date_created: 1512076585058, 41 | date_signed: false, 42 | date_approved: false, 43 | answers: ["No", "Yes", "Yes", "Yes", "Yes"] 44 | } 45 | }, 46 | tom_hughe: { 47 | A4: { 48 | userID: "tom_hughe", 49 | userName: "Tom Hughe", 50 | id: "A4", 51 | score: 0.75, 52 | date_created: 1512076575026, 53 | date_signed: 1512076609894, 54 | date_approved: false, 55 | answers: ["Yes", "No", "No", "Yes", "No"] 56 | }, 57 | M1: { 58 | userID: "tom_hughe", 59 | userName: "Tom Hughe", 60 | id: "M1", 61 | score: false, 62 | date_created: 1512076587361, 63 | date_signed: false, 64 | date_approved: false, 65 | answers: [false, false, false, false, false] 66 | } 67 | }, 68 | heidy_white: { 69 | L2: { 70 | userID: "heidy_white", 71 | userName: "Heidy White", 72 | id: "L2", 73 | score: false, 74 | date_created: 15120765766312, 75 | date_signed: false, 76 | date_approved: false, 77 | answers: [0, 1, 2, 3, 4] 78 | } 79 | } 80 | }; 81 | 82 | export default sampleData; 83 | -------------------------------------------------------------------------------- /scripts/copy-files.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const fse = require('fs-extra'); 3 | const glob = require('glob'); 4 | 5 | async function copyFile(file) { 6 | const distPath = path.resolve(__dirname, '../dist/', path.basename(file)); 7 | await fse.copy(file, distPath); 8 | console.log(`Copied ${file} to ${distPath}`); 9 | } 10 | 11 | function typescriptCopy(from, to) { 12 | const files = glob.sync('**/*.d.ts', { cwd: from }); 13 | const cmds = files.map(file => fse.copy(path.resolve(from, file), path.resolve(to, file))); 14 | return Promise.all(cmds); 15 | } 16 | 17 | async function createPackageFile() { 18 | const packageData = await fse.readFile(path.resolve(__dirname, '../package.json'), 'utf8'); 19 | const { jest, scripts, devDependencies, ...packageDataOther } = JSON.parse( 20 | packageData, 21 | ); 22 | const newPackageData = { 23 | ...packageDataOther, 24 | main: './index.js', 25 | module: './es/index.js', 26 | private: false, 27 | }; 28 | const distPath = path.resolve(__dirname, '../dist/package.json'); 29 | 30 | await fse.writeFile(distPath, JSON.stringify(newPackageData, null, 2), 'utf8'); 31 | console.log(`Created package.json in ${distPath}`); 32 | 33 | return newPackageData; 34 | } 35 | 36 | async function prepend(file, string) { 37 | const data = await fse.readFile(file, 'utf8'); 38 | await fse.writeFile(file, string + data, 'utf8'); 39 | } 40 | 41 | async function addLicense(packageData) { 42 | const license = `/** @license ${packageData.name} v${packageData.version} 43 | * 44 | * This source code is licensed under the ${packageData.license} license found in the 45 | * LICENSE file in the root directory of this source tree. 46 | */ 47 | `; 48 | await Promise.all( 49 | [ 50 | '../dist/index.js', 51 | '../dist/es/index.js', 52 | ].map(file => prepend(path.resolve(__dirname, file), license)), 53 | ); 54 | } 55 | 56 | async function run() { 57 | await Promise.all( 58 | ['./README.md', './CHANGELOG.md', './LICENSE.md'].map(file => copyFile(file)), 59 | ); 60 | const packageData = await createPackageFile(); 61 | await addLicense(packageData); 62 | 63 | // TypeScript - We don't have any typescript definitions yet, but if someone wants to add them, this will make our life easier. 64 | const from = path.resolve(__dirname, '../src'); 65 | await Promise.all([ 66 | typescriptCopy(from, path.resolve(__dirname, '../dist')), 67 | typescriptCopy(from, path.resolve(__dirname, '../dist/es')), 68 | ]); 69 | } 70 | 71 | run(); 72 | -------------------------------------------------------------------------------- /example/webpack-project/src/sampledata.js: -------------------------------------------------------------------------------- 1 | const sampleData = { 2 | 'example prop' : null, 3 | nancy_mccarty : { 4 | A1: { 5 | userID: "nancy_mccarty", 6 | userName: "Nancy's McCarty", 7 | id : "A1", 8 | score : '0.75', 9 | date_created : 151208443563, 10 | date_signed : 151208448055, 11 | date_approved: 151208471190, 12 | answers: [ 13 | { 14 | Q1 : true, 15 | Q2 : false 16 | }, 17 | { 18 | Q34 : 'This is an answer', 19 | Q35 : false 20 | } 21 | ] 22 | }, 23 | A2: { 24 | userID: "nancy_mccarty", 25 | userName: "Nancy McCarty", 26 | id : "A2", 27 | score : 0.9, 28 | date_created : 151208450090, 29 | date_signed : false, 30 | date_approved: false, 31 | answers: ['No','No','No','Yes','Yes'] 32 | } 33 | }, 34 | george_richardson : { 35 | A2: { 36 | userID: "george_richardson", 37 | userName: "George Richardson", 38 | id : "A2", 39 | score : 0.35, 40 | date_created : 1512076585058, 41 | date_signed : false, 42 | date_approved: false, 43 | answers: ['No','Yes','Yes','Yes','Yes'] 44 | } 45 | }, 46 | tom_hughe : { 47 | A4: { 48 | userID: "tom_hughe", 49 | userName: "Tom Hughe", 50 | id : "A4", 51 | score : 0.75, 52 | date_created : 1512076575026, 53 | date_signed : 1512076609894, 54 | date_approved: false, 55 | answers: ['Yes','No','No','Yes','No'] 56 | }, 57 | M1: { 58 | userID: "tom_hughe", 59 | userName: "Tom Hughe", 60 | id : "M1", 61 | score : false, 62 | date_created : 1512076587361, 63 | date_signed : false, 64 | date_approved: false, 65 | answers: [false,false,false,false,false] 66 | } 67 | }, 68 | heidy_white : { 69 | L2: { 70 | userID: "heidy_white", 71 | userName: "Heidy White", 72 | id : "L2", 73 | score : false, 74 | date_created : 15120765766312, 75 | date_signed : false, 76 | date_approved: false, 77 | answers: [0, 1, 2, 3, 4] 78 | } 79 | } 80 | }; 81 | 82 | export default sampleData; -------------------------------------------------------------------------------- /example/create-react-app-project/src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /test/render/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import JSONInput from '../../src'; 3 | import locale from '../../src/locale/en' 4 | import sampleData from "./../sampleData"; 5 | 6 | const sampleFunctions = { 7 | getResults: function (data) { 8 | console.log(data); 9 | }, 10 | modWarning: function (text) { 11 | return text; 12 | } 13 | }; 14 | 15 | function run() { 16 | test(`Basic Component Render`, () => { 17 | let wrapper = mount( 18 | , 21 | { attachTo: window.domNode } 22 | ); 23 | expect(wrapper).toMatchSnapshot(); 24 | }); 25 | 26 | test(`All Component Properties Render [1]`, () => { 27 | let wrapper = mount( 28 | , 53 | { attachTo: window.domNode } 54 | ); 55 | expect(wrapper).toMatchSnapshot(); 56 | }); 57 | 58 | test(`All Component Properties Render [2]`, () => { 59 | let wrapper = mount( 60 | , 85 | { attachTo: window.domNode } 86 | ); 87 | expect(wrapper).toMatchSnapshot(); 88 | }); 89 | 90 | test(`Custom Error Render`, () => { 91 | let wrapper = mount( 92 | , 97 | { attachTo: window.domNode } 98 | ); 99 | expect(wrapper).toMatchSnapshot(); 100 | }); 101 | } 102 | 103 | export default run; 104 | -------------------------------------------------------------------------------- /src/locale/zh-cn.js: -------------------------------------------------------------------------------- 1 | export default { 2 | format: "{reason} 位于第 {line} 行", 3 | symbols: { 4 | colon: "冒号", // : 5 | comma: "逗号", // , ، 、 6 | semicolon: "分号", // ; 7 | slash: "反斜杠", // / relevant for comment syntax support 8 | backslash: "正斜杠", // \ relevant for escaping character 9 | brackets: { 10 | round: "圆括号", // ( ) 11 | square: "方括号", // [ ] 12 | curly: "大括号", // { } 13 | angle: "尖括号" // < > 14 | }, 15 | period: "句号", // . Also known as full point, full stop, or dot 16 | quotes: { 17 | single: "单引号", // ' 18 | double: "双引号", // " 19 | grave: "反引号" // ` used on Javascript ES6 Syntax for String Templates 20 | }, 21 | space: "空格", //     22 | ampersand: "符号&", // & 23 | asterisk: "符号*", // * relevant for some comment sytanx 24 | at: "符号@", // @ multiple uses in other coding languages including certain data types 25 | equals: "符号=", // = 26 | hash: "符号#", // # 27 | percent: "百分号", // % 28 | plus: "加号", // + 29 | minus: "减号", // − 30 | dash: "破折号", // − 31 | hyphen: "连字符", // − 32 | tilde: "波浪号", // ~ 33 | underscore: "下划线", // _ 34 | bar: "竖线", // | 35 | }, 36 | types: { 37 | key: "key", 38 | value: "value", 39 | number: "number", 40 | string: "string", 41 | primitive: "primitive", 42 | boolean: "boolean", 43 | character: "character", 44 | integer: "integer", 45 | array: "array", 46 | float: "float" 47 | //... Reference: https://en.wikipedia.org/wiki/List_of_data_structures 48 | }, 49 | invalidToken: { 50 | tokenSequence: { 51 | prohibited: "'{firstToken}' 不能位于 '{secondToken}'之后", 52 | permitted: "'{firstToken}' 只能位于 '{secondToken}'之后" 53 | }, 54 | termSequence: { 55 | prohibited: " {firstTerm} 不能位于{secondTerm} 之后", 56 | permitted: " {firstTerm} 只能位于{secondTerm} 之后" 57 | }, 58 | double: "'{token}' 不能位于另一个 '{token}' 之后", 59 | useInstead: "'{badToken}' 不被接受. 使用 '{goodToken}' 替代", 60 | unexpected: "出乎意料的 '{token}' " 61 | }, 62 | brace: { 63 | curly: { 64 | missingOpen: "无法找到 '{' ", 65 | missingClose: "无法找到 '}' ", 66 | cannotWrap: "'{token}' 无法被包含在 '{}' 中" 67 | }, 68 | square: { 69 | missingOpen: "无法找到 '[' ", 70 | missingClose: "无法找到 ']' ", 71 | cannotWrap: "'{token}' 无法被包含在 '[]' 中" 72 | } 73 | }, 74 | string: { 75 | missingOpen: "无法找到/无效的 前缀 '{quote}' ", 76 | missingClose: "无法找到/无效的 后缀 '{quote}' ", 77 | mustBeWrappedByQuotes: "字符串必须用引号括起来", 78 | nonAlphanumeric: "非数字字符 '{token}' 无法使用外部字符串表示法", 79 | unexpectedKey: "在字符串位置找到意外键" 80 | }, 81 | key: { 82 | numberAndLetterMissingQuotes: "用数字和字母包含的开头必须用引号括起来.", 83 | spaceMissingQuotes: "包含关键字的空间必须用引号括起来.", 84 | unexpectedString: "在关键位置发现意外字符串." 85 | }, 86 | noTrailingOrLeadingComma: "不允许在数组和对象中拖尾或引导逗号." 87 | }; 88 | -------------------------------------------------------------------------------- /test/logic/testSyntaxLogic.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import JSONInput from '../../src'; 3 | import locale from '../../src/locale/en' 4 | import err from './../err'; 5 | import { deepRemoveAll_Key } from 'mitsuketa'; 6 | 7 | function removeKeys(identity={},keys=[]){ 8 | let newIdentity = identity; 9 | keys.forEach( keyName => { newIdentity = deepRemoveAll_Key(newIdentity,keyName); }); 10 | return newIdentity; 11 | }; 12 | 13 | function createElementFromHTML(htmlString='') { 14 | var span = document.createElement('span'); 15 | span.setAttribute('id','AJRM-JSON-EDITOR--unique_string-content-box'); 16 | span.innerHTML = htmlString.trim(); 17 | return span; 18 | }; 19 | 20 | function testSyntaxLogic(language='JS',scope,input,output){ 21 | err.isNotType('language',language,'string'); 22 | err.isNotType('scope',scope,'string'); 23 | err.isNotType('output',output,'object'); 24 | err.isUndefined('input',input); 25 | 26 | let markup; 27 | 28 | 29 | 30 | test(`[${language}] SYNTAX LOGIC for DATA INDENTITY with ${scope}`, () => { 31 | 32 | const 33 | wrapper = shallow( 34 | , 37 | { attachTo: window.domNode } 38 | ), 39 | results = wrapper.instance().tokenize(input), 40 | trimmedResults = removeKeys(results,['indented','markup']); 41 | markup = results.markup; 42 | expect(trimmedResults).toEqual(output); 43 | }); 44 | 45 | 46 | 47 | test(`[${language}] SYNTAX LOGIC for DOM NODE with ${scope}`, () => { 48 | 49 | function trimMarkupBasedResults(results){ 50 | let newResults = removeKeys(results,['indented','markup','error']); 51 | newResults = { 52 | ...newResults, 53 | tokens : (tokens => { 54 | tokens = removeKeys(tokens,['tokens']); 55 | let 56 | noWhiteSpaceTokens = [], 57 | noColonTypeTokens = []; 58 | tokens.forEach( token => { if(['space','linebreak'].indexOf(token.type)===-1) noWhiteSpaceTokens.push(token); }); 59 | noColonTypeTokens = noWhiteSpaceTokens.map( token => { 60 | if(token.type!=='colon') return token; 61 | return { ...token, type : 'symbol' }; 62 | }); 63 | return noColonTypeTokens; 64 | })(newResults.tokens) 65 | }; 66 | return newResults; 67 | }; 68 | 69 | const 70 | wrapper = shallow( 71 | , 74 | { attachTo: window.domNode } 75 | ), 76 | results = wrapper.instance().tokenize(createElementFromHTML(markup)), 77 | trimmedResults = trimMarkupBasedResults(results), 78 | trimmeOutput = removeKeys(output,['depth','value']); 79 | if(results.error) console.log({ error : results.error }); 80 | expect(trimmedResults).toEqual(trimmeOutput); 81 | }); 82 | 83 | }; 84 | 85 | export default testSyntaxLogic; 86 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at andrew.redican.mejia@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /src/locale/pt.js: -------------------------------------------------------------------------------- 1 | export default { 2 | format: "{reason} na linha {line}", 3 | symbols: { 4 | colon: "dois pontos", 5 | comma: "vírgula", 6 | semicolon: "ponto e vírgula", 7 | slash: "barra", 8 | backslash: "barra inversa", 9 | brackets: { 10 | round: "parênteses", 11 | square: "colchetes", 12 | curly: "chaves", 13 | angle: "colchetes angulares" 14 | }, 15 | period: "ponto", 16 | quotes: { 17 | single: "aspas simples", 18 | double: "aspas duplas", 19 | grave: "acento agudo" 20 | }, 21 | space: "espaço",   22 | ampersand: "e comercial", 23 | asterisk: "asterisco", 24 | at: "arroba", 25 | equals: "sinal de igual", 26 | hash: "jogo da velha", 27 | percent: "porcentagem", 28 | plus: "sinal de mais", 29 | minus: "sinal de menos", 30 | dash: "traço", 31 | hyphen: "hífen", 32 | tilde: "acento til", 33 | underscore: "travessão", 34 | bar: "barra vertical", 35 | }, 36 | types: { 37 | key: "chave", 38 | value: "valor", 39 | number: "número", 40 | string: "sequência de caracteres", 41 | primitive: "primitivo", 42 | boolean: "booleano", 43 | character: "caracter", 44 | integer: "inteiro", 45 | array: "vetor", 46 | float: "decimal" 47 | }, 48 | invalidToken: { 49 | tokenSequence: { 50 | prohibited: "O token '{firstToken}' não pode ser seguido do token '{secondToken}'", 51 | permitted: "O token '{firstToken}' apenas pode ser seguido pelo token '{secondToken}'" 52 | }, 53 | termSequence: { 54 | prohibited: "O termo '{firstTerm}' não pode ser seguido do termo '{secondTerm}'", 55 | permitted: "O termo '{firstTerm}' apenas pode ser seguido pelo termo '{secondTerm}'" 56 | }, 57 | double: "O token '{token}' não pode ser seguido por outro token '{token}'", 58 | useInstead: "O token '{badToken}' não é permitido. Use o token '{goodToken}' em seu lugar", 59 | unexpected: "O token '{token}' não foi encontrado" 60 | }, 61 | brace: { 62 | curly: { 63 | missingOpen: "Falta a chave de abrir '{'", 64 | missingClose: "A chave de abrir '{' não contém a chave de fechar '}'", 65 | cannotWrap: "O token '{token}' não pode estar dentro de '{}' chaves" 66 | }, 67 | square: { 68 | missingOpen: "Falta o colchete de abrir '['", 69 | missingClose: "O colchete de abrir '[' não contém o colchete de fechar ']'", 70 | cannotWrap: "O token '{token}' não pode estar dentro de '[]' colchetes" 71 | } 72 | }, 73 | string: { 74 | missingOpen: "Citação de abertura ausente/inválida na string' {quote}'", 75 | missingClose: "Citação de fechar ausente/inválida na string' {quote}'", 76 | mustBeWrappedByQuotes: "Strings devem estar entre citações", 77 | nonAlphanumeric: "O token não-alfanumerico '{token}' não é permitido fora de uma string", 78 | unexpectedKey: "Chave inesperada encontrada na posição de um valor de string" 79 | }, 80 | key: { 81 | numberAndLetterMissingQuotes: "A chave que começa com o número e contém letras deve estar entre citações", 82 | spaceMissingQuotes: "A chave contendo espaço deve estar entre citações", 83 | unexpectedString: "String inesperada encontrada na posição de uma chave" 84 | }, 85 | noTrailingOrLeadingComma: "Vírgulas adjacentes não são permitidas em listas ou objetos" 86 | }; -------------------------------------------------------------------------------- /src/locale/es.js: -------------------------------------------------------------------------------- 1 | export default { 2 | format: "{reason} en la línea {line}", 3 | symbols: { 4 | colon: "dos puntos", 5 | comma: "coma", 6 | semicolon: "punto y coma", 7 | slash: "barra oblicua", 8 | backslash: "barra invertida", 9 | brackets: { 10 | round: "paréntesis", 11 | square: "corchetes", 12 | curly: "llaves", 13 | angle: "paréntesis angulares" 14 | }, 15 | period: "punto", 16 | quotes: { 17 | single: "comillas simples", 18 | double: "comillas dobles", 19 | grave: "acento grave" 20 | }, 21 | space: "espacio",   22 | ampersand: "et", 23 | asterisk: "asterisco", 24 | at: "arroba", 25 | equals: "signo igual", 26 | hash: "almohadilla", 27 | percent: "porcentaje", 28 | plus: "signo más", 29 | minus: "signo menos", 30 | dash: "raya", 31 | hyphen: "guion", 32 | tilde: "tilde", 33 | underscore: "guion bajo", 34 | bar: "pleca", 35 | }, 36 | types: { 37 | key: "llave", 38 | value: "valor", 39 | number: "número", 40 | string: "cedena", 41 | primitive: "dato primitivo", 42 | boolean: "booleano", 43 | character: "carácter", 44 | integer: "número entero", 45 | array: "colección", 46 | float: "número flotante" 47 | }, 48 | invalidToken: { 49 | tokenSequence: { 50 | prohibited: "La ficha '{firstToken}' no puede ser seguida por fichas '{secondToken}'", 51 | permitted: "'La ficha {firstToken}' solo puede ser seguida por fichas '{secondToken}'" 52 | }, 53 | termSequence: { 54 | prohibited: "A {firstTerm} cannot be followed by a {secondTerm}", 55 | permitted: "A {firstTerm} can only be followed by a {secondTerm}" 56 | }, 57 | double: "'La ficha {token}' no puede ser seguida por otra ficha '{token}'", 58 | useInstead: "La ficha '{badToken}' no se permite. Utiliza '{goodToken}' en su lugar", 59 | unexpected: "Ficha inesperada '{token}'" 60 | }, 61 | brace: { 62 | curly: { 63 | missingOpen: "Falta llave de apertura '{'", 64 | missingClose: "Llave de apertura '{' carece de una llave de cierre '}'", 65 | cannotWrap: "La ficha '{token}' no puede ser envuelta por llaves '{}'" 66 | }, 67 | square: { 68 | missingOpen: "Falta corchete de apertura '['", 69 | missingClose: "Corchete de apertura '[' carece de un corchete de cierre ']'", 70 | cannotWrap: "La ficha '{token}' no puede ser envuelta por corchetes '[]'" 71 | } 72 | }, 73 | string: { 74 | missingOpen: "Faltan comillas de apertura para valor string, o carácter invalido '{quote}'", 75 | missingClose: "Faltan comillas de cierre para valor string, o carácter invalido '{quote}'", 76 | mustBeWrappedByQuotes: "Strings deben estar entre comillas", 77 | nonAlphanumeric: "Ficha no-alphanemerica '{token}' no esta permitida fuera de un string", 78 | unexpectedKey: "Ficha inesperada en la posición de un valor string" 79 | }, 80 | key: { 81 | numberAndLetterMissingQuotes: "Los nombres de propiedad que comienzan con números y contienen letras deben estar entre comillas", 82 | spaceMissingQuotes: "Los nombres de propiedad que contienen espacios deben estar entre comillas", 83 | unexpectedString: "Ficha inesperada de tipo string en la posicion de un nombre de propiedad" 84 | }, 85 | noTrailingOrLeadingComma: "No se permiten comas contiguas dentro de listas u objetos" 86 | }; -------------------------------------------------------------------------------- /src/locale/jpn.js: -------------------------------------------------------------------------------- 1 | export default { 2 | format: "{reason} ラインで {line}", 3 | symbols: { 4 | colon: "結腸", // : 5 | comma: "コンマ", // , 6 | semicolon: "セミコロン", // ; 7 | slash: "スラッシュ", // / relevant for comment syntax support 8 | backslash: "バックスラッシュ", // \ relevant for escaping character 9 | brackets: { 10 | round: "丸括弧", // ( ) 11 | square: "角括弧", // [ ] 12 | curly: "中括弧", // { } 13 | angle: "アングルブラケット" // < > 14 | }, 15 | period: "期間", // . Also known as full point, full stop, or dot 16 | quotes: { 17 | single: "一重引用符", // ' 18 | double: "二重引用符", // " 19 | grave: "深刻な引用" // ` used on Javascript ES6 Syntax for String Templates 20 | }, 21 | space: "スペース", //     22 | ampersand: "アンパサンド", // & 23 | asterisk: "アスタリスク", // * relevant for some comment sytanx 24 | at: "〜で", // @ multiple uses in other coding languages including certain data types 25 | equals: "等しい", // = 26 | hash: "ハッシュ", // # 27 | percent: "パーセント", // % 28 | plus: "プラス", // + 29 | minus: "マイナス", // − 30 | dash: "ダッシュ", // - 31 | hyphen: "ハイフン", // − 32 | tilde: "チルダ", // ~ 33 | underscore: "アンダースコア", // _ 34 | bar: "バー", // | 35 | }, 36 | types: { 37 | key: "キー", 38 | value: "値", 39 | number: "数", 40 | string: "文字列", 41 | primitive: "プリミティブ", 42 | boolean: "ブール値", 43 | character: "キャラクター", 44 | integer: "整数", 45 | array: "アレイ", 46 | float: "浮く" 47 | //... Reference: https://en.wikipedia.org/wiki/List_of_data_structures 48 | }, 49 | invalidToken: { 50 | tokenSequence: { 51 | prohibited: "'{firstToken}'トークンの後に '{secondToken}'トークンを続けることはできません", 52 | permitted: "'{firstToken}'トークンの後には '{secondToken}'トークンしか続けることができません" 53 | }, 54 | termSequence: { 55 | prohibited: "{firstTerm}の後に{secondTerm}を続けることはできません。", 56 | permitted: "{firstTerm}には必ず{secondTerm}が続かなければなりません。" 57 | }, 58 | double: "'{token}'トークンの後に別の '{token}'トークンを続けることはできません", 59 | useInstead: "'{badToken}'トークンは受け入れられません。 代わりに '{goodToken}'を使用してください", 60 | unexpected: "予期しない '{token}'トークンが見つかりました" 61 | }, 62 | brace: { 63 | curly: { 64 | missingOpen: "行方不明の '{' 開いた中かっこ", 65 | missingClose: "'{'中括弧は閉じた中括弧で閉じられていません '}'", 66 | cannotWrap: "'{token}'トークンを '{}'の中括弧で囲むことはできません" 67 | }, 68 | square: { 69 | missingOpen: "行方不明の '['角かっこ ", 70 | missingClose: "開く '['角括弧が欠けています ']'角括弧", 71 | cannotWrap: "'{token}'トークンを '[]'角カッコで囲むことはできません" 72 | } 73 | }, 74 | string: { 75 | missingOpen: "開始文字列 '{quote}'トークンがない/無効です", 76 | missingClose: "閉じた文字列 '{quote}'トークンがないか無効です", 77 | mustBeWrappedByQuotes: "文字列は引用符で囲む必要があります", 78 | nonAlphanumeric: "英数字以外のトークン '{token}'は文字列表記の外側では使用できません", 79 | unexpectedKey: "文字列の位置で予期しないキーが見つかり" 80 | }, 81 | key: { 82 | numberAndLetterMissingQuotes: "数字で始まり、文字を含むキーは引用符で囲む必要があります", 83 | spaceMissingQuotes: "スペースを含むキーは引用符で囲む必要があります", 84 | unexpectedString: "キー位置で予期しない文字列が見つかりました" 85 | 86 | }, 87 | noTrailingOrLeadingComma: "配列やオブジェクトの先頭や末尾にコンマをつけることはできません" 88 | }; 89 | -------------------------------------------------------------------------------- /src/locale/fr.js: -------------------------------------------------------------------------------- 1 | export default { 2 | format: "{reason} à la ligne {line}", 3 | symbols: { 4 | colon: "deux points", 5 | comma: "virgule", 6 | semicolon: "point-virgule", 7 | slash: "barre oblique", 8 | backslash: "barra oblique inversée", 9 | brackets: { 10 | round: "parenthèses", 11 | square: "crochets", 12 | curly: "accolades", 13 | angle: "chevrons" 14 | }, 15 | period: "point", 16 | quotes: { 17 | single: "guillemets simples", 18 | double: "guillemets doubles", 19 | grave: "accent grave" 20 | }, 21 | space: "espace",   22 | ampersand: "esperluette", 23 | asterisk: "astérisque", 24 | at: "arobase", 25 | equals: "signe égal", 26 | hash: "croisillon", 27 | percent: "pourcentage", 28 | plus: "signe plus", 29 | minus: "signe moins", 30 | dash: "tiret", 31 | hyphen: "trait d'union", 32 | tilde: "tilde", 33 | underscore: "tiret bas", 34 | bar: "barre verticale", 35 | }, 36 | types: { 37 | key: "clé", 38 | value: "valeur", 39 | number: "nombre", 40 | string: "chaine de caractères", 41 | primitive: "donnée primitive", 42 | boolean: "booléen", 43 | character: "caractère", 44 | integer: "entier", 45 | array: "collection", 46 | float: "nombre flottant" 47 | }, 48 | invalidToken: { 49 | tokenSequence: { 50 | prohibited: " Le signe '{firstToken}' ne peut être suivi par le(s) signe(s) '{secondToken}'", 51 | permitted: "Le signe '{firstToken}' peut seulement être suivi du(des) signe(s) '{secondToken}'" 52 | }, 53 | termSequence: { 54 | prohibited: "Un {firstTerm} ne peut pas être suivi d'un {secondTerm}", 55 | permitted: "Un {firstTerm} peut seulement être suivi d'un {secondTerm}" 56 | }, 57 | double: "Le signe '{token}' ne peut être suivi par un autre signe '{token}'", 58 | useInstead: "Le signe '{badToken}' n'est pas accepté. Utilisez '{goodToken}' à la place", // Using polite "you" (Utilisez/Use) 59 | unexpected: "Signe '{token}' inattendu trouvé" 60 | }, 61 | brace: { 62 | curly: { 63 | missingOpen: "Accolade ouvrante '{' manquante", 64 | missingClose: "Accolade fermante '}' manquant à une accolade ouvrante '{'", 65 | cannotWrap: "Le signe '{token}' ne peut être entouré par des '{}' accolades" 66 | }, 67 | square: { 68 | missingOpen: "Crochets ouvrants '[' manquants", 69 | missingClose: "Crochets fermants ']' manquant à des crochets ouvrants '['", 70 | cannotWrap: "Le signe '{token}' ne peut être entouré par des '[]' crochets" 71 | } 72 | }, 73 | string: { 74 | missingOpen: "Signe ouvrant la chaine de caractères '{quote}' manquant/invalide", 75 | missingClose: "Signe fermant la chaine de caractères '{quote}' manquant/invalide", 76 | mustBeWrappedByQuotes: "Les chaine de caractères doivent être entourées par des guillemets", 77 | nonAlphanumeric: "Le signe non-alphanumerique '{token}' n'est pas autorisé en dehors des chaines de caractères", 78 | unexpectedKey: "Clé inattendue trouvée à la place d'une chaine de caractère" 79 | }, 80 | key: { 81 | numberAndLetterMissingQuotes: "Les clés commençant avec un nombre et contenant des lettres doivent être entourées par des guillemets", 82 | spaceMissingQuotes: "Les clés contenant des espaces doivent être entourées par des guillemets", 83 | unexpectedString: "Chaine de caractère inattendue trouvée à la place d'une clé" 84 | }, 85 | noTrailingOrLeadingComma: "Les virgules initiales ou finales ne sont pas autorisées dans les collections et objets" 86 | }; 87 | -------------------------------------------------------------------------------- /src/locale/de.js: -------------------------------------------------------------------------------- 1 | export default { 2 | format: "{reason} in Zeile {line}", 3 | symbols: { 4 | colon: "Doppelpunkt", 5 | comma: "Komma", 6 | semicolon: "Semikolon", 7 | slash: "Schrägstrich", 8 | backslash: "Backslash", 9 | brackets: { 10 | round: "runde Klammern", 11 | square: "eckige Klammern", 12 | curly: "geschweifte Klammern", 13 | angle: "spitze Klammern" 14 | }, 15 | period: "Punkt", 16 | quotes: { 17 | single: "einfache Anführungszeichen", 18 | double: "doppelte Anführungszeichen", 19 | grave: "Gravis-Akzente" 20 | }, 21 | space: "Leerzeichen",   22 | ampersand: "Et-Zeichen", 23 | asterisk: "Sternchen", 24 | at: "At-Zeichen", 25 | equals: "Gleichheitszeichen", 26 | hash: "Doppelkreuz", 27 | percent: "Prozentzeichen", 28 | plus: "Pluszeichen", 29 | minus: "Minuszeichen", 30 | dash: "Halbgeviertstrich", 31 | hyphen: "Viertelgeviertstrich", 32 | tilde: "Tilde", 33 | underscore: "Unterstrich", 34 | bar: "senkrechter Strich", 35 | }, 36 | types: { 37 | key: "Zeichenerklärung", 38 | value: "Wert", 39 | number: "Zahl", 40 | string: "Zeichenkette", 41 | primitive: "primitiver Wert", 42 | boolean: "boolescher Wert", 43 | character: "Schriftzeichen", 44 | integer: "ganze Zahl", 45 | array: "Feld", // <- This translation is the Java term, there is probably a better translation 46 | float: "Kommazahl" 47 | }, 48 | invalidToken: { 49 | tokenSequence: { 50 | prohibited: "'{firstToken}' Zeichen kann nicht von '{secondToken}' Zeichen gefolgt werden", 51 | permitted: "'{firstToken}' Zeichen kann nur von '{secondToken}' Zeichen gefolgt werden" 52 | }, 53 | termSequence: { 54 | prohibited: "'{firstTerm}' kann nicht nicht von '{secondTerm}' gefolgt werden", 55 | permitted: "'{firstTerm}' kann nur von '{secondTerm}' gefolgt werden" 56 | }, 57 | double: "'{token}' Zeichen kann nicht von einem weiteren '{token}' Zeichen gefolgt werden", 58 | useInstead: "'{badToken}' Zeichen ist nicht akzeptiert. '{goodToken}' ist stattdessen zu verwenden", 59 | unexpected: "Unerwartetes '{token}' Zeichen gefunden" 60 | }, 61 | brace: { 62 | curly: { 63 | missingOpen: "Fehlende '{' geöffnete geschweifte Klammer", 64 | missingClose: "Geöffneter '{' geschweifte Klammer fehlt schließende '}' geschweifte Klammer", 65 | cannotWrap: "'{token}' Zeichen kann nicht von '{}' geschweiften Klammern umschlossen werden" 66 | }, 67 | square: { 68 | missingOpen: "Fehlende '[' geöffnete eckige Klammer", 69 | missingClose: "Geöffneter '[' eckige Klammer fehlt schließende ']' eckige Klammer", 70 | cannotWrap: "'{token}' Zeichen kann nicht von '[]' eckigen Klammern umschlossen werden" 71 | } 72 | }, 73 | string: { 74 | missingOpen: "Fehlendes/Ungültiges '{quote}' Zeichen um Zeichenkette zu starten", 75 | missingClose: "Fehlendes/Ungültiges '{quote}' Zeichen um Zeichenkette zu schließen", 76 | mustBeWrappedByQuotes: "Zeichenketten müssen von Anführungszeichen umschlossen sein", 77 | nonAlphanumeric: "Nicht-Alphanumerische Zeichen '{token}' sind nicht außerhalb der Zeichenketten-Notation erlaubt", 78 | unexpectedKey: "Unerwarteter Schlüssel in Zeichenkette gefunden" 79 | }, 80 | key: { 81 | numberAndLetterMissingQuotes: "Schlüssel welche mit Zahlen anfangen und andere Alphanumerische Zeichen beinhalten müssen von Anführungszeichen umschlossen sein", 82 | spaceMissingQuotes: "Schlüssel mit Leerzeichen müssen von Anführungszeichen umschlossen sein", 83 | unexpectedString: "Unerwartete Zeichenkette in Schlüssel gefunden" 84 | }, 85 | noTrailingOrLeadingComma: "Anführende oder Anschließende Kommas sind in Arrays und Objekten nicht erlaubt" 86 | }; -------------------------------------------------------------------------------- /src/locale/en.js: -------------------------------------------------------------------------------- 1 | export default { 2 | format: "{reason} at line {line}", 3 | symbols: { 4 | colon: "colon", // : 5 | comma: "comma", // , ، 、 6 | semicolon: "semicolon", // ; 7 | slash: "slash", // / relevant for comment syntax support 8 | backslash: "backslash", // \ relevant for escaping character 9 | brackets: { 10 | round: "round brackets", // ( ) 11 | square: "square brackets", // [ ] 12 | curly: "curly brackets", // { } 13 | angle: "angle brackets" // < > 14 | }, 15 | period: "period", // . Also known as full point, full stop, or dot 16 | quotes: { 17 | single: "single quote", // ' 18 | double: "double quote", // " 19 | grave: "grave accent" // ` used on Javascript ES6 Syntax for String Templates 20 | }, 21 | space: "space", //     22 | ampersand: "ampersand", // & 23 | asterisk: "asterisk", // * relevant for some comment sytanx 24 | at: "at sign", // @ multiple uses in other coding languages including certain data types 25 | equals: "equals sign", // = 26 | hash: "hash", // # 27 | percent: "percent", // % 28 | plus: "plus", // + 29 | minus: "minus", // − 30 | dash: "dash", // − 31 | hyphen: "hyphen", // − 32 | tilde: "tilde", // ~ 33 | underscore: "underscore", // _ 34 | bar: "vertical bar", // | 35 | }, 36 | types: { 37 | key: "key", 38 | value: "value", 39 | number: "number", 40 | string: "string", 41 | primitive: "primitive", 42 | boolean: "boolean", 43 | character: "character", 44 | integer: "integer", 45 | array: "array", 46 | float: "float" 47 | //... Reference: https://en.wikipedia.org/wiki/List_of_data_structures 48 | }, 49 | invalidToken: { 50 | tokenSequence: { 51 | prohibited: "'{firstToken}' token cannot be followed by '{secondToken}' token(s)", 52 | permitted: "'{firstToken}' token can only be followed by '{secondToken}' token(s)" 53 | }, 54 | termSequence: { 55 | prohibited: "A {firstTerm} cannot be followed by a {secondTerm}", 56 | permitted: "A {firstTerm} can only be followed by a {secondTerm}" 57 | }, 58 | double: "'{token}' token cannot be followed by another '{token}' token", 59 | useInstead: "'{badToken}' token is not accepted. Use '{goodToken}' instead", 60 | unexpected: "Unexpected '{token}' token found" 61 | }, 62 | brace: { 63 | curly: { 64 | missingOpen: "Missing '{' open curly brace", 65 | missingClose: "Open '{' curly brace is missing closing '}' curly brace", 66 | cannotWrap: "'{token}' token cannot be wrapped in '{}' curly braces" 67 | }, 68 | square: { 69 | missingOpen: "Missing '[' open square brace", 70 | missingClose: "Open '[' square brace is missing closing ']' square brace", 71 | cannotWrap: "'{token}' token cannot be wrapped in '[]' square braces" 72 | } 73 | }, 74 | string: { 75 | missingOpen: "Missing/invalid opening string '{quote}' token", 76 | missingClose: "Missing/invalid closing string '{quote}' token", 77 | mustBeWrappedByQuotes: "Strings must be wrapped by quotes", 78 | nonAlphanumeric: "Non-alphanumeric token '{token}' is not allowed outside string notation", 79 | unexpectedKey: "Unexpected key found at string position" 80 | }, 81 | key: { 82 | numberAndLetterMissingQuotes: "Key beginning with number and containing letters must be wrapped by quotes", 83 | spaceMissingQuotes: "Key containing space must be wrapped by quotes", 84 | unexpectedString: "Unexpected string found at key position" 85 | }, 86 | noTrailingOrLeadingComma: "Trailing or leading commas in arrays and objects are not permitted" 87 | }; 88 | -------------------------------------------------------------------------------- /src/locale/id.js: -------------------------------------------------------------------------------- 1 | export default { 2 | format: "{reason} pada baris {line}", 3 | symbols: { 4 | colon: "kolon", // : 5 | comma: "koma", // , ، 、 6 | semicolon: "titik dua", // ; 7 | slash: "garis miring", // / relevant for comment syntax support 8 | backslash: "garis miring terbalik", // \ relevant for escaping character 9 | brackets: { 10 | round: "kurung buka", // ( ) 11 | square: "kurung besar", // [ ] 12 | curly: "kurung keriting", // { } 13 | angle: "kurung sudut" // < > 14 | }, 15 | period: "titik", // . Also known as full point, full stop, or dot 16 | quotes: { 17 | single: "tanda kutip tunggal", // ' 18 | double: "tanda kutip ganda", // " 19 | grave: "tanda kutip satu" // ` used on Javascript ES6 Syntax for String Templates 20 | }, 21 | space: "spasi", //     22 | ampersand: "dan", // & 23 | asterisk: "asterisk", // * relevant for some comment sytanx 24 | at: "at sign", // @ multiple uses in other coding languages including certain data types 25 | equals: "sama dengan", // = 26 | hash: "pagar", // # 27 | percent: "persen", // % 28 | plus: "tambah", // + 29 | minus: "kurang", // − 30 | dash: "hubung", // − 31 | hyphen: "pisah", // − 32 | tilde: "tilde", // ~ 33 | underscore: "garis miring", // _ 34 | bar: "garis vertikal", // | 35 | }, 36 | types: { 37 | key: "key", 38 | value: "value", 39 | number: "angka", 40 | string: "string", 41 | primitive: "primitif", 42 | boolean: "boolean", 43 | character: "karakter", 44 | integer: "integer", 45 | array: "array", 46 | float: "float" 47 | //... Reference: https://en.wikipedia.org/wiki/List_of_data_structures 48 | }, 49 | invalidToken: { 50 | tokenSequence: { 51 | prohibited: "'Token {firstToken}' tidak dapat diikuti oleh token '{secondToken}' lainnya", 52 | permitted: "'Token {firstToken}' hanya dapat diikuti oleh token '{secondToken}' lainnya" 53 | }, 54 | termSequence: { 55 | prohibited: "Token {firstTerm} tidak dapat diikuti oleh {secondTerm}", 56 | permitted: "Token {firstTerm} hanya dapat diikuti oleh {secondTerm}" 57 | }, 58 | double: "'Token {token}' tidak dapat diikuti oleh token '{token}'", 59 | useInstead: "Token '{badToken}' tidak dapat diterima. Gunakan token '{goodToken}' ini", 60 | unexpected: "Token '{token}' tak terduga ditemukan" 61 | }, 62 | brace: { 63 | curly: { 64 | missingOpen: "Kurang '{' kurung kurawal terbuka", 65 | missingClose: "Kurung kurawal terbuka '{' kehilangan kurung '}' kurawal tertutup", 66 | cannotWrap: "Token '{token}' tidak dapat dibungkus di '{}' kurung kurawal" 67 | }, 68 | square: { 69 | missingOpen: "Kurang '[' kurung besar terbuka", 70 | missingClose: "Kurung besar terbuka '[' kekurangan ']' kurung besar tertutup", 71 | cannotWrap: "'Token {token}' tidak dapat dibungkus di '[]' kurung besar" 72 | } 73 | }, 74 | string: { 75 | missingOpen: "Token kekurangan/invalid string pembuka '{quote}'", 76 | missingClose: "Token kekurangan/invalid string penutup '{quote}'", 77 | mustBeWrappedByQuotes: "String harus dibungkus dengan tanda kutip", 78 | nonAlphanumeric: "Token non-alphanumeric '{token}' tidak diizinkan diluar notasi string", 79 | unexpectedKey: "Key tak terduga ditemukan di posisi string" 80 | }, 81 | key: { 82 | numberAndLetterMissingQuotes: "Key yang diawali dengan nomor dan berisi huruf harus dibungkus dengan tanda kutip", 83 | spaceMissingQuotes: "Key yang mengandung spasi harus dibungkus dengan tanda kutip", 84 | unexpectedString: "String tak terduga ditemukan pada posisi key" 85 | 86 | }, 87 | noTrailingOrLeadingComma: "Trailing atau koma utama dalam array dan objek tidak diizinkan" 88 | }; 89 | -------------------------------------------------------------------------------- /src/locale/ru.js: -------------------------------------------------------------------------------- 1 | export default { 2 | format: "{reason} на строке {line}", 3 | symbols: { 4 | colon: "двоеточие", // : 5 | comma: "запятая", // , ، 、 6 | semicolon: "точка с запятой", // ; 7 | slash: "косая черта", // / relevant for comment syntax support 8 | backslash: "обратная косая черта", // \ relevant for escaping character 9 | brackets: { 10 | round: "круглые скобки", // ( ) 11 | square: "квадратные скобки", // [ ] 12 | curly: "фигурные скобки", // { } 13 | angle: "угловые скобки" // < > 14 | }, 15 | period: "точка", // . Also known as full point, full stop, or dot 16 | quotes: { 17 | single: "одинарная кавычка", // ' 18 | double: "двойная кавычка", // " 19 | grave: "косая кавычка" // ` used on Javascript ES6 Syntax for String Templates 20 | }, 21 | space: "пробел", //     22 | ampersand: "амперсанд", // & 23 | asterisk: "астериск", // * relevant for some comment sytanx 24 | at: "коммерческое at ", // @ multiple uses in other coding languages including certain data types 25 | equals: "знак равенства", // = 26 | hash: "октоторп", // # 27 | percent: "процент", // % 28 | plus: "плюс", // + 29 | minus: "минус", // − 30 | dash: "тире", // − 31 | hyphen: "дефис", // − 32 | tilde: "тильда", // ~ 33 | underscore: "нижнее подчеркивание", // _ 34 | bar: "вертикальная черта", // | 35 | }, 36 | types: { 37 | key: "ключ", 38 | value: "значение", 39 | number: "число", 40 | string: "строка", 41 | primitive: "примитивный", 42 | boolean: "логический", 43 | character: "знак", 44 | integer: "целое число", 45 | array: "массив", 46 | float: "число с плавающей точкой" 47 | //... Reference: https://en.wikipedia.org/wiki/List_of_data_structures 48 | }, 49 | invalidToken: { 50 | tokenSequence: { 51 | prohibited: "'{firstToken}' знак не может следовать за '{secondToken}' знаком(-ами)", 52 | permitted: "'{firstToken}' знак может следовать только за '{secondToken}' знаком(-ами)" 53 | }, 54 | termSequence: { 55 | prohibited: "{firstTerm} не может следовать за {secondTerm}", 56 | permitted: "{firstTerm} может следовать только за {secondTerm}" 57 | }, 58 | double: "'{token}' знак не может следовать за другим '{token}' знаком", 59 | useInstead: "'{badToken}' знак не разрешен. Используйте '{goodToken}'", 60 | unexpected: "Неожиданный '{token}' знак" 61 | }, 62 | brace: { 63 | curly: { 64 | missingOpen: "Пропущена '{' открывающая фигурная скобка", 65 | missingClose: "Открывающая '{' фигурная скобка не имеет закрывающей '}' фигурной скобки", 66 | cannotWrap: "'{token}' не может быть обернут в '{}' фигурные скобки" 67 | }, 68 | square: { 69 | missingOpen: "Пропущена '[' открывающая квадратная скобка", 70 | missingClose: "Открыавающая '[' квадратная скобка не имеет закрывающей ']' квадратной скобки", 71 | cannotWrap: "'{token}' не может быть обернут в '[]' квадратные скобки" 72 | } 73 | }, 74 | string: { 75 | missingOpen: "Пропущенный/недопустимый '{quote}' знак начала строки", 76 | missingClose: "Недостающий/недопустимый '{quote}' знак закрытия строки", 77 | mustBeWrappedByQuotes: "Строки должны быть обернуты в кавычки", 78 | nonAlphanumeric: "Не буквенно-численный знак '{token}' не разрешен вне строки", 79 | unexpectedKey: "В качестве строки найден неожиданный ключ" 80 | }, 81 | key: { 82 | numberAndLetterMissingQuotes: "Ключ, начинающийся с цифры и содержащий буквы, должен быть обернут в кавычки", 83 | spaceMissingQuotes: "Ключ, содержащий пробел, должен быть обернут в кавычки", 84 | unexpectedString: "В качестве ключа найдена неожиданная строка" 85 | }, 86 | noTrailingOrLeadingComma: "Начальные или конечные запятые в массивах и объектах не разрешены" 87 | }; 88 | -------------------------------------------------------------------------------- /src/locale/hin.js: -------------------------------------------------------------------------------- 1 | export default { 2 | format: "{reason} रेखा पर {line}", 3 | symbols: { 4 | colon: "विरामचिह्न", // : 5 | comma: "अल्पविराम", // , ، 、 6 | semicolon: "अर्द्धविराम", // ; 7 | slash: "स्लैश", // / relevant for comment syntax support 8 | backslash: "बैकस्लैश", // \ relevant for escaping character 9 | brackets: { 10 | round: "गोलाकार कोष्ठक", // ( ) 11 | square: "वर्गाकार कोष्ठक", // [ ] 12 | curly: "कुंचित कोष्ठक", // { } 13 | angle: "कोणीय कोष्ठक" // < > 14 | }, 15 | period: "पूर्ण विराम", // . Also known as full point, full stop, or dot 16 | quotes: { 17 | single: "एक उद्धरण चिह्न", // ' 18 | double: "दोहरा उद्धरण चिह्न", // " 19 | grave: "गंभीर लहजा" // ` used on Javascript ES6 Syntax for String Templates 20 | }, 21 | space: "जगह", //     22 | ampersand: "ऐंपरसेंड", // & 23 | asterisk: "तारक चिह्न", // * relevant for some comment sytanx 24 | at: "ऐट् चिह्न", // @ multiple uses in other coding languages including certain data types 25 | equals: "समान चिह्न", // = 26 | hash: "हैश्", // # 27 | percent: "प्रतिशत", // % 28 | plus: "मिलाकर", // + 29 | minus: "घटाव", // − 30 | dash: "एक चिह्न", // − 31 | hyphen: "हाइफन", // − 32 | tilde: "टिल्ड", // ~ 33 | underscore: "अधोरेखा", // _ 34 | bar: "खड़ा बार", // | 35 | }, 36 | types: { 37 | key: "बार", 38 | value: "मूल्य", 39 | number: "अंक", 40 | string: "क़तार", 41 | primitive: "साधारण", 42 | boolean: "बूलियन", 43 | character: "अक्षर", 44 | integer: "पूर्णांक", 45 | array: "श्रृंखला", 46 | float: "फ्लोट" 47 | //... Reference: https://en.wikipedia.org/wiki/List_of_data_structures 48 | }, 49 | invalidToken: { 50 | tokenSequence: { 51 | prohibited: "'{firstToken}' टोकन '{secondToken}' टोकन के बाद नहीं हो सकता है", 52 | permitted: "'{firstToken}' टोकन केवल '{secondToken}' टोकन के बाद ही हो सकता है" 53 | }, 54 | termSequence: { 55 | prohibited: "{firstTerm} {secondTerm} के बाद नहीं हो सकता है", 56 | permitted: "{firstTerm} केवल {secondTerm} के बाद हो सकता है" 57 | }, 58 | double: "'{token}' एक और '{token}' के बाद नहीं हो सकता है", 59 | useInstead: "'{badToken}' स्वीकार नहीं किया जाता है। इसके बजाए '{goodToken}' का प्रयोग करें", 60 | unexpected: "अप्रत्याशित '{token}' टोकन मिला" 61 | }, 62 | brace: { 63 | curly: { 64 | missingOpen: "गुम '{' खुली घुंघराले ब्रेस", 65 | missingClose: "खुले '{' घुंघराले ब्रेस के पास बंद होने वाली '}' ब्रेस नहीं है", 66 | cannotWrap: "'{}' घुंघराले ब्रेसिज़ में '{token}' टोकन संलग्न नहीं किया जा सकता है" 67 | }, 68 | square: { 69 | missingOpen: "'[' खुली वर्ग ब्रेस नहीं है", 70 | missingClose: "खुले '[' वर्ग ब्रेस के पास बंद होने वाली ']' ब्रेस नहीं है", 71 | cannotWrap: "'[]' वर्ग ब्रेसिज़ में '{token}' टोकन संलग्न नहीं किया जा सकता है" 72 | } 73 | }, 74 | string: { 75 | missingOpen: "गुम / अमान्य खोलने वाली स्ट्रिंग '{quote}' टोकन", 76 | missingClose: "गुम / अमान्य समापन स्ट्रिंग '{quote}' टोकन", 77 | mustBeWrappedByQuotes: "स्ट्रिंग्स उद्धरण द्वारा लपेटा जाना चाहिए", 78 | nonAlphanumeric: "स्ट्रिंग नोटेशन के बाहर गैर-अल्फान्यूमेरिक टोकन '{token}' की अनुमति नहीं है", 79 | unexpectedKey: "स्ट्रिंग स्थिति पर अनपेक्षित कुंजी मिली" 80 | }, 81 | key: { 82 | numberAndLetterMissingQuotes: "संख्या और युक्त अक्षरों से शुरू होने वाली कुंजी उद्धरणों द्वारा लिपटा जाना चाहिए", 83 | spaceMissingQuotes: "कुंजी जिसमें स्पेस है उद्धरण द्वारा लपेटा जाना चाहिए", 84 | unexpectedString: "कुंजी स्थिति पर अनपेक्षित स्ट्रिंग मिली" 85 | }, 86 | noTrailingOrLeadingComma: "सरणी और ऑब्जेक्ट्स में पीछे या अग्रणी कॉमा की अनुमति नहीं है" 87 | }; 88 | -------------------------------------------------------------------------------- /src/locale/ta.js: -------------------------------------------------------------------------------- 1 | export default { 2 | format: "{reason} வரிசையில் {line}", 3 | symbols: { 4 | colon: "முழுப்புள்ளி", // : 5 | comma: "கமா", // , ، 、 6 | semicolon: "அரைப்புள்ளி", // ; 7 | slash: "வெட்டி", // / relevant for comment syntax support 8 | backslash: "பின்சாய்வு", // \ relevant for escaping character 9 | brackets: { 10 | round: "சுற்று அடைப்புக்குறி", // ( ) 11 | square: "சதுர அடைப்புக்குறி", // [ ] 12 | curly: "சுருள் அடைப்புக்குறி", // { } 13 | angle: "கோண அடைப்புக்குறி" // < > 14 | }, 15 | period: "காலம்", // . Also known as full point, full stop, or dot 16 | quotes: { 17 | single: "ஒற்றை மேற்கோள்", // ' 18 | double: "இரட்டை மேற்கோள்", // " 19 | grave: "கடுமையான உச்சரிப்பு" // ` used on Javascript ES6 Syntax for String Templates 20 | }, 21 | space: "இடம்", //     22 | ampersand: "உம்மைக்குறி", // & 23 | asterisk: "நட்சத்திர குறி", // * relevant for some comment sytanx 24 | at: "அடையாளம்", // @ multiple uses in other coding languages including certain data types 25 | equals: " சமஅடையாளம்", // = 26 | hash: "ஹாஷ்", // # 27 | percent: "சதவீதம்", // % 28 | plus: "பிளஸ்", // + 29 | minus: "குறை", // − 30 | dash: "கோடு", // − 31 | hyphen: "ஹைபன்", // − 32 | tilde: "டில்டு", // ~ 33 | underscore: "அடிக்கோடு", // _ 34 | bar: "செங்குத்துப் பட்டை", // | 35 | }, 36 | types: { 37 | key: "திறவுகோல்", 38 | value: "மதிப்பு", 39 | number: "எண்", 40 | string: "கோவை", 41 | primitive: "அடிப்படை", 42 | boolean: "பூலியன்", 43 | character: "எழுத்து", 44 | integer: "முழு", 45 | array: "படை", 46 | float: "மிதவை" 47 | //... Reference: https://en.wikipedia.org/wiki/List_of_data_structures 48 | }, 49 | invalidToken: { 50 | tokenSequence: { 51 | prohibited: "'{firstToken}' டோக்கனை மற்றொரு டோக்கன் '{secondToken}' தொடர்ந்து பின்பற்ற முடியாது", 52 | permitted: "'{firstToken}' டோக்கனை மற்றொரு டோக்கன் '{secondToken}' தொடர்ந்து பின்பற்ற முடியும்", 53 | }, 54 | termSequence: { 55 | prohibited: "ஒரு {firstTerm} ஒரு {secondTerm} தொடர முடியாது", 56 | permitted: "ஒரு {firstTerm} ஒரு {secondTerm} தொடர முடியும்" 57 | }, 58 | double: "'{token}' டோக்கனை மற்றொரு டோக்கன் '{token}' தொடர்ந்து பின்பற்ற முடியாது", 59 | useInstead: "'{badToken}' டோக்கன் ஏற்றுக்கொள்ளப்படவில்லை. '{goodToken}' பதிலாக பயன்படுத்தவும்", 60 | unexpected: "எதிர்பாராத டோக்கன் '{token}' கண்டறியப்பட்டது" 61 | }, 62 | brace: { 63 | curly: { 64 | missingOpen: " '{' திறந்த வளைகோடு காணவில்லை", 65 | missingClose: "'{' திறந்த வளைகோடு உடன் மூடிய வளைகோடு '}' காணவில்லை", 66 | cannotWrap: "'{token}' டோக்கன் சுருள் பிரேஸ்களில் '{}' மூட முடியாது" 67 | }, 68 | square: { 69 | missingOpen: " '[' திறந்த வளைகோடு காணவில்லை", 70 | missingClose: "'[' திறந்த வளைகோடு உடன் மூடிய வளைகோடு ']' காணவில்லை", 71 | cannotWrap: "'{token}' டோக்கன் சுருள் பிரேஸ்களில் '[]' மூட முடியாது" 72 | } 73 | }, 74 | string: { 75 | missingOpen: "காணாமற்போன / தவறான தொடக்க சரவு டோக்கன் '{quote}'", 76 | missingClose: "காணாமற்போன / தவறான இறுதி சரவு டோக்கன் '{quote}'", 77 | mustBeWrappedByQuotes: "சரங்களை மேற்கோள் மூலம் மூடப்பட்டிருக்க வேண்டும்", 78 | nonAlphanumeric: "எண்ணெழுத்து அல்லாத டோக்கன் '{token}' சர குறியீட்டு வெளியே அனுமதி இல்லை", 79 | unexpectedKey: "எதிர்பாராத திறவு இந்த இடத்தில் கண்டறியப்பட்டது" 80 | }, 81 | key: { 82 | numberAndLetterMissingQuotes: "எண் மற்றும் எழுத்து தொடக்கம் கொண்ட திறவு மேற்கோள் மூலம் மூடப்பட்டிருக்கும்", 83 | spaceMissingQuotes: "திறவு இடம் மேற்கோள் மூலம் மூடப்பட்டிருக்கும்", 84 | unexpectedString: "எதிர்பாராத கோவை இந்த இடத்தில் கண்டறியப்பட்டது" 85 | }, 86 | noTrailingOrLeadingComma: "வரிசைகள் மற்றும் பொருள்களில் முன்னணி அல்லது பின்னணி கமாக்கள் அனுமதிக்கப்படுவதில்லை" 87 | }; 88 | -------------------------------------------------------------------------------- /test/err.js: -------------------------------------------------------------------------------- 1 | import { 2 | getType, 3 | locate 4 | } from 'mitsuketa'; 5 | 6 | const err = { 7 | getCaller: (skip = 1) => { 8 | // A somewhat hacky solution that will yield different results in different JS engines. 9 | // Since we only call this function when an error will actually be thrown we typically don't 10 | // rally mind the performance impact this might have if called too often. 11 | // Lucky for us we use nodeJS and thus only V8. 12 | const stackTrace = (new Error()).stack; 13 | var callerName = stackTrace.replace(/^Error\s+/, ''); 14 | callerName = callerName.split("\n")[skip]; 15 | callerName = callerName.replace(/^\s+at Object./, '').replace(/^\s+at /, '').replace(/ \(.+\)$/, '') 16 | return callerName; 17 | }, 18 | 19 | throwError: (fxName = 'unknown function', paramName = 'unknown parameter', expectation = 'to be defined') => { 20 | throw ['@', fxName, '(): Expected parameter \'', paramName, '\' ', expectation].join(''); 21 | }, 22 | 23 | isUndefined: (paramName = '', param) => { 24 | if ([null, undefined].indexOf(param) > -1) err.throwError(err.getCaller(2), paramName); 25 | }, 26 | 27 | isFalsy: (paramName = '', param) => { 28 | if (!param) err.throwError(err.getCaller(2), paramName); 29 | }, 30 | 31 | isNoneOf: (paramName = '', param, contains = []) => { 32 | if (contains.indexOf(param) === -1) err.throwError(err.getCaller(2), paramName, 'to be any of' + JSON.stringify(contains)); 33 | }, 34 | 35 | isAnyOf: (paramName = '', param, contains = []) => { 36 | if (contains.indexOf(param) > -1) err.throwError(err.getCaller(2), paramName, 'not to be any of' + JSON.stringify(contains)); 37 | }, 38 | 39 | isNotType: (paramName = '', param, type = '') => { 40 | if (getType(param) !== type.toLowerCase()) err.throwError(err.getCaller(2), paramName, 'to be type ' + type.toLowerCase()); 41 | }, 42 | 43 | isAnyTypeOf: (paramName = '', param, types = []) => { 44 | types.forEach(type => { 45 | if (getType(param) === type) err.throwError(err.getCaller(2), paramName, 'not to be type of ' + type.toLowerCase()); 46 | }); 47 | }, 48 | 49 | missingKey: (paramName = '', param, keyName = '') => { 50 | err.isUndefined(paramName, param); 51 | if (Object.keys(param).indexOf(keyName) === -1) err.throwError(err.getCaller(2), paramName, 'to contain \'' + keyName + '\' key'); 52 | }, 53 | 54 | missingAnyKeys: (paramName = '', param, keyNames = ['']) => { 55 | err.isUndefined(paramName, param); 56 | const keyList = Object.keys(param); 57 | keyNames.forEach(keyName => { 58 | if (keyList.indexOf(keyName) === -1) err.throwError(err.getCaller(2), paramName, 'to contain \'' + keyName + '\' key'); 59 | }); 60 | }, 61 | 62 | containsUndefined: (paramName = '', param) => { 63 | [undefined, null].forEach(value => { 64 | const location = locate(param, value); 65 | if (location) err.throwError(err.getCaller(2), paramName, 'not to contain \'' + JSON.stringify(value) + '\' at ' + location); 66 | }); 67 | }, 68 | 69 | isInvalidPath: (paramName = '', param) => { 70 | err.isUndefined(paramName, param); 71 | err.isNotType(paramName, param, 'string'); 72 | err.isAnyOf(paramName, param, ['', '/']); 73 | '.$[]#'.split().forEach(invalidChar => { 74 | if (param.indexOf(invalidChar) > -1) err.throwError(err.getCaller(2), paramName, 'not to contain invalid character \'' + invalidChar + '\''); 75 | }); 76 | if (param.match(/\/{2,}/g)) err.throwError(err.getCaller(2), paramName, 'not to contain consecutive forward slash characters'); 77 | }, 78 | 79 | isInvalidWriteData: (paramName = '', param) => { 80 | err.isUndefined(paramName, param); 81 | err.containsUndefined(paramName, param); 82 | } 83 | 84 | }; 85 | 86 | export default err; -------------------------------------------------------------------------------- /src/err.js: -------------------------------------------------------------------------------- 1 | import { 2 | getType, 3 | locate 4 | } from './mitsuketa'; 5 | 6 | const err = { 7 | getCaller: (skip = 1) => { 8 | // A somewhat hacky solution that will yield different results in different JS engines. 9 | // Since we only call this function when an error will actually be thrown we typically don't 10 | // rally mind the performance impact this might have if called too often. 11 | // Lucky for us we use nodeJS and thus only V8. 12 | const stackTrace = (new Error()).stack; 13 | var callerName = stackTrace.replace(/^Error\s+/, ''); 14 | callerName = callerName.split("\n")[skip]; 15 | callerName = callerName.replace(/^\s+at Object./, '').replace(/^\s+at /, '').replace(/ \(.+\)$/, '') 16 | return callerName; 17 | }, 18 | 19 | throwError: (fxName = 'unknown function', paramName = 'unknown parameter', expectation = 'to be defined') => { 20 | throw ['@', fxName, '(): Expected parameter \'', paramName, '\' ', expectation].join(''); 21 | }, 22 | 23 | isUndefined: (paramName = '', param) => { 24 | if ([null, undefined].indexOf(param) > -1) err.throwError(err.getCaller(2), paramName); 25 | }, 26 | 27 | isFalsy: (paramName = '', param) => { 28 | if (!param) err.throwError(err.getCaller(2), paramName); 29 | }, 30 | 31 | isNoneOf: (paramName = '', param, contains = []) => { 32 | if (contains.indexOf(param) === -1) err.throwError(err.getCaller(2), paramName, 'to be any of' + JSON.stringify(contains)); 33 | }, 34 | 35 | isAnyOf: (paramName = '', param, contains = []) => { 36 | if (contains.indexOf(param) > -1) err.throwError(err.getCaller(2), paramName, 'not to be any of' + JSON.stringify(contains)); 37 | }, 38 | 39 | isNotType: (paramName = '', param, type = '') => { 40 | if (getType(param) !== type.toLowerCase()) err.throwError(err.getCaller(2), paramName, 'to be type ' + type.toLowerCase()); 41 | }, 42 | 43 | isAnyTypeOf: (paramName = '', param, types = []) => { 44 | types.forEach(type => { 45 | if (getType(param) === type) err.throwError(err.getCaller(2), paramName, 'not to be type of ' + type.toLowerCase()); 46 | }); 47 | }, 48 | 49 | missingKey: (paramName = '', param, keyName = '') => { 50 | err.isUndefined(paramName, param); 51 | if (Object.keys(param).indexOf(keyName) === -1) err.throwError(err.getCaller(2), paramName, 'to contain \'' + keyName + '\' key'); 52 | }, 53 | 54 | missingAnyKeys: (paramName = '', param, keyNames = ['']) => { 55 | err.isUndefined(paramName, param); 56 | const keyList = Object.keys(param); 57 | keyNames.forEach(keyName => { 58 | if (keyList.indexOf(keyName) === -1) err.throwError(err.getCaller(2), paramName, 'to contain \'' + keyName + '\' key'); 59 | }); 60 | }, 61 | 62 | containsUndefined: (paramName = '', param) => { 63 | [undefined, null].forEach(value => { 64 | const location = locate(param, value); 65 | if (location) err.throwError(err.getCaller(2), paramName, 'not to contain \'' + JSON.stringify(value) + '\' at ' + location); 66 | }); 67 | }, 68 | 69 | isInvalidPath: (paramName = '', param) => { 70 | err.isUndefined(paramName, param); 71 | err.isNotType(paramName, param, 'string'); 72 | err.isAnyOf(paramName, param, ['', '/']); 73 | '.$[]#'.split().forEach(invalidChar => { 74 | if (param.indexOf(invalidChar) > -1) err.throwError(err.getCaller(2), paramName, 'not to contain invalid character \'' + invalidChar + '\''); 75 | }); 76 | if (param.match(/\/{2,}/g)) err.throwError(err.getCaller(2), paramName, 'not to contain consecutive forward slash characters'); 77 | }, 78 | 79 | isInvalidWriteData: (paramName = '', param) => { 80 | err.isUndefined(paramName, param); 81 | err.containsUndefined(paramName, param); 82 | } 83 | 84 | }; 85 | 86 | export default err; -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) 5 | and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). 6 | 7 | ## [Unreleased] 8 | 9 | ## [2.5.13] - 2020-10-15 10 | ### Fix 11 | - Re-published project to fix import issue introduced on version `2.5.10`. @andrewredican 12 | 13 | ## [2.5.12] - 2020-10-15 - DO NOT USE 14 | 15 | ## [2.5.11] - 2020-10-12 16 | ### Added 17 | - onBlur property. @tonynguyenit18. 18 | 19 | ## [2.5.10] - 2020-08-25 20 | ### Added 21 | - Custom errors can now be displayed on editor from props. @rm-hull. 22 | 23 | ### Changed 24 | - Newline is now accepted in strings @terencehuynh. 25 | 26 | ## [2.5.9] - 2018-12-08 27 | ### Added 28 | - EsLint added to project @JustFly1984. 29 | 30 | ## [2.5.8] - 2018-10-13 31 | ### Added 32 | - Japanese translation for warnings @Adityaperiwal. 33 | - Tamil translation for warnings @vasind. 34 | 35 | ## [2.5.7] - 2018-10-10 36 | ### Added 37 | - Hindi translation for warnings @shehbazjafri. 38 | 39 | ### Changed 40 | - `id` property is no longer mandatory @PatrickSachs. 41 | - Project is now server-side rendering/testing friendly @PatrickSachs. 42 | 43 | ## [2.5.6] - 2018-10-07 44 | ### Added 45 | - Reset option @AndrewRedican. 46 | - Russian translation for warnings @askesis. 47 | - French translation for warnings @cbonaudo. 48 | - Bahasa Indonesia translation for warnings @radityasurya. 49 | 50 | ### Fixed 51 | - Issue where component did not compare new and previous `placeholder` object correctly. 52 | 53 | ## [2.5.5] - 2018-09-19 54 | ### Added 55 | - Simplified Chinese translation for warnings @ADirtyCat. 56 | - Missing Portuguese terms translation for warnings @AllanKDeveloper. 57 | - Specfic backslash-related incorrect syntax warning @AndrewRedican. 58 | 59 | ## [2.5.4] - 2018-09-06 60 | ### Added 61 | - Additional terms for locale support, and spanish translation @AndrewRedican. 62 | - Portuguese translation for warnings @AllanKDeveloper. 63 | - IE 11 Support @PatrickSachs @AndrewRedican. 64 | 65 | ### Fixed 66 | - Pressing the "Tab" key in the editor no longer switches focus @PatrickSachs @ankitr. 67 | - Text can now be copied in `viewOnly` mode @rickbrunstedt. 68 | - Correct line is now provided for incomplete property/value assignment warning @AndrewRedican. 69 | 70 | ## [2.5.3] - 2018-08-13 71 | ### Added 72 | - `@babel/runtime` as dependency @PatrickSachs. 73 | 74 | ## [2.5.2] - 2018-08-04 75 | ### Changed 76 | - Switched build system from webpack to babel @PatrickSachs. 77 | - Overhauled test structure & system @AndrewRedican. 78 | - `locale` import statement made shorter @PatrickSachs. 79 | 80 | ### Added 81 | - New build output: `/build/es` using the latest ES features @PatrickSachs. 82 | - New syntax logic tests @AndrewRedican. 83 | - New locale tests @PatrickSachs. 84 | 85 | ## [2.5.1] - 2018-07-27 86 | ### Changed 87 | - Documentation and example/src/index.js with correct locale import statement @AndrewRedican. 88 | 89 | ## [2.5.0] - 2018-07-26 90 | ### Added 91 | - CHANGELOG.md @AndrewRedican. 92 | - Locale Support System @PatrickSachs. 93 | - German translation for warnings @PatrickSachs. 94 | - Spanish translation for warnings @AndrewRedican. 95 | - Contributors list @AndrewRedican. 96 | 97 | ### Changed 98 | - Some original warning texts in English @PatrickSachs. 99 | 100 | ### Fixed 101 | - React depency module casing warning due to webpack's bundle configuation of external peer dependencies @AndrewRedican. 102 | 103 | ## [2.4.9] - 2018-07-24 104 | ### Added 105 | - `modifyErrorText` property to customize warnings @AndrewRedican. 106 | 107 | ### Fixed 108 | - Shorthand properties `width` and `height` not properly working with percentages @AndrewRedican. 109 | 110 | ... 111 | 112 | ## [2.3.3] - 2018-05-25 113 | ### Added 114 | - Re-render on KeyPress feature @AndrewRedican. 115 | 116 | ## [2.2.2] - 2018-05-14 117 | ### Added 118 | - Added more customization options @AndrewRedican. 119 | 120 | ## [2.0.3] - 2018-05-09 121 | ### Added 122 | - New logic for syntax recognition and rendering by @AndrewRedican. -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-json-editor-ajrm", 3 | "version": "2.5.14", 4 | "description": "A stylish, editor-like, modular, react component for viewing, editing, and debugging javascript object syntax!", 5 | "author": "andrew.redican.mejia@gmail.com", 6 | "license": "MIT", 7 | "homepage": "https://github.com/AndrewRedican/react-json-editor-ajrm#readme", 8 | "bugs": { 9 | "url": "https://github.com/AndrewRedican/react-json-editor-ajrm/issues" 10 | }, 11 | "main": "index.js", 12 | "files": [ 13 | "*" 14 | ], 15 | "sideEffects": false, 16 | "scripts": { 17 | "contributors:add": "all-contributors add", 18 | "contributors:generate": "all-contributors generate", 19 | "test": "npm run test:start && npm run test:clear", 20 | "test:start": "cross-env NODE_ENV=test BABEL_ENV=modules:commonjs jest --updateSnapshot", 21 | "test:clear": "del-cli test/__snapshots__", 22 | "test:watch": "cross-env NODE_ENV=test BABEL_ENV=modules:commonjs jest --watch", 23 | "test:coverage": "cross-env NODE_ENV=test BABEL_ENV=modules:commonjs jest --coverage", 24 | "test:release": "npm run build && npm pack ./dist", 25 | "build": "npm run build:commonjs && npm run build:es && npm run build:copy-files && npm run test", 26 | "build:commonjs": "cross-env NODE_ENV=production BABEL_ENV=modules:commonjs babel ./src --out-dir ./dist/ --ignore *.test.js", 27 | "build:es": "cross-env NODE_ENV=production BABEL_ENV=modules:es babel ./src --out-dir ./dist/es --ignore *.test.js", 28 | "build:copy-files": "node ./scripts/copy-files.js", 29 | "release": "npm run build && npm publish ./dist" 30 | }, 31 | "jest": { 32 | "verbose": true, 33 | "modulePathIgnorePatterns": [ 34 | "/dist/" 35 | ], 36 | "transform": { 37 | "^.+\\.js$": "/test/jest.transform.js" 38 | }, 39 | "moduleFileExtensions": [ 40 | "js", 41 | "jsx" 42 | ], 43 | "testURL": "http://localhost", 44 | "setupFiles": [ 45 | "./test/jest.setup.js" 46 | ], 47 | "snapshotSerializers": [ 48 | "enzyme-to-json/serializer" 49 | ] 50 | }, 51 | "repository": "git@github.com:AndrewRedican/react-json-editor-ajrm.git", 52 | "keywords": [ 53 | "react-json-editor-ajrm", 54 | "ajrm", 55 | "react json editor", 56 | "json", 57 | "input box", 58 | "editor", 59 | "react-json", 60 | "json editor", 61 | "json debug", 62 | "json schema", 63 | "json parser", 64 | "json viewer", 65 | "json validator", 66 | "mitsuketajs.org", 67 | "mitsuketa", 68 | "javascript object viewer", 69 | "javascript object notation", 70 | "json validator", 71 | "javascript object syntax validator", 72 | "react", 73 | "component", 74 | "syntax editor", 75 | "nosql", 76 | "wysiwyg", 77 | "WYSIWYG", 78 | "what you see is what you get", 79 | "schema editor", 80 | "english", 81 | "german", 82 | "spanish", 83 | "hindi", 84 | "indonesian", 85 | "portuguese", 86 | "chinese", 87 | "french", 88 | "russian", 89 | "japanese", 90 | "tamil" 91 | ], 92 | "peerDependencies": { 93 | "react": ">=16.2.0", 94 | "react-dom": ">=16.2.0" 95 | }, 96 | "devDependencies": { 97 | "@babel/cli": "^7.0.0-rc.0", 98 | "@babel/core": "^7.0.0-beta.55", 99 | "@babel/plugin-proposal-object-rest-spread": "^7.0.0-rc.0", 100 | "@babel/plugin-transform-modules-commonjs": "^7.0.0-rc.0", 101 | "@babel/plugin-transform-object-assign": "^7.0.0-rc.0", 102 | "@babel/plugin-transform-runtime": "^7.0.0-rc.0", 103 | "@babel/preset-env": "^7.0.0-rc.0", 104 | "@babel/preset-react": "^7.0.0-rc.0", 105 | "all-contributors-cli": "^6.17.2", 106 | "babel-core": "^7.0.0-bridge.0", 107 | "babel-jest": "^23.4.2", 108 | "babel-loader": "^8.0.0-beta.4", 109 | "babel-plugin-extensible-destructuring": "^4.2.3", 110 | "babel-plugin-module-resolver": "^3.1.1", 111 | "babel-plugin-transform-react-constant-elements": "^6.23.0", 112 | "cross-env": "^5.2.0", 113 | "del-cli": "^1.1.0", 114 | "enzyme": "^3.3.0", 115 | "enzyme-adapter-react-16": "^1.1.1", 116 | "enzyme-to-json": "^3.3.4", 117 | "fs-extra": "^7.0.0", 118 | "jest": "^26.4.2", 119 | "mitsuketa": "^1.4.3", 120 | "react": ">=16.2.0", 121 | "react-dom": ">=16.2.0", 122 | "react-test-renderer": "^16.4.1", 123 | "rimraf": "^2.6.2" 124 | }, 125 | "dependencies": { 126 | "@babel/runtime": "^7.0.0-rc.0" 127 | } 128 | } -------------------------------------------------------------------------------- /example/create-react-app-project/src/registerServiceWorker.js: -------------------------------------------------------------------------------- 1 | // In production, we register a service worker to serve assets from local cache. 2 | 3 | // This lets the app load faster on subsequent visits in production, and gives 4 | // it offline capabilities. However, it also means that developers (and users) 5 | // will only see deployed updates on the "N+1" visit to a page, since previously 6 | // cached resources are updated in the background. 7 | 8 | // To learn more about the benefits of this model, read https://goo.gl/KwvDNy. 9 | // This link also includes instructions on opting out of this behavior. 10 | 11 | const isLocalhost = Boolean( 12 | window.location.hostname === 'localhost' || 13 | // [::1] is the IPv6 localhost address. 14 | window.location.hostname === '[::1]' || 15 | // 127.0.0.1/8 is considered localhost for IPv4. 16 | window.location.hostname.match( 17 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 18 | ) 19 | ); 20 | 21 | export default function register() { 22 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 23 | // The URL constructor is available in all browsers that support SW. 24 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location); 25 | if (publicUrl.origin !== window.location.origin) { 26 | // Our service worker won't work if PUBLIC_URL is on a different origin 27 | // from what our page is served on. This might happen if a CDN is used to 28 | // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374 29 | return; 30 | } 31 | 32 | window.addEventListener('load', () => { 33 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 34 | 35 | if (isLocalhost) { 36 | // This is running on localhost. Lets check if a service worker still exists or not. 37 | checkValidServiceWorker(swUrl); 38 | 39 | // Add some additional logging to localhost, pointing developers to the 40 | // service worker/PWA documentation. 41 | navigator.serviceWorker.ready.then(() => { 42 | console.log( 43 | 'This web app is being served cache-first by a service ' + 44 | 'worker. To learn more, visit https://goo.gl/SC7cgQ' 45 | ); 46 | }); 47 | } else { 48 | // Is not local host. Just register service worker 49 | registerValidSW(swUrl); 50 | } 51 | }); 52 | } 53 | } 54 | 55 | function registerValidSW(swUrl) { 56 | navigator.serviceWorker 57 | .register(swUrl) 58 | .then(registration => { 59 | registration.onupdatefound = () => { 60 | const installingWorker = registration.installing; 61 | installingWorker.onstatechange = () => { 62 | if (installingWorker.state === 'installed') { 63 | if (navigator.serviceWorker.controller) { 64 | // At this point, the old content will have been purged and 65 | // the fresh content will have been added to the cache. 66 | // It's the perfect time to display a "New content is 67 | // available; please refresh." message in your web app. 68 | console.log('New content is available; please refresh.'); 69 | } else { 70 | // At this point, everything has been precached. 71 | // It's the perfect time to display a 72 | // "Content is cached for offline use." message. 73 | console.log('Content is cached for offline use.'); 74 | } 75 | } 76 | }; 77 | }; 78 | }) 79 | .catch(error => { 80 | console.error('Error during service worker registration:', error); 81 | }); 82 | } 83 | 84 | function checkValidServiceWorker(swUrl) { 85 | // Check if the service worker can be found. If it can't reload the page. 86 | fetch(swUrl) 87 | .then(response => { 88 | // Ensure service worker exists, and that we really are getting a JS file. 89 | if ( 90 | response.status === 404 || 91 | response.headers.get('content-type').indexOf('javascript') === -1 92 | ) { 93 | // No service worker found. Probably a different app. Reload the page. 94 | navigator.serviceWorker.ready.then(registration => { 95 | registration.unregister().then(() => { 96 | window.location.reload(); 97 | }); 98 | }); 99 | } else { 100 | // Service worker found. Proceed as normal. 101 | registerValidSW(swUrl); 102 | } 103 | }) 104 | .catch(() => { 105 | console.log( 106 | 'No internet connection found. App is running in offline mode.' 107 | ); 108 | }); 109 | } 110 | 111 | export function unregister() { 112 | if ('serviceWorker' in navigator) { 113 | navigator.serviceWorker.ready.then(registration => { 114 | registration.unregister(); 115 | }); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "projectName": "react-json-editor-ajrm", 3 | "projectOwner": "AndrewRedican", 4 | "repoType": "github", 5 | "repoHost": "https://github.com", 6 | "files": [ 7 | "README.md" 8 | ], 9 | "imageSize": 100, 10 | "commit": true, 11 | "contributors": [ 12 | { 13 | "login": "AndrewRedican", 14 | "name": "Andrew Redican", 15 | "avatar_url": "https://avatars2.githubusercontent.com/u/24832471?v=4", 16 | "profile": "https://github.com/AndrewRedican", 17 | "contributions": [ 18 | "talk", 19 | "code", 20 | "translation", 21 | "test" 22 | ] 23 | }, 24 | { 25 | "login": "PatrickSachs", 26 | "name": "Patrick Sachs", 27 | "avatar_url": "https://avatars3.githubusercontent.com/u/7840502?v=4", 28 | "profile": "https://patrick-sachs.de/", 29 | "contributions": [ 30 | "code", 31 | "translation", 32 | "test" 33 | ] 34 | }, 35 | { 36 | "login": "AllanKDeveloper", 37 | "name": "Allan Kehl", 38 | "avatar_url": "https://avatars3.githubusercontent.com/u/37770361?v=4", 39 | "profile": "https://allankehl.com", 40 | "contributions": [ 41 | "translation" 42 | ] 43 | }, 44 | { 45 | "login": "esbenvb", 46 | "name": "esbenvb", 47 | "avatar_url": "https://avatars3.githubusercontent.com/u/426051?v=4", 48 | "profile": "https://github.com/esbenvb", 49 | "contributions": [ 50 | "doc" 51 | ] 52 | }, 53 | { 54 | "login": "PetrykowskiM", 55 | "name": "Markus Petrykowski", 56 | "avatar_url": "https://avatars2.githubusercontent.com/u/5831420?v=4", 57 | "profile": "http://markus-petrykowski.de", 58 | "contributions": [ 59 | "example" 60 | ] 61 | }, 62 | { 63 | "login": "rickbrunstedt", 64 | "name": "Rick Brunstedt", 65 | "avatar_url": "https://avatars0.githubusercontent.com/u/5797143?v=4", 66 | "profile": "https://github.com/rickbrunstedt", 67 | "contributions": [ 68 | "code" 69 | ] 70 | }, 71 | { 72 | "login": "ADirtyCat", 73 | "name": "ADirtyCat", 74 | "avatar_url": "https://avatars3.githubusercontent.com/u/20251640?v=4", 75 | "profile": "https://github.com/ADirtyCat", 76 | "contributions": [ 77 | "translation" 78 | ] 79 | }, 80 | { 81 | "login": "cbonaudo", 82 | "name": "Cédric", 83 | "avatar_url": "https://avatars0.githubusercontent.com/u/13097851?v=4", 84 | "profile": "https://github.com/cbonaudo", 85 | "contributions": [ 86 | "translation" 87 | ] 88 | }, 89 | { 90 | "login": "radityasurya", 91 | "name": "Radit", 92 | "avatar_url": "https://avatars3.githubusercontent.com/u/6660141?v=4", 93 | "profile": "http://radityasurya.com", 94 | "contributions": [ 95 | "translation" 96 | ] 97 | }, 98 | { 99 | "login": "askesis", 100 | "name": "asketes", 101 | "avatar_url": "https://avatars2.githubusercontent.com/u/23220242?v=4", 102 | "profile": "https://github.com/askesis", 103 | "contributions": [ 104 | "translation" 105 | ] 106 | }, 107 | { 108 | "login": "cgvedant", 109 | "name": "C.G.Vedant", 110 | "avatar_url": "https://avatars2.githubusercontent.com/u/40763859?v=4", 111 | "profile": "https://github.com/cgvedant", 112 | "contributions": [ 113 | "ideas" 114 | ] 115 | }, 116 | { 117 | "login": "shehbazjafri", 118 | "name": "Shehbaz Jafri", 119 | "avatar_url": "https://avatars2.githubusercontent.com/u/19728508?v=4", 120 | "profile": "https://github.com/shehbazjafri", 121 | "contributions": [ 122 | "translation" 123 | ] 124 | }, 125 | { 126 | "login": "vasind", 127 | "name": "Vasantha Kumar R B", 128 | "avatar_url": "https://avatars0.githubusercontent.com/u/5652920?v=4", 129 | "profile": "https://www.linkedin.com/in/vasanthakumarbe", 130 | "contributions": [ 131 | "translation" 132 | ] 133 | }, 134 | { 135 | "login": "Adityaperiwal", 136 | "name": "Aditya Periwal", 137 | "avatar_url": "https://avatars1.githubusercontent.com/u/35131225?v=4", 138 | "profile": "https://github.com/Adityaperiwal", 139 | "contributions": [ 140 | "translation" 141 | ] 142 | }, 143 | { 144 | "login": "JustFly1984", 145 | "name": "Alexey Lyakhov", 146 | "avatar_url": "https://avatars3.githubusercontent.com/u/2255993?v=4", 147 | "profile": "https://github.com/JustFly1984", 148 | "contributions": [ 149 | "code" 150 | ] 151 | }, 152 | { 153 | "login": "terencehuynh", 154 | "name": "Terence Huynh", 155 | "avatar_url": "https://avatars1.githubusercontent.com/u/1747517?v=4", 156 | "profile": "http://terencehuynh.com/", 157 | "contributions": [ 158 | "code" 159 | ] 160 | }, 161 | { 162 | "login": "rm-hull", 163 | "name": "Richard Hull", 164 | "avatar_url": "https://avatars3.githubusercontent.com/u/1915543?v=4", 165 | "profile": "https://github.com/rm-hull", 166 | "contributions": [ 167 | "code" 168 | ] 169 | }, 170 | { 171 | "login": "tonynguyenit18", 172 | "name": "tonynguyenit18", 173 | "avatar_url": "https://avatars2.githubusercontent.com/u/37351890?v=4", 174 | "profile": "https://github.com/tonynguyenit18", 175 | "contributions": [ 176 | "code" 177 | ] 178 | } 179 | ], 180 | "commitConvention": "none" 181 | } 182 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | ### First off, thank you for considering contributing to react-json-editor-ajrm. It's people like you that make it such a great repository. 4 | 5 | Following these guidelines helps to communicate that you respect the time of the developers managing and developing this open source project. In return, they should reciprocate that respect in addressing your issue, assessing changes, and helping you finalize your pull requests. 6 | 7 | 8 | RJEA is an open source project and we love to receive contributions from our community — you! There are many ways to contribute, from writing tutorials or blog posts, improving the documentation, submitting bug reports and feature requests or writing code which can be incorporated into RJEA itself. 9 | 10 | ### About Inquiries 11 | 12 | Until our slack channel is set up, feel free to use the [issue tracker](https://github.com/AndrewRedican/react-json-editor-ajrm/issues) for support questions. 13 | 14 | # Your First Contribution 15 | Unsure where to begin contributing to RJEA? You can start by looking through these beginner and help-wanted issues: 16 | 17 | * [Beginner issues](https://github.com/AndrewRedican/react-json-editor-ajrm/labels/beginner) - issues which should only require a few lines of code, and a test or two. 18 | * [Help wanted issues](https://github.com/AndrewRedican/react-json-editor-ajrm/labels/help%20wanted) - issues which should be a bit more involved than beginner issues. 19 | 20 | Both issue lists are sorted by total number of comments. While not perfect, number of comments is a reasonable proxy for impact a given change will have. 21 | 22 | ### Working on your first Pull Request? 23 | 24 | You can learn how from this *free* series, [How to Contribute to an Open Source Project on GitHub](https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github). 25 | 26 | At this point, you're ready to make your changes! Feel free to ask for help; everyone is a beginner at first :smile_cat: 27 | 28 | FYI - If a maintainer asks you to "rebase" your PR, they're saying that a lot of code has changed, and that you need to update your branch so it's easier to merge. 29 | 30 | # Getting started 31 | 32 | As a rule of thumb, changes are obvious fixes if they do not introduce any new functionality or creative thinking. As long as the change does not affect functionality, some likely examples include the following: 33 | * Spelling / grammar fixes 34 | * Typo correction, white space and formatting changes 35 | * Comment clean up 36 | * Bug fixes that change default return values or error codes stored in constants 37 | * Adding logging messages or debugging output 38 | * Changes to ‘metadata’ files like Gemfile, .gitignore, build scripts, etc. 39 | * Moving source files from one directory or package to another 40 | 41 | # How to report a bug 42 | If you find a security vulnerability, do NOT open an issue. Email andrew.redican.mejia@gmail.com instead. 43 | In order to determine whether you are dealing with a security issue, ask yourself these two questions: 44 | 45 | * Can I access something that's not mine, or something I shouldn't have access to? 46 | * Can I disable something for other people? 47 | 48 | If you don’t want to use your personal contact information, set up a “security@” email address. Larger projects might have more formal processes for disclosing security, including encrypted communication. (Disclosure: I am not a security expert.) 49 | If the answer to either of those two questions are "yes", then you're probably dealing with a security issue. Note that even if you answer "no" to both questions, you may still be dealing with a security issue, so if you're unsure, just email us at andrew.redican.mejia@gmail.com. 50 | 51 | ### When filling an issue, make sure to answer these five questions: 52 | 53 | 1. What version of node are you using (node version)? * REQUIRED 54 | 2. What operating system and processor architecture are you using? * REQUIRED 55 | 3. What did you do? * REQUIRED 56 | 4. What did you expect to see? * REQUIRED 57 | 5. What did you see instead? * REQUIRED 58 | 59 | #### Complete Issue Policy: All questions must be answered when submitting an issue. 60 | > Please make sure to provide as much detail as possible, including reproduction steps, and/or error logs. This will ensure that we get all the information we can to better solve your inquiry in the shortest amount of time. Any issues that do not meet this criteria will be closed automatically. 61 | 62 | ### Timely Confirmation Policy: All answered inquiries must be confirmed in a timely manner. 63 | > Please make sure to provide confirmation to any answers / solutions provided to an issue or inquiry in a timely manner. We expect a confirmation within 48 hours time. A thumbs up reaction will do. We volunteer our time to review inquiries to the best of our abbility in a timely manner. We expect the same kind of courtesy from those that approach us with inquiries but most importantly this is done to prevent resolved issues to remain open and stack. Any issues we consider to be resolved but lack confirmation will be closed automatically. 64 | 65 | # How to suggest a feature or enhancement 66 | If you find yourself wishing for a feature that doesn't exist in RJEA, you are probably not alone. There are bound to be others out there with similar needs. The proper way to do it is to open up a new issue [here](https://github.com/AndrewRedican/react-json-editor-ajrm/issues). Please make sure to check the list of existing feature requests to avoid duplication. 67 | 68 | # Code review process 69 | This is the checklist that I try to go through for every single pull request that I get. If you're wondering why it takes so long for me to accept pull requests, this is why. 70 | 71 | - [ ] **General** 72 | 73 | - [ ] Is this change useful to me, or something that I think will benefit others greatly? 74 | - [ ] Check for overlap with other PRs. 75 | - [ ] Think carefully about the long-term implications of the change. How will it affect existing projects that are dependent on this? How will it affect my projects? If this is complicated, do I really want to maintain it forever? Is there any way it could be implemented as a separate package, for better modularity and flexibility? 76 | 77 | - [ ] **Check the Code** 78 | 79 | - [ ] If it does too much, ask for it to be broken up into smaller PRs. 80 | - [ ] Is it consistent? 81 | - [ ] Review the changes carefully, line by line. Make sure you understand every single part of every line. Learn whatever you do not know yet. 82 | - [ ] Take the time to get things right. PRs almost always require additional improvements to meet the bar for quality. Be very strict about quality. This usually takes several commits on top of the original PR. 83 | 84 | - [ ] **Check the Tests** 85 | 86 | - [ ] Does it have tests? If not: 87 | 88 | - [ ] Comment on the PR "Can you please add tests for this code to `foo_bar.js`", or... 89 | - [ ] Write the tests yourself. 90 | 91 | - [ ] Do the tests pass for all of the following? If not, write a note in the PR, or fix them yourself. [**Read about testing**](https://github.com/AndrewRedican/react-json-editor-ajrm/wiki/How-to-Create-and-Run-Tests) 92 | 93 | - [ ] *Outlines have not been defined yet.* 94 | 95 | - [ ] **Check the Doc** 96 | 97 | - [ ] Does it have docs? If not: 98 | 99 | - [ ] Comment on the PR "Can you please add docs for this feature to `docs/usage.rst`", or... 100 | - [ ] Write the docs yourself. 101 | 102 | - [ ] If any new functions/classes are added, do they contain docstrings? 103 | - [ ] If any new features are added, are they in `README.rst`? 104 | 105 | - [ ] **Credit the Authors** 106 | 107 | - [ ] Add name and URL to `AUTHORS.rst`. 108 | - [ ] Copy and paste title and PR number into `HISTORY.rst`. 109 | - [ ] Thank them for their hard work. 110 | 111 | - [ ] **Close Issues** 112 | 113 | - [ ] Merge the PR branch. This will close the PR's issue. 114 | - [ ] Close any duplicate or related issues that can now be closed. Write thoughtful comments explaining how the issues were resolved. 115 | 116 | - [ ] **Release** 117 | 118 | - [ ] Decide whether the changes in master make sense as a major, minor, or patch release. 119 | - [ ] Look at the clock. If you're tired, release later when you have time to deal with release problems. 120 | - [ ] Then follow all the steps in [post-release guidelines](). 121 | 122 | # Community 123 | 1. Github 124 | 2. Twitter 125 | 3. Slack 126 | -------------------------------------------------------------------------------- /test/logic/syntax.js: -------------------------------------------------------------------------------- 1 | import testSyntaxLogic from './testSyntaxLogic'; 2 | import sampleData from "./../sampleData"; 3 | 4 | function run() { 5 | testSyntaxLogic('JS', 'Basic Sample', sampleData.basic, { 6 | jsObject: { ...sampleData.basic }, 7 | json: `{"hello":"world","foo":"bar"}`, 8 | lines: 5, 9 | noSpaces: `{hello:'world',foo:'bar'}`, 10 | tokens: [ 11 | { depth: 1, string: '{', type: 'symbol', value: '{' }, 12 | { depth: 1, string: 'hello', type: 'key', value: 'hello' }, 13 | { depth: 1, string: ':', type: 'symbol', value: ':' }, 14 | { depth: 1, string: "'world'", type: 'string', value: "'world'" }, 15 | { depth: 1, string: ',', type: 'symbol', value: ',' }, 16 | { depth: 1, string: 'foo', type: 'key', value: 'foo' }, 17 | { depth: 1, string: ':', type: 'symbol', value: ':' }, 18 | { depth: 1, string: "'bar'", type: 'string', value: "'bar'" }, 19 | { depth: 0, string: '}', type: 'symbol', value: '}' } 20 | ] 21 | }); 22 | 23 | testSyntaxLogic('JS', 'Common Sample', sampleData.common, { 24 | jsObject: { ...sampleData.common }, 25 | json: "{\"strings\":[\"xyz\",\"This is a test\",\"+_)(*&^%$#@!~/|}{:?/.,;][=-`\",\"This is a test with a newline\\n\"],\"numbers\":[0,1,-100,-7.5,500,1.823],\"primitives\":[false,true],\"escape\":[\"\\n\",\"\\r\"]}", 26 | lines: 25, 27 | noSpaces: "{strings:['xyz','This is a test','+_)(*&^%$#@!~/|}{:?/.,;][=-`','This is a test with a newline\\n'],numbers:[0,1,-100,-7.5,500,1.823],primitives:[false,true],escape:['\\n','\\r']}", 28 | tokens: [ 29 | { depth: 1, string: '{', type: 'symbol', value: '{' }, 30 | { depth: 1, string: 'strings', type: 'key', value: 'strings' }, 31 | { depth: 1, string: ':', type: 'symbol', value: ':' }, 32 | { depth: 2, string: '[', type: 'symbol', value: '[' }, 33 | { depth: 2, string: "'xyz'", type: 'string', value: "'xyz'" }, 34 | { depth: 2, string: ',', type: 'symbol', value: ',' }, 35 | { depth: 2, string: "'This is a test'", type: 'string', value: "'This is a test'" }, 36 | { depth: 2, string: ',', type: 'symbol', value: ',' }, 37 | { depth: 2, string: "'+_)(*&^%$#@!~/|}{:?/.,;][=-`'", type: 'string', value: "'+_)(*&^%$#@!~/|}{:?/.,;][=-`'" }, 38 | { depth: 2, string: ',', type: 'symbol', value: ',' }, 39 | { depth: 2, string: "'This is a test with a newline\\n'", type: 'string', value: "'This is a test with a newline\\n'" }, 40 | { depth: 1, string: ']', type: 'symbol', value: ']' }, 41 | { depth: 1, string: ',', type: 'symbol', value: ',' }, 42 | { depth: 1, string: 'numbers', type: 'key', value: 'numbers' }, 43 | { depth: 1, string: ':', type: 'symbol', value: ':' }, 44 | { depth: 2, string: '[', type: 'symbol', value: '[' }, 45 | { depth: 2, string: '0', type: 'number', value: 0 }, 46 | { depth: 2, string: ',', type: 'symbol', value: ',' }, 47 | { depth: 2, string: '1', type: 'number', value: 1 }, 48 | { depth: 2, string: ',', type: 'symbol', value: ',' }, 49 | { depth: 2, string: '-100', type: 'number', value: -100 }, 50 | { depth: 2, string: ',', type: 'symbol', value: ',' }, 51 | { depth: 2, string: '-7.5', type: 'number', value: -7.5 }, 52 | { depth: 2, string: ',', type: 'symbol', value: ',' }, 53 | { depth: 2, string: '500', type: 'number', value: 500 }, 54 | { depth: 2, string: ',', type: 'symbol', value: ',' }, 55 | { depth: 2, string: '1.823', type: 'number', value: 1.823 }, 56 | { depth: 1, string: ']', type: 'symbol', value: ']' }, 57 | { depth: 1, string: ',', type: 'symbol', value: ',' }, 58 | { depth: 1, string: 'primitives', type: 'key', value: 'primitives' }, 59 | { depth: 1, string: ':', type: 'symbol', value: ':' }, 60 | { depth: 2, string: '[', type: 'symbol', value: '[' }, 61 | { depth: 2, string: 'false', type: 'primitive', value: false }, 62 | { depth: 2, string: ',', type: 'symbol', value: ',' }, 63 | { depth: 2, string: 'true', type: 'primitive', value: true }, 64 | { depth: 1, string: ']', type: 'symbol', value: ']' }, 65 | { depth: 1, string: ',', type: 'symbol', value: ',' }, 66 | { depth: 1, string: 'escape', type: 'key', value: 'escape' }, 67 | { depth: 1, string: ':', type: 'symbol', value: ':' }, 68 | { depth: 2, string: '[', type: 'symbol', value: '[' }, 69 | { depth: 2, string: '\'\\n\'', type: 'string', value: '\'\\n\'' }, 70 | { depth: 2, string: ',', type: 'symbol', value: ',' }, 71 | { depth: 2, string: '\'\\r\'', type: 'string', value: '\'\\r\'' }, 72 | { depth: 1, string: ']', type: 'symbol', value: ']' }, 73 | { depth: 0, string: '}', type: 'symbol', value: '}' }, 74 | ] 75 | }); 76 | 77 | testSyntaxLogic('JS', 'Uncommon Key Names', sampleData.uncommonKeys, { 78 | jsObject: { ...sampleData.uncommonKeys }, 79 | json: "{\"0\":\"number-like text\",\"true\":true,\"false\":false,\"undefined\":\"undefined\",\"null\":\"null\",\"\":0,\"compound word\":[\"*\"],\"~!@#$%\":\"non-alphanumeric\",\"$\":\"dollar\",\"_\":\"underscore\",\"{}\":\"curly brackets\",\"[]\":\"square brackets\",\"A423423\":\"letter-number\",\"0A\":\"number-letter\",\"A 4\":\"letter-space-number\",\"0 A\":\"number-space-letter\",\"0 A,&\":\"number-space-letter-nonAlphanumeric\"}", 80 | lines: 22, 81 | noSpaces: "{0:'number-like text',true:true,false:false,undefined:'undefined',null:'null','':0,'compound word':['*'],'~!@#$%':'non-alphanumeric','$':'dollar',_:'underscore','{}':'curly brackets','[]':'square brackets',A423423:'letter-number','0A':'number-letter','A 4':'letter-space-number','0 A':'number-space-letter','0 A,&':'number-space-letter-nonAlphanumeric'}", 82 | tokens: [ 83 | { depth: 1, string: '{', type: 'symbol', value: '{' }, 84 | { depth: 1, string: '0', type: 'key', value: '0' }, 85 | { depth: 1, string: ':', type: 'symbol', value: ':' }, 86 | { depth: 1, string: "'number-like text'", type: 'string', value: "'number-like text'" }, 87 | { depth: 1, string: ',', type: 'symbol', value: ',' }, 88 | { depth: 1, string: 'true', type: 'key', value: 'true' }, 89 | { depth: 1, string: ':', type: 'symbol', value: ':' }, 90 | { depth: 1, string: 'true', type: 'primitive', value: true }, 91 | { depth: 1, string: ',', type: 'symbol', value: ',' }, 92 | { depth: 1, string: 'false', type: 'key', value: 'false' }, 93 | { depth: 1, string: ':', type: 'symbol', value: ':' }, 94 | { depth: 1, string: 'false', type: 'primitive', value: false }, 95 | { depth: 1, string: ',', type: 'symbol', value: ',' }, 96 | { depth: 1, string: 'undefined', type: 'key', value: 'undefined' }, 97 | { depth: 1, string: ':', type: 'symbol', value: ':' }, 98 | { depth: 1, string: "'undefined'", type: 'string', value: "'undefined'" }, 99 | { depth: 1, string: ',', type: 'symbol', value: ',' }, 100 | { depth: 1, string: 'null', type: 'key', value: 'null' }, 101 | { depth: 1, string: ':', type: 'symbol', value: ':' }, 102 | { depth: 1, string: "'null'", type: 'string', value: "'null'" }, 103 | { depth: 1, string: ',', type: 'symbol', value: ',' }, 104 | { depth: 1, string: "''", type: 'key', value: "''" }, 105 | { depth: 1, string: ':', type: 'symbol', value: ':' }, 106 | { depth: 1, string: '0', type: 'number', value: 0 }, 107 | { depth: 1, string: ',', type: 'symbol', value: ',' }, 108 | { depth: 1, string: "'compound word'", type: 'key', value: "'compound word'" }, 109 | { depth: 1, string: ':', type: 'symbol', value: ':' }, 110 | { depth: 2, string: '[', type: 'symbol', value: '[' }, 111 | { depth: 2, string: "'*'", type: 'string', value: "'*'" }, 112 | { depth: 1, string: ']', type: 'symbol', value: ']' }, 113 | { depth: 1, string: ',', type: 'symbol', value: ',' }, 114 | { depth: 1, string: "'~!@#$%'", type: 'key', value: "'~!@#$%'" }, 115 | { depth: 1, string: ':', type: 'symbol', value: ':' }, 116 | { depth: 1, string: "'non-alphanumeric'", type: 'string', value: "'non-alphanumeric'" }, 117 | { depth: 1, string: ',', type: 'symbol', value: ',' }, 118 | { depth: 1, string: "'$'", type: 'key', value: "'$'" }, 119 | { depth: 1, string: ':', type: 'symbol', value: ':' }, 120 | { depth: 1, string: "'dollar'", type: 'string', value: "'dollar'" }, 121 | { depth: 1, string: ',', type: 'symbol', value: ',' }, 122 | { depth: 1, string: '_', type: 'key', value: '_' }, 123 | { depth: 1, string: ':', type: 'symbol', value: ':' }, 124 | { depth: 1, string: "'underscore'", type: 'string', value: "'underscore'" }, 125 | { depth: 1, string: ',', type: 'symbol', value: ',' }, 126 | { depth: 1, string: "'{}'", type: 'key', value: "'{}'" }, 127 | { depth: 1, string: ':', type: 'symbol', value: ':' }, 128 | { depth: 1, string: "'curly brackets'", type: 'string', value: "'curly brackets'" }, 129 | { depth: 1, string: ',', type: 'symbol', value: ',' }, 130 | { depth: 1, string: "'[]'", type: 'key', value: "'[]'" }, 131 | { depth: 1, string: ':', type: 'symbol', value: ':' }, 132 | { depth: 1, string: "'square brackets'", type: 'string', value: "'square brackets'" }, 133 | { depth: 1, string: ',', type: 'symbol', value: ',' }, 134 | { depth: 1, string: 'A423423', type: 'key', value: 'A423423' }, 135 | { depth: 1, string: ':', type: 'symbol', value: ':' }, 136 | { depth: 1, string: "'letter-number'", type: 'string', value: "'letter-number'" }, 137 | { depth: 1, string: ',', type: 'symbol', value: ',' }, 138 | { depth: 1, string: "'0A'", type: 'key', value: "'0A'" }, 139 | { depth: 1, string: ':', type: 'symbol', value: ':' }, 140 | { depth: 1, string: "'number-letter'", type: 'string', value: "'number-letter'" }, 141 | { depth: 1, string: ',', type: 'symbol', value: ',' }, 142 | { depth: 1, string: "'A 4'", type: 'key', value: "'A 4'" }, 143 | { depth: 1, string: ':', type: 'symbol', value: ':' }, 144 | { depth: 1, string: "'letter-space-number'", type: 'string', value: "'letter-space-number'" }, 145 | { depth: 1, string: ',', type: 'symbol', value: ',' }, 146 | { depth: 1, string: "'0 A'", type: 'key', value: "'0 A'" }, 147 | { depth: 1, string: ':', type: 'symbol', value: ':' }, 148 | { depth: 1, string: "'number-space-letter'", type: 'string', value: "'number-space-letter'" }, 149 | { depth: 1, string: ',', type: 'symbol', value: ',' }, 150 | { depth: 1, string: "'0 A,&'", type: 'key', value: "'0 A,&'" }, 151 | { depth: 1, string: ':', type: 'symbol', value: ':' }, 152 | { depth: 1, string: "'number-space-letter-nonAlphanumeric'", type: 'string', value: "'number-space-letter-nonAlphanumeric'" }, 153 | { depth: 0, string: '}', type: 'symbol', value: '}' } 154 | ] 155 | }); 156 | } 157 | 158 | export default run; 159 | 160 | /** 161 | * TODO - Add missing Syntax Logic validations: 162 | * 1. Quotes in key and string notations and nested. I.e. "" '' `` 163 | * 2. Escape character. I.e \ 164 | * 3. Html Tags and stand alone reserved words I.e.
 
<> ><
165 | * 166 | * 6. Provide invalid information, validate warnings 167 | **/ 168 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **Warning:** 2 | 3 | As you may already know, the react-json-editor-ajrm's orignal project is not actively maintained and that 4 | it will eventually be deprecated. So I've decided to set an official date for deprecation. The tentative date for this is June 15, 2023. 5 | 6 | ### What does deprecation mean? 7 | - It means the Github project will be archived as read only. 8 | - It means the npm packages will appear deprecated, but it **WILL NOT be deleted**. 9 | - It means the new project will be available officially on that date. 10 | 11 | I would like to thank those who used it in their projects and those who have contributed in some way to the project. I simply no longer wish to maintain this project. It was made in the early days of my software engineer career, and it has not caught up to today's standards nor mine. 12 | 13 | But don't fret. I intend to breathe new life into this project rewriting it from the ground up. 14 | 15 | I would like to take the learnings of the past, and avoid some of the issues react-json-editor-ajrm currently has. I would also like to highlight the things done well, and I wish to carry on. 16 | 17 | I've setup home for this new project here [enio](https://github.com/enio-ireland/enio). 18 | I've also set up a [discussion here](https://github.com/enio-ireland/enio/discussions/62) if you have any questions or comments. 19 | 20 |
21 | 22 | # react-json-editor-ajrm 23 | 24 | ![npm](https://img.shields.io/npm/v/react-json-editor-ajrm.svg) ![Build Status](https://travis-ci.com/AndrewRedican/react-json-editor-ajrm.svg?branch=master) ![npm](https://img.shields.io/npm/dm/react-json-editor-ajrm.svg) [![Known Vulnerabilities](https://snyk.io/test/github/AndrewRedican/react-json-editor-ajrm/badge.svg)](https://snyk.io/test/github/{username}/{repo}) [![All Contributors](https://img.shields.io/badge/all_contributors-15-orange.svg?style=flat-square)](#contributors) 25 | 26 |



A stylish, editor-like, modular, react component for viewing, editing, and debugging javascript object syntax!

27 | 28 | ## Installing Dependency 29 | 30 | - Using node package manager: 31 | 32 | ``` 33 | $ npm i --save react-json-editor-ajrm 34 | ``` 35 | 36 | ## How to Use 37 | 38 | ``` 39 | import JSONInput from 'react-json-editor-ajrm'; 40 | import locale from 'react-json-editor-ajrm/locale/en'; 41 | 42 | 49 | ``` 50 | 51 | *Hint*: There are two different root paths: `react-json-editor-ajrm` and `react-json-editor-ajrm/es`. The first contains polyfilled ES5 code, the second unpolyfilled ES6. The `react-json-editor-ajrm/es` version is **not compatible** with [`create-react-app`](https://github.com/facebook/create-react-app). If you are unsure of which one you need/want, pick the first - it has the best compatibility with tools and browsers. 52 | 53 | ## Examples 54 | 55 | The `./examples` folder contains two examples: 56 | 57 | 1. webpack-project - A basic example without much overload 58 | 2. create-react-app-project - A small example using the create-react-app template 59 | 60 | ## Testing right away! 61 | 62 | 1. Fork and/or clone this Github repository 63 | 2. Go to an example project under [react-json-editor-ajrm/example](https://github.com/AndrewRedican/react-json-editor-ajrm/tree/master/example): 64 | 65 | ``` 66 | $ cd path/to/repo/react-json-editor-ajrm/example/webpack-project 67 | ``` 68 | 69 | 3. Install example project dependencies: 70 | 71 | ``` 72 | $ npm i 73 | ``` 74 | 75 | 4. Serve sample website to port 8080: 76 | 77 | ``` 78 | $ npm start 79 | ``` 80 | 81 | 5. Open `http://localhost:8080` in the web browser 82 | 83 | ## Latest Spotlight Release Notes [v2.5.12] - October 15, 2020 84 | 85 | 1. Fixed [import issue](https://github.com/AndrewRedican/react-json-editor-ajrm/issues/140). 86 | 87 | ## Upcoming Features 88 | 89 | 1. Bug fixes. 90 | 91 | ## Features 92 | 93 | 1. Write as if you are in a text editor. 94 | 2. Checks for syntax mistakes and provides feedback; Custom errors can also be overlaid on the editor. 95 | 3. You can customize color palette as you please. 96 | 4. Accepts a javascript object in `placeholder` property to display after component mounts. 97 | 5. For any valid textContent, calculates and makes available in this.state as plain text, markup text, and javascript object. 98 | 6. Locale support for `English`, `German`, `Spanish`, `Chinese`, `French`, `Indonesian`, `Russian`, `Hindi`, `Japanese` and `Tamil`. 99 | 100 | ## Component Properties 101 | 102 | | Name | Description | Type | Required | 103 | | ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------: | :-------: | 104 | | [locale]() | The locale of your editor. Import locales like this: `import locale from 'react-json-editor-ajrm/locale/en'`. [Learn More](https://github.com/AndrewRedican/react-json-editor-ajrm/wiki/Locale-Support) | object | Mandatory | 105 | | [id]() | An optional `id` to assign to the actual text input DOM node. Asides the from the text input, the following nodes will also receive an id: `{id}-outer-box`, `{id}-container`, `{id}-warning-box`, `{id}-labels` | string | Optional | 106 | | [placeholder]() | Send a valid javascript object to be shown once the component is mounted. Assign a different value to have the component's initial content re-rendered. | object | Optional | 107 | | [reset]() | Send `true` to have component always re-render or 'reset' to the value provided on the `placeholder` property. | boolean | Optional | 108 | | [viewOnly]() | Send `true` if you would like for content shown not to be editable. | boolean | Optional | 109 | | [onChange]() | Whenever `onKeyPress` event take place, it will return content values. | object | Optional | 110 | | [onBlur]() | Whenever `onBlur` event take place, it will return content values. | object | Optional | 111 | | [confirmGood]() | Send `false` if you would like for the checkmark to confirm good syntax to be hidden. | boolean | Optional | 112 | | [height]() | A shorthand property to set a specific height for the entire component. | string | Optional | 113 | | [width]() | A shorthand property to set a specific width for the entire component. | string | Optional | 114 | | [onKeyPressUpdate]() | Send `false` if you would like for component not to automatically update on key press. | boolean | Optional | 115 | | [waitAfterKeyPress]() | Amount of milliseconds to wait before re-rendering content after keypress. Value defaults to `1000` when not specified. In other words, component will update if there is no additional keystroke after the last one within 1 second. Less than `100` milliseconds does not makes a difference. | number | Optional | 116 | | [modifyErrorText]() | A custom function to modify the component's original warning text. This function will receive a single parameter of type `string` and must equally return a `string`. | function | Optional | 117 | | [error]() | **Contains the following properties:** | object | Optional | 118 | | error.[reason]() | A string containing a custom error messsage | string | Optional | 119 | | error.[line]() | A number indicating the line number related to the custom error message | number | Optional | 120 | | [theme]() | Specify which [built-in theme](https://github.com/AndrewRedican/react-json-editor-ajrm/wiki/Built-In-Themes) to use. | string | Optional | 121 | | [colors]() | **Contains the following properties:** | object | Optional | 122 | | colors.[default]() | Hex color code for any symbols, like curly `braces`, and `comma`. | string | Optional | 123 | | colors.[string]() | Hex color code for tokens identified as `string` values. | string | Optional | 124 | | colors.[number]() | Hex color code for tokens identified as `integeter`, `double`, or `float` values. | string | Optional | 125 | | colors.[colon]() | Hex color code for tokens identified as `colon`. | string | Optional | 126 | | colors.[keys]() | Hex color code for tokens identified as `keys` or property names. | string | Optional | 127 | | colors.[keys_whiteSpace]() | Hex color code for tokens identified as `keys` wrapped in quotes. | string | Optional | 128 | | colors.[primitive]() | Hex color code for tokens identified as `boolean` values and null. | string | Optional | 129 | | colors.[error]() | Hex color code for tokens marked with an `error` tag. | string | Optional | 130 | | colors.[background]() | Hex color code for component's background. | string | Optional | 131 | | colors.[background_warning]() | Hex color code for warning message displaying at the top in component. | string | Optional | 132 | | [style]() | **Contains the following properties:** | object | Optional | 133 | | style.[outerBox]() | Property to modify the default style of the outside container div of component. | object | Optional | 134 | | style.[container]() | Property to modify the default style of the `container` of component. | object | Optional | 135 | | style.[warningBox]() | Property to modify the default style of the container div of the warning message. | object | Optional | 136 | | style.[errorMessage]() | Property to modify the default style of the warning message. | object | Optional | 137 | | style.[body]() | Property to modify the default style of the container div of row labels and code. | object | Optional | 138 | | style.[labelColumn]() | Property to modify the default style of the container div of row labels. | object | Optional | 139 | | style.[labels]() | Property to modify the default style of each row label. | object | Optional | 140 | | style.[contentBox]() | Property to modify the default style of the container div of the code. | object | Optional | 141 | 142 | ## Component Sections 143 | 144 | ``` 145 | outerBox 146 | +-- container 147 | +--- warningBox 148 | +---- errorMessage 149 | +--- body 150 | +---- labelColumn 151 | +----- labels 152 | +---- contentBox 153 | +----- auto generated markup 154 | ``` 155 | 156 | ## Content Values 157 | 158 | Whenever RJEA re-renders its content, any function passed onto `onChange` property will receive a single object parameter with the following keys and values: 159 | 160 | | Key | Description | 161 | | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 162 | | plainText | A string representation of then content which includes linebreaks and indentation. Great to console.log() | 163 | | markupText | A string representation of the auto-generated markup used to render content. | 164 | | json | A JSON.stringify version of content. | 165 | | jsObject | A `javascript object` version of content. Will return `undefined` if the content's syntax is incorrect. | 166 | | lines | Number of lines rendered for content to be displayed. | 167 | | error | Returns `false` unless the content's syntax is incorrect, in which case returns an object with a `token` and a `line` number which corresponds to the location at which error occurred and a `reason` | 168 | 169 | ## Built-In Themes 170 | 171 | RJEA supports built-in theme. Here is the [list](https://github.com/AndrewRedican/react-json-editor-ajrm/wiki/Built-In-Themes). 172 | 173 | ## Built With 174 | 175 | - [**React.js**](https://reactjs.org/) 176 | - [**Babel.js**](https://babeljs.io/) for transpiling. 177 | - [**Enzyme**](http://airbnb.io/enzyme/) for react-specific testing utilities. 178 | - [**Jest**](https://jestjs.io/docs/en/tutorial-react) for unit testing, also react-specific tests. 179 | - [**Travis CI**](https://travis-ci.org/) for continuous integration. 180 | 181 | ## License 182 | 183 | This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details. 184 | 185 | ## Contributors 186 | 187 | Thanks goes to these wonderful people :smile:: 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 |

Andrew Redican

📢 💻 🌍 ⚠️

Patrick Sachs

💻 🌍 ⚠️

Allan Kehl

🌍

esbenvb

📖

Markus Petrykowski

💡

Rick Brunstedt

💻

ADirtyCat

🌍

Cédric

🌍

Radit

🌍

asketes

🌍

C.G.Vedant

🤔

Shehbaz Jafri

🌍

Vasantha Kumar R B

🌍

Aditya Periwal

🌍

Alexey Lyakhov

💻

Terence Huynh

💻

Richard Hull

💻

tonynguyenit18

💻
218 | 219 | 220 | 221 | 222 | 223 | This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome! 224 | -------------------------------------------------------------------------------- /src/mitsuketa/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Andrew Redican 3 | */ 4 | 5 | /** 6 | * Performs deep search on object tree, removes all properties with matching key, returns a new identity without the specified property 7 | * @param {Any} identity 8 | * @param {string} keyName 9 | * @param {Optional Number} maxDepth 10 | * @return {Any} identity 11 | */ 12 | function deepRemoveAll_Key(identity,keyName,maxDepth){ 13 | if(getType(keyName)!=='string') return undefined; 14 | if(keyName==='') return undefined; 15 | let clonedIdentity = deepClone(identity); 16 | var paths = locateAll_Key(clonedIdentity,keyName,maxDepth); 17 | if(paths===[]||paths===false) return clonedIdentity; 18 | paths.forEach( path => { 19 | if(path === '') path = keyName; else path += ('.' + keyName); 20 | path = path.split('.'); 21 | var ref = clonedIdentity; 22 | if(!Array.isArray(path)) delete ref[path]; 23 | for(var i = 0; i < path.length; i++){ 24 | var key = path[i]; 25 | if(key in ref){ 26 | if(i { if(i { _deepClone(identity[key],maxDepth,startDepth,currentDepth + 1); }); 168 | } 169 | return; 170 | } 171 | if( startDepth !== null ? currentDepth == startDepth : false){ 172 | if(startDepth==0){ R = _deepClone(identity,maxDepth,null,currentDepth); return; } 173 | if(isIterable(identity)) R.push(_deepClone(identity,maxDepth,startDepth,currentDepth + 1)); 174 | return; 175 | } 176 | switch(getType(identity)){ 177 | case 'array': 178 | var Arr = []; 179 | keys = Object.keys(identity); 180 | if( maxDepth !== null ? currentDepth < maxDepth : true) 181 | for(var i = 0, l = keys.length; i < l; i++){ 182 | const 183 | key = keys[i], 184 | subIdentity = identity[key]; 185 | Arr[key] = _deepClone(subIdentity,maxDepth,startDepth,currentDepth + 1); 186 | } 187 | return Arr; 188 | case 'object': 189 | var Obj = {}; 190 | keys = Object.keys(identity); 191 | if( maxDepth !== null ? currentDepth < maxDepth : true) 192 | for(var i = 0, l = keys.length; i < l; i++){ 193 | const 194 | key = keys[i], 195 | subIdentity = identity[key]; 196 | Obj[key] = _deepClone(subIdentity,maxDepth,startDepth,currentDepth + 1); 197 | } 198 | return Obj; 199 | case 'string': return '' + identity; 200 | case 'number': return 0 + identity; 201 | case 'boolean': if(identity) return true; return false; 202 | case 'null': return null; 203 | case 'undefined': return undefined; 204 | } 205 | } 206 | if(startDepth === null) return _deepClone(identity,maxDepth,startDepth,0); 207 | _deepClone(identity,maxDepth,startDepth,0); return R; 208 | } 209 | 210 | /** 211 | * Performs deep search on collection to find all matches to the key name, and returns a list of identities containing the matched instances. If no matches found, it returns `undefined`. 212 | * @param {Any} collection 213 | * @param {Any} keyName 214 | * @param {Optional Number} maxDepth 215 | * @return {Array || undefined} Identities 216 | */ 217 | function deepFilter_Key(collection,keyName,maxDepth=null){ 218 | if(getType(keyName)!=='string') return undefined; 219 | if(keyName==='') return undefined; 220 | var paths = locateAll_Key(collection,keyName,maxDepth); 221 | if(paths === false) return undefined; 222 | const results = paths.map(path => { 223 | if(path === false) return undefined; 224 | if(path === '') path = keyName; else path += ('.' + keyName); 225 | path = path.split('.'); 226 | var result = collection; 227 | if(!Array.isArray(path)) return result[path]; 228 | path.forEach( key => { result = result[key]; }); 229 | return result; 230 | }) 231 | return results; 232 | } 233 | 234 | /** 235 | * Performs deep search on collection to find all matches to the key name, returns the location of each match in a string array. If no matches found, it returns `false`. 236 | * @param {Any} collection 237 | * @param {Any} keyName 238 | * @param {Optional Number} maxDepth 239 | * @return {Array || false} Paths 240 | */ 241 | function locateAll_Key(collection,keyName,maxDepth=null){ 242 | if(getType(keyName)!=='string') return undefined; 243 | if(keyName==='') return undefined; 244 | var R = []; 245 | function _locateAll_Key(collection,keyName,xKey='',path='',maxDepth=null,currentDepth=0){ 246 | if(xKey===keyName) R[R.length] = path; 247 | var result = false; 248 | if(maxDepth!==null)if(currentDepth>=maxDepth) return result; 249 | if(isIterable(collection)) 250 | for(var i = 0, keys = Object.keys(collection), l = keys.length; i < l; i++ ){ 251 | const key = keys[i], subcollection = collection[key]; 252 | _locateAll_Key(subcollection,keyName,key,(path === '' ? path : path + '.') + key,maxDepth,currentDepth + 1); 253 | } 254 | } 255 | _locateAll_Key(collection,keyName,'','',maxDepth); 256 | R = R.map( path => { 257 | if(getType(path)==='boolean') return path; 258 | if(path==='') return path; 259 | path = path.split('.'); 260 | path.pop(); 261 | path = path.join('.'); 262 | return path; 263 | }); 264 | return R.length === 0 ? false : R; 265 | } 266 | 267 | /** 268 | * Performs deep search on collection to find a match to the key name, and returns the first identity containing the match. If no match found, it returns `undefined`. 269 | * @param {Any} collection 270 | * @param {Any} keyName 271 | * @param {Optional number} maxDepth 272 | * @return {Identity || undefined} identity 273 | */ 274 | function deepGet_Key(collection,keyName,maxDepth=null){ 275 | if(getType(keyName)!=='string') return undefined; 276 | if(keyName==='') return undefined; 277 | var path = locate_Key(collection,keyName,maxDepth); 278 | if(path === false) return undefined; 279 | if(path === '') path = keyName; else path += ('.' + keyName); 280 | path = path.split('.'); 281 | var result = collection; 282 | if(!Array.isArray(path)) return result[path]; 283 | path.forEach( key => { result = result[key]; }); 284 | return result; 285 | } 286 | 287 | /** 288 | * Performs deep search on collection to find a match to the key name, will return the path of the first instance matched. If no match found, it returns `false`. 289 | * @param {Any} collection 290 | * @param {Any} keyName 291 | * @param {Optional number} maxDepth 292 | * @return {String || false} Path 293 | */ 294 | function locate_Key(collection,keyName,maxDepth=null){ 295 | if(getType(keyName)!=='string') return undefined; 296 | if(keyName==='') return undefined; 297 | function _locate_Key(collection,keyName,path='',maxDepth,currentDepth=0){ 298 | if(path===keyName) return path; 299 | var result = false; 300 | if(maxDepth!==null)if(currentDepth>=maxDepth) return result; 301 | if(isIterable(collection)) 302 | for(var i = 0, keys = Object.keys(collection), l = keys.length; i < l; i++ ){ 303 | const 304 | key = keys[i], subcollection = collection[key], 305 | res = _locate_Key(subcollection,keyName,key,maxDepth,currentDepth + 1); 306 | if(res) { path = path === '' ? path : path + '.'; result = path + res; break; } 307 | } 308 | return result; 309 | } 310 | var path = _locate_Key(collection,keyName,'',maxDepth,0); 311 | if(getType(path)==='boolean') return path; 312 | if(path==='') return path; 313 | path = path.split('.'); 314 | path.pop(); 315 | path = path.join('.'); 316 | return path; 317 | } 318 | 319 | /** 320 | * Performs deep search for identity on collection to return the location's depth of the first match. If no match found, it returns `false`. 321 | * @param {Any} collection 322 | * @param {Any} identity 323 | * @param {Optional Number} maxDepth 324 | * @return {boolean} 325 | */ 326 | function matchDepth(collection,identity,maxDepth=null){ 327 | var path = locate(collection, identity, maxDepth); 328 | if(path === false) return false; 329 | if(path === '') return 0; 330 | path = path.split('.'); 331 | return path.length; 332 | } 333 | 334 | /** 335 | * Walks through the entire object tree to return the maximum number of layers it contains. 336 | * @param {Any} identity 337 | * @param {Optional Number} maxDepth 338 | */ 339 | function maxDepth(identity,maxLayer=null){ 340 | let R = 0; 341 | function _maxDepth(identity,maxLayer,currentDepth=0){ 342 | if(R < currentDepth) R = currentDepth; 343 | if(maxLayer!==null) if(currentDepth >= maxLayer) return; 344 | if(isIterable(identity)){ 345 | var keys = Object.keys(identity); 346 | keys.forEach( key => { 347 | var subIdentity = identity[key]; 348 | _maxDepth(subIdentity,maxLayer,currentDepth + 1); 349 | }); 350 | } 351 | } 352 | _maxDepth(identity,maxLayer); 353 | return R; 354 | } 355 | 356 | /** 357 | * Performs deep search for identity on collection, returns the number of matches found. 358 | * @param {Any} collection 359 | * @param {Any} identity 360 | * @param {Number} nthDepth 361 | * @param {Optional Number} maxDepth 362 | * @return {Any} Returns number of matches found. 363 | */ 364 | function countMatches(collection,identity,nthDepth=null,maxDepth=null){ 365 | var 366 | depth, 367 | nthDepth_isNull = nthDepth === null, 368 | maxDepth_isNull = maxDepth === null; 369 | if(nthDepth_isNull && maxDepth_isNull) 370 | depth = null; 371 | else 372 | if(!nthDepth_isNull && !maxDepth_isNull) 373 | if(nthDepth < maxDepth) depth = nthDepth; else depth = maxDepth; 374 | else 375 | if(nthDepth) depth = nthDepth; else depth = maxDepth; 376 | var paths = locateAll(collection,identity,depth); 377 | if(paths===false) return 0; 378 | if(nthDepth===null) return paths.length; 379 | if(getType(nthDepth)==='number'){ 380 | let count = 0; 381 | paths.forEach( path => { 382 | path = path.split('.'); 383 | if(path.length===nthDepth) count++; 384 | }); 385 | return count; 386 | } 387 | return undefined; 388 | } 389 | 390 | /** 391 | * Performs deep search for each identity on collection, to shorten the identities to those that meets the match criteria 392 | * @param {Any} collection 393 | * @param {Any} identities 394 | * @param {Any} property 395 | * @param {Optional Number} maxDepth 396 | * @return {Any} Returns a collection of the same type as the 'identities' parameter provided with only the identities that matched. 397 | */ 398 | function onlyFalsy(collection,identities,property,maxDepth=null){ 399 | if(getType(identities)==='array'){ 400 | let result = []; 401 | identities.forEach( identity => { 402 | const subCollection = deepFilter(collection,identity); 403 | if(isTruthy(subCollection)) 404 | if(foundFalsy(subCollection,property,maxDepth)) result.push(identity); 405 | }); 406 | return result; 407 | } 408 | if(getType(identities)==='object'){ 409 | let result = {}; 410 | Object.keys(identities).forEach( key => { 411 | const 412 | identity = identities[key], 413 | subCollection = deepFilter(collection,identity); 414 | if(isTruthy(subCollection)) 415 | if(foundFalsy(subCollection,property,maxDepth)) result[key] = identity; 416 | }); 417 | return result; 418 | } 419 | if(foundFalsy(collection,property,maxDepth)) return identities; 420 | } 421 | 422 | /** 423 | * Performs deep search on collection to find any match to the property and evalutates if truthy 424 | * @param {Any} collection 425 | * @param {Property} identity 426 | * @param {Optional Number} maxDepth 427 | * @return {boolean} If match confirmed and truthy will return true, otherwise false 428 | */ 429 | function foundFalsy(collection,identity,maxDepth=null){ 430 | identity = singleProperty(identity); 431 | if(isFalsy(identity)) return undefined; 432 | function _foundFalsy(collection,identity,maxDepth,currentDepth=0){ 433 | if(containsKeys(collection,[identity])) return isFalsy(collection[identity]); 434 | if(maxDepth!==null) if(currentDepth >= maxDepth) return false; 435 | if(isIterable(collection)) 436 | for(var i = 0, keys = Object.keys(collection), l = keys.length; i < l; i++ ){ 437 | const 438 | key = keys[i], subcollection = collection[key], 439 | res = _foundFalsy(subcollection,identity,maxDepth,currentDepth + 1); 440 | if(res) return true; 441 | } 442 | return false; 443 | } 444 | return _foundFalsy(collection,identity,maxDepth); 445 | } 446 | 447 | /** 448 | * Performs deep search for each identity on collection, to shorten the identities to those that meets the match criteria 449 | * @param {Any} collection 450 | * @param {Any} identities 451 | * @param {Any} property 452 | * @param {Optional Number} maxDepth 453 | * @return {Any} Returns a collection of the same type as the 'identities' parameter provided with only the identities that matched. 454 | */ 455 | function onlyTruthy(collection,identities,property,maxDepth=null){ 456 | if(getType(identities)==='array'){ 457 | let result = []; 458 | identities.forEach( identity => { 459 | const subCollection = deepFilter(collection,identity); 460 | if(isTruthy(subCollection)) 461 | if(foundTruthy(subCollection,property,maxDepth)) result.push(identity); 462 | }); 463 | return result; 464 | } 465 | if(getType(identities)==='object'){ 466 | let result = {}; 467 | Object.keys(identities).forEach( key => { 468 | const 469 | identity = identities[key], 470 | subCollection = deepFilter(collection,identity); 471 | if(isTruthy(subCollection)) 472 | if(foundTruthy(subCollection,property,maxDepth)) result[key] = identity; 473 | }); 474 | return result; 475 | } 476 | if(foundTruthy(collection,property,maxDepth)) return identities; 477 | } 478 | 479 | /** 480 | * Performs deep search on collection to find any match to the property and evalutates if truthy 481 | * @param {Any} collection 482 | * @param {Property} identity 483 | * @param {Optional Number} maxDepth 484 | * @return {boolean} If match confirmed and truthy will return true, otherwise false 485 | */ 486 | function foundTruthy(collection,identity,maxDepth=null){ 487 | identity = singleProperty(identity); 488 | if(isFalsy(identity)) return undefined; 489 | function _foundTruthy(collection,identity,maxDepth,currentDepth=0){ 490 | if(containsKeys(collection,[identity])) return isTruthy(collection[identity]); 491 | if(maxDepth!==null) if(currentDepth >= maxDepth) return false; 492 | if(isIterable(collection)) 493 | for(var i = 0, keys = Object.keys(collection), l = keys.length; i < l; i++ ){ 494 | const 495 | key = keys[i], subcollection = collection[key], 496 | res = _foundTruthy(subcollection,identity,maxDepth,currentDepth + 1); 497 | if(res) return true; 498 | } 499 | return false; 500 | } 501 | return _foundTruthy(collection,identity,maxDepth,0); 502 | } 503 | 504 | /** 505 | * Validates if identity is equal to a property definition or contains a single property key. 506 | * @param {Property} identity 507 | * @return {String || boolean} If criteria matched will return property name as string, otherwise false 508 | */ 509 | function singleProperty(identity){ 510 | const propCount = length(identity); 511 | if(propCount > 1) return false; 512 | if(propCount===1) return Object.keys(identity)[0]; 513 | if(propCount===0) if(['string','number'].indexOf(getType(identity))>-1) return identity; 514 | return false; 515 | } 516 | 517 | /** 518 | * Determines if identity is non-falsy 519 | * @param {Any} identity 520 | * @return {boolean} Returns true if criteria matched, otherwise false. 521 | */ 522 | function isTruthy(identity){ return !isFalsy(identity); } 523 | 524 | /** 525 | * Determines if identity is falsy 526 | * @param {Any} identity 527 | * @return {boolean} Returns true if criteria matched, otherwise false. 528 | */ 529 | function isFalsy(identity){ 530 | if(falser(identity)===false) return true; 531 | return false; 532 | } 533 | 534 | /** 535 | * Converts false-like values into actual boolean value of false 536 | * @param {Any} identity 537 | * @return {Any || boolean} Returns false is value is falsy, otherwise returns original value. 538 | */ 539 | function falser(identity){ 540 | if(isIterable(identity)) return identity; 541 | if(['null','undefined'].indexOf(getType(identity))>-1) return false; 542 | if(['',0,false].indexOf(identity)>-1) return false; 543 | return identity; 544 | } 545 | 546 | /** 547 | * Check the length of the top-most depth of the identity 548 | * @param {Any} identity 549 | * @return {integer} Greater than or equal to 0. 550 | */ 551 | function length(identity){ 552 | if(['array','object'].indexOf(getType(identity)) === -1) return 0; 553 | return Object.keys(identity).length; 554 | } 555 | 556 | /** 557 | * Performs deep search for each identity on collection, to shorten the identities to those that does meets the match criteria 558 | * @param {Any} collection 559 | * @param {Any} identities 560 | * @param {Optional Number} maxDepth 561 | * @return {Any} Returns a collection of the same type as the 'identities' parameter provided with only the identities that were not matched. 562 | */ 563 | function onlyMissing(collection,identities,maxDepth=null){ 564 | if(getType(identities)==='array'){ 565 | let result = []; 566 | identities.forEach( identity => { 567 | if(!exists(collection,identity,maxDepth)) result.push(identity); 568 | }); 569 | return result; 570 | } 571 | if(getType(identities)==='object'){ 572 | let result = {}; 573 | Object.keys(identities).forEach( key => { 574 | let identity = identities[key]; 575 | if(!exists(collection,identity,maxDepth)) result[key] = identity; 576 | }); 577 | return result; 578 | } 579 | if(!exists(collection,identities,maxDepth)) return identities; 580 | } 581 | 582 | /** 583 | * Performs deep search for each identity on collection, to shorten the identities to those that meets the match criteria 584 | * @param {Any} collection 585 | * @param {Any} identities 586 | * @param {Optional Number} maxDepth 587 | * @return {Any} Returns a collection of the same type as the 'identities' parameter provided with only the identities that matched. 588 | */ 589 | function onlyExisting(collection,identities,maxDepth=null){ 590 | if(getType(identities)==='array'){ 591 | let result = []; 592 | identities.forEach( identity => { 593 | if(exists(collection,identity,maxDepth)) result.push(identity); 594 | }); 595 | return result; 596 | } 597 | if(getType(identities)==='object'){ 598 | let result = {}; 599 | Object.keys(identities).forEach( key => { 600 | let identity = identities[key]; 601 | if(exists(collection,identity,maxDepth)) result[key] = identity; 602 | }); 603 | return result; 604 | } 605 | if(exists(collection,identities,maxDepth)) return identities; 606 | } 607 | 608 | /** 609 | * Performs deep search on collection to find any match to the identity 610 | * @param {Any} collection 611 | * @param {Any} identity 612 | * @param {Optional Number} maxDepth 613 | * @return {boolean} If a match is confirmed will return true, otherwise false 614 | */ 615 | function exists(collection, identity, maxDepth=null, currentDepth=0){ 616 | if(identical(collection,identity)) return true; 617 | if(isIterable(identity)) 618 | if(sameType(collection,identity)) 619 | if(containsKeys(collection,Object.keys(identity))){ 620 | const trimmed = trim(collection,Object.keys(identity)); 621 | if(identical(trimmed,identity)) return true; 622 | } 623 | if(maxDepth === null ? true: (currentDepth < maxDepth)) 624 | if(isIterable(collection)) 625 | for(var i = 0, keys = Object.keys(collection), l = keys.length; i < l; i++ ){ 626 | const 627 | key = keys[i], subcollection = collection[key], 628 | res = exists(subcollection,identity,maxDepth,currentDepth + 1); 629 | if(res) return true; 630 | } 631 | return false; 632 | } 633 | 634 | /** 635 | * Performs deep search on collection to find all matches to the identity, will return a list of identities containing the match. If no matches found, it returns `undefined`. 636 | * @param {Any} collection 637 | * @param {Any} identity 638 | * @param {Optional Number} maxDepth 639 | * @return {Array || undefined} identities 640 | */ 641 | function deepFilter(collection, identity, maxDepth=null){ 642 | var paths = locateAll(collection, identity, maxDepth); 643 | if(paths === false) return undefined; 644 | const results = paths.map(path => { 645 | if(path === '') return collection; 646 | path = path.split('.'); 647 | if(['array','object'].indexOf(getType(identity)) === - 1) path.splice(-1,1); 648 | var result = collection; 649 | if(!Array.isArray(path)) return result[path]; 650 | path.forEach( key => { result = result[key]; }); 651 | return result; 652 | }) 653 | return results; 654 | } 655 | 656 | /** 657 | * Performs deep search on collection to find all matches to the identity, returns a string array containing the location of all matches. If no matches found, it returns `false`. 658 | * @param {Any} collection 659 | * @param {Any} identity 660 | * @param {Optional Number} maxDepth 661 | * @return {Array || false} Paths 662 | */ 663 | function locateAll(collection, identity, maxDepth=null){ 664 | var R = []; 665 | function _locateAll(collection, identity, path = '',maxDepth,currentDepth){ 666 | if(isIterable(identity)) 667 | if(sameType(collection,identity)) 668 | if(containsKeys(collection,Object.keys(identity))){ 669 | const trimmed = trim(collection,Object.keys(identity)); 670 | if(identical(trimmed,identity)) R[R.length] = path; 671 | } 672 | if(identical(collection,identity)) R[R.length] = path; 673 | var result = false; 674 | if(maxDepth!==null)if(currentDepth>=maxDepth) return result; 675 | if(isIterable(collection)) 676 | for(var i = 0, keys = Object.keys(collection), l = keys.length; i < l; i++ ){ 677 | const key = keys[i], subcollection = collection[key]; 678 | _locateAll(subcollection,identity,(path === '' ? path : path + '.') + key,maxDepth,currentDepth + 1); 679 | } 680 | } 681 | _locateAll(collection, identity, '', maxDepth, 0); 682 | return R.length === 0 ? false : R; 683 | } 684 | 685 | /** 686 | * Performs deep search on collection to find a match to the identity, will return the identity containing of the first instance matched. If no matches found, it returns `undefined`. 687 | * @param {Any} collection 688 | * @param {Any} identity 689 | * @param {Optional Number} maxDepth 690 | * @return {identity || undefined} identity 691 | */ 692 | function deepGet(collection, identity, maxDepth=null){ 693 | var path = locate(collection, identity, maxDepth); 694 | if(path === false) return undefined; 695 | if(path === '') return collection; 696 | path = path.split('.'); 697 | if(['array','object'].indexOf(getType(identity)) === - 1) path.splice(-1,1); 698 | var result = collection; 699 | if(!Array.isArray(path)) return result[path]; 700 | path.forEach( key => { result = result[key]; }); 701 | return result; 702 | } 703 | 704 | /** 705 | * Performs deep search on collection to find a match to the identity, will return the path of the first instance matched as string. If no matches found, returns `false`. 706 | * @param {Any} collection 707 | * @param {Any} identity 708 | * @param {Optional number} maxDepth 709 | * @return {string || false} path 710 | */ 711 | function locate(collection, identity, maxDepth=null){ 712 | function _locate(collection, identity, path = '', maxDepth,currentDepth){ 713 | if(isIterable(identity)) 714 | if(sameType(collection,identity)) 715 | if(containsKeys(collection,Object.keys(identity))){ 716 | const trimmed = trim(collection,Object.keys(identity)); 717 | if(identical(trimmed,identity)) return path; 718 | } 719 | if(identical(collection,identity)) return path; 720 | var result = false; 721 | if(maxDepth!==null)if(currentDepth>=maxDepth) return result; 722 | 723 | if(isIterable(collection)) 724 | for(var i = 0, keys = Object.keys(collection), l = keys.length; i < l; i++ ){ 725 | const 726 | key = keys[i], subcollection = collection[key], 727 | res = _locate(subcollection,identity,key,maxDepth,currentDepth + 1); 728 | if(res) { path = path === '' ? path : path + '.'; result = path + res; break; } 729 | } 730 | return result; 731 | } 732 | return _locate(collection, identity,'', maxDepth,0); 733 | } 734 | 735 | /** 736 | * Trims an identity to only contain the specified properties. 737 | * @param {Any} identity 738 | * @param {Any} keyList 739 | * @return {Object or Array} Returns , otherwise false 740 | */ 741 | function trim(identity,keyList){ 742 | const identityType = getType(identity); 743 | if(['array','object'].indexOf(identityType) === -1) return undefined; 744 | const keyCount = keyList.length; 745 | if(keyCount === 0) return undefined; 746 | var newIdentity; 747 | switch(identityType){ 748 | case 'object' : newIdentity = {}; keyList.forEach(key => { if(key in identity) newIdentity[key] = identity[key]; }); break; 749 | case 'array' : newIdentity = []; keyList.forEach(key => { if(key in identity) newIdentity.push(identity[key]); }); break; 750 | } 751 | return newIdentity; 752 | } 753 | 754 | /** 755 | * Check if identity contains all of the specified keys 756 | * @param {Any} identity 757 | * @param {Array} keyList 758 | * @return {boolean} true || false 759 | */ 760 | function containsKeys(identity,keyList){ 761 | const keyCount = keyList.length; 762 | if(keyCount === 0 || !isIterable(identity)) return false; 763 | const identitykeys = Object.keys(identity); 764 | var result = true; 765 | for(var i = 0; i < keyCount; i++){ 766 | const key = '' + keyList[i]; 767 | if(identitykeys.indexOf(key) === -1){ result = false; break; } 768 | } 769 | return result; 770 | } 771 | 772 | /** 773 | * Check if identity has one or more keys to iterate 774 | * @param {Any} identity 775 | * @return {boolean} true || false 776 | */ 777 | function isIterable(identity){ 778 | if(['array','object'].indexOf(getType(identity)) === -1) return false; 779 | if(Object.keys(identity).length === 0) return false; 780 | return true; 781 | } 782 | 783 | /** 784 | * Compares two identities, will return either true if identical, otherwise false. 785 | * @param {Any} identityA 786 | * @param {Any} identityB 787 | * @return {boolean} true || false 788 | */ 789 | function identical(identityA,identityB){ 790 | const structureMatch = sameStructure(identityA,identityB); 791 | if(structureMatch === false) return structureMatch; 792 | if(['array','object'].indexOf(structureMatch) === -1) return identityA === identityB; 793 | const Keys = Object.keys(identityA), KeyCount = Keys.length; 794 | var childMatch = true; 795 | for(var i = 0; i < KeyCount; i++) { 796 | const Key = Keys[i], identicalMatch = identical(identityA[Key],identityB[Key]); 797 | if(identicalMatch === false){ childMatch = identicalMatch; break; }; 798 | } 799 | return childMatch; 800 | } 801 | 802 | /** 803 | * Compares data structure of two identities, will return either the dataType or true/false. 804 | * @param {Any} identityA 805 | * @param {Any} identityB 806 | * @return {String || False} DataType as string for positive match, otherwise false 807 | */ 808 | function sameStructure(identityA,identityB){ 809 | const typeMatch = sameType(identityA,identityB); 810 | if(typeMatch === false) return false; 811 | if(['array','object'].indexOf(typeMatch) > -1){ 812 | const 813 | AKeys = Object.keys(identityA), 814 | BKeys = Object.keys(identityB), 815 | AKeyCount = AKeys.length, 816 | BKeyCount = BKeys.length; 817 | if(!(AKeyCount === BKeyCount)) return false; 818 | if(AKeyCount === 0) return true; 819 | for (var i = 0; i < AKeyCount; i++) { 820 | if(AKeys[i] !== BKeys[i]) return false; 821 | } 822 | } 823 | return typeMatch; 824 | } 825 | 826 | /** 827 | * Compares data type of two identities, will dataType if true. 828 | * @param {Any} identityA 829 | * @param {Any} identityB 830 | * @return {boolean} true || false 831 | */ 832 | function sameType(identityA,identityB){ 833 | const typeA = getType(identityA); return typeA === getType(identityB) ? typeA : false; 834 | } 835 | 836 | /** 837 | * Gets data type; makes distintion between object, array, and null. 838 | * @param {Any} identity 839 | * @return {String} dataType 840 | */ 841 | function getType(identity) { 842 | if(identity === null) return 'null'; 843 | const it = typeof identity; 844 | if(it === 'object') if(Array.isArray(identity)) return 'array'; 845 | return it; 846 | } 847 | 848 | var mitsuketa = { 849 | getType : function(identity) { return getType(identity); }, 850 | sameType : function(identityA,identityB) { return sameType(identityA,identityB); }, 851 | sameStructure : function(identityA,identityB) { return sameStructure(identityA,identityB); }, 852 | identical : function(identityA,identityB) { return identical(identityA,identityB); }, 853 | isIterable : function(identity) { return isIterable(identity); }, 854 | containsKeys : function(identity,keyList) { return containsKeys(identity,keyList); }, 855 | trim : function(identity,keyList) { return trim(identity,keyList); }, 856 | locate : function(collection,identity,maxDepth) { return locate(collection,identity,maxDepth); }, 857 | deepGet : function(collection,identity,maxDepth) { return deepGet(collection,identity,maxDepth); }, 858 | locateAll : function(collection,identity,maxDepth) { return locateAll(collection,identity,maxDepth); }, 859 | deepFilter : function(collection,identity,maxDepth) { return deepFilter(collection,identity,maxDepth); }, 860 | exists : function(collection,identity,maxDepth) { return exists(collection,identity,maxDepth); }, 861 | onlyExisting : function(collection,identities,maxDepth) { return onlyExisting(collection,identities,maxDepth); }, 862 | onlyMissing : function(collection,identities,maxDepth) { return onlyMissing(collection,identities,maxDepth); }, 863 | length : function(identity) { return length(identity); }, 864 | isFalsy : function(identity) { return isFalsy(identity); }, 865 | isTruthy : function(identity) { return isTruthy(identity); }, 866 | foundTruthy : function(collection,identity,maxDepth) { return foundTruthy(collection,identity,maxDepth); }, 867 | onlyTruthy : function(collection,identities,property,maxDepth) { return onlyTruthy(collection,identities,property,maxDepth); }, 868 | foundFalsy : function(collection,identity,maxDepth) { return foundFalsy(collection,identity,maxDepth); }, 869 | onlyFalsy : function(collection,identities,property,maxDepth) { return onlyFalsy(collection,identities,property,maxDepth); }, 870 | countMatches : function(collection,identity,nthDepth,maxDepth) { return countMatches(collection,identity,nthDepth,maxDepth); }, 871 | matchDepth : function(collection,identity,maxDepth) { return matchDepth(collection,identity,maxDepth); }, 872 | maxDepth : function(identity,maxLayer) { return maxDepth(identity,maxLayer); }, 873 | locate_Key : function(collection,keyName,maxDepth) { return locate_Key(collection,keyName,maxDepth); }, 874 | deepGet_Key : function(collection,keyName,maxDepth) { return deepGet_Key(collection,keyName,maxDepth); }, 875 | locateAll_Key : function(collection,keyName,maxDepth) { return locateAll_Key(collection,keyName,maxDepth); }, 876 | deepFilter_Key : function(collection,keyName,maxDepth) { return deepFilter_Key(collection,keyName,maxDepth); }, 877 | deepClone : function(identity,maxDepth,startDepth) { return deepClone(identity,maxDepth,startDepth); }, 878 | renameKey : function(identity,keyName,newKeyName,maxDepth) { return renameKey(identity,keyName,newKeyName,maxDepth); }, 879 | renameKeys : function(identity,keyName,newKeyName,maxDepth) { return renameKeys(identity,keyName,newKeyName,maxDepth); }, 880 | deepRemove_Key : function(identity,keyName,maxDepth) { return deepRemove_Key(identity,keyName,maxDepth); }, 881 | deepRemoveAll_Key : function(identity,keyName,maxDepth) { return deepRemoveAll_Key(identity,keyName,maxDepth); } 882 | } 883 | 884 | module.exports = exports = mitsuketa; --------------------------------------------------------------------------------