├── .eslintrc.yml
├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── commands
├── ajv.js
├── help.js
├── index.js
├── options.js
├── test.js
├── util.js
└── validate.js
├── index.js
├── package.json
└── test
├── .eslintrc.yml
├── cli.js
├── custom
├── invalid_custom.js
├── invalid_data.json
├── schema.json
├── typeof.js
└── valid_data.json
├── data_with_additional.json
├── help.spec.js
├── invalid_data.json
├── invalid_data2.json
├── meta
├── invalid_data.json
├── invalid_schema.json
├── invalid_schema2.json
├── meta_schema.json
├── schema.json
└── valid_data.json
├── schema.json
├── schema_with_ref.json
├── test.spec.js
├── valid_data.json
├── valid_data.yml
├── valid_data2.json
└── validate.spec.js
/.eslintrc.yml:
--------------------------------------------------------------------------------
1 | ---
2 | env:
3 | node: true
4 | extends: 'eslint:recommended'
5 | rules:
6 | indent: [2, 4, { SwitchCase : 1 } ]
7 | no-trailing-spaces: 2
8 | quotes: [ 2, single, avoid-escape ]
9 | linebreak-style: [ 2, unix ]
10 | semi: [ 2, always ]
11 | valid-jsdoc: [ 2, { requireReturn: false } ]
12 | no-invalid-this: 2
13 | no-unused-vars: [ 2, { args: none } ]
14 | no-console: 0
15 | block-scoped-var: 2
16 | complexity: [ 2, 12 ]
17 | curly: [ 2, multi-or-nest, consistent ]
18 | dot-location: [ 2, property ]
19 | dot-notation: 2
20 | no-else-return: 2
21 | no-eq-null: 2
22 | no-fallthrough: 2
23 | no-return-assign: 2
24 | strict: [ 2, global ]
25 | no-shadow: 1
26 | no-use-before-define: [ 2, nofunc ]
27 | callback-return: 2
28 | no-path-concat: 2
29 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 |
5 | # Runtime data
6 | pids
7 | *.pid
8 | *.seed
9 |
10 | # Coverage directory
11 | coverage
12 | .nyc_output
13 |
14 | # Dependency directory
15 | node_modules
16 |
17 | .DS_Store
18 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | before_script:
3 | - npm install -g codeclimate-test-reporter
4 | node_js:
5 | - '6'
6 | - '7'
7 | after_script:
8 | - codeclimate-test-reporter < coverage/lcov.info
9 | - coveralls < coverage/lcov.info
10 | deploy:
11 | - provider: releases
12 | api_key:
13 | secure: >-
14 | aCtltCB91v1CCQapAR/3DQhlric25pguvg7OxemIOKXr8xQiG3JNJ9rrb3wp0Onw4Gugcceubka5IfozgX/OnhoKyc8W3TANy7MLMtoV8h0CgALqxAPbjlPU5EamrGIHHvryHq2tyCYygGeZVSs+NiDgQwR7DBw8MLuQiQ3+aNejro0R5UrSm44XTiA2wJmKQqYOldsF9GpVoR/LuNRBiaEQgLfdVxlXTiNw7UzWYbVnhvTdxcuyvcC5IiN2pANT+ZFXHfkqvszx9q4JB4qQoRl0WLmYN86SacziN/p+5MoTmyoJnXNOMJb0pDmbWXJfjsEZOMwJzsOUogVsV38sDN0cjaFBnRdQbo9iiLOZ1Ap8mHc3ErA8mXbA4jrXrIWv6PDhLvE+lavRWDFPjaQ24Y2gQPtDa+WUAjj36hOYQVRjM+7ugZgybPJ5hsWkKwFWad0t7Rb3SPeJO6JuI83iyauDmTR8ooQoDqC/Pb2TF9M8y1yVRc43B6zCVs097MbTNbcGB++YSEpbI6k1/c5YqyxetRGzDlW1e1WhUySYQeQZFktSVK1wGyr2jNQY8QdXHjsVacCN1X4JkajSX06JB+R5D/ta73F3tInO1rBl+o1/gujyu5v9gWSoxvrBb7f8N+4yS7N3rjKpyYi1qQ0YJy6d5yWkM9yIDG8nKlpxH4I=
15 | 'on':
16 | tags: true
17 | - provider: npm
18 | api_key:
19 | secure: >-
20 | GZPWd1vS6FdbLG3usxZnImymG+AS0WdOY5NYz4DNW1UYhmJzOIilSbF0PGqjL0OzbtpeFvRPVEuqvu3LYI623YwsTDg4faycRXMo0OyVjS5vBq4CFF/JBTfkauxUZNq6cpMSg6f55sNshGuS4gGpnKBKkK6Bx8IkQRnEFJ44yfLWmyjPWmaGVEo5aXe6ZStdgLjvXNqL+uIcD57ssn8/nPsezZEAC+S3Kn9fYTqgyt21AaQQ7Hy/QW8JsYNikUlV/3xvueQftd8ILupm8PQ0SYhAgR35aIUbhDk8rEHmezFXGKOovNxDmqnZCAoZyP8WOn81Ey0Z14INZCz/qPBbPgjhhs7Q4O5Pq7SbwCEjqFUkQQ97yvUog28YwsRajl21tC20DXLxknWN06nKtu5EHnmGL9FGwUQt9mVumuJXF2NGHv8KS0EGMGMn9LSdCS89CtMrR/MhkRxCnjikHWxLIxIsDlklyQLY+6Lxc0cXAcLOULTDlOJFLlRCUU8FNxiHJkocFbw+oeVrn4ZzwAhdgAPmWGA+/fxx7cnxs4DSHaEZ3CnAC6rL5vEsKbA0IOjWDER0KbcVTU2OKm6+vZ1W3HP2fl4xbdENYTl78kk2ZXdTi4JtGoBeYX7nNuy+iDcYpLG4Jltna3L3UfvOblTSrXu8dEeTBZOYhryN6eQUi50=
21 | email: vossad01@gmail.com
22 | 'on':
23 | tags: true
24 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) Adam Voss
4 | Copyright (c) Jesse Collis
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Polyglottal JSON Schema Validator (Polyglottal Ajv)
2 |
3 | Command line interface for [ajv](https://github.com/epoberezkin/ajv) that utilizes [any-json](https://github.com/laktak/any-json/) to provide validation against many data formats. `pajv` can validate: **[CSON](https://github.com/bevry/cson), [Hjson](http://hjson.org/), [JSON](http://json.org/), [JSON5](http://json5.org/), [TOML](https://github.com/toml-lang/toml), and [YAML](http://yaml.org/)** files using JSON Schema. pajv is a fork of [ajv-cli](https://github.com/jessedc/ajv-cli).
4 |
5 | [](https://travis-ci.org/json-schema-everywhere/pajv)
6 | [](https://www.npmjs.com/package/pajv)
7 | [](https://codeclimate.com/github/json-schema-everywhere/pajv)
8 | [](https://coveralls.io/github/json-schema-everywhere/pajv?branch=master)
9 |
10 | ## Contents
11 |
12 | - [Installation](#installation)
13 | - Commands
14 | - [Help](#help)
15 | - [Validate data](#validate-data)
16 | - [Test validation result](#test-validation-result)
17 | - [Ajv options](#ajv-options)
18 | - [Version History, License](#version_history)
19 |
20 |
21 | ## Installation
22 |
23 | ```sh
24 | npm install -g pajv
25 | ```
26 |
27 |
28 | ## Help
29 |
30 | ```sh
31 | pajv help
32 | pajv help validate
33 | pajv help test
34 | ```
35 |
36 |
37 | ## Validate data
38 |
39 | This command validates data files against JSON-schema
40 |
41 | ```sh
42 | pajv validate -s test/schema.json -d test/valid_data.json
43 | pajv -s test/schema.json -d test/valid_data.json
44 | ```
45 |
46 | You can omit `validate` command name.
47 |
48 |
49 | #### Parameters
50 |
51 | ##### `-s` - file name of JSON-schema
52 |
53 | Only one schema can be passed in this parameter
54 |
55 |
56 | ##### `-d` - JSON data
57 |
58 | Multiple data files can be passed, as in `-r` parameter:
59 |
60 | ```sh
61 | pajv -s test/schema.json -d "test/valid*.json"
62 | ```
63 |
64 | If some file is invalid exit code will be 1.
65 |
66 |
67 | ##### `-r` - referenced schemas
68 |
69 | The schema in `-s` parameter can reference any of these schemas with `$ref` keyword.
70 |
71 | Multiple schemas can be passed both by using this parameter mupltiple times and with [glob patterns](https://github.com/isaacs/node-glob#glob-primer). Glob pattern should be quoted and extensions cannot be omitted.
72 |
73 |
74 | ##### `-m` - meta-schemas
75 |
76 | Schemas can use any of these schemas as a meta-schema (that is the schema used in `$schema` keyword - it is used to validate the schema itself).
77 |
78 | Multiple meta-schemas can be passed, as in `-r` parameter.
79 |
80 |
81 | ##### `-c` - custom keywords/formats definitions
82 |
83 | You can pass module(s) that define custom keywords/formats. The modules should export a function that accepts Ajv instance as a parameter. The file name should start with ".", it will be resolved relative to the current folder. The package name can also be passed - it will be used in require as is.
84 |
85 | For example, you can use `-c ajv-keywords` to add all keywords from [ajv-keywords](https://github.com/epoberezkin/ajv-keywords) package or `-c ajv-keywords/keywords/typeof` to add only typeof keyword.
86 |
87 |
88 | #### Options
89 |
90 | - `--errors=`: error reporting format. Possible values:
91 | - `js` (default): JavaScript object
92 | - `json`: JSON with indentation and line-breaks
93 | - `line`: JSON without indentaion/line-breaks (for easy parsing)
94 | - `text`: human readable error messages with data paths
95 |
96 | - `--changes=`: detect changes in data after validation.
97 | Data can be modifyed with [Ajv options](#ajv-options) `--remove-additional`, `--use-defaults` and `--coerce-types`).
98 | The changes are reported in JSON-patch format ([RFC6902](https://tools.ietf.org/html/rfc6902)).
99 | Possible values are `js` (default), `json` and `line` (see `--errors` option).
100 |
101 |
102 | ## Test validation result
103 |
104 | This command asserts that the result of the validation is as expected.
105 |
106 | ```sh
107 | pajv test -s test/schema.json -d test/valid_data.json --valid
108 | pajv test -s test/schema.json -d test/invalid_data.json --invalid
109 | ```
110 |
111 | If the option `--valid` (`--invalid`) is used for the `test` to pass (exit code 0) the data file(s) should be valid (invalid).
112 |
113 | This command supports the same options and parameters as [validate](#validate-data) with the exception of `--changes`.
114 |
115 |
116 | ## Ajv options
117 |
118 | You can pass the following Ajv options:
119 |
120 | |Option|Description|
121 | |---|---|
122 | |`--data`|use [$data references](https://github.com/epoberezkin/ajv#data-reference)|
123 | |`--all-errors`|collect all errors|
124 | |`--unknown-formats=`|handling of unknown formats|
125 | |`--verbose`|include schema and data in errors|
126 | |`--json-pointers`|report data paths in errors using JSON-pointers|
127 | |`--unique-items=false`|do not validate uniqueItems keyword|
128 | |`--unicode=false`|count unicode pairs as 2 characters|
129 | |`--format=full`|format mode|
130 | |`--schema-id=`|keyword(s) to use as schema ID|
131 | |`--extend-refs=`|validation of other keywords when $ref is present in the schema|
132 | |`--missing-refs=`|handle missing referenced schemas (true/ignore/fail)|
133 | |`--inline-refs=`|referenced schemas compilation mode (true/false/\)|
134 | |`--remove-additional`|remove additional properties (true/all/failing)|
135 | |`--use-defaults`|replace missing properties/items with the values from default keyword|
136 | |`--coerce-types`|change type of data to match type keyword|
137 | |`--multiple-of-precision`|precision of multipleOf, pass integer number|
138 | |`--error-data-path=property`|data path in errors|
139 | |`--messages=false`|do not include text messages in errors|
140 |
141 | Options can be passed in either dash-case and camelCase.
142 |
143 | See [Ajv Options](https://github.com/epoberezkin/ajv#options) for more information.
144 |
145 |
146 | ## Version History
147 |
148 | See https://github.com/json-schema-everywhere/pajv/releases
149 |
150 |
151 | ## Licence
152 |
153 | MIT
154 |
--------------------------------------------------------------------------------
/commands/ajv.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var Ajv = require('ajv');
4 | var options = require('./options');
5 | var util = require('./util');
6 | var path = require('path');
7 |
8 |
9 | module.exports = function (argv) {
10 | var opts = options.get(argv);
11 | if (argv.o) opts.sourceCode = true;
12 | var ajv = new Ajv(opts);
13 | var invalid;
14 | ajv.addMetaSchema(require('ajv/lib/refs/json-schema-draft-04.json'));
15 | addSchemas(argv.m, 'addMetaSchema', 'meta-schema');
16 | addSchemas(argv.r, 'addSchema', 'schema');
17 | customFormatsKeywords(argv.c);
18 | if (invalid) process.exit(1);
19 | return ajv;
20 |
21 | function addSchemas(args, method, fileType) {
22 | if (!args) return;
23 | var files = util.getFiles(args);
24 | files.forEach(function (file) {
25 | var schema = util.openFile(file, fileType);
26 | try { ajv[method](schema); }
27 | catch (err) {
28 | console.error(fileType, file, 'is invalid');
29 | console.error('error:', err.message);
30 | invalid = true;
31 | }
32 | });
33 | }
34 |
35 | function customFormatsKeywords(args) {
36 | if (!args) return;
37 | var files = util.getFiles(args);
38 | files.forEach(function (file) {
39 | if (file[0] == '.') file = path.resolve(process.cwd(), file);
40 | try {
41 | require(file)(ajv);
42 | } catch (err) {
43 | console.error('module', file, 'is invalid; it should export function');
44 | console.error('error:', err.message);
45 | invalid = true;
46 | }
47 | });
48 | }
49 | };
50 |
--------------------------------------------------------------------------------
/commands/help.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | execute: execute,
5 | usage: usage,
6 | schema: {
7 | type: 'object',
8 | properties: {
9 | _: { maxItems: 2 }
10 | },
11 | _ajvOptions: false
12 | }
13 | };
14 |
15 |
16 | var commands = {
17 | validate: helpValidate,
18 | test: helpTest
19 | };
20 |
21 |
22 | function execute(argv) {
23 | var command = argv._[1];
24 | if (!command || command == 'help') {
25 | mainHelp();
26 | return true;
27 | }
28 |
29 | var cmdHelp = commands[command];
30 |
31 | if (cmdHelp) {
32 | cmdHelp();
33 | return true;
34 | }
35 |
36 | console.error('Unknown command', command);
37 | usage();
38 | }
39 |
40 |
41 | function usage() {
42 | console.error('\
43 | usage:\n\
44 | validate: pajv [validate] -s schema_file -d data_file\n\
45 | test: pajv test -s schema_file -d data_file --[in]valid\n\
46 | \n\
47 | help: pajv help\n\
48 | pajv help ');
49 | }
50 |
51 |
52 | function mainHelp() {
53 | _helpValidate();
54 | _helpTest();
55 | console.log('\
56 | More information:\n\
57 | pajv help validate\n\
58 | pajv help test');
59 | }
60 |
61 |
62 | function helpValidate() {
63 | _helpValidate();
64 | console.log('\
65 | parameters\n\
66 | -s JSON schema to validate against (required, only one schema allowed)\n\
67 | -d data file(s) to be validated (required)\n\
68 | -r referenced schema(s)\n\
69 | -m meta schema(s)\n\
70 | -c custom keywords/formats definitions\n\
71 | \n\
72 | -d, -r, -m, -c can be globs and can be used multiple times\n\
73 | glob should be enclosed in double quotes\n\
74 | -c module(s) should export a function that accepts Ajv instance as parameter\n\
75 | (file path should start with ".", otherwise used as require package)\n\
76 | \n\
77 | options:\n\
78 | --errors= error reporting format ("js" by deafult)\n\
79 | --changes= log changes in data after validation ("no" by default)\n\
80 | js JavaScript object\n\
81 | json JSON format\n\
82 | line JSON single line\n\
83 | text text message (only for --errors option)\n\
84 | no don\'t log errors');
85 | helpAjvOptions();
86 | }
87 |
88 |
89 | function _helpValidate() {
90 | console.log('\
91 | Validate data file(s) against schema\n\
92 | pajv [validate] -s schema_file -d data_file\n\
93 | pajv [validate] -s schema_file -d "data*.ext"\n');
94 | }
95 |
96 | function helpTest() {
97 | _helpTest();
98 | console.log('\
99 | parameters\n\
100 | -s JSON schema to validate against (required, only one schema allowed)\n\
101 | -d data file(s) to be validated (required)\n\
102 | -r referenced schema(s)\n\
103 | -m meta schema(s)\n\
104 | -c custom keywords/formats definitions\n\
105 | --valid/--invalid data file(s) must be valid/invalid for this command to succeed\n\
106 | \n\
107 | -d, -r, -m, -c can be globs and can be used multiple times\n\
108 | glob should be enclosed in double quotes\n\
109 | -c module(s) should export a function that accepts Ajv instance as parameter\n\
110 | (file path should start with ".", otherwise used as require package)\n\
111 | --valid=false can be used instead of --invalid\n\
112 | \n\
113 | options:\n\
114 | --errors= error reporting\n\
115 | js JavaScript object (default)\n\
116 | json JSON format\n\
117 | line JSON single line\n\
118 | text text message\n');
119 | helpAjvOptions();
120 | }
121 |
122 |
123 | function _helpTest() {
124 | console.log('\
125 | Test data validation result\n\
126 | pajv test -s schema_file -d data_file --valid\n\
127 | pajv test -s schema_file -d data_file --invalid\n\
128 | pajv test -s schema_file -d "data*.ext" --valid \n');
129 | }
130 |
131 |
132 | function helpAjvOptions() {
133 | console.log('\
134 | Ajv options (see https://github.com/epoberezkin/ajv#options):\n\
135 | --data use $data references\n\
136 | \n\
137 | --all-errors collect all errors\n\
138 | \n\
139 | --unknown-formats= handling of unknown formats\n\
140 | true throw exception during schema compilation (default)\n\
141 | allowed unknown format name, multiple names can be used\n\
142 | \n\
143 | --json-pointers report data paths as JSON pointers\n\
144 | \n\
145 | --unique-items=false do not validate uniqueItems keyword\n\
146 | \n\
147 | --unicode=false count unicode pairs as 2 characters\n\
148 | \n\
149 | --format= format validation mode\n\
150 | fast using regex (default)\n\
151 | full using functions\n\
152 | \n\
153 | --schema-id= (by default both IDs will be used)\n\
154 | $id use $id\n\
155 | id use id\n\
156 | \n\
157 | --extend-refs= validation of other keywords when $ref is present in the schema\n\
158 | ignore ignore other keywords (default)\n\
159 | fail throw exception (recommended)\n\
160 | true validate all keywords\n\
161 | \n\
162 | --missing-refs= handling missing referenced schemas\n\
163 | true fail schema compilation (default)\n\
164 | ignore log error and pass validation\n\
165 | fail log error and fail validation if ref is used\n\
166 | \n\
167 | --remove-additional= remove additional properties\n\
168 | all remove all additional properties\n\
169 | true remove if additionalProperties is false\n\
170 | failing also remove if fails validation of schema in additionalProperties\n\
171 | \n\
172 | --use-defaults replace missing properties/items with the values from default keyword\n\
173 | \n\
174 | --coerce-types change type of data to match type keyword\n\
175 | \n\
176 | --multiple-of-precision=N pass integer number\n\
177 | \n\
178 | --error-data-path= data path in errors of required, additionalProperties and dependencies\n\
179 | object point to object (default)\n\
180 | property point to property\n\
181 | \n\
182 | --messages=false do not include text messages in errors');
183 | }
184 |
--------------------------------------------------------------------------------
/commands/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | help: require('./help'),
5 | validate: require('./validate'),
6 | test: require('./test')
7 | };
8 |
--------------------------------------------------------------------------------
/commands/options.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var Ajv = require('ajv');
4 | var glob = require('glob');
5 | var ajv = new Ajv({
6 | allErrors: true,
7 | coerceTypes: 'array',
8 | jsonPointers: true,
9 | formats: {
10 | notGlob: function(s) { return !glob.hasMagic(s); }
11 | }
12 | });
13 |
14 | var AJV_OPTIONS = {
15 | 'data': { type: 'boolean' },
16 | 'all-errors': { type: 'boolean' },
17 | 'verbose': { type: 'boolean' },
18 | 'json-pointers': { type: 'boolean' },
19 | 'unique-items': { type: 'boolean' },
20 | 'unicode': { type: 'boolean' },
21 | 'format': { anyOf: [
22 | { type: 'boolean' },
23 | { enum: ['fast', 'full'] }
24 | ] },
25 | 'unknown-formats': { anyOf: [
26 | { type: 'boolean' },
27 | { const: 'ignore' },
28 | { type: 'array', items: { type: 'string' } }
29 | ] },
30 | 'schema-id': { enum: ['$id', 'id'] },
31 | 'extend-refs': { anyOf: [
32 | { type: 'boolean' },
33 | { enum: ['ignore', 'fail'] }
34 | ] },
35 | 'missing-refs': { anyOf: [
36 | { type: 'boolean' },
37 | { enum: ['ignore', 'fail'] }
38 | ] },
39 | 'inline-refs': { type: ['boolean', 'integer'], minimum: 0 },
40 | 'multiple-of-precision': { type: 'integer' },
41 | 'error-data-path': { enum: ['object', 'property'] },
42 | 'messages': { type: 'boolean' },
43 | // modifying options
44 | 'remove-additional': { anyOf: [
45 | { type: 'boolean' },
46 | { enum: ['all', 'failing'] }
47 | ] },
48 | 'use-defaults': { type: 'boolean' },
49 | 'coerce-types': { anyOf: [
50 | { type: 'boolean' },
51 | { enum: ['array'] }
52 | ] }
53 | };
54 |
55 |
56 | module.exports = {
57 | check: checkOptions,
58 | get: getOptions
59 | };
60 |
61 |
62 | var DEFINITIONS = {
63 | stringOrArray: {
64 | anyOf: [
65 | { type: 'string' },
66 | {
67 | type: 'array',
68 | items: { type: 'string' }
69 | }
70 | ]
71 | }
72 | };
73 |
74 | function checkOptions(schema, argv) {
75 | schema.definitions = DEFINITIONS;
76 | if (schema._ajvOptions !== false) {
77 | for (var opt in AJV_OPTIONS) {
78 | var optSchema = AJV_OPTIONS[opt];
79 | schema.properties[opt] = optSchema;
80 | schema.properties[toCamelCase(opt)] = optSchema;
81 | }
82 | }
83 | schema.properties._ = schema.properties._ || { maxItems: 1 };
84 | schema.additionalProperties = false;
85 |
86 | var valid = ajv.validate(schema, argv);
87 | if (valid) return null;
88 | var errors = '';
89 | ajv.errors.forEach(function (err) {
90 | errors += 'error: ';
91 | switch (err.keyword) {
92 | case 'required':
93 | errors += 'parameter ' + parameter(err.params.missingProperty) + ' is required';
94 | break;
95 | case 'additionalProperties':
96 | errors += 'parameter ' + parameter(err.params.additionalProperty) + ' is unknown';
97 | break;
98 | case 'maxItems':
99 | errors += 'invalid syntax (too many arguments)';
100 | break;
101 | case 'format':
102 | if (err.params.format == 'notGlob') {
103 | errors += 'only one file is allowed in parameter ' + parameter(err.dataPath.slice(1));
104 | break;
105 | }
106 | // falls through
107 | default:
108 | errors += 'parameter ' + parameter(err.dataPath.slice(1)) + ' ' + err.message;
109 | }
110 | errors += '\n';
111 | });
112 |
113 | return errors;
114 | }
115 |
116 |
117 | function parameter(str) {
118 | return (str.length == 1 ? '-' : '--') + str;
119 | }
120 |
121 |
122 | function getOptions(argv) {
123 | var options = {};
124 | for (var opt in AJV_OPTIONS) {
125 | var optCC = toCamelCase(opt);
126 | var value = argv[opt] === undefined ? argv[optCC] : argv[opt];
127 | if (value !== undefined) options[optCC] = value;
128 | }
129 | return options;
130 | }
131 |
132 |
133 | function toCamelCase(str) {
134 | return str.replace(/-[a-z]/g, function (s) {
135 | return s[1].toUpperCase();
136 | });
137 | }
138 |
--------------------------------------------------------------------------------
/commands/test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var util = require('./util');
4 | var getAjv = require('./ajv');
5 |
6 |
7 | module.exports = {
8 | execute: execute,
9 | schema: {
10 | type: 'object',
11 | required: ['s', 'd'],
12 | oneOf: [
13 | { required: [ 'valid' ] },
14 | { required: [ 'invalid' ] }
15 | ],
16 | properties: {
17 | s: {
18 | type: 'string',
19 | format: 'notGlob'
20 | },
21 | d: { $ref: '#/definitions/stringOrArray' },
22 | r: { $ref: '#/definitions/stringOrArray' },
23 | m: { $ref: '#/definitions/stringOrArray' },
24 | c: { $ref: '#/definitions/stringOrArray' },
25 | valid: { type: 'boolean' },
26 | invalid: { type: 'boolean', enum: [true] },
27 | errors: { enum: ['json', 'line', 'text', 'js', 'no'] }
28 | }
29 | }
30 | };
31 |
32 |
33 | function execute(argv) {
34 | var ajv = getAjv(argv);
35 | var validate = util.compile(ajv, argv.s);
36 | var shouldBeValid = !!argv.valid && argv.valid != 'false';
37 | var allPassed = true;
38 |
39 | var dataFiles = util.getFiles(argv.d);
40 | dataFiles.forEach(testDataFile);
41 |
42 | return allPassed;
43 |
44 |
45 | function testDataFile(file) {
46 | var data = util.openFile(file, 'data file ' + file);
47 | var validData = validate(data);
48 | var errors;
49 | if (!validData) errors = util.logJSON(argv.errors, validate.errors, ajv);
50 |
51 | if (validData === shouldBeValid) {
52 | console.log(file, 'passed test');
53 | if (errors) console.log(errors);
54 | } else {
55 | allPassed = false;
56 | console.error(file, 'failed test');
57 | if (errors) console.error(errors);
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/commands/util.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var anyjson = require('any-json');
4 | var glob = require('glob');
5 | var path = require('path');
6 | var fs = require('fs');
7 | var wait = require('deasync-promise');
8 |
9 |
10 | module.exports = {
11 | getFiles: getFiles,
12 | openFile: openFile,
13 | logJSON: logJSON,
14 | compile: compile
15 | };
16 |
17 |
18 | function getFiles(args) {
19 | var files = [];
20 | if (Array.isArray(args)) args.forEach(_getFiles);
21 | else _getFiles(args);
22 | return files;
23 |
24 | function _getFiles(fileOrPattern) {
25 | if (glob.hasMagic(fileOrPattern)) {
26 | var dataFiles = glob.sync(fileOrPattern, { cwd: process.cwd() });
27 | files = files.concat(dataFiles);
28 | } else {
29 | files.push(fileOrPattern);
30 | }
31 | }
32 | }
33 |
34 | function getFormatFromFileName(filename) {
35 | var format = path.extname(filename).substr(1).toLowerCase();
36 | return format === 'yml' ? 'yaml' : format;
37 | }
38 |
39 |
40 | function openFile(filename, suffix){
41 | var file = path.resolve(process.cwd(), filename);
42 | try {
43 | var contents = fs.readFileSync(file).toString();
44 | var format = getFormatFromFileName(filename);
45 | return wait(anyjson.decode(contents, format));
46 | } catch(err) {
47 | console.error('error: ' + err.message.replace(' module', ' ' + suffix));
48 | process.exit(2);
49 | }
50 | }
51 |
52 |
53 | function logJSON(mode, data, ajv) {
54 | switch (mode) {
55 | case 'json': data = JSON.stringify(data, null, ' '); break;
56 | case 'line': data = JSON.stringify(data); break;
57 | case 'no': data = ''; break;
58 | case 'text': if (ajv) data = ajv.errorsText(data);
59 | }
60 | return data;
61 | }
62 |
63 |
64 | function compile(ajv, schemaFile) {
65 | var schema = openFile(schemaFile, 'schema');
66 | try { return ajv.compile(schema); }
67 | catch (err) {
68 | console.error('schema', schemaFile, 'is invalid');
69 | console.error('error:', err.message);
70 | process.exit(1);
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/commands/validate.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var util = require('./util');
4 | var getAjv = require('./ajv');
5 | var jsonPatch = require('fast-json-patch');
6 |
7 |
8 | module.exports = {
9 | execute: execute,
10 | schema: {
11 | type: 'object',
12 | required: ['s', 'd'],
13 | properties: {
14 | s: {
15 | type: 'string',
16 | format: 'notGlob'
17 | },
18 | d: { $ref: '#/definitions/stringOrArray' },
19 | r: { $ref: '#/definitions/stringOrArray' },
20 | m: { $ref: '#/definitions/stringOrArray' },
21 | c: { $ref: '#/definitions/stringOrArray' },
22 | errors: { enum: ['json', 'line', 'text', 'js', 'no'] },
23 | changes: { enum: [ true, 'json', 'line', 'js' ] }
24 | }
25 | }
26 | };
27 |
28 |
29 | function execute(argv) {
30 | var ajv = getAjv(argv);
31 | var validate = util.compile(ajv, argv.s);
32 | var allValid = true;
33 |
34 | var dataFiles = util.getFiles(argv.d);
35 | dataFiles.forEach(validateDataFile);
36 |
37 | return allValid;
38 |
39 |
40 | function validateDataFile(file) {
41 | var data = util.openFile(file, 'data file ' + file);
42 | var original;
43 | if (argv.changes) original = JSON.parse(JSON.stringify(data));
44 | var validData = validate(data);
45 |
46 | if (validData) {
47 | console.log(file, 'valid');
48 | if (argv.changes) {
49 | var patch = jsonPatch.compare(original, data);
50 | if (patch.length == 0) {
51 | console.log('no changes');
52 | } else {
53 | console.log('changes:');
54 | console.log(util.logJSON(argv.changes, patch));
55 | }
56 | }
57 | } else {
58 | allValid = false;
59 | console.error(file, 'invalid');
60 | console.error(util.logJSON(argv.errors, validate.errors, ajv));
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env node
2 | 'use strict';
3 |
4 | var argv = require('minimist')(process.argv.slice(2));
5 | var commands = require('./commands');
6 | var options = require('./commands/options');
7 |
8 | var command = argv._[0] || 'validate';
9 | var cmd = commands[command];
10 |
11 | if (cmd) {
12 | var errors = options.check(cmd.schema, argv);
13 | if (errors) {
14 | console.error(errors);
15 | commands.help.usage();
16 | process.exit(2);
17 | } else {
18 | var ok = cmd.execute(argv);
19 | process.exit(ok ? 0 : 1);
20 | }
21 | } else {
22 | console.error('Unknown command', command);
23 | commands.help.usage();
24 | process.exit(2);
25 | }
26 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pajv",
3 | "displayName": "Polyglottal JSON Schema Validator",
4 | "version": "1.2.0",
5 | "description": "A command line JSON Schema validator that supports many file formats. Fork of jessedc/ajv-cli.",
6 | "scripts": {
7 | "eslint": "eslint index.js commands/*.js test/*.js test/**/*.js",
8 | "test-spec": "mocha test/*.spec.js -R spec",
9 | "test-cov": "nyc npm run test-spec",
10 | "test": "npm run eslint && npm run test-cov"
11 | },
12 | "nyc": {
13 | "exclude": [
14 | "test",
15 | "node_modules"
16 | ],
17 | "reporter": [
18 | "lcov",
19 | "text-summary"
20 | ],
21 | "cache": true
22 | },
23 | "bin": {
24 | "pajv": "index.js"
25 | },
26 | "preferGlobal": true,
27 | "keywords": [
28 | "JSON",
29 | "schema",
30 | "validator",
31 | "validation",
32 | "jsonschema",
33 | "json-schema",
34 | "json-schema-validator",
35 | "json-schema-validation",
36 | "cson",
37 | "hjson",
38 | "ini",
39 | "json5",
40 | "toml",
41 | "xml",
42 | "yaml"
43 | ],
44 | "author": "Adam Voss",
45 | "contributors": [
46 | {
47 | "name": "Jesse Collis",
48 | "email": "jesse@jcmultimedia.com.au"
49 | }
50 | ],
51 | "license": "MIT",
52 | "repository": {
53 | "type": "git",
54 | "url": "https://github.com/json-schema-everywhere/pajv"
55 | },
56 | "dependencies": {
57 | "ajv": "^5.0.0",
58 | "any-json": "^3.0.0",
59 | "deasync": "^0.1.10",
60 | "deasync-promise": "^1.0.1",
61 | "fast-json-patch": "^0.5.6",
62 | "glob": "^7.0.3",
63 | "minimist": "^1.2.0",
64 | "util.promisify": "^1.0.0"
65 | },
66 | "devDependencies": {
67 | "ajv-keywords": "^2.0.0",
68 | "coveralls": "^2.11.8",
69 | "eslint": "^2.4.0",
70 | "mocha": "^2.4.5",
71 | "nyc": "^8.3.0",
72 | "pre-commit": "^1.1.2"
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/test/.eslintrc.yml:
--------------------------------------------------------------------------------
1 | ---
2 | rules:
3 | indent: [2, 2, { SwitchCase : 1 } ]
4 | no-invalid-this: 0
5 | no-empty: [2, allowEmptyCatch: true]
6 |
7 | globals:
8 | describe: false
9 | it: false
10 | beforeEach: false
11 |
--------------------------------------------------------------------------------
/test/cli.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var exec = require('child_process').exec;
4 | var path = require('path');
5 | var CWD = path.join(__dirname, '..');
6 |
7 |
8 | module.exports = function cli(params, callback) {
9 | exec('node index ' + params, { cwd: CWD }, callback);
10 | };
11 |
--------------------------------------------------------------------------------
/test/custom/invalid_custom.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {};
4 |
--------------------------------------------------------------------------------
/test/custom/invalid_data.json:
--------------------------------------------------------------------------------
1 | "foo"
--------------------------------------------------------------------------------
/test/custom/schema.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json-schema.org/draft-06/schema#",
3 | "id": "schema.json",
4 | "typeof": "number"
5 | }
6 |
--------------------------------------------------------------------------------
/test/custom/typeof.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var ajvKeywords = require('ajv-keywords');
4 |
5 | module.exports = function (ajv) {
6 | ajvKeywords(ajv, 'typeof');
7 | };
8 |
--------------------------------------------------------------------------------
/test/custom/valid_data.json:
--------------------------------------------------------------------------------
1 | 1
--------------------------------------------------------------------------------
/test/data_with_additional.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "id": 2,
4 | "name": "An ice sculpture",
5 | "price": 12.50,
6 | "tags": ["cold", "ice"],
7 | "dimensions": {
8 | "length": 7.0,
9 | "width": 12.0,
10 | "height": 9.5
11 | },
12 | "warehouseLocation": {
13 | "latitude": -78.75,
14 | "longitude": 20.4
15 | },
16 | "additionalInfo": "Store in the cold"
17 | },
18 | {
19 | "id": 3,
20 | "name": "A blue mouse",
21 | "price": 25.50,
22 | "dimensions": {
23 | "length": 3.1,
24 | "width": 1.0,
25 | "height": 1.0
26 | },
27 | "warehouseLocation": {
28 | "latitude": 54.4,
29 | "longitude": -32.7
30 | },
31 | "additionalInfo": "Feed every hour"
32 | }
33 | ]
34 |
--------------------------------------------------------------------------------
/test/help.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var cli = require('./cli');
4 | var assert = require('assert');
5 |
6 |
7 | describe('help', function() {
8 | this.timeout(10000);
9 |
10 | it('should print help', function (done) {
11 | cli('help', function (error, stdout, stderr) {
12 | assert.strictEqual(error, null);
13 | assert(/Validate/.test(stdout));
14 | assert(/Test/.test(stdout));
15 | assert.equal(stderr, '');
16 | done();
17 | });
18 | });
19 |
20 | it('should print help for validate', function (done) {
21 | cli('help validate', function (error, stdout, stderr) {
22 | assert.strictEqual(error, null);
23 | assert(/Validate/.test(stdout));
24 | assert(/options/.test(stdout));
25 | assert.equal(stderr, '');
26 | done();
27 | });
28 | });
29 |
30 | it('should print help for test', function (done) {
31 | cli('help test', function (error, stdout, stderr) {
32 | assert.strictEqual(error, null);
33 | assert(/Test/.test(stdout));
34 | assert(/options/.test(stdout));
35 | assert.equal(stderr, '');
36 | done();
37 | });
38 | });
39 |
40 | it('should print usage if unknown command is used', function (done) {
41 | cli('unknown', function (error, stdout, stderr) {
42 | assert(error instanceof Error);
43 | assert.equal(stdout, '');
44 | assert(/command/.test(stderr));
45 | assert(/unknown/.test(stderr));
46 | assert(/usage/.test(stderr));
47 | done();
48 | });
49 | });
50 |
51 | it('should print usage if help command is unknown', function (done) {
52 | cli('help unknown', function (error, stdout, stderr) {
53 | assert(error instanceof Error);
54 | assert.equal(stdout, '');
55 | assert(/command/.test(stderr));
56 | assert(/unknown/.test(stderr));
57 | assert(/usage/.test(stderr));
58 | done();
59 | });
60 | });
61 |
62 | it('should print usage if syntax is invalid', function (done) {
63 | cli('help -s test/schema.json', function (error, stdout, stderr) {
64 | assert(error instanceof Error);
65 | assert.equal(stdout, '');
66 | assert(/usage/.test(stderr));
67 | assert(/parameter/.test(stderr));
68 | assert(/unknown/.test(stderr));
69 | done();
70 | });
71 | });
72 | });
73 |
--------------------------------------------------------------------------------
/test/invalid_data.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "id": 1,
4 | "name": "A blue mouse",
5 | "price": 25.50,
6 | "dimensions": {
7 | "length": 3.1,
8 | "width": 1.0
9 | },
10 | "warehouseLocation": {
11 | "latitude": 54.4,
12 | "longitude": -32.7
13 | }
14 | },
15 | {
16 | "id": 2,
17 | "name": "An ice sculpture",
18 | "price": 12.50,
19 | "tags": ["cold", "ice"],
20 | "dimensions": {
21 | "length": 7.0,
22 | "width": 12.0,
23 | "height": "9.5"
24 | },
25 | "warehouseLocation": {
26 | "latitude": -78.75,
27 | "longitude": 20.4
28 | }
29 | }
30 | ]
31 |
--------------------------------------------------------------------------------
/test/invalid_data2.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "id": 1,
4 | "name": "A blue mouse",
5 | "price": 25.50,
6 | "dimensions": {
7 | "length": 3.1,
8 | "width": 1.0
9 | },
10 | "warehouseLocation": {
11 | "latitude": 54.4,
12 | "longitude": -32.7
13 | }
14 | },
15 | {
16 | "id": 2,
17 | "name": "An ice sculpture",
18 | "price": 12.50,
19 | "tags": ["cold", "ice"],
20 | "dimensions": {
21 | "length": 7.0,
22 | "width": 12.0,
23 | "height": "9.5"
24 | },
25 | "warehouseLocation": {
26 | "latitude": -78.75,
27 | "longitude": 20.4
28 | }
29 | }
30 | ]
31 |
--------------------------------------------------------------------------------
/test/meta/invalid_data.json:
--------------------------------------------------------------------------------
1 | {
2 | "foo": "bar"
3 | }
4 |
--------------------------------------------------------------------------------
/test/meta/invalid_schema.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://example.com/my_meta_schema#",
3 | "type": "object",
4 | "properties": {
5 | "foo": {
6 | "my_keyword": 1,
7 | "type": "integer"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/test/meta/invalid_schema2.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": false
3 | }
4 |
--------------------------------------------------------------------------------
/test/meta/meta_schema.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json-schema.org/draft-06/schema#",
3 | "$id": "http://example.com/my_meta_schema#",
4 | "title": "Core schema meta-schema",
5 | "definitions": {
6 | "schemaArray": {
7 | "type": "array",
8 | "minItems": 1,
9 | "items": { "$ref": "#" }
10 | },
11 | "nonNegativeInteger": {
12 | "type": "integer",
13 | "minimum": 0
14 | },
15 | "nonNegativeIntegerDefault0": {
16 | "allOf": [
17 | { "$ref": "#/definitions/nonNegativeInteger" },
18 | { "default": 0 }
19 | ]
20 | },
21 | "simpleTypes": {
22 | "enum": [
23 | "array",
24 | "boolean",
25 | "integer",
26 | "null",
27 | "number",
28 | "object",
29 | "string"
30 | ]
31 | },
32 | "stringArray": {
33 | "type": "array",
34 | "items": { "type": "string" },
35 | "uniqueItems": true,
36 | "default": []
37 | }
38 | },
39 | "type": ["object", "boolean"],
40 | "properties": {
41 | "$id": {
42 | "type": "string",
43 | "format": "uri-reference"
44 | },
45 | "$schema": {
46 | "type": "string",
47 | "format": "uri"
48 | },
49 | "$ref": {
50 | "type": "string",
51 | "format": "uri-reference"
52 | },
53 | "title": {
54 | "type": "string"
55 | },
56 | "description": {
57 | "type": "string"
58 | },
59 | "default": {},
60 | "multipleOf": {
61 | "type": "number",
62 | "exclusiveMinimum": 0
63 | },
64 | "maximum": {
65 | "type": "number"
66 | },
67 | "exclusiveMaximum": {
68 | "type": "number"
69 | },
70 | "minimum": {
71 | "type": "number"
72 | },
73 | "exclusiveMinimum": {
74 | "type": "number"
75 | },
76 | "maxLength": { "$ref": "#/definitions/nonNegativeInteger" },
77 | "minLength": { "$ref": "#/definitions/nonNegativeIntegerDefault0" },
78 | "pattern": {
79 | "type": "string",
80 | "format": "regex"
81 | },
82 | "additionalItems": { "$ref": "#" },
83 | "items": {
84 | "anyOf": [
85 | { "$ref": "#" },
86 | { "$ref": "#/definitions/schemaArray" }
87 | ],
88 | "default": {}
89 | },
90 | "maxItems": { "$ref": "#/definitions/nonNegativeInteger" },
91 | "minItems": { "$ref": "#/definitions/nonNegativeIntegerDefault0" },
92 | "uniqueItems": {
93 | "type": "boolean",
94 | "default": false
95 | },
96 | "contains": { "$ref": "#" },
97 | "maxProperties": { "$ref": "#/definitions/nonNegativeInteger" },
98 | "minProperties": { "$ref": "#/definitions/nonNegativeIntegerDefault0" },
99 | "required": { "$ref": "#/definitions/stringArray" },
100 | "additionalProperties": { "$ref": "#" },
101 | "definitions": {
102 | "type": "object",
103 | "additionalProperties": { "$ref": "#" },
104 | "default": {}
105 | },
106 | "properties": {
107 | "type": "object",
108 | "additionalProperties": { "$ref": "#" },
109 | "default": {}
110 | },
111 | "patternProperties": {
112 | "type": "object",
113 | "additionalProperties": { "$ref": "#" },
114 | "default": {}
115 | },
116 | "dependencies": {
117 | "type": "object",
118 | "additionalProperties": {
119 | "anyOf": [
120 | { "$ref": "#" },
121 | { "$ref": "#/definitions/stringArray" }
122 | ]
123 | }
124 | },
125 | "propertyNames": { "$ref": "#" },
126 | "const": {},
127 | "enum": {
128 | "type": "array",
129 | "minItems": 1,
130 | "uniqueItems": true
131 | },
132 | "type": {
133 | "anyOf": [
134 | { "$ref": "#/definitions/simpleTypes" },
135 | {
136 | "type": "array",
137 | "items": { "$ref": "#/definitions/simpleTypes" },
138 | "minItems": 1,
139 | "uniqueItems": true
140 | }
141 | ]
142 | },
143 | "format": { "type": "string" },
144 | "allOf": { "$ref": "#/definitions/schemaArray" },
145 | "anyOf": { "$ref": "#/definitions/schemaArray" },
146 | "oneOf": { "$ref": "#/definitions/schemaArray" },
147 | "not": { "$ref": "#" },
148 | "my_keyword": { "type": "boolean" }
149 | },
150 | "default": {}
151 | }
152 |
--------------------------------------------------------------------------------
/test/meta/schema.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://example.com/my_meta_schema#",
3 | "type": "object",
4 | "properties": {
5 | "foo": {
6 | "my_keyword": true,
7 | "type": "integer"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/test/meta/valid_data.json:
--------------------------------------------------------------------------------
1 | {
2 | "foo": 1
3 | }
4 |
--------------------------------------------------------------------------------
/test/schema.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json-schema.org/draft-06/schema#",
3 | "$id": "schema.json",
4 | "description": "basic schema from z-schema benchmark (https://github.com/zaggino/z-schema)",
5 | "title": "Product set",
6 | "type": "array",
7 | "items": {
8 | "title": "Product",
9 | "type": "object",
10 | "additionalProperties": false,
11 | "properties": {
12 | "id": {
13 | "description": "The unique identifier for a product",
14 | "type": "number"
15 | },
16 | "name": {
17 | "type": "string"
18 | },
19 | "price": {
20 | "type": "number",
21 | "exclusiveMinimum": 0
22 | },
23 | "tags": {
24 | "type": "array",
25 | "items": {
26 | "type": "string"
27 | },
28 | "minItems": 1,
29 | "uniqueItems": true
30 | },
31 | "dimensions": {
32 | "type": "object",
33 | "properties": {
34 | "length": {"type": "number"},
35 | "width": {"type": "number"},
36 | "height": {"type": "number"}
37 | },
38 | "required": ["length", "width", "height"]
39 | },
40 | "warehouseLocation": {
41 | "description": "Coordinates of the warehouse with the product"
42 | }
43 | },
44 | "required": ["id", "name", "price"]
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/test/schema_with_ref.json:
--------------------------------------------------------------------------------
1 | {
2 | "$ref": "schema.json"
3 | }
4 |
--------------------------------------------------------------------------------
/test/test.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var cli = require('./cli');
4 | var assert = require('assert');
5 |
6 |
7 | describe('test', function() {
8 | this.timeout(10000);
9 |
10 | describe('test valid data', function() {
11 | it('should pass if expected result is valid', function (done) {
12 | cli('test -s test/schema.json -d test/valid_data.json --valid', function (error, stdout, stderr) {
13 | assert.strictEqual(error, null);
14 | assertNoErrors(stdout, 1, /\spassed/);
15 | assert.equal(stderr, '');
16 | done();
17 | });
18 | });
19 |
20 | it('should pass multiple files if expected result is valid', function (done) {
21 | cli('test -s test/schema.json -d "test/valid*.json" --valid', function (error, stdout, stderr) {
22 | assert.strictEqual(error, null);
23 | assertNoErrors(stdout, 2, /\spassed/);
24 | assert.equal(stderr, '');
25 | done();
26 | });
27 | });
28 |
29 | it('should fail if expected result is invalid', function (done) {
30 | cli('test -s test/schema.json -d test/valid_data.json --invalid', function (error, stdout, stderr) {
31 | assert(error instanceof Error);
32 | assertNoErrors(stderr, 1, /\sfailed/);
33 | assert.equal(stdout, '');
34 | done();
35 | });
36 | });
37 |
38 | it('should fail multiple files if expected result is invalid', function (done) {
39 | cli('test -s test/schema.json -d "test/valid*.json" --invalid', function (error, stdout, stderr) {
40 | assert(error instanceof Error);
41 | assertNoErrors(stderr, 2, /\sfailed/);
42 | assert.equal(stdout, '');
43 | done();
44 | });
45 | });
46 | });
47 |
48 |
49 | describe('test invalid data', function() {
50 | it('should pass if expected result is invalid', function (done) {
51 | cli('test -s test/schema.json -d test/invalid_data.json --invalid --errors=line', function (error, stdout, stderr) {
52 | assert.strictEqual(error, null);
53 | assertRequiredErrors(stdout, 1, /\spassed/);
54 | assert.equal(stderr, '');
55 | done();
56 | });
57 | });
58 |
59 | it('should pass if expected result is invalid (valid=false)', function (done) {
60 | cli('test -s test/schema.json -d test/invalid_data.json --valid=false --errors=line', function (error, stdout, stderr) {
61 | assert.strictEqual(error, null);
62 | assertRequiredErrors(stdout, 1, /\spassed/);
63 | assert.equal(stderr, '');
64 | done();
65 | });
66 | });
67 |
68 |
69 | it('should pass multiple files if expected result is invalid', function (done) {
70 | cli('test -s test/schema.json -d "test/invalid*.json" --invalid --errors=line', function (error, stdout, stderr) {
71 | assert.strictEqual(error, null);
72 | assertRequiredErrors(stdout, 2, /\spassed/);
73 | assert.equal(stderr, '');
74 | done();
75 | });
76 | });
77 |
78 | it('should fail if expected result is valid', function (done) {
79 | cli('test -s test/schema.json -d test/invalid_data.json --valid --errors=line', function (error, stdout, stderr) {
80 | assert(error instanceof Error);
81 | assertRequiredErrors(stderr, 1, /\sfailed/);
82 | assert.equal(stdout, '');
83 | done();
84 | });
85 | });
86 |
87 | it('should fail multiple files if expected result is valid', function (done) {
88 | cli('test -s test/schema.json -d "test/invalid*.json" --valid --errors=line', function (error, stdout, stderr) {
89 | assert(error instanceof Error);
90 | assertRequiredErrors(stderr, 2, /\sfailed/);
91 | assert.equal(stdout, '');
92 | done();
93 | });
94 | });
95 | });
96 |
97 |
98 | describe('test valid and invalid data', function() {
99 | it('should pass valid, fail invalid and return error if expected result is valid', function (done) {
100 | cli('test -s test/schema.json -d test/valid_data.json -d test/invalid_data.json --valid --errors=line', function (error, stdout, stderr) {
101 | assert(error instanceof Error);
102 | assertNoErrors(stdout, 1, /\spassed/);
103 | assertRequiredErrors(stderr, 1, /\sfailed/);
104 | done();
105 | });
106 | });
107 |
108 | it('should fail valid, pass invalid and return error if expected result is invalid', function (done) {
109 | cli('test -s test/schema.json -d test/valid_data.json -d test/invalid_data.json --invalid --errors=line', function (error, stdout, stderr) {
110 | assert(error instanceof Error);
111 | assertNoErrors(stderr, 1, /\sfailed/);
112 | assertRequiredErrors(stdout, 1, /\spassed/);
113 | done();
114 | });
115 | });
116 | });
117 | });
118 |
119 |
120 | function assertNoErrors(out, count, regexp) {
121 | var lines = out.split('\n');
122 | assert.equal(lines.length, count + 1);
123 | for (var i=0; i