├── .babelrc ├── test ├── data.zip ├── setup │ ├── .globals.json │ ├── browser.js │ ├── node.js │ └── setup.js ├── .eslintrc ├── data │ ├── types.json │ ├── simple.json │ ├── conditional-required.json │ ├── generator-definition.json │ ├── grid.json │ ├── complex-keys.json │ ├── tabarray.json │ ├── array.json │ ├── titlemaps.json │ └── sink.json ├── unit │ └── json-schema-form-generator.js └── runner.html ├── CHANGELOG.md ├── .eslintrc ├── .travis.yml ├── .editorconfig ├── src ├── model-to-jsf.js ├── json-schema-form-generator.js ├── jsf-to-model.js ├── generator-form.js ├── form-definitions-generator.js └── generator-schema.js ├── .gitignore ├── LICENSE ├── package.json ├── README.md ├── gulpfile.js └── dist └── json-schema-form-generator.min.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015"] 3 | } 4 | -------------------------------------------------------------------------------- /test/data.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/json-schema-form/json-schema-form-generator-es6/master/test/data.zip -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ### [0.0.1](https://github.com/json-schema-form/json-schema-form-generator/releases/tag/v0.0.1) 2 | 3 | - The first release 4 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parserOptions": { 3 | "ecmaVersion": 6, 4 | "sourceType": "module" 5 | }, 6 | "rules": {}, 7 | "env": { 8 | "browser": true, 9 | "node": true 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "4" 4 | - "5" 5 | - "stable" 6 | sudo: false 7 | script: "gulp coverage" 8 | after_success: 9 | - npm install -g codeclimate-test-reporter 10 | - codeclimate-test-reporter < coverage/lcov.info 11 | -------------------------------------------------------------------------------- /test/setup/.globals.json: -------------------------------------------------------------------------------- 1 | { 2 | "globals": { 3 | "expect": true, 4 | "mock": true, 5 | "sandbox": true, 6 | "spy": true, 7 | "stub": true, 8 | "useFakeServer": true, 9 | "useFakeTimers": true, 10 | "useFakeXMLHttpRequest": true 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/setup/browser.js: -------------------------------------------------------------------------------- 1 | var mochaGlobals = require('./.globals.json').globals; 2 | 3 | window.mocha.setup('bdd'); 4 | window.onload = function() { 5 | window.mocha.checkLeaks(); 6 | window.mocha.globals(Object.keys(mochaGlobals)); 7 | window.mocha.run(); 8 | require('./setup')(window); 9 | }; 10 | -------------------------------------------------------------------------------- /test/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./setup/.globals.json", 3 | "parserOptions": { 4 | "ecmaVersion": 6, 5 | "sourceType": "module" 6 | }, 7 | "rules": { 8 | "strict": 0, 9 | "quotes": [2, "single"], 10 | "no-unused-expressions": 0 11 | }, 12 | "env": { 13 | "browser": true, 14 | "node": true, 15 | "mocha": true 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | root = true; 4 | 5 | [*] 6 | # Ensure there's no lingering whitespace 7 | trim_trailing_whitespace = true 8 | # Ensure a newline at the end of each file 9 | insert_final_newline = true 10 | 11 | [*.js] 12 | # Unix-style newlines 13 | end_of_line = lf 14 | charset = utf-8 15 | indent_style = space 16 | indent_size = 2 17 | -------------------------------------------------------------------------------- /test/data/types.json: -------------------------------------------------------------------------------- 1 | { 2 | "schema": { 3 | "type": "object", 4 | "title": "Types", 5 | "properties": { 6 | "string": { 7 | "type": "string", 8 | "minLength": 3 9 | }, 10 | "integer": { 11 | "type": "integer" 12 | }, 13 | "number": { 14 | "type": "number" 15 | }, 16 | "boolean": { 17 | "type": "boolean" 18 | } 19 | }, 20 | "required": ["number"] 21 | }, 22 | "form": [ 23 | "*", 24 | {"type": "submit", "title": "OK"} 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /test/unit/json-schema-form-generator.js: -------------------------------------------------------------------------------- 1 | import jsonSchemaFormGenerator from '../../src/json-schema-form-generator'; 2 | 3 | describe('jsonSchemaFormGenerator', () => { 4 | describe('Greet function', () => { 5 | beforeEach(() => { 6 | spy(jsonSchemaFormGenerator, 'greet'); 7 | jsonSchemaFormGenerator.greet(); 8 | }); 9 | 10 | it('should have been run once', () => { 11 | expect(jsonSchemaFormGenerator.greet).to.have.been.calledOnce; 12 | }); 13 | 14 | it('should have always returned hello', () => { 15 | expect(jsonSchemaFormGenerator.greet).to.have.always.returned('hello'); 16 | }); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /src/model-to-jsf.js: -------------------------------------------------------------------------------- 1 | var _ = require('lodash'), 2 | formGenerator = require('./form-definitions-generator').default, 3 | definitions; 4 | 5 | const modelToJSF = { 6 | getFormDefinitions(model){ 7 | "use strict"; 8 | definitions = {schema: {type: 'object', properties: {}}, form: []}; 9 | if (_.isArray(model.fields)) { 10 | _.forEach(model.fields, (field) => { 11 | if (field.type) { 12 | definitions = formGenerator.generateField(field, definitions); 13 | } 14 | } 15 | ); 16 | } 17 | return definitions; 18 | }, 19 | addField(field){ 20 | 21 | } 22 | }; 23 | 24 | export default modelToJSF; 25 | -------------------------------------------------------------------------------- /src/json-schema-form-generator.js: -------------------------------------------------------------------------------- 1 | const _ = require('lodash'), 2 | jsfToModel = require('./jsf-to-model.js').default, 3 | modelToJsf = require('./model-to-jsf.js').default; 4 | const jsonSchemaFormGenerator = { 5 | getFormBuilder(schema, form) { 6 | let _schema, _form, _model; 7 | _schema = jsfToModel.getSchema(); 8 | _form = jsfToModel.getForm(); 9 | _model = jsfToModel.getModel(schema, form); 10 | return { 11 | schema: _schema, 12 | form: _form, 13 | model: _model 14 | } 15 | }, 16 | getDefinitions(model){ 17 | "use strict"; 18 | return modelToJsf.getFormDefinitions(model); 19 | }, 20 | 21 | }; 22 | 23 | export default jsonSchemaFormGenerator; 24 | -------------------------------------------------------------------------------- /test/setup/node.js: -------------------------------------------------------------------------------- 1 | global.chai = require('chai'); 2 | global.sinon = require('sinon'); 3 | global.chai.use(require('sinon-chai')); 4 | 5 | require('babel-core/register'); 6 | require('./setup')(); 7 | 8 | /* 9 | Uncomment the following if your library uses features of the DOM, 10 | for example if writing a jQuery extension, and 11 | add 'simple-jsdom' to the `devDependencies` of your package.json 12 | 13 | Note that JSDom doesn't implement the entire DOM API. If you're using 14 | more advanced or experimental features, you may need to switch to 15 | PhantomJS. Setting that up is currently outside of the scope of this 16 | boilerplate. 17 | */ 18 | // import simpleJSDom from 'simple-jsdom'; 19 | // simpleJSDom.install(); 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # Compiled binary addons (http://nodejs.org/api/addons.html) 20 | build/Release 21 | 22 | # Dependency directory 23 | # Commenting this out is preferred by some people, see 24 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 25 | node_modules 26 | bower_components 27 | coverage 28 | tmp 29 | 30 | # Users Environment Variables 31 | .lock-wscript 32 | .idea -------------------------------------------------------------------------------- /test/setup/setup.js: -------------------------------------------------------------------------------- 1 | module.exports = function(root) { 2 | root = root ? root : global; 3 | root.expect = root.chai.expect; 4 | 5 | beforeEach(function() { 6 | // Using these globally-available Sinon features is preferrable, as they're 7 | // automatically restored for you in the subsequent `afterEach` 8 | root.sandbox = root.sinon.sandbox.create(); 9 | root.stub = root.sandbox.stub.bind(root.sandbox); 10 | root.spy = root.sandbox.spy.bind(root.sandbox); 11 | root.mock = root.sandbox.mock.bind(root.sandbox); 12 | root.useFakeTimers = root.sandbox.useFakeTimers.bind(root.sandbox); 13 | root.useFakeXMLHttpRequest = root.sandbox.useFakeXMLHttpRequest.bind(root.sandbox); 14 | root.useFakeServer = root.sandbox.useFakeServer.bind(root.sandbox); 15 | }); 16 | 17 | afterEach(function() { 18 | delete root.stub; 19 | delete root.spy; 20 | root.sandbox.restore(); 21 | }); 22 | }; 23 | -------------------------------------------------------------------------------- /test/data/simple.json: -------------------------------------------------------------------------------- 1 | { 2 | "schema": { 3 | "type": "object", 4 | "title": "Comment", 5 | "properties": { 6 | "name": { 7 | "title": "Name", 8 | "type": "string" 9 | }, 10 | "email": { 11 | "title": "Email", 12 | "type": "string", 13 | "pattern": "^\\S+@\\S+$", 14 | "description": "Email will be used for evil." 15 | }, 16 | "comment": { 17 | "title": "Comment", 18 | "type": "string", 19 | "maxLength": 20, 20 | "validationMessage": "Don't be greedy!" 21 | } 22 | }, 23 | "required": ["name","email","comment"] 24 | }, 25 | "form": [ 26 | "name", 27 | "email", 28 | { 29 | "key": "comment", 30 | "type": "textarea", 31 | "placeholder": "Make a comment" 32 | }, 33 | { 34 | "type": "submit", 35 | "style": "btn-info", 36 | "title": "OK" 37 | } 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /test/data/conditional-required.json: -------------------------------------------------------------------------------- 1 | { 2 | "schema": { 3 | "type": "object", 4 | "properties": { 5 | "switch": { 6 | "title": "Spam me, please", 7 | "type": "boolean" 8 | }, 9 | "email": { 10 | "title": "Email", 11 | "type": "string", 12 | "pattern": "^\\S+@\\S+$", 13 | "description": "Email will be used for evil." 14 | } 15 | }, 16 | "required": ["switch"] 17 | }, 18 | "form": [ 19 | { 20 | "type": "help", 21 | "helpvalue": "

Schema Form does not support oneOf (yet), but you can do a workaround and simulate certain scenarios with 'condition' and 'required' (and/or 'readonly') in the form.

" 22 | }, 23 | "switch", 24 | { 25 | "key": "email", 26 | "condition": "model.switch", 27 | "required": true 28 | }, 29 | { 30 | "key": "email", 31 | "condition": "!model.switch" 32 | }, 33 | { 34 | "type": "submit", 35 | "style": "btn-info", 36 | "title": "OK" 37 | } 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /test/runner.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Tests 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Raphael Owino 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /test/data/generator-definition.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Sample Form", 3 | "type": "schema-form", 4 | "fields": [ 5 | { 6 | "type": "text", 7 | "key": "first_name", 8 | "title": "First name", 9 | "open": false 10 | }, 11 | { 12 | "type": "text", 13 | "key": "last_name", 14 | "title": "Last name", 15 | "open": false 16 | }, 17 | { 18 | "type": "email", 19 | "key": "email", 20 | "title": "Email", 21 | "open": false, 22 | "showAdvance": true, 23 | "fieldAddonRight": "" 24 | }, 25 | { 26 | "type": "date", 27 | "key": "dob", 28 | "title": "Date of Birth", 29 | "open": false 30 | }, 31 | { 32 | "type": "dropdown", 33 | "key": "marital-status", 34 | "title": "Marital Status", 35 | "open": false 36 | }, 37 | { 38 | "type": "date-time", 39 | "key": "check-in", 40 | "title": "Check In", 41 | "open": false 42 | }, 43 | { 44 | "type": "date-time", 45 | "key": "check-out", 46 | "title": "Check Out", 47 | "open": false 48 | }, 49 | { 50 | "type": "textarea", 51 | "key": "bio", 52 | "title": "Biography", 53 | "open": false 54 | } 55 | ] 56 | } 57 | -------------------------------------------------------------------------------- /src/jsf-to-model.js: -------------------------------------------------------------------------------- 1 | var _ = require('lodash'); 2 | const JSFToModel = { 3 | getModel(schema, form){ 4 | let model = {}; 5 | 6 | let index = _.indexOf(form, '*'); 7 | if (index > -1) { 8 | form.splice(index, 1); 9 | _.each(schema.properties, (item, slug)=> { 10 | form.splice(index, 0, {key: slug}); 11 | index++; 12 | }); 13 | } 14 | 15 | 16 | form = _.map(form, (field)=> { 17 | "use strict"; 18 | if (_.isString(field)) { 19 | field = {key: field}; 20 | } 21 | 22 | field.schema = _.get(schema.properties, field.key, {}); 23 | 24 | field = _.defaultsDeep(_.get(field.schema, 'x-schema-form', {}), field, field.schema); 25 | 26 | if(field.type == 'string') 27 | { 28 | field.type = 'text' 29 | if(field.enum) 30 | { 31 | field.type = 'select' 32 | } 33 | } 34 | 35 | return field; 36 | }); 37 | model.fields = form; 38 | return model; 39 | 40 | }, 41 | 42 | getSchema(){ 43 | let definition = require('./generator-schema.js'); 44 | console.log(definition.schema); 45 | return definition.schema; 46 | }, 47 | getForm(){ 48 | let definition = require('./generator-form.js'); 49 | return definition.form; 50 | } 51 | 52 | }; 53 | 54 | export default JSFToModel; 55 | -------------------------------------------------------------------------------- /test/data/grid.json: -------------------------------------------------------------------------------- 1 | { 2 | "schema": { 3 | "type": "object", 4 | "title": "Comment", 5 | "properties": { 6 | "name": { 7 | "title": "Name", 8 | "type": "string" 9 | }, 10 | "email": { 11 | "title": "Email", 12 | "type": "string", 13 | "pattern": "^\\S+@\\S+$", 14 | "description": "Email will be used for evil." 15 | }, 16 | "comment": { 17 | "title": "Comment", 18 | "type": "string", 19 | "maxLength": 20, 20 | "validationMessage": "Don't be greedy!" 21 | } 22 | }, 23 | "required": ["name","email","comment"] 24 | }, 25 | "form": [ 26 | { 27 | "type": "help", 28 | "helpvalue": "
Grid it up with bootstrap
" 29 | }, 30 | { 31 | "type": "section", 32 | "htmlClass": "row", 33 | "items": [ 34 | { 35 | "type": "section", 36 | "htmlClass": "col-xs-6", 37 | "items": ["name"] 38 | }, 39 | { 40 | "type": "section", 41 | "htmlClass": "col-xs-6", 42 | "items": ["email"] 43 | } 44 | ] 45 | }, 46 | { 47 | "key": "comment", 48 | "type": "textarea", 49 | "placeholder": "Make a comment" 50 | }, 51 | { 52 | "type": "submit", 53 | "style": "btn-info", 54 | "title": "OK" 55 | } 56 | ] 57 | } 58 | -------------------------------------------------------------------------------- /test/data/complex-keys.json: -------------------------------------------------------------------------------- 1 | { 2 | "schema": { 3 | "type": "object", 4 | "title": "Complex Key Support", 5 | "properties": { 6 | "a[\"b\"].c": { 7 | "type": "string" 8 | }, 9 | "simple": { 10 | "type": "object", 11 | "properties": { 12 | "prøp": { 13 | "title": "UTF8 in both dot and bracket notation", 14 | "type": "string" 15 | } 16 | } 17 | }, 18 | "array-key": { 19 | "type": "array", 20 | "items": { 21 | "type": "object", 22 | "properties": { 23 | "a'rr[\"l": { 24 | "title": "Control Characters", 25 | "type": "string" 26 | }, 27 | "˙∆∂∞˚¬": { 28 | "type": "string" 29 | } 30 | }, 31 | "required": [ 32 | "a'rr[\"l", 33 | "˙∆∂∞˚¬" 34 | ] 35 | } 36 | } 37 | } 38 | }, 39 | "form": [ 40 | { 41 | "type": "help", 42 | "helpvalue": "Complex keys are only supported with AngularJS version 1.3.x, see known limitations in the docs." 43 | }, 44 | "['a[\"b\"].c']", 45 | { 46 | "key": "array-key", 47 | "items": [ 48 | "['array-key'][]['a'rr[\"l']", 49 | { 50 | "key": "['array-key'][]['˙∆∂∞˚¬']", 51 | "title": "Unicode Characters" 52 | } 53 | ] 54 | }, 55 | { 56 | "key": "simple", 57 | "items": [ 58 | "simple.prøp" 59 | ] 60 | } 61 | ] 62 | } 63 | -------------------------------------------------------------------------------- /test/data/tabarray.json: -------------------------------------------------------------------------------- 1 | { 2 | "schema": { 3 | "type": "object", 4 | "title": "Comment", 5 | "properties": { 6 | "comments": { 7 | "type": "array", 8 | "items": { 9 | "type": "object", 10 | "properties": { 11 | "name": { 12 | "title": "Name", 13 | "type": "string" 14 | }, 15 | "email": { 16 | "title": "Email", 17 | "type": "string", 18 | "pattern": "^\\S+@\\S+$", 19 | "description": "Email will be used for evil." 20 | }, 21 | "comment": { 22 | "title": "Comment", 23 | "type": "string", 24 | "maxLength": 20, 25 | "validationMessage": "Don't be greedy!" 26 | } 27 | }, 28 | "required": ["name","email","comment"] 29 | } 30 | } 31 | } 32 | }, 33 | "form": [ 34 | { 35 | "type": "help", 36 | "helpvalue": "

Tabbed Array Example

Tab arrays can have tabs to the left, top or right.

" 37 | }, 38 | { 39 | "key": "comments", 40 | "type": "tabarray", 41 | "add": "New", 42 | "remove": "Delete", 43 | "style": { 44 | "remove": "btn-danger" 45 | }, 46 | "title": "{{ value.name || 'Tab '+$index }}", 47 | "items": [ 48 | "comments[].name", 49 | "comments[].email", 50 | { 51 | "key": "comments[].comment", 52 | "type": "textarea" 53 | } 54 | ] 55 | }, 56 | { 57 | "type": "submit", 58 | "style": "btn-default", 59 | "title": "OK" 60 | } 61 | ] 62 | } 63 | -------------------------------------------------------------------------------- /test/data/array.json: -------------------------------------------------------------------------------- 1 | { 2 | "schema": { 3 | "type": "object", 4 | "title": "Comment", 5 | "required": ["comments"], 6 | "properties": { 7 | "comments": { 8 | "type": "array", 9 | "maxItems": 2, 10 | "items": { 11 | "type": "object", 12 | "properties": { 13 | "name": { 14 | "title": "Name", 15 | "type": "string" 16 | }, 17 | "email": { 18 | "title": "Email", 19 | "type": "string", 20 | "pattern": "^\\S+@\\S+$", 21 | "description": "Email will be used for evil." 22 | }, 23 | "spam": { 24 | "title": "Spam", 25 | "type": "boolean", 26 | "default": true 27 | }, 28 | "comment": { 29 | "title": "Comment", 30 | "type": "string", 31 | "maxLength": 20, 32 | "validationMessage": "Don't be greedy!" 33 | } 34 | }, 35 | "required": ["name","comment"] 36 | } 37 | } 38 | } 39 | }, 40 | "form": [ 41 | { 42 | "type": "help", 43 | "helpvalue": "

Array Example

Try adding a couple of forms, reorder by drag'n'drop.

" 44 | }, 45 | { 46 | "key": "comments", 47 | "add": "New", 48 | "style": { 49 | "add": "btn-success" 50 | }, 51 | "items": [ 52 | "comments[].name", 53 | "comments[].email", 54 | { 55 | "key": "comments[].spam", 56 | "type": "checkbox", 57 | "title": "Yes I want spam.", 58 | "condition": "model.comments[arrayIndex].email" 59 | }, 60 | { 61 | "key": "comments[].comment", 62 | "type": "textarea" 63 | } 64 | ] 65 | }, 66 | { 67 | "type": "submit", 68 | "style": "btn-info", 69 | "title": "OK" 70 | } 71 | ] 72 | } 73 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "json-schema-form-generator", 3 | "version": "0.0.1", 4 | "description": "A tool to generate json schema forms", 5 | "main": "dist/json-schema-form-generator.js", 6 | "scripts": { 7 | "test": "gulp", 8 | "lint": "gulp lint", 9 | "test-browser": "gulp test-browser", 10 | "watch": "gulp watch", 11 | "build": "gulp build", 12 | "coverage": "gulp coverage" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/json-schema-form/json-schema-form-generator-es6.git" 17 | }, 18 | "keywords": [], 19 | "author": "Raphael Owino ", 20 | "license": "MIT", 21 | "bugs": { 22 | "url": "https://github.com/json-schema-form/json-schema-form-generator-es6/issues" 23 | }, 24 | "homepage": "https://github.com/json-schema-form/json-schema-form-generator-es6", 25 | "devDependencies": { 26 | "babel-core": "^6.3.26", 27 | "babel-loader": "^6.2.0", 28 | "babel-polyfill": "^6.3.14", 29 | "babel-preset-es2015": "^6.3.13", 30 | "babel-register": "^6.3.13", 31 | "chai": "^3.4.1", 32 | "del": "^2.2.0", 33 | "glob": "^7.0.3", 34 | "gulp": "^3.9.0", 35 | "gulp-eslint": "^2.0.0", 36 | "gulp-filter": "^4.0.0", 37 | "gulp-istanbul": "^0.10.3", 38 | "gulp-livereload": "^3.8.1", 39 | "gulp-load-plugins": "^1.1.0", 40 | "gulp-mocha": "^2.2.0", 41 | "gulp-plumber": "^1.0.1", 42 | "gulp-rename": "^1.2.2", 43 | "gulp-sourcemaps": "^1.6.0", 44 | "gulp-uglify": "^1.5.1", 45 | "isparta": "^4.0.0", 46 | "json-loader": "^0.5.3", 47 | "mocha": "^2.3.4", 48 | "sinon": "^1.17.2", 49 | "sinon-chai": "^2.8.0", 50 | "vinyl-source-stream": "^1.1.0", 51 | "webpack": "^1.12.9", 52 | "webpack-stream": "^3.1.0" 53 | }, 54 | "babelBoilerplateOptions": { 55 | "entryFileName": "json-schema-form-generator.js", 56 | "mainVarName": "jsonSchemaFormGenerator" 57 | }, 58 | "dependencies": { 59 | "lodash": "^4.13.1" 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /test/data/titlemaps.json: -------------------------------------------------------------------------------- 1 | { 2 | "model": { 3 | "select": "a", 4 | "array": ["b"] 5 | }, 6 | "schema": { 7 | "type": "object", 8 | "properties": { 9 | "select": { 10 | "title": "Select without titleMap", 11 | "type": "string", 12 | "enum": ["a","b","c"] 13 | }, 14 | "select2": { 15 | "title": "Select with titleMap (old style)", 16 | "type": "string", 17 | "enum": ["a","b","c"] 18 | }, 19 | "noenum": { "type": "string", "title": "No enum, but forms says it's a select" }, 20 | "array": { 21 | "title": "Array with enum defaults to 'checkboxes'", 22 | "type": "array", 23 | "items": { 24 | "type": "string", 25 | "enum": ["a","b","c"] 26 | } 27 | }, 28 | "array2": { 29 | "title": "Array with titleMap", 30 | "type": "array", 31 | "default": ["b","c"], 32 | "items": { 33 | "type": "string", 34 | "enum": ["a","b","c"] 35 | } 36 | }, 37 | "radios": { 38 | "title": "Basic radio button example", 39 | "type": "string", 40 | "enum": ["a","b","c"] 41 | }, 42 | "radiobuttons": { 43 | "title": "Radio buttons used to switch a boolean", 44 | "type": "boolean", 45 | "default": false 46 | } 47 | } 48 | }, 49 | "form": [ 50 | "select", 51 | { 52 | "key": "select2", 53 | "type": "select", 54 | "titleMap": { 55 | "a": "A", 56 | "b": "B", 57 | "c": "C" 58 | } 59 | }, 60 | { 61 | "key": "noenum", 62 | "type": "select", 63 | "titleMap": [ 64 | { "value":"a", "name": "A" }, 65 | { "value":"b", "name":"B" }, 66 | { "value":"c", "name":"C" } 67 | ] 68 | }, 69 | "array", 70 | { 71 | "key": "array2", 72 | "type": "checkboxes", 73 | "titleMap": [ 74 | { "value":"a", "name": "A" }, 75 | { "value":"b", "name":"B" }, 76 | { "value":"c", "name":"C" } 77 | ] 78 | }, 79 | { 80 | "key": "radios", 81 | "type": "radios", 82 | "titleMap": [ 83 | { "value":"c", "name": "C" }, 84 | { "value":"b", "name":"B" }, 85 | { "value":"a", "name":"A" } 86 | ] 87 | }, 88 | { 89 | "key":"radiobuttons", 90 | "type": "radiobuttons", 91 | "titleMap": [ 92 | {"value": false, "name": "No way"}, 93 | {"value": true, "name": "OK"} 94 | ] 95 | } 96 | ] 97 | } 98 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # json-schema-form-generator 2 | 3 | A tool to generate json schema forms 4 | 5 | [![Travis build status](http://img.shields.io/travis/json-schema-form/json-schema-form-generator-es6.svg?style=flat)](https://travis-ci.org/json-schema-form/json-schema-form-generator-es6) 6 | [![Code Climate](https://codeclimate.com/github/json-schema-form/json-schema-form-generator-es6/badges/gpa.svg)](https://codeclimate.com/github/json-schema-form/json-schema-form-generator-es6) 7 | [![Test Coverage](https://codeclimate.com/github/json-schema-form/json-schema-form-generator-es6/badges/coverage.svg)](https://codeclimate.com/github/json-schema-form/json-schema-form-generator-es6) 8 | [![Dependency Status](https://david-dm.org/json-schema-form/json-schema-form-generator-es6.svg)](https://david-dm.org/json-schema-form/json-schema-form-generator-es6) 9 | [![devDependency Status](https://david-dm.org/json-schema-form/json-schema-form-generator-es6/dev-status.svg)](https://david-dm.org/json-schema-form/json-schema-form-generator-es6#info=devDependencies) 10 | 11 | ## Objective 12 | 13 | The goal for this libary is to provide a generator that will allow users of json-schema-form to generate form definitions through various means. This is the base package and will provide translations of simple data into json-schema-form syntax. It will also import json-schema-form definitions and return it in a format that can be used with the GUI. 14 | 15 | ## Installation 16 | 17 | npm install json-schema-generator 18 | 19 | ## Usage 20 | 21 | The generator accepts standard json schema form schema and form as input and will output json schema form schema, form and model that use jsf to edit the form definition. 22 | 23 | 24 | var jsonSchemaFormGenerator = require('json-schema-generator').default; 25 | generator = jsonSchemaFormGenerator.getFormBuilder(schema, form); 26 | 27 | In html: 28 | 29 |
30 | 31 | To get the form definitions, simply call ```getDefinitions``` with the model as parameter 32 | 33 | var output = jsonSchemaFormGenerator.getDefinitions(generator.model); 34 | 35 | 36 | In html, you can then show the form like any standard json schema form: 37 | 38 |
39 | 40 | 41 | NB: The examples use the angular-builder, however the generator is framework agnostic and uses plain javascript. Adapters for different frameworks are required for drop-in usage. 42 | 43 | 44 | ## Todo 45 | 46 | - Support the full json schema form definition 47 | - Enum and Titlemaps 48 | - Fields without keys 49 | - All Json Schema Draft 4 keywords 50 | - Fields with items 51 | - Unit tests 52 | - Framework adapters 53 | - Angular Directive 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /src/generator-form.js: -------------------------------------------------------------------------------- 1 | module.exports.form = [ 2 | { 3 | key: 'fields', 4 | type: 'array', 5 | title: 'Form Fields', 6 | add: 'Add a new Field', 7 | remove: 'Remove Field', 8 | startEmpty: true, 9 | items: [ 10 | { 11 | key: 'fields[].title', 12 | htmlClass: 'hide-label', 13 | placeholder: 'Title' 14 | }, 15 | { 16 | type: 'section', 17 | htmlClass: 'row', 18 | items: [ 19 | { 20 | key: 'fields[].type', 21 | placeholder: 'Type', 22 | notitle: true, 23 | htmlClass: 'col-sm-6 hide-label', 24 | }, 25 | { 26 | key: 'fields[].key', 27 | //type: 'section', 28 | placeholder: 'Key (Unique Identifier)', 29 | notitle: true, 30 | htmlClass: 'col-sm-6 hide-label', 31 | } 32 | ] 33 | }, 34 | { 35 | key: 'fields[].open', 36 | notitle: true, 37 | type: 'hidden' 38 | }, 39 | { 40 | key: 'fields[].description', 41 | type: 'textarea', 42 | placeholder: 'Description', 43 | notitle: true, 44 | }, 45 | { 46 | type: 'section', 47 | htmlClass: 'row', 48 | items: [ 49 | { 50 | key: 'fields[].notitle', 51 | htmlClass: 'col-sm-6' 52 | }, 53 | { 54 | key: 'fields[].showAdvanced', 55 | htmlClass: 'col-sm-6' 56 | }, 57 | ] 58 | }, 59 | { 60 | condition: 'model.fields[arrayIndex].showAdvanced', 61 | type: 'help', 62 | helpvalue: '
' 63 | }, 64 | { 65 | type: 'section', 66 | htmlClass: 'row', 67 | items: [ 68 | { 69 | type: 'section', 70 | htmlClass: 'col-md-4', 71 | items: [ 72 | { 73 | condition: 'model.fields[arrayIndex].showAdvanced', 74 | key: 'fields[].disableSuccessState' 75 | } 76 | ] 77 | }, 78 | { 79 | type: 'section', 80 | htmlClass: 'col-md-4', 81 | items: [ 82 | { 83 | condition: 'model.fields[arrayIndex].showAdvanced', 84 | key: 'fields[].disableErrorState' 85 | } 86 | ] 87 | }, 88 | { 89 | type: 'section', 90 | htmlClass: 'col-md-4', 91 | items: [ 92 | { 93 | condition: 'model.fields[arrayIndex].showAdvanced', 94 | key: 'fields[].readonly' 95 | }, 96 | ] 97 | } 98 | ] 99 | }, 100 | { 101 | condition: 'model.fields[arrayIndex].showAdvanced', 102 | type: 'help', 103 | helpvalue: '
' 104 | }, 105 | { 106 | condition: 'model.fields[arrayIndex].showAdvanced', 107 | key: 'fields[].validationMessage', 108 | type: 'textarea' 109 | }, 110 | { 111 | condition: 'model.fields[arrayIndex].showAdvanced', 112 | key: 'fields[].onChange', 113 | type: 'textarea' 114 | }, 115 | { 116 | condition: 'model.fields[arrayIndex].showAdvanced', 117 | key: 'fields[].feedback' 118 | }, 119 | { 120 | condition: 'model.fields[arrayIndex].showAdvanced', 121 | key: 'fields[].placeholder' 122 | }, 123 | { 124 | condition: 'model.fields[arrayIndex].showAdvanced', 125 | key: 'fields[].ngModelOptions', 126 | type: 'textarea' 127 | }, 128 | { 129 | condition: 'model.fields[arrayIndex].showAdvanced', 130 | key: 'fields[].htmlClass' 131 | }, 132 | { 133 | condition: 'model.fields[arrayIndex].showAdvanced', 134 | key: 'fields[].destroyStrategy' 135 | }, 136 | { 137 | condition: 'model.fields[arrayIndex].showAdvanced', 138 | key: 'fields[].copyValueTo' 139 | }, 140 | { 141 | condition: 'model.fields[arrayIndex].showAdvanced', 142 | key: 'fields[].fieldHtmlClass' 143 | }, 144 | { 145 | condition: 'model.fields[arrayIndex].showAdvanced', 146 | key: 'fields[].labelHtmlClass' 147 | }, 148 | { 149 | condition: 'model.fields[arrayIndex].showAdvanced', 150 | key: 'fields[].condition' 151 | }, 152 | { 153 | condition: 'model.fields[arrayIndex].showAdvanced', 154 | 'key': 'fields[].fieldAddonLeft' 155 | }, 156 | { 157 | condition: 'model.fields[arrayIndex].showAdvanced', 158 | key: 'fields[].fieldAddonRight' 159 | } 160 | 161 | ] 162 | } 163 | ]; 164 | -------------------------------------------------------------------------------- /src/form-definitions-generator.js: -------------------------------------------------------------------------------- 1 | var _ = require('lodash'); 2 | 3 | const formDefinitionsGenerator = { 4 | generateField(field, definitions){ 5 | "use strict"; 6 | let morpher = _.camelCase('_generate_' + field.type.replace('-', '_') + '_field'); 7 | 8 | definitions = this.generateStandardFormAttributes(field, definitions); 9 | definitions = this.generateStandardSchemaAttributes(field, definitions); 10 | 11 | if (_.isFunction(this[morpher])) { 12 | definitions = this[morpher](field, definitions); 13 | } 14 | 15 | return definitions; 16 | }, 17 | generateStandardFormAttributes(field, definitions) { 18 | 19 | let form, formIndex, formProps = [ 20 | 'key', 21 | 'condition', 22 | 'onChange', 23 | 'notitle', 24 | 'showAdvanced', 25 | 'validationMessage', 26 | 'onChange', 27 | 'ngModelOptions', 28 | 'condition', 29 | 'fieldAddonLeft', 30 | 'fieldAddonRight', 31 | 'showAdvanced', 32 | 'validationMessage', 33 | 'onChange', 34 | 'feedback', 35 | 'disableSuccessState', 36 | 'disableErrorState', 37 | 'placeholder', 38 | 'ngModelOptions', 39 | 'readonly', 40 | 'htmlClass', 41 | 'destroyStrategy', 42 | 'copyValueTo', 43 | 'fieldHtmlClass', 44 | 'labelHtmlClass', 45 | 'items' 46 | ]; 47 | form = _.pick(field, formProps); 48 | formIndex = _.findIndex(definitions, {key: field.key}); 49 | if (!form.key) { 50 | form.type = field.type; 51 | form.title = field.title; 52 | formIndex = _.findIndex(definitions, {key: undefined, type: field.type, title: field.title}); 53 | } 54 | if (formIndex > -1) { 55 | definitions.form[formIndex] = form; 56 | } else { 57 | definitions.form.push(form); 58 | } 59 | return definitions; 60 | }, 61 | generateStandardSchemaAttributes(field, definitions) { 62 | 63 | let schemaProps = [ 64 | 'type', 65 | 'format', 66 | 'description', 67 | 'title', 68 | 'minLength', 69 | 'maxLength' 70 | ]; 71 | if (field.key) { 72 | definitions.schema.properties[field.key] = _.pick(field, schemaProps); 73 | } 74 | return definitions; 75 | }, 76 | updateForm(definitions, key, attr, value) { 77 | let index = _.findKey(definitions.form, 'key', key); 78 | definitions.form[index][attr] = value; 79 | return definitions; 80 | }, 81 | generateTextField(field, definitions){ 82 | definitions.schema.properties[field.key]['type'] = 'string'; 83 | return definitions; 84 | }, 85 | generateTextareaField(field, definitions){ 86 | definitions.schema.properties[field.key]['type'] = 'string'; 87 | definitions = this.updateForm(definitions, field.key, 'type', 'textarea'); 88 | return definitions; 89 | }, 90 | generateEmailField(field, definitions){ 91 | definitions.schema.properties[field.key]['type'] = 'string'; 92 | definitions.schema.properties[field.key]['format'] = 'email'; 93 | return definitions; 94 | }, 95 | generateSelectField(field, definitions){ 96 | definitions.schema.properties[field.key]['type'] = 'string'; 97 | definitions.schema.properties[field.key]['enum'] = field.enum; 98 | return definitions; 99 | }, 100 | generateCheckboxField(field, definitions){ 101 | definitions.schema.properties[field.key]['type'] = 'string'; 102 | definitions.schema.properties[field.key]['enum'] = field.enum; 103 | return definitions; 104 | }, 105 | generateDateField(field, definitions){ 106 | definitions.schema.properties[field.key]['type'] = 'string'; 107 | definitions.schema.properties[field.key]['format'] = 'date'; 108 | return definitions; 109 | }, 110 | generateTimeField(field, definitions){ 111 | definitions.schema.properties[field.key]['type'] = 'string'; 112 | definitions.schema.properties[field.key]['format'] = 'time'; 113 | return definitions; 114 | }, 115 | generateDateTimeField(field, definitions){ 116 | definitions.schema.properties[field.key]['type'] = 'string'; 117 | definitions.schema.properties[field.key]['format'] = 'date-time'; 118 | return definitions; 119 | }, 120 | generateFieldsetField(field, definitions){ 121 | if (field.key) { 122 | delete definitions.schema.properties[field.key] 123 | } 124 | return definitions; 125 | }, 126 | generateSectionField(field, definitions){ 127 | return definitions; 128 | }, 129 | generateActionsField(field, definitions){ 130 | return definitions; 131 | }, 132 | generateNumberField(field, definitions){ 133 | return definitions; 134 | }, 135 | generatePasswordField(field, definitions){ 136 | return definitions; 137 | }, 138 | generateCheckboxField(field, definitions){ 139 | return definitions; 140 | }, 141 | generateCheckboxesField(field, definitions){ 142 | return definitions; 143 | }, 144 | generateSubmitField(field, definitions){ 145 | return definitions; 146 | }, 147 | generateButtonField(field, definitions){ 148 | return definitions; 149 | }, 150 | generateRadiosField(field, definitions){ 151 | return definitions; 152 | }, 153 | generateRadiosInlineField(field, definitions){ 154 | return definitions; 155 | }, 156 | generateRadioButtonsField(field, definitions){ 157 | return definitions; 158 | }, 159 | generateHelpField(field, definitions){ 160 | return definitions; 161 | }, 162 | generateTemplateField(field, definitions){ 163 | return definitions; 164 | }, 165 | generateTabField(field, definitions){ 166 | return definitions; 167 | }, 168 | generateArrayField(field, definitions){ 169 | return definitions; 170 | }, 171 | generateTabArrayField(field, definitions){ 172 | return definitions; 173 | }, 174 | } 175 | 176 | export default formDefinitionsGenerator; -------------------------------------------------------------------------------- /src/generator-schema.js: -------------------------------------------------------------------------------- 1 | module.exports.schema = { 2 | type: 'object', 3 | title: 'Comment', 4 | properties: { 5 | name: { 6 | type: 'string' 7 | }, 8 | fields: { 9 | type: 'array', 10 | title: 'Fields', 11 | items: { 12 | type: 'object', 13 | properties: { 14 | open: { 15 | type: 'boolean', 16 | default: true 17 | }, 18 | type: { 19 | title: 'Type', 20 | type: 'string', 21 | enum: [ 22 | 'actions', 23 | 'array', 24 | 'boolean', 25 | 'button', 26 | 'checkbox', 27 | 'checkboxes', 28 | 'date', 29 | 'date-time', 30 | 'email', 31 | 'fieldset', 32 | 'help', 33 | 'number', 34 | 'password', 35 | 'radiobuttons', 36 | 'radios', 37 | 'radios-inline', 38 | 'reset', 39 | 'section', 40 | 'select', 41 | 'submit', 42 | 'submit', 43 | 'tab', 44 | 'tabarray', 45 | 'template', 46 | 'text', 47 | 'textarea', 48 | 'time' 49 | ] 50 | }, 51 | key: { 52 | title: 'Key', 53 | type: 'string', 54 | description: 'Unique identifier' 55 | }, 56 | title: { 57 | condition: 'model.notitle', 58 | title: 'Title', 59 | type: 'string' 60 | }, 61 | notitle: { 62 | type: 'boolean', 63 | title: 'Don\'t show title' 64 | }, 65 | description: { 66 | title: 'Description', 67 | type: 'string' 68 | }, 69 | validationMessage: { 70 | title: 'Validation Message', 71 | description: 'A custom validation error message. It can be a string, an object with error codes as key and messages as values or a custom message function', 72 | type: 'string' 73 | }, 74 | onChange: { 75 | title: 'onChange', 76 | description: 'onChange event handler, expression or function. For expression, modelValue and form are both available. For a function, they will be passed as parameters in that order', 77 | type: 'string' 78 | }, 79 | feedback: { 80 | title: 'Feedback Icon', 81 | description: 'Inline feedback icons. To turn off just set feedback to false. If set to a string that string is evaluated by a ngClass in the decorators scope. If not set att all the default value is { "glyphicon": true, "glyphicon-ok": hasSuccess(), "glyphicon-remove": hasError() }', 82 | type: 'string' 83 | }, 84 | disableSuccessState: { 85 | type: 'boolean', 86 | title: 'Disable Success State', 87 | default: false 88 | }, 89 | disableErrorState: { 90 | type: 'boolean', 91 | title: 'Disable Error State', 92 | default: false 93 | }, 94 | placeholder: { 95 | title: 'Placeholder', 96 | description: 'Placeholder on inputs and textarea', 97 | type: 'string' 98 | }, 99 | ngModelOptions: { 100 | title: 'ng-Model Options', 101 | description: 'Passed along to ng-model-options', 102 | type: 'string' 103 | }, 104 | readonly: { 105 | type: 'boolean', 106 | title: 'Readonly', 107 | default: false 108 | }, 109 | htmlClass: { 110 | title: 'Class', 111 | description: 'CSS Class(es) to be added to the container div e.g. : \'street foobar\'', 112 | type: 'string' 113 | }, 114 | destroyStrategy: { 115 | title: 'Destroy Strategy', 116 | description: 'One of null, empty , remove, or retain. Changes model on $destroy event. default is remove.', 117 | type: 'string' 118 | }, 119 | copyValueTo: { 120 | title: 'Copy Value To', 121 | description: 'Copy values to these schema keys e.g [\'address.street\']. The receiving fields can be shown, but the intent for them is to be hidden.', 122 | type: 'string' 123 | }, 124 | fieldHtmlClass: { 125 | title: 'Field Class', 126 | description: 'CSS Class(es) to be added to field input (or similar)', 127 | type: 'string' 128 | }, 129 | labelHtmlClass: { 130 | title: 'Label Class', 131 | description: 'CSS Class(es) to be added to the label of the field (or similar)', 132 | type: 'string' 133 | }, 134 | condition: { 135 | title: 'Condition', 136 | description: 'Show or hide field depending on an angular expression e.g \'model.age < 18\'. The expression has access to model, modelValue, arrayIndex. The condition need not reference a model value it could be anything on scope.', 137 | type: 'string' 138 | }, 139 | fieldAddonLeft: { 140 | title: 'Field Addon - Left', 141 | description: 'Add html code to left of input field. For reference check bootstrap input groups.', 142 | type: 'string' 143 | }, 144 | fieldAddonRight: { 145 | title: 'Field Addon - Right', 146 | description: 'Add html code to right of input field. For reference check bootstrap input groups.', 147 | type: 'string' 148 | }, 149 | onClick: { 150 | title: 'onClick', 151 | description: 'Function to call when a button/submit is clicked', 152 | type: 'string' 153 | }, 154 | showAdvanced: { 155 | title: 'Show advance options', 156 | type: 'boolean' 157 | } 158 | }, 159 | required: [ 160 | 'key' 161 | ] 162 | } 163 | } 164 | }, 165 | required: ['name'] 166 | }; 167 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | const gulp = require('gulp'); 2 | const loadPlugins = require('gulp-load-plugins'); 3 | const del = require('del'); 4 | const glob = require('glob'); 5 | const path = require('path'); 6 | const isparta = require('isparta'); 7 | const webpack = require('webpack'); 8 | const webpackStream = require('webpack-stream'); 9 | const source = require('vinyl-source-stream'); 10 | 11 | const Instrumenter = isparta.Instrumenter; 12 | const mochaGlobals = require('./test/setup/.globals'); 13 | const manifest = require('./package.json'); 14 | 15 | // Load all of our Gulp plugins 16 | const $ = loadPlugins(); 17 | 18 | // Gather the library data from `package.json` 19 | const config = manifest.babelBoilerplateOptions; 20 | const mainFile = manifest.main; 21 | const destinationFolder = path.dirname(mainFile); 22 | const exportFileName = path.basename(mainFile, path.extname(mainFile)); 23 | 24 | function cleanDist(done) { 25 | del([destinationFolder]).then(() => done()); 26 | } 27 | 28 | function cleanTmp(done) { 29 | del(['tmp']).then(() => done()); 30 | } 31 | 32 | // Lint a set of files 33 | function lint(files) { 34 | return gulp.src(files) 35 | .pipe($.eslint()) 36 | .pipe($.eslint.format()) 37 | .pipe($.eslint.failAfterError()); 38 | } 39 | 40 | function lintSrc() { 41 | return lint('src/**/*.js'); 42 | } 43 | 44 | function lintTest() { 45 | return lint('test/**/*.js'); 46 | } 47 | 48 | function lintGulpfile() { 49 | return lint('gulpfile.js'); 50 | } 51 | 52 | function build() { 53 | return gulp.src(path.join('src', config.entryFileName)) 54 | .pipe(webpackStream({ 55 | output: { 56 | filename: exportFileName + '.js', 57 | libraryTarget: 'umd', 58 | library: config.mainVarName 59 | }, 60 | // Add your own externals here. For instance, 61 | // { 62 | // jquery: true 63 | // } 64 | // would externalize the `jquery` module. 65 | externals: {}, 66 | module: { 67 | loaders: [ 68 | { test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader' } 69 | ] 70 | }, 71 | devtool: 'source-map' 72 | })) 73 | .pipe(gulp.dest(destinationFolder)) 74 | .pipe($.filter(['**', '!**/*.js.map'])) 75 | .pipe($.rename(exportFileName + '.min.js')) 76 | .pipe($.sourcemaps.init({ loadMaps: true })) 77 | .pipe($.uglify()) 78 | .pipe($.sourcemaps.write('./')) 79 | .pipe(gulp.dest(destinationFolder)); 80 | } 81 | 82 | function _mocha() { 83 | return gulp.src(['test/setup/node.js', 'test/unit/**/*.js'], {read: false}) 84 | .pipe($.mocha({ 85 | reporter: 'dot', 86 | globals: Object.keys(mochaGlobals.globals), 87 | ignoreLeaks: false 88 | })); 89 | } 90 | 91 | function _registerBabel() { 92 | require('babel-register'); 93 | } 94 | 95 | function test() { 96 | _registerBabel(); 97 | return _mocha(); 98 | } 99 | 100 | function coverage(done) { 101 | _registerBabel(); 102 | gulp.src(['src/**/*.js']) 103 | .pipe($.istanbul({ instrumenter: Instrumenter })) 104 | .pipe($.istanbul.hookRequire()) 105 | .on('finish', () => { 106 | return test() 107 | .pipe($.istanbul.writeReports()) 108 | .on('end', done); 109 | }); 110 | } 111 | 112 | const watchFiles = ['src/**/*', 'test/**/*', 'package.json', '**/.eslintrc', '.jscsrc']; 113 | 114 | // Run the headless unit tests as you make changes. 115 | function watch() { 116 | gulp.watch(watchFiles, ['test']); 117 | } 118 | // Run the headless unit tests as you make changes. 119 | function watchAndBuild() { 120 | gulp.watch(watchFiles, ['build']); 121 | } 122 | 123 | function testBrowser() { 124 | // Our testing bundle is made up of our unit tests, which 125 | // should individually load up pieces of our application. 126 | // We also include the browser setup file. 127 | const testFiles = glob.sync('./test/unit/**/*.js'); 128 | const allFiles = ['./test/setup/browser.js'].concat(testFiles); 129 | 130 | // Lets us differentiate between the first build and subsequent builds 131 | var firstBuild = true; 132 | 133 | // This empty stream might seem like a hack, but we need to specify all of our files through 134 | // the `entry` option of webpack. Otherwise, it ignores whatever file(s) are placed in here. 135 | return gulp.src('') 136 | .pipe($.plumber()) 137 | .pipe(webpackStream({ 138 | watch: true, 139 | entry: allFiles, 140 | output: { 141 | filename: '__spec-build.js' 142 | }, 143 | // Externals isn't necessary here since these are for tests. 144 | module: { 145 | loaders: [ 146 | // This is what allows us to author in future JavaScript 147 | { test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader' }, 148 | // This allows the test setup scripts to load `package.json` 149 | { test: /\.json$/, exclude: /node_modules/, loader: 'json-loader' } 150 | ] 151 | }, 152 | plugins: [ 153 | // By default, webpack does `n=>n` compilation with entry files. This concatenates 154 | // them into a single chunk. 155 | new webpack.optimize.LimitChunkCountPlugin({ maxChunks: 1 }) 156 | ], 157 | devtool: 'inline-source-map' 158 | }, null, function() { 159 | if (firstBuild) { 160 | $.livereload.listen({port: 35729, host: 'localhost', start: true}); 161 | var watcher = gulp.watch(watchFiles, ['lint']); 162 | } else { 163 | $.livereload.reload('./tmp/__spec-build.js'); 164 | } 165 | firstBuild = false; 166 | })) 167 | .pipe(gulp.dest('./tmp')); 168 | } 169 | 170 | // Remove the built files 171 | gulp.task('clean', cleanDist); 172 | 173 | // Remove our temporary files 174 | gulp.task('clean-tmp', cleanTmp); 175 | 176 | // Lint our source code 177 | gulp.task('lint-src', lintSrc); 178 | 179 | // Lint our test code 180 | gulp.task('lint-test', lintTest); 181 | 182 | // Lint this file 183 | gulp.task('lint-gulpfile', lintGulpfile); 184 | 185 | // Lint everything 186 | gulp.task('lint', ['lint-src', 'lint-test', 'lint-gulpfile']); 187 | 188 | // Build two versions of the library 189 | gulp.task('build', ['lint', 'clean'], build); 190 | 191 | // Lint and run our tests 192 | gulp.task('test', ['lint'], test); 193 | 194 | // Set up coverage and run tests 195 | gulp.task('coverage', ['lint'], coverage); 196 | 197 | // Set up a livereload environment for our spec runner `test/runner.html` 198 | gulp.task('test-browser', ['lint', 'clean-tmp'], testBrowser); 199 | 200 | // Run the headless unit tests as you make changes. 201 | gulp.task('watch', watch); 202 | 203 | // Build new dist as you make changes. 204 | gulp.task('watch-build', watchAndBuild); 205 | 206 | // An alias of test 207 | gulp.task('default', ['test']); 208 | -------------------------------------------------------------------------------- /test/data/sink.json: -------------------------------------------------------------------------------- 1 | { 2 | "schema": { 3 | "type": "object", 4 | "required": [ 5 | "name", 6 | "shoesizeLeft" 7 | ], 8 | "properties": { 9 | "name": { 10 | "title": "Name", 11 | "description": "Gimme yea name lad", 12 | "type": "string", 13 | "pattern": "^[^/]*$", 14 | "minLength": 2 15 | }, 16 | "invitation": { 17 | "type": "string", 18 | "format": "html", 19 | "title": "Invitation Design", 20 | "description": "Design the invitation in full technicolor HTML" 21 | }, 22 | "favorite": { 23 | "title": "Favorite", 24 | "type": "string", 25 | "enum": [ 26 | "undefined", 27 | "null", 28 | "NaN" 29 | ] 30 | }, 31 | "shoesizeLeft": { 32 | "title": "Shoe size (left)", 33 | "default": 42, 34 | "type": "number" 35 | }, 36 | "shoesizeRight": { 37 | "title": "Shoe size (right)", 38 | "default": 42, 39 | "type": "number" 40 | }, 41 | "attributes": { 42 | "type": "object", 43 | "title": "Attributes", 44 | "required": [ 45 | "eyecolor" 46 | ], 47 | "properties": { 48 | "eyecolor": { 49 | "type": "string", 50 | "format": "color", 51 | "title": "Eye color", 52 | "default": "pink" 53 | }, 54 | "haircolor": { 55 | "type": "string", 56 | "title": "Hair color" 57 | }, 58 | "shoulders": { 59 | "type": "object", 60 | "title": "Shoulders", 61 | "properties": { 62 | "left": { 63 | "type": "string", 64 | "title": "Left" 65 | }, 66 | "right": { 67 | "type": "string", 68 | "title": "Right" 69 | } 70 | } 71 | } 72 | } 73 | }, 74 | "things": { 75 | "type": "array", 76 | "title": "I like...", 77 | "items": { 78 | "type": "string", 79 | "enum": [ 80 | "clowns", 81 | "compiling", 82 | "sleeping" 83 | ] 84 | } 85 | }, 86 | "dislike": { 87 | "type": "array", 88 | "title": "I dislike...", 89 | "items": { 90 | "type": "string", 91 | "title": "I hate" 92 | } 93 | }, 94 | "soul": { 95 | "title": "Terms Of Service", 96 | "description": "I agree to sell my undying soul", 97 | "type": "boolean", 98 | "default": true 99 | }, 100 | "soulserial": { 101 | "title": "Soul Serial No", 102 | "type": "string" 103 | }, 104 | "date": { 105 | "title": "Date of party", 106 | "type": "string", 107 | "format": "date" 108 | }, 109 | "radio": { 110 | "title": "Radio type", 111 | "type": "string", 112 | "enum": [ 113 | "Transistor", 114 | "Tube" 115 | ] 116 | }, 117 | "radio2": { 118 | "title": "My Second Radio", 119 | "type": "string", 120 | "enum": [ 121 | "Transistor", 122 | "Tube" 123 | ] 124 | }, 125 | "radiobuttons": { 126 | "type": "string", 127 | "enum": [ 128 | "Select me!", 129 | "No me!" 130 | ] 131 | } 132 | } 133 | }, 134 | "form": [ 135 | { 136 | "type": "fieldset", 137 | "title": "Stuff", 138 | "items": [ 139 | { 140 | "type": "tabs", 141 | "tabs": [ 142 | { 143 | "title": "Simple stuff", 144 | "items": [ 145 | { 146 | "key": "name", 147 | "placeholder": "Check the console", 148 | "onChange": "log(modelValue)", 149 | "feedback": "{'glyphicon': true, 'glyphicon-ok': hasSuccess(), 'glyphicon-star': !hasSuccess() }" 150 | }, 151 | { 152 | "key": "favorite", 153 | "feedback": false 154 | } 155 | ] 156 | }, 157 | { 158 | "title": "More stuff", 159 | "items": [ 160 | "attributes.eyecolor", 161 | "attributes.haircolor", 162 | { 163 | "key": "attributes.shoulders.left", 164 | "title": "Left shoulder", 165 | "description": "This value is copied to attributes.shoulders.right in the model", 166 | "copyValueTo": ["attributes.shoulders.right"] 167 | }, 168 | { 169 | "key": "shoesizeLeft", 170 | "feedback": false, 171 | "copyValueTo":["shoesizeRight"] 172 | }, 173 | { 174 | "key": "shoesizeRight" 175 | }, 176 | { 177 | "key": "invitation", 178 | "tinymceOptions": { 179 | "toolbar": [ 180 | "undo redo| styleselect | bold italic | link image", 181 | "alignleft aligncenter alignright" 182 | ] 183 | } 184 | }, 185 | "things", 186 | "dislike" 187 | ] 188 | } 189 | ] 190 | } 191 | ] 192 | }, 193 | { 194 | "type": "help", 195 | "helpvalue": "
" 196 | }, 197 | "soul", 198 | { 199 | "type": "conditional", 200 | "condition": "modelData.soul", 201 | "items": [ 202 | { 203 | "key": "soulserial", 204 | "placeholder": "ex. 666" 205 | } 206 | ] 207 | }, 208 | { 209 | "key": "date", 210 | "minDate": "2014-06-20" 211 | }, 212 | { 213 | "key": "radio", 214 | "type": "radios", 215 | "titleMap": [ 216 | { 217 | "value": "Transistor", 218 | "name": "Transistor
Not the tube kind." 219 | }, 220 | { 221 | "value": "Tube", 222 | "name": "Tube
The tube kind." 223 | } 224 | ] 225 | }, 226 | { 227 | "key": "radio2", 228 | "type": "radios-inline", 229 | "titleMap": [ 230 | { 231 | "value": "Transistor", 232 | "name": "Transistor
Not the tube kind." 233 | }, 234 | { 235 | "value": "Tube", 236 | "name": "Tube
The tube kind." 237 | } 238 | ] 239 | }, 240 | { 241 | "key": "radiobuttons", 242 | "style": { 243 | "selected": "btn-success", 244 | "unselected": "btn-default" 245 | }, 246 | "type": "radiobuttons", 247 | "notitle": true 248 | }, 249 | { 250 | "type": "actions", 251 | "items": [ 252 | { 253 | "type": "submit", 254 | "style": "btn-info", 255 | "title": "Do It!" 256 | }, 257 | { 258 | "type": "button", 259 | "style": "btn-danger", 260 | "title": "Noooooooooooo", 261 | "onClick": "sayNo()" 262 | } 263 | ] 264 | } 265 | ] 266 | } 267 | -------------------------------------------------------------------------------- /dist/json-schema-form-generator.min.js: -------------------------------------------------------------------------------- 1 | !function(t,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define([],n):"object"==typeof exports?exports.jsonSchemaFormGenerator=n():t.jsonSchemaFormGenerator=n()}(this,function(){return function(t){function n(r){if(e[r])return e[r].exports;var i=e[r]={exports:{},id:r,loaded:!1};return t[r].call(i.exports,i,i.exports,n),i.loaded=!0,i.exports}var e={};return n.m=t,n.c=e,n.p="",n(0)}([function(t,n,e){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var r=(e(1),e(3)["default"]),i=e(6)["default"],u={getFormBuilder:function(t,n){var e=void 0,i=void 0,u=void 0;return e=r.getSchema(),i=r.getForm(),u=r.getModel(t,n),{schema:e,form:i,model:u}},getDefinitions:function(t){return i.getFormDefinitions(t)}};n["default"]=u},function(t,n,e){var r;(function(t,i){(function(){function u(t,n){return t.set(n[0],n[1]),t}function o(t,n){return t.add(n),t}function a(t,n,e){var r=e.length;switch(r){case 0:return t.call(n);case 1:return t.call(n,e[0]);case 2:return t.call(n,e[0],e[1]);case 3:return t.call(n,e[0],e[1],e[2])}return t.apply(n,e)}function c(t,n,e,r){for(var i=-1,u=t?t.length:0;++i-1}function d(t,n,e){for(var r=-1,i=t?t.length:0;++r-1;);return e}function W(t,n){for(var e=t.length;e--&&x(n,t[e],0)>-1;);return e}function M(t){return t&&t.Object===Object?t:null}function B(t,n){for(var e=t.length,r=0;e--;)t[e]===n&&r++;return r}function T(t){return Ie[t]}function D(t){return Fe[t]}function $(t){return"\\"+Ee[t]}function z(t,n){return null==t?Q:t[n]}function P(t,n,e){for(var r=t.length,i=n+(e?1:-1);e?i--:++i-1}function Gn(t,n){var e=this.__data__,r=de(e,t);return r<0?e.push([t,n]):e[r][1]=n,this}function Jn(t){var n=-1,e=t?t.length:0;for(this.clear();++n=n?t:n)),t}function we(t,n,e,r,i,u,o){var a;if(r&&(a=u?r(t,i,u,o):r(t)),a!==Q)return a;if(!ga(t))return t;var c=gs(t);if(c){if(a=Ni(t),!n)return ei(t,a)}else{var l=Pi(t),s=l==Mt||l==Bt;if(ys(t))return Nr(t,n);if(l==$t||l==Ft||s&&!u){if(U(t))return u?t:{};if(a=Vi(s?{}:t),!n)return ii(t,_e(a,t))}else{if(!Se[l])return u?t:{};a=Ki(t,l,we,n)}}o||(o=new ue);var p=o.get(t);if(p)return p;if(o.set(t,a),!c)var h=e?Ri(t):rc(t);return f(h||t,function(i,u){h&&(u=i,i=t[u]),he(a,u,we(i,n,e,r,u,t,o))}),a}function Ie(t){var n=rc(t),e=n.length;return function(r){if(null==r)return!e;for(var i=e;i--;){var u=n[i],o=t[u],a=r[u];if(a===Q&&!(u in Object(r))||!o(a))return!1}return!0}}function Fe(t){return ga(t)?qf(t):{}}function Re(t,n,e){if("function"!=typeof t)throw new kf(nt);return Kf(function(){t.apply(Q,e)},n)}function Ee(t,n,e,r){var i=-1,u=h,o=!0,a=t.length,c=[],f=n.length;if(!a)return c;e&&(n=v(n,F(e))),r?(u=d,o=!1):n.length>=tt&&(u=E,o=!1,n=new ee(n));t:for(;++ii?0:i+e),r=r===Q||r>i?i:$a(r),r<0&&(r+=i),r=e>r?0:za(r);e0&&e(a)?n>1?ze(a,n-1,e,r,i):_(i,a):r||(i[i.length]=a)}return i}function qe(t,n){return t&&jl(t,n,rc)}function Ne(t,n){return t&&Ol(t,n,rc)}function Ve(t,n){return p(n,function(n){return da(t[n])})}function Ke(t,n){n=Qi(n,t)?[n]:Ur(n);for(var e=0,r=n.length;null!=t&&en}function Ge(t,n){return null!=t&&(Ff.call(t,n)||"object"==typeof t&&n in t&&null===$i(t))}function Je(t,n){return null!=t&&n in Object(t)}function Ye(t,n,e){return t>=tl(n,e)&&t=120&&l.length>=120)?new ee(o&&l):Q}l=t[0];var s=-1,p=a[0];t:for(;++s-1;)a!==t&&Vf.call(a,c,1),Vf.call(t,c,1);return t}function wr(t,n){for(var e=t?n.length:0,r=e-1;e--;){var i=n[e];if(e==r||i!==u){var u=i;if(Ji(i))Vf.call(t,i,1);else if(Qi(i,t))delete t[fu(i)];else{var o=Ur(i),a=au(t,o);null!=a&&delete a[fu(Fu(o))]}}}return t}function xr(t,n){return t+Zf(el()*(n-t+1))}function kr(t,n,e,r){for(var i=-1,u=Xf(Hf((n-t)/(e||1)),0),o=Array(u);u--;)o[r?u:++i]=t,t+=e;return o}function Ar(t,n){var e="";if(!t||n<1||n>At)return e;do n%2&&(e+=t),n=Zf(n/2),n&&(t+=t);while(n);return e}function jr(t,n,e,r){n=Qi(n,t)?[n]:Ur(n);for(var i=-1,u=n.length,o=u-1,a=t;null!=a&&++ii?0:i+n),e=e>i?i:e,e<0&&(e+=i),i=n>e?0:e-n>>>0,n>>>=0;for(var u=Array(i);++r>>1,o=t[u];null!==o&&!Ea(o)&&(e?o<=n:o=tt){var f=n?null:Sl(t);if(f)return K(f);o=!1,i=E,c=new ee}else c=n?[]:a;t:for(;++r=r?t:Or(t,n,e)}function Nr(t,n){if(n)return t.slice();var e=new t.constructor(t.length);return t.copy(e),e}function Vr(t){var n=new t.constructor(t.byteLength);return new $f(n).set(new $f(t)),n}function Kr(t,n){var e=n?Vr(t.buffer):t.buffer;return new t.constructor(e,t.byteOffset,t.byteLength)}function Hr(t,n,e){var r=n?e(N(t),!0):N(t);return g(r,u,new t.constructor)}function Zr(t){var n=new t.constructor(t.source,On.exec(t));return n.lastIndex=t.lastIndex,n}function Gr(t,n,e){var r=n?e(K(t),!0):K(t);return g(r,o,new t.constructor)}function Jr(t){return wl?Object(wl.call(t)):{}}function Yr(t,n){var e=n?Vr(t.buffer):t.buffer;return new t.constructor(e,t.byteOffset,t.length)}function Qr(t,n){if(t!==n){var e=t!==Q,r=null===t,i=t===t,u=Ea(t),o=n!==Q,a=null===n,c=n===n,f=Ea(n);if(!a&&!f&&!u&&t>n||u&&o&&c&&!a&&!f||r&&o&&c||!e&&c||!i)return 1;if(!r&&!u&&!f&&t=a)return c;var f=e[r];return c*("desc"==f?-1:1)}}return t.index-n.index}function ti(t,n,e,r){for(var i=-1,u=t.length,o=e.length,a=-1,c=n.length,f=Xf(u-o,0),l=Array(c+f),s=!r;++a1?e[i-1]:Q,o=i>2?e[2]:Q;for(u=t.length>3&&"function"==typeof u?(i--,u):Q,o&&Yi(e[0],e[1],o)&&(u=i<3?Q:u,i=1),n=Object(n);++r-1?n[u?u[o]:o]:Q}}function vi(t){return Vo(function(n){n=ze(n,1);var e=n.length,i=e,u=r.prototype.thru;for(t&&n.reverse();i--;){var o=n[i];if("function"!=typeof o)throw new kf(nt);if(u&&!a&&"wrapper"==Li(o))var a=new r([],(!0))}for(i=a?i:e;++i=tt)return a.plant(r).value();for(var i=0,u=e?n[i].apply(this,t):r;++i1&&y.reverse(),s&&ca))return!1;var f=u.get(t);if(f)return f==n;var l=-1,s=!0,p=i&dt?new ee:Q;for(u.set(t,n);++l-1&&t%1==0&&t=this.__values__.length,n=t?Q:this.__values__[this.__index__++];return{done:t,value:n}}function so(){return this}function po(t){for(var n,r=this;r instanceof e;){var i=su(r);i.__index__=0,i.__values__=Q,n?u.__wrapped__=i:n=i;var u=i;r=r.__wrapped__}return u.__wrapped__=t,n}function ho(){var t=this.__wrapped__;if(t instanceof i){var n=t;return this.__actions__.length&&(n=new i(this)),n=n.reverse(),n.__actions__.push({func:ao,args:[Tu],thisArg:Q}),new r(n,this.__chain__)}return this.thru(Tu)}function vo(){return Tr(this.__wrapped__,this.__actions__)}function _o(t,n,e){var r=gs(t)?s:Me;return e&&Yi(t,n,e)&&(n=Q),r(t,Mi(n,3))}function go(t,n){var e=gs(t)?p:$e;return e(t,Mi(n,3))}function yo(t,n){return ze(Ao(t,n),1)}function mo(t,n){return ze(Ao(t,n),kt)}function bo(t,n,e){return e=e===Q?1:$a(e),ze(Ao(t,n),e)}function wo(t,n){var e=gs(t)?f:kl;return e(t,Mi(n,3))}function xo(t,n){var e=gs(t)?l:Al;return e(t,Mi(n,3))}function ko(t,n,e,r){t=ia(t)?t:_c(t),e=e&&!r?$a(e):0;var i=t.length;return e<0&&(e=Xf(i+e,0)),Ra(t)?e<=i&&t.indexOf(n,e)>-1:!!i&&x(t,n,e)>-1}function Ao(t,n){var e=gs(t)?v:fr;return e(t,Mi(n,3))}function jo(t,n,e,r){return null==t?[]:(gs(n)||(n=null==n?[]:[n]),e=r?Q:e,gs(e)||(e=null==e?[]:[e]),vr(t,n,e))}function Oo(t,n,e){var r=gs(t)?g:j,i=arguments.length<3;return r(t,Mi(n,4),e,i,kl)}function Co(t,n,e){var r=gs(t)?y:j,i=arguments.length<3;return r(t,Mi(n,4),e,i,Al)}function So(t,n){var e=gs(t)?p:$e;return n=Mi(n,3),e(t,function(t,e,r){return!n(t,e,r)})}function Io(t){var n=ia(t)?t:_c(t),e=n.length;return e>0?n[xr(0,e-1)]:Q}function Fo(t,n,e){var r=-1,i=Ta(t),u=i.length,o=u-1;for(n=(e?Yi(t,n,e):n===Q)?1:ye($a(n),0,u);++r0&&(e=n.apply(this,arguments)),t<=1&&(n=Q),e}}function Do(t,n,e){n=e?Q:n;var r=Ci(t,at,Q,Q,Q,Q,Q,n);return r.placeholder=Do.placeholder,r}function $o(t,n,e){n=e?Q:n;var r=Ci(t,ct,Q,Q,Q,Q,Q,n);return r.placeholder=$o.placeholder,r}function zo(t,n,e){function r(n){var e=p,r=h;return p=h=Q,y=n,v=t.apply(r,e)}function i(t){return y=t,_=Kf(a,n),m?r(t):v}function u(t){var e=t-g,r=t-y,i=n-e;return b?tl(i,d-r):i}function o(t){var e=t-g,r=t-y;return g===Q||e>=n||e<0||b&&r>=d}function a(){var t=Wo();return o(t)?c(t):void(_=Kf(a,u(t)))}function c(t){return _=Q,w&&p?r(t):(p=h=Q,v)}function f(){y=0,p=g=h=_=Q}function l(){return _===Q?v:c(Wo())}function s(){var t=Wo(),e=o(t);if(p=arguments,h=this,g=t,e){if(_===Q)return i(g);if(b)return _=Kf(a,n),r(g)}return _===Q&&(_=Kf(a,n)),v}var p,h,d,v,_,g,y=0,m=!1,b=!1,w=!0;if("function"!=typeof t)throw new kf(nt);return n=Pa(n)||0,ga(e)&&(m=!!e.leading,b="maxWait"in e,d=b?Xf(Pa(e.maxWait)||0,n):d,w="trailing"in e?!!e.trailing:w),s.cancel=f,s.flush=l,s}function Po(t){return Ci(t,ht)}function Uo(t,n){if("function"!=typeof t||n&&"function"!=typeof n)throw new kf(nt);var e=function(){var r=arguments,i=n?n.apply(this,r):r[0],u=e.cache;if(u.has(i))return u.get(i);var o=t.apply(this,r);return e.cache=u.set(i,o),o};return e.cache=new(Uo.Cache||Jn),e}function qo(t){if("function"!=typeof t)throw new kf(nt);return function(){return!t.apply(this,arguments)}}function No(t){return To(2,t)}function Vo(t,n){if("function"!=typeof t)throw new kf(nt);return n=Xf(n===Q?t.length-1:$a(n),0),function(){for(var e=arguments,r=-1,i=Xf(e.length-n,0),u=Array(i);++r-1&&t%1==0&&t<=At}function ga(t){var n=typeof t;return!!t&&("object"==n||"function"==n)}function ya(t){return!!t&&"object"==typeof t}function ma(t){return ya(t)&&Pi(t)==Tt}function ba(t,n){return t===n||rr(t,n,Ti(n))}function wa(t,n,e){return e="function"==typeof e?e:Q,rr(t,n,Ti(n),e)}function xa(t){return Oa(t)&&t!=+t}function ka(t){if(El(t))throw new bf("This method is not supported with `core-js`. Try https://github.com/es-shims.");return ir(t)}function Aa(t){return null===t}function ja(t){return null==t}function Oa(t){return"number"==typeof t||ya(t)&&Lf.call(t)==Dt}function Ca(t){if(!ya(t)||Lf.call(t)!=$t||U(t))return!1;var n=$i(t);if(null===n)return!0;var e=Ff.call(n,"constructor")&&n.constructor;return"function"==typeof e&&e instanceof e&&If.call(e)==Ef}function Sa(t){return ga(t)&&Lf.call(t)==Pt}function Ia(t){return va(t)&&t>=-At&&t<=At}function Fa(t){return ya(t)&&Pi(t)==Ut}function Ra(t){return"string"==typeof t||!gs(t)&&ya(t)&&Lf.call(t)==qt}function Ea(t){return"symbol"==typeof t||ya(t)&&Lf.call(t)==Nt}function La(t){return ya(t)&&_a(t.length)&&!!Ce[Lf.call(t)]}function Wa(t){return t===Q}function Ma(t){return ya(t)&&Pi(t)==Vt}function Ba(t){return ya(t)&&Lf.call(t)==Kt}function Ta(t){if(!t)return[];if(ia(t))return Ra(t)?G(t):ei(t);if(Uf&&t[Uf])return q(t[Uf]());var n=Pi(t),e=n==Tt?N:n==Ut?K:_c;return e(t)}function Da(t){if(!t)return 0===t?t:0;if(t=Pa(t),t===kt||t===-kt){var n=t<0?-1:1;return n*jt}return t===t?t:0}function $a(t){var n=Da(t),e=n%1;return n===n?e?n-e:n:0}function za(t){return t?ye($a(t),0,Ct):0}function Pa(t){if("number"==typeof t)return t;if(Ea(t))return Ot;if(ga(t)){var n=da(t.valueOf)?t.valueOf():t;t=ga(n)?n+"":n}if("string"!=typeof t)return 0===t?t:+t;t=t.replace(bn,"");var e=In.test(t);return e||Rn.test(t)?We(t.slice(2),e?2:8):Sn.test(t)?Ot:+t}function Ua(t){return ri(t,ic(t))}function qa(t){return ye($a(t),-At,At)}function Na(t){return null==t?"":Er(t)}function Va(t,n){var e=Fe(t);return n?_e(e,n):e}function Ka(t,n){return b(t,Mi(n,3),qe)}function Ha(t,n){return b(t,Mi(n,3),Ne)}function Za(t,n){return null==t?t:jl(t,Mi(n,3),ic)}function Ga(t,n){return null==t?t:Ol(t,Mi(n,3),ic)}function Ja(t,n){return t&&qe(t,Mi(n,3))}function Ya(t,n){return t&&Ne(t,Mi(n,3))}function Qa(t){return null==t?[]:Ve(t,rc(t))}function Xa(t){return null==t?[]:Ve(t,ic(t))}function tc(t,n,e){var r=null==t?Q:Ke(t,n);return r===Q?e:r}function nc(t,n){return null!=t&&qi(t,n,Ge)}function ec(t,n){return null!=t&&qi(t,n,Je)}function rc(t){var n=eu(t);if(!n&&!ia(t))return or(t);var e=Hi(t),r=!!e,i=e||[],u=i.length;for(var o in t)!Ge(t,o)||r&&("length"==o||Ji(o,u))||n&&"constructor"==o||i.push(o);return i}function ic(t){for(var n=-1,e=eu(t),r=ar(t),i=r.length,u=Hi(t),o=!!u,a=u||[],c=a.length;++nn){var r=t;t=n,n=r}if(e||t%1||n%1){var i=el();return tl(t+i*(n-t+Le("1e-"+((i+"").length-1))),n)}return xr(t,n)}function wc(t){return Ns(Na(t).toLowerCase())}function xc(t){return t=Na(t),t&&t.replace(Ln,T).replace(be,"")}function kc(t,n,e){t=Na(t),n=Er(n);var r=t.length;return e=e===Q?r:ye($a(e),0,r),e-=n.length,e>=0&&t.indexOf(n,e)==e}function Ac(t){return t=Na(t),t&&sn.test(t)?t.replace(fn,D):t}function jc(t){return t=Na(t),t&&mn.test(t)?t.replace(yn,"\\$&"):t}function Oc(t,n,e){t=Na(t),n=$a(n);var r=n?Z(t):0;if(!n||r>=n)return t;var i=(n-r)/2;return bi(Zf(i),e)+t+bi(Hf(i),e)}function Cc(t,n,e){t=Na(t),n=$a(n);var r=n?Z(t):0;return n&&r>>0)?(t=Na(t),t&&("string"==typeof n||null!=n&&!Sa(n))&&(n=Er(n),""==n&&ke.test(t))?qr(G(t),0,e):ul.call(t,n,e)):[]}function Lc(t,n,e){return t=Na(t),e=ye($a(e),0,t.length),t.lastIndexOf(Er(n),e)==e}function Wc(t,e,r){var i=n.templateSettings;r&&Yi(t,e,r)&&(e=Q),t=Na(t),e=ks({},e,i,se);var u,o,a=ks({},e.imports,i.imports,se),c=rc(a),f=R(a,c),l=0,s=e.interpolate||Wn,p="__p += '",h=xf((e.escape||Wn).source+"|"+s.source+"|"+(s===dn?jn:Wn).source+"|"+(e.evaluate||Wn).source+"|$","g"),d="//# sourceURL="+("sourceURL"in e?e.sourceURL:"lodash.templateSources["+ ++Oe+"]")+"\n";t.replace(h,function(n,e,r,i,a,c){return r||(r=i),p+=t.slice(l,c).replace(Mn,$),e&&(u=!0,p+="' +\n__e("+e+") +\n'"),a&&(o=!0,p+="';\n"+a+";\n__p += '"),r&&(p+="' +\n((__t = ("+r+")) == null ? '' : __t) +\n'"),l=c+n.length,n}),p+="';\n";var v=e.variable;v||(p="with (obj) {\n"+p+"\n}\n"),p=(o?p.replace(un,""):p).replace(on,"$1").replace(an,"$1;"),p="function("+(v||"obj")+") {\n"+(v?"":"obj || (obj = {});\n")+"var __t, __p = ''"+(u?", __e = _.escape":"")+(o?", __j = Array.prototype.join;\nfunction print() { __p += __j.call(arguments, '') }\n":";\n")+p+"return __p\n}";var _=Vs(function(){return Function(c,d+"return "+p).apply(Q,f)});if(_.source=p,pa(_))throw _;return _}function Mc(t){return Na(t).toLowerCase()}function Bc(t){return Na(t).toUpperCase()}function Tc(t,n,e){if(t=Na(t),t&&(e||n===Q))return t.replace(bn,"");if(!t||!(n=Er(n)))return t;var r=G(t),i=G(n),u=L(r,i),o=W(r,i)+1;return qr(r,u,o).join("")}function Dc(t,n,e){if(t=Na(t),t&&(e||n===Q))return t.replace(xn,"");if(!t||!(n=Er(n)))return t;var r=G(t),i=W(r,G(n))+1;return qr(r,0,i).join("")}function $c(t,n,e){if(t=Na(t),t&&(e||n===Q))return t.replace(wn,"");if(!t||!(n=Er(n)))return t;var r=G(t),i=L(r,G(n));return qr(r,i).join("")}function zc(t,n){var e=_t,r=gt;if(ga(n)){var i="separator"in n?n.separator:i;e="length"in n?$a(n.length):e,r="omission"in n?Er(n.omission):r}t=Na(t);var u=t.length;if(ke.test(t)){var o=G(t);u=o.length}if(e>=u)return t;var a=e-Z(r);if(a<1)return r;var c=o?qr(o,0,a).join(""):t.slice(0,a);if(i===Q)return c+r;if(o&&(a+=c.length-a),Sa(i)){if(t.slice(a).search(i)){var f,l=c;for(i.global||(i=xf(i.source,Na(On.exec(i))+"g")),i.lastIndex=0;f=i.exec(l);)var s=f.index;c=c.slice(0,s===Q?a:s)}}else if(t.indexOf(Er(i),a)!=a){var p=c.lastIndexOf(i);p>-1&&(c=c.slice(0,p))}return c+r}function Pc(t){return t=Na(t),t&&ln.test(t)?t.replace(cn,J):t}function Uc(t,n,e){return t=Na(t),n=e?Q:n,n===Q&&(n=Ae.test(t)?xe:kn),t.match(n)||[]}function qc(t){var n=t?t.length:0,e=Mi();return t=n?v(t,function(t){if("function"!=typeof t[1])throw new kf(nt);return[e(t[0]),t[1]]}):[],Vo(function(e){for(var r=-1;++rAt)return[];var e=Ct,r=tl(t,Ct);n=Mi(n),t-=Ct;for(var i=S(r,n);++e0){if(++t>=yt)return e}else t=0;return Cl(e,r)}}(),Wl=Uo(function(t){var n=[];return Na(t).replace(gn,function(t,e,r,i){n.push(r?i.replace(An,"$1"):e||t)}),n}),Ml=Vo(function(t,n){return ua(t)?Ee(t,ze(n,1,ua,!0)):[]}),Bl=Vo(function(t,n){var e=Fu(n);return ua(e)&&(e=Q),ua(t)?Ee(t,ze(n,1,ua,!0),Mi(e)):[]}),Tl=Vo(function(t,n){var e=Fu(n);return ua(e)&&(e=Q),ua(t)?Ee(t,ze(n,1,ua,!0),Q,e):[]}),Dl=Vo(function(t){var n=v(t,zr);return n.length&&n[0]===t[0]?Qe(n):[]}),$l=Vo(function(t){var n=Fu(t),e=v(t,zr);return n===Fu(e)?n=Q:e.pop(),e.length&&e[0]===t[0]?Qe(e,Mi(n)):[]}),zl=Vo(function(t){var n=Fu(t),e=v(t,zr);return n===Fu(e)?n=Q:e.pop(),e.length&&e[0]===t[0]?Qe(e,Q,n):[]}),Pl=Vo(Lu),Ul=Vo(function(t,n){n=ze(n,1);var e=t?t.length:0,r=ge(t,n);return wr(t,v(n,function(t){return Ji(t,e)?+t:t}).sort(Qr)),r}),ql=Vo(function(t){return Lr(ze(t,1,ua,!0))}),Nl=Vo(function(t){var n=Fu(t);return ua(n)&&(n=Q),Lr(ze(t,1,ua,!0),Mi(n))}),Vl=Vo(function(t){var n=Fu(t);return ua(n)&&(n=Q),Lr(ze(t,1,ua,!0),Q,n)}),Kl=Vo(function(t,n){return ua(t)?Ee(t,n):[]}),Hl=Vo(function(t){return Dr(p(t,ua))}),Zl=Vo(function(t){var n=Fu(t);return ua(n)&&(n=Q),Dr(p(t,ua),Mi(n))}),Gl=Vo(function(t){var n=Fu(t);return ua(n)&&(n=Q),Dr(p(t,ua),Q,n)}),Jl=Vo(no),Yl=Vo(function(t){var n=t.length,e=n>1?t[n-1]:Q;return e="function"==typeof e?(t.pop(),e):Q,eo(t,e)}),Ql=Vo(function(t){t=ze(t,1);var n=t.length,e=n?t[0]:0,u=this.__wrapped__,o=function(n){return ge(n,t)};return!(n>1||this.__actions__.length)&&u instanceof i&&Ji(e)?(u=u.slice(e,+e+(n?1:0)),u.__actions__.push({func:ao,args:[o],thisArg:Q}),new r(u,this.__chain__).thru(function(t){return n&&!t.length&&t.push(Q),t})):this.thru(o)}),Xl=ui(function(t,n,e){Ff.call(t,e)?++t[e]:t[e]=1}),ts=di(bu),ns=di(wu),es=ui(function(t,n,e){Ff.call(t,e)?t[e].push(n):t[e]=[n]}),rs=Vo(function(t,n,e){var r=-1,i="function"==typeof n,u=Qi(n),o=ia(t)?Array(t.length):[];return kl(t,function(t){var c=i?n:u&&null!=t?t[n]:Q;o[++r]=c?a(c,t,e):tr(t,n,e)}),o}),is=ui(function(t,n,e){t[e]=n}),us=ui(function(t,n,e){t[e?0:1].push(n)},function(){return[[],[]]}),os=Vo(function(t,n){if(null==t)return[];var e=n.length;return e>1&&Yi(t,n[0],n[1])?n=[]:e>2&&Yi(n[0],n[1],n[2])&&(n=[n[0]]),n=1==n.length&&gs(n[0])?n[0]:ze(n,1,Gi),vr(t,n,[])}),as=Vo(function(t,n,e){var r=it;if(e.length){var i=V(e,Wi(as));r|=ft}return Ci(t,r,n,e,i)}),cs=Vo(function(t,n,e){var r=it|ut;if(e.length){var i=V(e,Wi(cs));r|=ft}return Ci(n,r,t,e,i)}),fs=Vo(function(t,n){return Re(t,1,n)}),ls=Vo(function(t,n,e){return Re(t,Pa(n)||0,e)});Uo.Cache=Jn;var ss=Vo(function(t,n){n=1==n.length&&gs(n[0])?v(n[0],F(Mi())):v(ze(n,1,Gi),F(Mi()));var e=n.length;return Vo(function(r){for(var i=-1,u=tl(r.length,e);++i=n}),gs=Array.isArray,ys=Bf?function(t){return t instanceof Bf}:rf,ms=ki(cr),bs=ki(function(t,n){return t<=n}),ws=oi(function(t,n){if(hl||eu(n)||ia(n))return void ri(n,rc(n),t);for(var e in n)Ff.call(n,e)&&he(t,e,n[e])}),xs=oi(function(t,n){if(hl||eu(n)||ia(n))return void ri(n,ic(n),t);for(var e in n)he(t,e,n[e])}),ks=oi(function(t,n,e,r){ri(n,ic(n),t,r)}),As=oi(function(t,n,e,r){ri(n,rc(n),t,r)}),js=Vo(function(t,n){return ge(t,ze(n,1))}),Os=Vo(function(t){return t.push(Q,se),a(ks,Q,t)}),Cs=Vo(function(t){return t.push(Q,ou),a(Es,Q,t)}),Ss=gi(function(t,n,e){t[n]=e},Vc(Kc)),Is=gi(function(t,n,e){Ff.call(t,n)?t[n].push(e):t[n]=[e]},Mi),Fs=Vo(tr),Rs=oi(function(t,n,e){pr(t,n,e)}),Es=oi(function(t,n,e,r){pr(t,n,e,r)}),Ls=Vo(function(t,n){return null==t?{}:(n=v(ze(n,1),fu),_r(t,Ee(Ei(t),n)))}),Ws=Vo(function(t,n){return null==t?{}:_r(t,v(ze(n,1),fu))}),Ms=Oi(rc),Bs=Oi(ic),Ts=si(function(t,n,e){return n=n.toLowerCase(),t+(e?wc(n):n)}),Ds=si(function(t,n,e){return t+(e?"-":"")+n.toLowerCase()}),$s=si(function(t,n,e){return t+(e?" ":"")+n.toLowerCase()}),zs=li("toLowerCase"),Ps=si(function(t,n,e){return t+(e?"_":"")+n.toLowerCase()}),Us=si(function(t,n,e){return t+(e?" ":"")+Ns(n)}),qs=si(function(t,n,e){return t+(e?" ":"")+n.toUpperCase()}),Ns=li("toUpperCase"),Vs=Vo(function(t,n){try{return a(t,Q,n)}catch(e){return pa(e)?e:new bf(e)}}),Ks=Vo(function(t,n){return f(ze(n,1),function(n){n=fu(n),t[n]=as(t[n],t)}),t}),Hs=vi(),Zs=vi(!0),Gs=Vo(function(t,n){return function(e){return tr(e,t,n)}}),Js=Vo(function(t,n){return function(e){return tr(t,e,n)}}),Ys=mi(v),Qs=mi(s),Xs=mi(m),tp=xi(),np=xi(!0),ep=yi(function(t,n){return t+n}),rp=ji("ceil"),ip=yi(function(t,n){return t/n}),up=ji("floor"),op=yi(function(t,n){return t*n}),ap=ji("round"),cp=yi(function(t,n){return t-n});return n.after=Mo,n.ary=Bo,n.assign=ws,n.assignIn=xs,n.assignInWith=ks,n.assignWith=As,n.at=js,n.before=To,n.bind=as,n.bindAll=Ks,n.bindKey=cs,n.castArray=Jo,n.chain=uo,n.chunk=pu,n.compact=hu,n.concat=du,n.cond=qc,n.conforms=Nc,n.constant=Vc,n.countBy=Xl,n.create=Va,n.curry=Do,n.curryRight=$o,n.debounce=zo,n.defaults=Os,n.defaultsDeep=Cs,n.defer=fs,n.delay=ls,n.difference=Ml,n.differenceBy=Bl,n.differenceWith=Tl,n.drop=vu,n.dropRight=_u,n.dropRightWhile=gu,n.dropWhile=yu,n.fill=mu,n.filter=go,n.flatMap=yo,n.flatMapDeep=mo,n.flatMapDepth=bo,n.flatten=xu,n.flattenDeep=ku,n.flattenDepth=Au,n.flip=Po,n.flow=Hs,n.flowRight=Zs,n.fromPairs=ju,n.functions=Qa,n.functionsIn=Xa,n.groupBy=es,n.initial=Su,n.intersection=Dl,n.intersectionBy=$l,n.intersectionWith=zl,n.invert=Ss,n.invertBy=Is,n.invokeMap=rs,n.iteratee=Hc,n.keyBy=is,n.keys=rc,n.keysIn=ic,n.map=Ao,n.mapKeys=uc,n.mapValues=oc,n.matches=Zc,n.matchesProperty=Gc,n.memoize=Uo,n.merge=Rs,n.mergeWith=Es,n.method=Gs,n.methodOf=Js,n.mixin=Jc,n.negate=qo,n.nthArg=Xc,n.omit=Ls,n.omitBy=ac,n.once=No,n.orderBy=jo,n.over=Ys,n.overArgs=ss,n.overEvery=Qs,n.overSome=Xs,n.partial=ps,n.partialRight=hs,n.partition=us,n.pick=Ws,n.pickBy=cc,n.property=tf,n.propertyOf=nf,n.pull=Pl,n.pullAll=Lu,n.pullAllBy=Wu,n.pullAllWith=Mu,n.pullAt=Ul,n.range=tp,n.rangeRight=np,n.rearg=ds,n.reject=So,n.remove=Bu,n.rest=Vo,n.reverse=Tu,n.sampleSize=Fo,n.set=lc,n.setWith=sc,n.shuffle=Ro,n.slice=Du,n.sortBy=os,n.sortedUniq=Vu,n.sortedUniqBy=Ku,n.split=Ec,n.spread=Ko,n.tail=Hu,n.take=Zu,n.takeRight=Gu,n.takeRightWhile=Ju,n.takeWhile=Yu,n.tap=oo,n.throttle=Ho,n.thru=ao,n.toArray=Ta,n.toPairs=Ms,n.toPairsIn=Bs,n.toPath=ff,n.toPlainObject=Ua,n.transform=pc,n.unary=Zo,n.union=ql,n.unionBy=Nl,n.unionWith=Vl,n.uniq=Qu,n.uniqBy=Xu,n.uniqWith=to,n.unset=hc,n.unzip=no,n.unzipWith=eo,n.update=dc,n.updateWith=vc,n.values=_c,n.valuesIn=gc,n.without=Kl,n.words=Uc,n.wrap=Go,n.xor=Hl,n.xorBy=Zl,n.xorWith=Gl,n.zip=Jl,n.zipObject=ro,n.zipObjectDeep=io,n.zipWith=Yl,n.entries=Ms,n.entriesIn=Bs,n.extend=xs,n.extendWith=ks,Jc(n,n),n.add=ep,n.attempt=Vs,n.camelCase=Ts,n.capitalize=wc,n.ceil=rp,n.clamp=yc,n.clone=Yo,n.cloneDeep=Xo,n.cloneDeepWith=ta,n.cloneWith=Qo,n.deburr=xc,n.divide=ip,n.endsWith=kc,n.eq=na,n.escape=Ac,n.escapeRegExp=jc,n.every=_o,n.find=ts,n.findIndex=bu,n.findKey=Ka,n.findLast=ns,n.findLastIndex=wu,n.findLastKey=Ha,n.floor=up,n.forEach=wo,n.forEachRight=xo,n.forIn=Za,n.forInRight=Ga,n.forOwn=Ja,n.forOwnRight=Ya,n.get=tc,n.gt=vs,n.gte=_s,n.has=nc,n.hasIn=ec,n.head=Ou,n.identity=Kc,n.includes=ko,n.indexOf=Cu,n.inRange=mc,n.invoke=Fs,n.isArguments=ea,n.isArray=gs,n.isArrayBuffer=ra,n.isArrayLike=ia,n.isArrayLikeObject=ua,n.isBoolean=oa,n.isBuffer=ys,n.isDate=aa,n.isElement=ca,n.isEmpty=fa,n.isEqual=la,n.isEqualWith=sa,n.isError=pa,n.isFinite=ha,n.isFunction=da,n.isInteger=va,n.isLength=_a,n.isMap=ma,n.isMatch=ba,n.isMatchWith=wa,n.isNaN=xa,n.isNative=ka,n.isNil=ja,n.isNull=Aa,n.isNumber=Oa,n.isObject=ga,n.isObjectLike=ya,n.isPlainObject=Ca,n.isRegExp=Sa,n.isSafeInteger=Ia,n.isSet=Fa,n.isString=Ra,n.isSymbol=Ea,n.isTypedArray=La,n.isUndefined=Wa,n.isWeakMap=Ma,n.isWeakSet=Ba,n.join=Iu,n.kebabCase=Ds,n.last=Fu,n.lastIndexOf=Ru,n.lowerCase=$s,n.lowerFirst=zs,n.lt=ms,n.lte=bs,n.max=sf,n.maxBy=pf,n.mean=hf,n.meanBy=df,n.min=vf,n.minBy=_f,n.stubArray=ef,n.stubFalse=rf,n.stubObject=uf,n.stubString=of,n.stubTrue=af,n.multiply=op,n.nth=Eu,n.noConflict=Yc,n.noop=Qc,n.now=Wo,n.pad=Oc,n.padEnd=Cc,n.padStart=Sc,n.parseInt=Ic,n.random=bc,n.reduce=Oo,n.reduceRight=Co,n.repeat=Fc,n.replace=Rc,n.result=fc,n.round=ap,n.runInContext=Y,n.sample=Io,n.size=Eo,n.snakeCase=Ps,n.some=Lo,n.sortedIndex=$u,n.sortedIndexBy=zu,n.sortedIndexOf=Pu,n.sortedLastIndex=Uu,n.sortedLastIndexBy=qu,n.sortedLastIndexOf=Nu,n.startCase=Us,n.startsWith=Lc,n.subtract=cp,n.sum=gf,n.sumBy=yf,n.template=Wc,n.times=cf,n.toFinite=Da,n.toInteger=$a,n.toLength=za,n.toLower=Mc,n.toNumber=Pa,n.toSafeInteger=qa,n.toString=Na,n.toUpper=Bc,n.trim=Tc,n.trimEnd=Dc,n.trimStart=$c,n.truncate=zc,n.unescape=Pc,n.uniqueId=lf,n.upperCase=qs,n.upperFirst=Ns,n.each=wo,n.eachRight=xo,n.first=Ou,Jc(n,function(){var t={};return qe(n,function(e,r){Ff.call(n.prototype,r)||(t[r]=e)}),t}(),{chain:!1}),n.VERSION=X,f(["bind","bindKey","curry","curryRight","partial","partialRight"],function(t){n[t].placeholder=n}),f(["drop","take"],function(t,n){i.prototype[t]=function(e){var r=this.__filtered__;if(r&&!n)return new i(this);e=e===Q?1:Xf($a(e),0);var u=this.clone();return r?u.__takeCount__=tl(e,u.__takeCount__):u.__views__.push({size:tl(e,Ct),type:t+(u.__dir__<0?"Right":"")}),u},i.prototype[t+"Right"]=function(n){return this.reverse()[t](n).reverse()}}),f(["filter","map","takeWhile"],function(t,n){var e=n+1,r=e==bt||e==xt;i.prototype[t]=function(t){var n=this.clone();return n.__iteratees__.push({iteratee:Mi(t,3),type:e}),n.__filtered__=n.__filtered__||r,n}}),f(["head","last"],function(t,n){var e="take"+(n?"Right":"");i.prototype[t]=function(){return this[e](1).value()[0]}}),f(["initial","tail"],function(t,n){var e="drop"+(n?"":"Right");i.prototype[t]=function(){return this.__filtered__?new i(this):this[e](1)}}),i.prototype.compact=function(){return this.filter(Kc)},i.prototype.find=function(t){return this.filter(t).head()},i.prototype.findLast=function(t){return this.reverse().find(t)},i.prototype.invokeMap=Vo(function(t,n){return"function"==typeof t?new i(this):this.map(function(e){return tr(e,t,n)})}),i.prototype.reject=function(t){return t=Mi(t,3),this.filter(function(n){return!t(n)})},i.prototype.slice=function(t,n){t=$a(t);var e=this;return e.__filtered__&&(t>0||n<0)?new i(e):(t<0?e=e.takeRight(-t):t&&(e=e.drop(t)),n!==Q&&(n=$a(n),e=n<0?e.dropRight(-n):e.take(n-t)),e)},i.prototype.takeRightWhile=function(t){return this.reverse().takeWhile(t).reverse()},i.prototype.toArray=function(){return this.take(Ct)},qe(i.prototype,function(t,e){var u=/^(?:filter|find|map|reject)|While$/.test(e),o=/^(?:head|last)$/.test(e),a=n[o?"take"+("last"==e?"Right":""):e],c=o||/^find/.test(e);a&&(n.prototype[e]=function(){var e=this.__wrapped__,f=o?[1]:arguments,l=e instanceof i,s=f[0],p=l||gs(e),h=function(t){var e=a.apply(n,_([t],f));return o&&d?e[0]:e};p&&u&&"function"==typeof s&&1!=s.length&&(l=p=!1);var d=this.__chain__,v=!!this.__actions__.length,g=c&&!d,y=l&&!v;if(!c&&p){e=y?e:new i(this);var m=t.apply(e,f);return m.__actions__.push({func:ao,args:[h],thisArg:Q}),new r(m,d)}return g&&y?t.apply(this,f):(m=this.thru(h),g?o?m.value()[0]:m.value():m)})}),f(["pop","push","shift","sort","splice","unshift"],function(t){var e=Af[t],r=/^(?:push|sort|unshift)$/.test(t)?"tap":"thru",i=/^(?:pop|shift)$/.test(t);n.prototype[t]=function(){var t=arguments;if(i&&!this.__chain__){var n=this.value();return e.apply(gs(n)?n:[],t)}return this[r](function(n){return e.apply(gs(n)?n:[],t)})}}),qe(i.prototype,function(t,e){var r=n[e];if(r){var i=r.name+"",u=dl[i]||(dl[i]=[]);u.push({name:e,func:r})}}),dl[_i(Q,ut).name]=[{name:"wrapper",func:Q}],i.prototype.clone=M,i.prototype.reverse=Bn,i.prototype.value=Tn,n.prototype.at=Ql,n.prototype.chain=co,n.prototype.commit=fo,n.prototype.next=lo,n.prototype.plant=po,n.prototype.reverse=ho,n.prototype.toJSON=n.prototype.valueOf=n.prototype.value=vo,Uf&&(n.prototype[Uf]=so),n}var Q,X="4.13.1",tt=200,nt="Expected a function",et="__lodash_hash_undefined__",rt="__lodash_placeholder__",it=1,ut=2,ot=4,at=8,ct=16,ft=32,lt=64,st=128,pt=256,ht=512,dt=1,vt=2,_t=30,gt="...",yt=150,mt=16,bt=1,wt=2,xt=3,kt=1/0,At=9007199254740991,jt=1.7976931348623157e308,Ot=NaN,Ct=4294967295,St=Ct-1,It=Ct>>>1,Ft="[object Arguments]",Rt="[object Array]",Et="[object Boolean]",Lt="[object Date]",Wt="[object Error]",Mt="[object Function]",Bt="[object GeneratorFunction]",Tt="[object Map]",Dt="[object Number]",$t="[object Object]",zt="[object Promise]",Pt="[object RegExp]",Ut="[object Set]",qt="[object String]",Nt="[object Symbol]",Vt="[object WeakMap]",Kt="[object WeakSet]",Ht="[object ArrayBuffer]",Zt="[object DataView]",Gt="[object Float32Array]",Jt="[object Float64Array]",Yt="[object Int8Array]",Qt="[object Int16Array]",Xt="[object Int32Array]",tn="[object Uint8Array]",nn="[object Uint8ClampedArray]",en="[object Uint16Array]",rn="[object Uint32Array]",un=/\b__p \+= '';/g,on=/\b(__p \+=) '' \+/g,an=/(__e\(.*?\)|\b__t\)) \+\n'';/g,cn=/&(?:amp|lt|gt|quot|#39|#96);/g,fn=/[&<>"'`]/g,ln=RegExp(cn.source),sn=RegExp(fn.source),pn=/<%-([\s\S]+?)%>/g,hn=/<%([\s\S]+?)%>/g,dn=/<%=([\s\S]+?)%>/g,vn=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,_n=/^\w*$/,gn=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(\.|\[\])(?:\4|$))/g,yn=/[\\^$.*+?()[\]{}|]/g,mn=RegExp(yn.source),bn=/^\s+|\s+$/g,wn=/^\s+/,xn=/\s+$/,kn=/[a-zA-Z0-9]+/g,An=/\\(\\)?/g,jn=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,On=/\w*$/,Cn=/^0x/i,Sn=/^[-+]0x[0-9a-f]+$/i,In=/^0b[01]+$/i,Fn=/^\[object .+?Constructor\]$/,Rn=/^0o[0-7]+$/i,En=/^(?:0|[1-9]\d*)$/,Ln=/[\xc0-\xd6\xd8-\xde\xdf-\xf6\xf8-\xff]/g,Wn=/($^)/,Mn=/['\n\r\u2028\u2029\\]/g,Bn="\\ud800-\\udfff",Tn="\\u0300-\\u036f\\ufe20-\\ufe23",Dn="\\u20d0-\\u20f0",$n="\\u2700-\\u27bf",zn="a-z\\xdf-\\xf6\\xf8-\\xff",Pn="\\xac\\xb1\\xd7\\xf7",Un="\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf",qn="\\u2000-\\u206f",Nn=" \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000",Vn="A-Z\\xc0-\\xd6\\xd8-\\xde",Kn="\\ufe0e\\ufe0f",Hn=Pn+Un+qn+Nn,Zn="['’]",Gn="["+Bn+"]",Jn="["+Hn+"]",Yn="["+Tn+Dn+"]",Qn="\\d+",Xn="["+$n+"]",te="["+zn+"]",ne="[^"+Bn+Hn+Qn+$n+zn+Vn+"]",ee="\\ud83c[\\udffb-\\udfff]",re="(?:"+Yn+"|"+ee+")",ie="[^"+Bn+"]",ue="(?:\\ud83c[\\udde6-\\uddff]){2}",oe="[\\ud800-\\udbff][\\udc00-\\udfff]",ae="["+Vn+"]",ce="\\u200d",fe="(?:"+te+"|"+ne+")",le="(?:"+ae+"|"+ne+")",se="(?:"+Zn+"(?:d|ll|m|re|s|t|ve))?",pe="(?:"+Zn+"(?:D|LL|M|RE|S|T|VE))?",he=re+"?",de="["+Kn+"]?",ve="(?:"+ce+"(?:"+[ie,ue,oe].join("|")+")"+de+he+")*",_e=de+he+ve,ge="(?:"+[Xn,ue,oe].join("|")+")"+_e,ye="(?:"+[ie+Yn+"?",Yn,ue,oe,Gn].join("|")+")",me=RegExp(Zn,"g"),be=RegExp(Yn,"g"),we=RegExp(ee+"(?="+ee+")|"+ye+_e,"g"),xe=RegExp([ae+"?"+te+"+"+se+"(?="+[Jn,ae,"$"].join("|")+")",le+"+"+pe+"(?="+[Jn,ae+fe,"$"].join("|")+")",ae+"?"+fe+"+"+se,ae+"+"+pe,Qn,ge].join("|"),"g"),ke=RegExp("["+ce+Bn+Tn+Dn+Kn+"]"),Ae=/[a-z][A-Z]|[A-Z]{2,}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,je=["Array","Buffer","DataView","Date","Error","Float32Array","Float64Array","Function","Int8Array","Int16Array","Int32Array","Map","Math","Object","Promise","Reflect","RegExp","Set","String","Symbol","TypeError","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","WeakMap","_","isFinite","parseInt","setTimeout"],Oe=-1,Ce={}; 3 | Ce[Gt]=Ce[Jt]=Ce[Yt]=Ce[Qt]=Ce[Xt]=Ce[tn]=Ce[nn]=Ce[en]=Ce[rn]=!0,Ce[Ft]=Ce[Rt]=Ce[Ht]=Ce[Et]=Ce[Zt]=Ce[Lt]=Ce[Wt]=Ce[Mt]=Ce[Tt]=Ce[Dt]=Ce[$t]=Ce[Pt]=Ce[Ut]=Ce[qt]=Ce[Vt]=!1;var Se={};Se[Ft]=Se[Rt]=Se[Ht]=Se[Zt]=Se[Et]=Se[Lt]=Se[Gt]=Se[Jt]=Se[Yt]=Se[Qt]=Se[Xt]=Se[Tt]=Se[Dt]=Se[$t]=Se[Pt]=Se[Ut]=Se[qt]=Se[Nt]=Se[tn]=Se[nn]=Se[en]=Se[rn]=!0,Se[Wt]=Se[Mt]=Se[Vt]=!1;var Ie={"À":"A","Á":"A","Â":"A","Ã":"A","Ä":"A","Å":"A","à":"a","á":"a","â":"a","ã":"a","ä":"a","å":"a","Ç":"C","ç":"c","Ð":"D","ð":"d","È":"E","É":"E","Ê":"E","Ë":"E","è":"e","é":"e","ê":"e","ë":"e","Ì":"I","Í":"I","Î":"I","Ï":"I","ì":"i","í":"i","î":"i","ï":"i","Ñ":"N","ñ":"n","Ò":"O","Ó":"O","Ô":"O","Õ":"O","Ö":"O","Ø":"O","ò":"o","ó":"o","ô":"o","õ":"o","ö":"o","ø":"o","Ù":"U","Ú":"U","Û":"U","Ü":"U","ù":"u","ú":"u","û":"u","ü":"u","Ý":"Y","ý":"y","ÿ":"y","Æ":"Ae","æ":"ae","Þ":"Th","þ":"th","ß":"ss"},Fe={"&":"&","<":"<",">":">",'"':""","'":"'","`":"`"},Re={"&":"&","<":"<",">":">",""":'"',"'":"'","`":"`"},Ee={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},Le=parseFloat,We=parseInt,Me="object"==typeof n&&n,Be=Me&&"object"==typeof t&&t,Te=Be&&Be.exports===Me,De=M("object"==typeof i&&i),$e=M("object"==typeof self&&self),ze=M("object"==typeof this&&this),Pe=De||$e||ze||Function("return this")(),Ue=Y();($e||{})._=Ue,r=function(){return Ue}.call(n,e,n,t),!(r!==Q&&(t.exports=r))}).call(this)}).call(n,e(2)(t),function(){return this}())},function(t,n){t.exports=function(t){return t.webpackPolyfill||(t.deprecate=function(){},t.paths=[],t.children=[],t.webpackPolyfill=1),t}},function(t,n,e){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var r=e(1),i={getModel:function(t,n){var e={},i=r.indexOf(n,"*");return i>-1&&(n.splice(i,1),r.each(t.properties,function(t,e){n.splice(i,0,{key:e}),i++})),n=r.map(n,function(n){return r.isString(n)&&(n={key:n}),n.schema=r.get(t.properties,n.key,{}),n=r.defaultsDeep(r.get(n.schema,"x-schema-form",{}),n,n.schema),"string"==n.type&&(n.type="text",n["enum"]&&(n.type="select")),n}),e.fields=n,e},getSchema:function(){var t=e(4);return console.log(t.schema),t.schema},getForm:function(){var t=e(5);return t.form}};n["default"]=i},function(t,n){"use strict";t.exports.schema={type:"object",title:"Comment",properties:{name:{type:"string"},fields:{type:"array",title:"Fields",items:{type:"object",properties:{open:{type:"boolean","default":!0},type:{title:"Type",type:"string","enum":["actions","array","boolean","button","checkbox","checkboxes","date","date-time","email","fieldset","help","number","password","radiobuttons","radios","radios-inline","reset","section","select","submit","submit","tab","tabarray","template","text","textarea","time"]},key:{title:"Key",type:"string",description:"Unique identifier"},title:{condition:"model.notitle",title:"Title",type:"string"},notitle:{type:"boolean",title:"Don't show title"},description:{title:"Description",type:"string"},validationMessage:{title:"Validation Message",description:"A custom validation error message. It can be a string, an object with error codes as key and messages as values or a custom message function",type:"string"},onChange:{title:"onChange",description:"onChange event handler, expression or function. For expression, modelValue and form are both available. For a function, they will be passed as parameters in that order",type:"string"},feedback:{title:"Feedback Icon",description:'Inline feedback icons. To turn off just set feedback to false. If set to a string that string is evaluated by a ngClass in the decorators scope. If not set att all the default value is { "glyphicon": true, "glyphicon-ok": hasSuccess(), "glyphicon-remove": hasError() }',type:"string"},disableSuccessState:{type:"boolean",title:"Disable Success State","default":!1},disableErrorState:{type:"boolean",title:"Disable Error State","default":!1},placeholder:{title:"Placeholder",description:"Placeholder on inputs and textarea",type:"string"},ngModelOptions:{title:"ng-Model Options",description:"Passed along to ng-model-options",type:"string"},readonly:{type:"boolean",title:"Readonly","default":!1},htmlClass:{title:"Class",description:"CSS Class(es) to be added to the container div e.g. : 'street foobar'",type:"string"},destroyStrategy:{title:"Destroy Strategy",description:"One of null, empty , remove, or retain. Changes model on $destroy event. default is remove.",type:"string"},copyValueTo:{title:"Copy Value To",description:"Copy values to these schema keys e.g ['address.street']. The receiving fields can be shown, but the intent for them is to be hidden.",type:"string"},fieldHtmlClass:{title:"Field Class",description:"CSS Class(es) to be added to field input (or similar)",type:"string"},labelHtmlClass:{title:"Label Class",description:"CSS Class(es) to be added to the label of the field (or similar)",type:"string"},condition:{title:"Condition",description:"Show or hide field depending on an angular expression e.g 'model.age < 18'. The expression has access to model, modelValue, arrayIndex. The condition need not reference a model value it could be anything on scope.",type:"string"},fieldAddonLeft:{title:"Field Addon - Left",description:"Add html code to left of input field. For reference check bootstrap input groups.",type:"string"},fieldAddonRight:{title:"Field Addon - Right",description:"Add html code to right of input field. For reference check bootstrap input groups.",type:"string"},onClick:{title:"onClick",description:"Function to call when a button/submit is clicked",type:"string"},showAdvanced:{title:"Show advance options",type:"boolean"}},required:["key"]}}},required:["name"]}},function(t,n){"use strict";t.exports.form=[{key:"fields",type:"array",title:"Form Fields",add:"Add a new Field",remove:"Remove Field",startEmpty:!0,items:[{key:"fields[].title",htmlClass:"hide-label",placeholder:"Title"},{type:"section",htmlClass:"row",items:[{key:"fields[].type",placeholder:"Type",notitle:!0,htmlClass:"col-sm-6 hide-label"},{key:"fields[].key",placeholder:"Key (Unique Identifier)",notitle:!0,htmlClass:"col-sm-6 hide-label"}]},{key:"fields[].open",notitle:!0,type:"hidden"},{key:"fields[].description",type:"textarea",placeholder:"Description",notitle:!0},{type:"section",htmlClass:"row",items:[{key:"fields[].notitle",htmlClass:"col-sm-6"},{key:"fields[].showAdvanced",htmlClass:"col-sm-6"}]},{condition:"model.fields[arrayIndex].showAdvanced",type:"help",helpvalue:"
"},{type:"section",htmlClass:"row",items:[{type:"section",htmlClass:"col-md-4",items:[{condition:"model.fields[arrayIndex].showAdvanced",key:"fields[].disableSuccessState"}]},{type:"section",htmlClass:"col-md-4",items:[{condition:"model.fields[arrayIndex].showAdvanced",key:"fields[].disableErrorState"}]},{type:"section",htmlClass:"col-md-4",items:[{condition:"model.fields[arrayIndex].showAdvanced",key:"fields[].readonly"}]}]},{condition:"model.fields[arrayIndex].showAdvanced",type:"help",helpvalue:"
"},{condition:"model.fields[arrayIndex].showAdvanced",key:"fields[].validationMessage",type:"textarea"},{condition:"model.fields[arrayIndex].showAdvanced",key:"fields[].onChange",type:"textarea"},{condition:"model.fields[arrayIndex].showAdvanced",key:"fields[].feedback"},{condition:"model.fields[arrayIndex].showAdvanced",key:"fields[].placeholder"},{condition:"model.fields[arrayIndex].showAdvanced",key:"fields[].ngModelOptions",type:"textarea"},{condition:"model.fields[arrayIndex].showAdvanced",key:"fields[].htmlClass"},{condition:"model.fields[arrayIndex].showAdvanced",key:"fields[].destroyStrategy"},{condition:"model.fields[arrayIndex].showAdvanced",key:"fields[].copyValueTo"},{condition:"model.fields[arrayIndex].showAdvanced",key:"fields[].fieldHtmlClass"},{condition:"model.fields[arrayIndex].showAdvanced",key:"fields[].labelHtmlClass"},{condition:"model.fields[arrayIndex].showAdvanced",key:"fields[].condition"},{condition:"model.fields[arrayIndex].showAdvanced",key:"fields[].fieldAddonLeft"},{condition:"model.fields[arrayIndex].showAdvanced",key:"fields[].fieldAddonRight"}]}]},function(t,n,e){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var r,i=e(1),u=e(7)["default"],o={getFormDefinitions:function(t){return r={schema:{type:"object",properties:{}},form:[]},i.isArray(t.fields)&&i.forEach(t.fields,function(t){t.type&&(r=u.generateField(t,r))}),r},addField:function(t){}};n["default"]=o},function(t,n,e){"use strict";function r(t,n,e){return n in t?Object.defineProperty(t,n,{value:e,enumerable:!0,configurable:!0,writable:!0}):t[n]=e,t}Object.defineProperty(n,"__esModule",{value:!0});var i,u=e(1),o=(i={generateField:function(t,n){var e=u.camelCase("_generate_"+t.type.replace("-","_")+"_field");return n=this.generateStandardFormAttributes(t,n),n=this.generateStandardSchemaAttributes(t,n),u.isFunction(this[e])&&(n=this[e](t,n)),n},generateStandardFormAttributes:function(t,n){var e=void 0,r=void 0,i=["key","condition","onChange","notitle","showAdvanced","validationMessage","onChange","ngModelOptions","condition","fieldAddonLeft","fieldAddonRight","showAdvanced","validationMessage","onChange","feedback","disableSuccessState","disableErrorState","placeholder","ngModelOptions","readonly","htmlClass","destroyStrategy","copyValueTo","fieldHtmlClass","labelHtmlClass","items"];return e=u.pick(t,i),r=u.findIndex(n,{key:t.key}),e.key||(e.type=t.type,e.title=t.title,r=u.findIndex(n,{key:void 0,type:t.type,title:t.title})),r>-1?n.form[r]=e:n.form.push(e),n},generateStandardSchemaAttributes:function(t,n){var e=["type","format","description","title","minLength","maxLength"];return t.key&&(n.schema.properties[t.key]=u.pick(t,e)),n},updateForm:function(t,n,e,r){var i=u.findKey(t.form,"key",n);return t.form[i][e]=r,t},generateTextField:function(t,n){return n.schema.properties[t.key].type="string",n},generateTextareaField:function(t,n){return n.schema.properties[t.key].type="string",n=this.updateForm(n,t.key,"type","textarea")},generateEmailField:function(t,n){return n.schema.properties[t.key].type="string",n.schema.properties[t.key].format="email",n},generateSelectField:function(t,n){return n.schema.properties[t.key].type="string",n.schema.properties[t.key]["enum"]=t["enum"],n},generateCheckboxField:function(t,n){return n.schema.properties[t.key].type="string",n.schema.properties[t.key]["enum"]=t["enum"],n},generateDateField:function(t,n){return n.schema.properties[t.key].type="string",n.schema.properties[t.key].format="date",n},generateTimeField:function(t,n){return n.schema.properties[t.key].type="string",n.schema.properties[t.key].format="time",n},generateDateTimeField:function(t,n){return n.schema.properties[t.key].type="string",n.schema.properties[t.key].format="date-time",n},generateFieldsetField:function(t,n){return t.key&&delete n.schema.properties[t.key],n},generateSectionField:function(t,n){return n},generateActionsField:function(t,n){return n},generateNumberField:function(t,n){return n},generatePasswordField:function(t,n){return n}},r(i,"generateCheckboxField",function(t,n){return n}),r(i,"generateCheckboxesField",function(t,n){return n}),r(i,"generateSubmitField",function(t,n){return n}),r(i,"generateButtonField",function(t,n){return n}),r(i,"generateRadiosField",function(t,n){return n}),r(i,"generateRadiosInlineField",function(t,n){return n}),r(i,"generateRadioButtonsField",function(t,n){return n}),r(i,"generateHelpField",function(t,n){return n}),r(i,"generateTemplateField",function(t,n){return n}),r(i,"generateTabField",function(t,n){return n}),r(i,"generateArrayField",function(t,n){return n}),r(i,"generateTabArrayField",function(t,n){return n}),i);n["default"]=o}])}); 4 | //# sourceMappingURL=json-schema-form-generator.min.js.map 5 | --------------------------------------------------------------------------------