Fix European trip return heuristic for weekend location tracking

Adjust European short trip heuristic from >3 days to >1 day to correctly
detect when user has returned home from European trips. This fixes the
April 29-30, 2023 case where the location incorrectly showed "Sankt Georg, Hamburg"
instead of "Bristol" when the user was free (no events scheduled) after
the foss-north trip ended on April 27.

The previous logic required more than 3 days to pass before assuming
return home from European countries, but for short European trips by
rail/ferry, users typically return within 1-2 days.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Edward Betts 2025-07-16 06:38:37 +02:00
parent 663dc479c2
commit ea4980a5d7
6407 changed files with 1072847 additions and 18 deletions

19
node_modules/@eslint/eslintrc/LICENSE generated vendored Normal file
View file

@ -0,0 +1,19 @@
Copyright OpenJS Foundation and other contributors, <www.openjsf.org>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

126
node_modules/@eslint/eslintrc/README.md generated vendored Normal file
View file

@ -0,0 +1,126 @@
# ESLintRC Library
This repository contains the legacy ESLintRC configuration file format for ESLint. This package is not intended for use outside of the ESLint ecosystem. It is ESLint-specific and not intended for use in other programs.
**Note:** This package is frozen except for critical bug fixes as ESLint moves to a new config system.
## Installation
You can install the package as follows:
```
npm install @eslint/eslintrc --save-dev
# or
yarn add @eslint/eslintrc -D
```
## Usage (ESM)
The primary class in this package is `FlatCompat`, which is a utility to translate ESLintRC-style configs into flat configs. Here's how you use it inside of your `eslint.config.js` file:
```js
import { FlatCompat } from "@eslint/eslintrc";
import js from "@eslint/js";
import path from "path";
import { fileURLToPath } from "url";
// mimic CommonJS variables -- not needed if using CommonJS
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const compat = new FlatCompat({
baseDirectory: __dirname, // optional; default: process.cwd()
resolvePluginsRelativeTo: __dirname, // optional
recommendedConfig: js.configs.recommended, // optional unless you're using "eslint:recommended"
allConfig: js.configs.all, // optional unless you're using "eslint:all"
});
export default [
// mimic ESLintRC-style extends
...compat.extends("standard", "example"),
// mimic environments
...compat.env({
es2020: true,
node: true
}),
// mimic plugins
...compat.plugins("airbnb", "react"),
// translate an entire config
...compat.config({
plugins: ["airbnb", "react"],
extends: "standard",
env: {
es2020: true,
node: true
},
rules: {
semi: "error"
}
})
];
```
## Usage (CommonJS)
Using `FlatCompat` in CommonJS files is similar to ESM, but you'll use `require()` and `module.exports` instead of `import` and `export`. Here's how you use it inside of your `eslint.config.js` CommonJS file:
```js
const { FlatCompat } = require("@eslint/eslintrc");
const js = require("@eslint/js");
const compat = new FlatCompat({
baseDirectory: __dirname, // optional; default: process.cwd()
resolvePluginsRelativeTo: __dirname, // optional
recommendedConfig: js.configs.recommended, // optional unless using "eslint:recommended"
allConfig: js.configs.all, // optional unless using "eslint:all"
});
module.exports = [
// mimic ESLintRC-style extends
...compat.extends("standard", "example"),
// mimic environments
...compat.env({
es2020: true,
node: true
}),
// mimic plugins
...compat.plugins("airbnb", "react"),
// translate an entire config
...compat.config({
plugins: ["airbnb", "react"],
extends: "standard",
env: {
es2020: true,
node: true
},
rules: {
semi: "error"
}
})
];
```
## Troubleshooting
**TypeError: Missing parameter 'recommendedConfig' in FlatCompat constructor**
The `recommendedConfig` option is required when any config uses `eslint:recommended`, including any config in an `extends` clause. To fix this, follow the example above using `@eslint/js` to provide the `eslint:recommended` config.
**TypeError: Missing parameter 'allConfig' in FlatCompat constructor**
The `allConfig` option is required when any config uses `eslint:all`, including any config in an `extends` clause. To fix this, follow the example above using `@eslint/js` to provide the `eslint:all` config.
## License
MIT License

79
node_modules/@eslint/eslintrc/conf/config-schema.js generated vendored Normal file
View file

@ -0,0 +1,79 @@
/**
* @fileoverview Defines a schema for configs.
* @author Sylvan Mably
*/
const baseConfigProperties = {
$schema: { type: "string" },
env: { type: "object" },
extends: { $ref: "#/definitions/stringOrStrings" },
globals: { type: "object" },
overrides: {
type: "array",
items: { $ref: "#/definitions/overrideConfig" },
additionalItems: false
},
parser: { type: ["string", "null"] },
parserOptions: { type: "object" },
plugins: { type: "array" },
processor: { type: "string" },
rules: { type: "object" },
settings: { type: "object" },
noInlineConfig: { type: "boolean" },
reportUnusedDisableDirectives: { type: "boolean" },
ecmaFeatures: { type: "object" } // deprecated; logs a warning when used
};
const configSchema = {
definitions: {
stringOrStrings: {
oneOf: [
{ type: "string" },
{
type: "array",
items: { type: "string" },
additionalItems: false
}
]
},
stringOrStringsRequired: {
oneOf: [
{ type: "string" },
{
type: "array",
items: { type: "string" },
additionalItems: false,
minItems: 1
}
]
},
// Config at top-level.
objectConfig: {
type: "object",
properties: {
root: { type: "boolean" },
ignorePatterns: { $ref: "#/definitions/stringOrStrings" },
...baseConfigProperties
},
additionalProperties: false
},
// Config in `overrides`.
overrideConfig: {
type: "object",
properties: {
excludedFiles: { $ref: "#/definitions/stringOrStrings" },
files: { $ref: "#/definitions/stringOrStringsRequired" },
...baseConfigProperties
},
required: ["files"],
additionalProperties: false
}
},
$ref: "#/definitions/objectConfig"
};
export default configSchema;

215
node_modules/@eslint/eslintrc/conf/environments.js generated vendored Normal file
View file

@ -0,0 +1,215 @@
/**
* @fileoverview Defines environment settings and globals.
* @author Elan Shanker
*/
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
import globals from "globals";
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
/**
* Get the object that has difference.
* @param {Record<string,boolean>} current The newer object.
* @param {Record<string,boolean>} prev The older object.
* @returns {Record<string,boolean>} The difference object.
*/
function getDiff(current, prev) {
const retv = {};
for (const [key, value] of Object.entries(current)) {
if (!Object.hasOwnProperty.call(prev, key)) {
retv[key] = value;
}
}
return retv;
}
const newGlobals2015 = getDiff(globals.es2015, globals.es5); // 19 variables such as Promise, Map, ...
const newGlobals2017 = {
Atomics: false,
SharedArrayBuffer: false
};
const newGlobals2020 = {
BigInt: false,
BigInt64Array: false,
BigUint64Array: false,
globalThis: false
};
const newGlobals2021 = {
AggregateError: false,
FinalizationRegistry: false,
WeakRef: false
};
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
/** @type {Map<string, import("../lib/shared/types").Environment>} */
export default new Map(Object.entries({
// Language
builtin: {
globals: globals.es5
},
es6: {
globals: newGlobals2015,
parserOptions: {
ecmaVersion: 6
}
},
es2015: {
globals: newGlobals2015,
parserOptions: {
ecmaVersion: 6
}
},
es2016: {
globals: newGlobals2015,
parserOptions: {
ecmaVersion: 7
}
},
es2017: {
globals: { ...newGlobals2015, ...newGlobals2017 },
parserOptions: {
ecmaVersion: 8
}
},
es2018: {
globals: { ...newGlobals2015, ...newGlobals2017 },
parserOptions: {
ecmaVersion: 9
}
},
es2019: {
globals: { ...newGlobals2015, ...newGlobals2017 },
parserOptions: {
ecmaVersion: 10
}
},
es2020: {
globals: { ...newGlobals2015, ...newGlobals2017, ...newGlobals2020 },
parserOptions: {
ecmaVersion: 11
}
},
es2021: {
globals: { ...newGlobals2015, ...newGlobals2017, ...newGlobals2020, ...newGlobals2021 },
parserOptions: {
ecmaVersion: 12
}
},
es2022: {
globals: { ...newGlobals2015, ...newGlobals2017, ...newGlobals2020, ...newGlobals2021 },
parserOptions: {
ecmaVersion: 13
}
},
es2023: {
globals: { ...newGlobals2015, ...newGlobals2017, ...newGlobals2020, ...newGlobals2021 },
parserOptions: {
ecmaVersion: 14
}
},
es2024: {
globals: { ...newGlobals2015, ...newGlobals2017, ...newGlobals2020, ...newGlobals2021 },
parserOptions: {
ecmaVersion: 15
}
},
// Platforms
browser: {
globals: globals.browser
},
node: {
globals: globals.node,
parserOptions: {
ecmaFeatures: {
globalReturn: true
}
}
},
"shared-node-browser": {
globals: globals["shared-node-browser"]
},
worker: {
globals: globals.worker
},
serviceworker: {
globals: globals.serviceworker
},
// Frameworks
commonjs: {
globals: globals.commonjs,
parserOptions: {
ecmaFeatures: {
globalReturn: true
}
}
},
amd: {
globals: globals.amd
},
mocha: {
globals: globals.mocha
},
jasmine: {
globals: globals.jasmine
},
jest: {
globals: globals.jest
},
phantomjs: {
globals: globals.phantomjs
},
jquery: {
globals: globals.jquery
},
qunit: {
globals: globals.qunit
},
prototypejs: {
globals: globals.prototypejs
},
shelljs: {
globals: globals.shelljs
},
meteor: {
globals: globals.meteor
},
mongo: {
globals: globals.mongo
},
protractor: {
globals: globals.protractor
},
applescript: {
globals: globals.applescript
},
nashorn: {
globals: globals.nashorn
},
atomtest: {
globals: globals.atomtest
},
embertest: {
globals: globals.embertest
},
webextensions: {
globals: globals.webextensions
},
greasemonkey: {
globals: globals.greasemonkey
}
}));

1143
node_modules/@eslint/eslintrc/dist/eslintrc-universal.cjs generated vendored Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

4370
node_modules/@eslint/eslintrc/dist/eslintrc.cjs generated vendored Normal file

File diff suppressed because it is too large Load diff

1
node_modules/@eslint/eslintrc/dist/eslintrc.cjs.map generated vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,532 @@
/**
* @fileoverview `CascadingConfigArrayFactory` class.
*
* `CascadingConfigArrayFactory` class has a responsibility:
*
* 1. Handles cascading of config files.
*
* It provides two methods:
*
* - `getConfigArrayForFile(filePath)`
* Get the corresponded configuration of a given file. This method doesn't
* throw even if the given file didn't exist.
* - `clearCache()`
* Clear the internal cache. You have to call this method when
* `additionalPluginPool` was updated if `baseConfig` or `cliConfig` depends
* on the additional plugins. (`CLIEngine#addPlugin()` method calls this.)
*
* @author Toru Nagashima <https://github.com/mysticatea>
*/
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
import debugOrig from "debug";
import os from "os";
import path from "path";
import { ConfigArrayFactory } from "./config-array-factory.js";
import {
ConfigArray,
ConfigDependency,
IgnorePattern
} from "./config-array/index.js";
import ConfigValidator from "./shared/config-validator.js";
import { emitDeprecationWarning } from "./shared/deprecation-warnings.js";
const debug = debugOrig("eslintrc:cascading-config-array-factory");
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
// Define types for VSCode IntelliSense.
/** @typedef {import("./shared/types").ConfigData} ConfigData */
/** @typedef {import("./shared/types").Parser} Parser */
/** @typedef {import("./shared/types").Plugin} Plugin */
/** @typedef {import("./shared/types").Rule} Rule */
/** @typedef {ReturnType<ConfigArrayFactory["create"]>} ConfigArray */
/**
* @typedef {Object} CascadingConfigArrayFactoryOptions
* @property {Map<string,Plugin>} [additionalPluginPool] The map for additional plugins.
* @property {ConfigData} [baseConfig] The config by `baseConfig` option.
* @property {ConfigData} [cliConfig] The config by CLI options (`--env`, `--global`, `--ignore-pattern`, `--parser`, `--parser-options`, `--plugin`, and `--rule`). CLI options overwrite the setting in config files.
* @property {string} [cwd] The base directory to start lookup.
* @property {string} [ignorePath] The path to the alternative file of `.eslintignore`.
* @property {string[]} [rulePaths] The value of `--rulesdir` option.
* @property {string} [specificConfigPath] The value of `--config` option.
* @property {boolean} [useEslintrc] if `false` then it doesn't load config files.
* @property {Function} loadRules The function to use to load rules.
* @property {Map<string,Rule>} builtInRules The rules that are built in to ESLint.
* @property {Object} [resolver=ModuleResolver] The module resolver object.
* @property {string} eslintAllPath The path to the definitions for eslint:all.
* @property {Function} getEslintAllConfig Returns the config data for eslint:all.
* @property {string} eslintRecommendedPath The path to the definitions for eslint:recommended.
* @property {Function} getEslintRecommendedConfig Returns the config data for eslint:recommended.
*/
/**
* @typedef {Object} CascadingConfigArrayFactoryInternalSlots
* @property {ConfigArray} baseConfigArray The config array of `baseConfig` option.
* @property {ConfigData} baseConfigData The config data of `baseConfig` option. This is used to reset `baseConfigArray`.
* @property {ConfigArray} cliConfigArray The config array of CLI options.
* @property {ConfigData} cliConfigData The config data of CLI options. This is used to reset `cliConfigArray`.
* @property {ConfigArrayFactory} configArrayFactory The factory for config arrays.
* @property {Map<string, ConfigArray>} configCache The cache from directory paths to config arrays.
* @property {string} cwd The base directory to start lookup.
* @property {WeakMap<ConfigArray, ConfigArray>} finalizeCache The cache from config arrays to finalized config arrays.
* @property {string} [ignorePath] The path to the alternative file of `.eslintignore`.
* @property {string[]|null} rulePaths The value of `--rulesdir` option. This is used to reset `baseConfigArray`.
* @property {string|null} specificConfigPath The value of `--config` option. This is used to reset `cliConfigArray`.
* @property {boolean} useEslintrc if `false` then it doesn't load config files.
* @property {Function} loadRules The function to use to load rules.
* @property {Map<string,Rule>} builtInRules The rules that are built in to ESLint.
* @property {Object} [resolver=ModuleResolver] The module resolver object.
* @property {string} eslintAllPath The path to the definitions for eslint:all.
* @property {Function} getEslintAllConfig Returns the config data for eslint:all.
* @property {string} eslintRecommendedPath The path to the definitions for eslint:recommended.
* @property {Function} getEslintRecommendedConfig Returns the config data for eslint:recommended.
*/
/** @type {WeakMap<CascadingConfigArrayFactory, CascadingConfigArrayFactoryInternalSlots>} */
const internalSlotsMap = new WeakMap();
/**
* Create the config array from `baseConfig` and `rulePaths`.
* @param {CascadingConfigArrayFactoryInternalSlots} slots The slots.
* @returns {ConfigArray} The config array of the base configs.
*/
function createBaseConfigArray({
configArrayFactory,
baseConfigData,
rulePaths,
cwd,
loadRules
}) {
const baseConfigArray = configArrayFactory.create(
baseConfigData,
{ name: "BaseConfig" }
);
/*
* Create the config array element for the default ignore patterns.
* This element has `ignorePattern` property that ignores the default
* patterns in the current working directory.
*/
baseConfigArray.unshift(configArrayFactory.create(
{ ignorePatterns: IgnorePattern.DefaultPatterns },
{ name: "DefaultIgnorePattern" }
)[0]);
/*
* Load rules `--rulesdir` option as a pseudo plugin.
* Use a pseudo plugin to define rules of `--rulesdir`, so we can validate
* the rule's options with only information in the config array.
*/
if (rulePaths && rulePaths.length > 0) {
baseConfigArray.push({
type: "config",
name: "--rulesdir",
filePath: "",
plugins: {
"": new ConfigDependency({
definition: {
rules: rulePaths.reduce(
(map, rulesPath) => Object.assign(
map,
loadRules(rulesPath, cwd)
),
{}
)
},
filePath: "",
id: "",
importerName: "--rulesdir",
importerPath: ""
})
}
});
}
return baseConfigArray;
}
/**
* Create the config array from CLI options.
* @param {CascadingConfigArrayFactoryInternalSlots} slots The slots.
* @returns {ConfigArray} The config array of the base configs.
*/
function createCLIConfigArray({
cliConfigData,
configArrayFactory,
cwd,
ignorePath,
specificConfigPath
}) {
const cliConfigArray = configArrayFactory.create(
cliConfigData,
{ name: "CLIOptions" }
);
cliConfigArray.unshift(
...(ignorePath
? configArrayFactory.loadESLintIgnore(ignorePath)
: configArrayFactory.loadDefaultESLintIgnore())
);
if (specificConfigPath) {
cliConfigArray.unshift(
...configArrayFactory.loadFile(
specificConfigPath,
{ name: "--config", basePath: cwd }
)
);
}
return cliConfigArray;
}
/**
* The error type when there are files matched by a glob, but all of them have been ignored.
*/
class ConfigurationNotFoundError extends Error {
// eslint-disable-next-line jsdoc/require-description
/**
* @param {string} directoryPath The directory path.
*/
constructor(directoryPath) {
super(`No ESLint configuration found in ${directoryPath}.`);
this.messageTemplate = "no-config-found";
this.messageData = { directoryPath };
}
}
/**
* This class provides the functionality that enumerates every file which is
* matched by given glob patterns and that configuration.
*/
class CascadingConfigArrayFactory {
/**
* Initialize this enumerator.
* @param {CascadingConfigArrayFactoryOptions} options The options.
*/
constructor({
additionalPluginPool = new Map(),
baseConfig: baseConfigData = null,
cliConfig: cliConfigData = null,
cwd = process.cwd(),
ignorePath,
resolvePluginsRelativeTo,
rulePaths = [],
specificConfigPath = null,
useEslintrc = true,
builtInRules = new Map(),
loadRules,
resolver,
eslintRecommendedPath,
getEslintRecommendedConfig,
eslintAllPath,
getEslintAllConfig
} = {}) {
const configArrayFactory = new ConfigArrayFactory({
additionalPluginPool,
cwd,
resolvePluginsRelativeTo,
builtInRules,
resolver,
eslintRecommendedPath,
getEslintRecommendedConfig,
eslintAllPath,
getEslintAllConfig
});
internalSlotsMap.set(this, {
baseConfigArray: createBaseConfigArray({
baseConfigData,
configArrayFactory,
cwd,
rulePaths,
loadRules
}),
baseConfigData,
cliConfigArray: createCLIConfigArray({
cliConfigData,
configArrayFactory,
cwd,
ignorePath,
specificConfigPath
}),
cliConfigData,
configArrayFactory,
configCache: new Map(),
cwd,
finalizeCache: new WeakMap(),
ignorePath,
rulePaths,
specificConfigPath,
useEslintrc,
builtInRules,
loadRules
});
}
/**
* The path to the current working directory.
* This is used by tests.
* @type {string}
*/
get cwd() {
const { cwd } = internalSlotsMap.get(this);
return cwd;
}
/**
* Get the config array of a given file.
* If `filePath` was not given, it returns the config which contains only
* `baseConfigData` and `cliConfigData`.
* @param {string} [filePath] The file path to a file.
* @param {Object} [options] The options.
* @param {boolean} [options.ignoreNotFoundError] If `true` then it doesn't throw `ConfigurationNotFoundError`.
* @returns {ConfigArray} The config array of the file.
*/
getConfigArrayForFile(filePath, { ignoreNotFoundError = false } = {}) {
const {
baseConfigArray,
cliConfigArray,
cwd
} = internalSlotsMap.get(this);
if (!filePath) {
return new ConfigArray(...baseConfigArray, ...cliConfigArray);
}
const directoryPath = path.dirname(path.resolve(cwd, filePath));
debug(`Load config files for ${directoryPath}.`);
return this._finalizeConfigArray(
this._loadConfigInAncestors(directoryPath),
directoryPath,
ignoreNotFoundError
);
}
/**
* Set the config data to override all configs.
* Require to call `clearCache()` method after this method is called.
* @param {ConfigData} configData The config data to override all configs.
* @returns {void}
*/
setOverrideConfig(configData) {
const slots = internalSlotsMap.get(this);
slots.cliConfigData = configData;
}
/**
* Clear config cache.
* @returns {void}
*/
clearCache() {
const slots = internalSlotsMap.get(this);
slots.baseConfigArray = createBaseConfigArray(slots);
slots.cliConfigArray = createCLIConfigArray(slots);
slots.configCache.clear();
}
/**
* Load and normalize config files from the ancestor directories.
* @param {string} directoryPath The path to a leaf directory.
* @param {boolean} configsExistInSubdirs `true` if configurations exist in subdirectories.
* @returns {ConfigArray} The loaded config.
* @private
*/
_loadConfigInAncestors(directoryPath, configsExistInSubdirs = false) {
const {
baseConfigArray,
configArrayFactory,
configCache,
cwd,
useEslintrc
} = internalSlotsMap.get(this);
if (!useEslintrc) {
return baseConfigArray;
}
let configArray = configCache.get(directoryPath);
// Hit cache.
if (configArray) {
debug(`Cache hit: ${directoryPath}.`);
return configArray;
}
debug(`No cache found: ${directoryPath}.`);
const homePath = os.homedir();
// Consider this is root.
if (directoryPath === homePath && cwd !== homePath) {
debug("Stop traversing because of considered root.");
if (configsExistInSubdirs) {
const filePath = ConfigArrayFactory.getPathToConfigFileInDirectory(directoryPath);
if (filePath) {
emitDeprecationWarning(
filePath,
"ESLINT_PERSONAL_CONFIG_SUPPRESS"
);
}
}
return this._cacheConfig(directoryPath, baseConfigArray);
}
// Load the config on this directory.
try {
configArray = configArrayFactory.loadInDirectory(directoryPath);
} catch (error) {
/* istanbul ignore next */
if (error.code === "EACCES") {
debug("Stop traversing because of 'EACCES' error.");
return this._cacheConfig(directoryPath, baseConfigArray);
}
throw error;
}
if (configArray.length > 0 && configArray.isRoot()) {
debug("Stop traversing because of 'root:true'.");
configArray.unshift(...baseConfigArray);
return this._cacheConfig(directoryPath, configArray);
}
// Load from the ancestors and merge it.
const parentPath = path.dirname(directoryPath);
const parentConfigArray = parentPath && parentPath !== directoryPath
? this._loadConfigInAncestors(
parentPath,
configsExistInSubdirs || configArray.length > 0
)
: baseConfigArray;
if (configArray.length > 0) {
configArray.unshift(...parentConfigArray);
} else {
configArray = parentConfigArray;
}
// Cache and return.
return this._cacheConfig(directoryPath, configArray);
}
/**
* Freeze and cache a given config.
* @param {string} directoryPath The path to a directory as a cache key.
* @param {ConfigArray} configArray The config array as a cache value.
* @returns {ConfigArray} The `configArray` (frozen).
*/
_cacheConfig(directoryPath, configArray) {
const { configCache } = internalSlotsMap.get(this);
Object.freeze(configArray);
configCache.set(directoryPath, configArray);
return configArray;
}
/**
* Finalize a given config array.
* Concatenate `--config` and other CLI options.
* @param {ConfigArray} configArray The parent config array.
* @param {string} directoryPath The path to the leaf directory to find config files.
* @param {boolean} ignoreNotFoundError If `true` then it doesn't throw `ConfigurationNotFoundError`.
* @returns {ConfigArray} The loaded config.
* @private
*/
_finalizeConfigArray(configArray, directoryPath, ignoreNotFoundError) {
const {
cliConfigArray,
configArrayFactory,
finalizeCache,
useEslintrc,
builtInRules
} = internalSlotsMap.get(this);
let finalConfigArray = finalizeCache.get(configArray);
if (!finalConfigArray) {
finalConfigArray = configArray;
// Load the personal config if there are no regular config files.
if (
useEslintrc &&
configArray.every(c => !c.filePath) &&
cliConfigArray.every(c => !c.filePath) // `--config` option can be a file.
) {
const homePath = os.homedir();
debug("Loading the config file of the home directory:", homePath);
const personalConfigArray = configArrayFactory.loadInDirectory(
homePath,
{ name: "PersonalConfig" }
);
if (
personalConfigArray.length > 0 &&
!directoryPath.startsWith(homePath)
) {
const lastElement =
personalConfigArray[personalConfigArray.length - 1];
emitDeprecationWarning(
lastElement.filePath,
"ESLINT_PERSONAL_CONFIG_LOAD"
);
}
finalConfigArray = finalConfigArray.concat(personalConfigArray);
}
// Apply CLI options.
if (cliConfigArray.length > 0) {
finalConfigArray = finalConfigArray.concat(cliConfigArray);
}
// Validate rule settings and environments.
const validator = new ConfigValidator({
builtInRules
});
validator.validateConfigArray(finalConfigArray);
// Cache it.
Object.freeze(finalConfigArray);
finalizeCache.set(configArray, finalConfigArray);
debug(
"Configuration was determined: %o on %s",
finalConfigArray,
directoryPath
);
}
// At least one element (the default ignore patterns) exists.
if (!ignoreNotFoundError && useEslintrc && finalConfigArray.length <= 1) {
throw new ConfigurationNotFoundError(directoryPath);
}
return finalConfigArray;
}
}
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
export { CascadingConfigArrayFactory };

1151
node_modules/@eslint/eslintrc/lib/config-array-factory.js generated vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,510 @@
/**
* @fileoverview `ConfigArray` class.
*
* `ConfigArray` class expresses the full of a configuration. It has the entry
* config file, base config files that were extended, loaded parsers, and loaded
* plugins.
*
* `ConfigArray` class provides three properties and two methods.
*
* - `pluginEnvironments`
* - `pluginProcessors`
* - `pluginRules`
* The `Map` objects that contain the members of all plugins that this
* config array contains. Those map objects don't have mutation methods.
* Those keys are the member ID such as `pluginId/memberName`.
* - `isRoot()`
* If `true` then this configuration has `root:true` property.
* - `extractConfig(filePath)`
* Extract the final configuration for a given file. This means merging
* every config array element which that `criteria` property matched. The
* `filePath` argument must be an absolute path.
*
* `ConfigArrayFactory` provides the loading logic of config files.
*
* @author Toru Nagashima <https://github.com/mysticatea>
*/
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
import { ExtractedConfig } from "./extracted-config.js";
import { IgnorePattern } from "./ignore-pattern.js";
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
// Define types for VSCode IntelliSense.
/** @typedef {import("../../shared/types").Environment} Environment */
/** @typedef {import("../../shared/types").GlobalConf} GlobalConf */
/** @typedef {import("../../shared/types").RuleConf} RuleConf */
/** @typedef {import("../../shared/types").Rule} Rule */
/** @typedef {import("../../shared/types").Plugin} Plugin */
/** @typedef {import("../../shared/types").Processor} Processor */
/** @typedef {import("./config-dependency").DependentParser} DependentParser */
/** @typedef {import("./config-dependency").DependentPlugin} DependentPlugin */
/** @typedef {import("./override-tester")["OverrideTester"]} OverrideTester */
/**
* @typedef {Object} ConfigArrayElement
* @property {string} name The name of this config element.
* @property {string} filePath The path to the source file of this config element.
* @property {InstanceType<OverrideTester>|null} criteria The tester for the `files` and `excludedFiles` of this config element.
* @property {Record<string, boolean>|undefined} env The environment settings.
* @property {Record<string, GlobalConf>|undefined} globals The global variable settings.
* @property {IgnorePattern|undefined} ignorePattern The ignore patterns.
* @property {boolean|undefined} noInlineConfig The flag that disables directive comments.
* @property {DependentParser|undefined} parser The parser loader.
* @property {Object|undefined} parserOptions The parser options.
* @property {Record<string, DependentPlugin>|undefined} plugins The plugin loaders.
* @property {string|undefined} processor The processor name to refer plugin's processor.
* @property {boolean|undefined} reportUnusedDisableDirectives The flag to report unused `eslint-disable` comments.
* @property {boolean|undefined} root The flag to express root.
* @property {Record<string, RuleConf>|undefined} rules The rule settings
* @property {Object|undefined} settings The shared settings.
* @property {"config" | "ignore" | "implicit-processor"} type The element type.
*/
/**
* @typedef {Object} ConfigArrayInternalSlots
* @property {Map<string, ExtractedConfig>} cache The cache to extract configs.
* @property {ReadonlyMap<string, Environment>|null} envMap The map from environment ID to environment definition.
* @property {ReadonlyMap<string, Processor>|null} processorMap The map from processor ID to environment definition.
* @property {ReadonlyMap<string, Rule>|null} ruleMap The map from rule ID to rule definition.
*/
/** @type {WeakMap<ConfigArray, ConfigArrayInternalSlots>} */
const internalSlotsMap = new class extends WeakMap {
get(key) {
let value = super.get(key);
if (!value) {
value = {
cache: new Map(),
envMap: null,
processorMap: null,
ruleMap: null
};
super.set(key, value);
}
return value;
}
}();
/**
* Get the indices which are matched to a given file.
* @param {ConfigArrayElement[]} elements The elements.
* @param {string} filePath The path to a target file.
* @returns {number[]} The indices.
*/
function getMatchedIndices(elements, filePath) {
const indices = [];
for (let i = elements.length - 1; i >= 0; --i) {
const element = elements[i];
if (!element.criteria || (filePath && element.criteria.test(filePath))) {
indices.push(i);
}
}
return indices;
}
/**
* Check if a value is a non-null object.
* @param {any} x The value to check.
* @returns {boolean} `true` if the value is a non-null object.
*/
function isNonNullObject(x) {
return typeof x === "object" && x !== null;
}
/**
* Merge two objects.
*
* Assign every property values of `y` to `x` if `x` doesn't have the property.
* If `x`'s property value is an object, it does recursive.
* @param {Object} target The destination to merge
* @param {Object|undefined} source The source to merge.
* @returns {void}
*/
function mergeWithoutOverwrite(target, source) {
if (!isNonNullObject(source)) {
return;
}
for (const key of Object.keys(source)) {
if (key === "__proto__") {
continue;
}
if (isNonNullObject(target[key])) {
mergeWithoutOverwrite(target[key], source[key]);
} else if (target[key] === void 0) {
if (isNonNullObject(source[key])) {
target[key] = Array.isArray(source[key]) ? [] : {};
mergeWithoutOverwrite(target[key], source[key]);
} else if (source[key] !== void 0) {
target[key] = source[key];
}
}
}
}
/**
* The error for plugin conflicts.
*/
class PluginConflictError extends Error {
/**
* Initialize this error object.
* @param {string} pluginId The plugin ID.
* @param {{filePath:string, importerName:string}[]} plugins The resolved plugins.
*/
constructor(pluginId, plugins) {
super(`Plugin "${pluginId}" was conflicted between ${plugins.map(p => `"${p.importerName}"`).join(" and ")}.`);
this.messageTemplate = "plugin-conflict";
this.messageData = { pluginId, plugins };
}
}
/**
* Merge plugins.
* `target`'s definition is prior to `source`'s.
* @param {Record<string, DependentPlugin>} target The destination to merge
* @param {Record<string, DependentPlugin>|undefined} source The source to merge.
* @returns {void}
*/
function mergePlugins(target, source) {
if (!isNonNullObject(source)) {
return;
}
for (const key of Object.keys(source)) {
if (key === "__proto__") {
continue;
}
const targetValue = target[key];
const sourceValue = source[key];
// Adopt the plugin which was found at first.
if (targetValue === void 0) {
if (sourceValue.error) {
throw sourceValue.error;
}
target[key] = sourceValue;
} else if (sourceValue.filePath !== targetValue.filePath) {
throw new PluginConflictError(key, [
{
filePath: targetValue.filePath,
importerName: targetValue.importerName
},
{
filePath: sourceValue.filePath,
importerName: sourceValue.importerName
}
]);
}
}
}
/**
* Merge rule configs.
* `target`'s definition is prior to `source`'s.
* @param {Record<string, Array>} target The destination to merge
* @param {Record<string, RuleConf>|undefined} source The source to merge.
* @returns {void}
*/
function mergeRuleConfigs(target, source) {
if (!isNonNullObject(source)) {
return;
}
for (const key of Object.keys(source)) {
if (key === "__proto__") {
continue;
}
const targetDef = target[key];
const sourceDef = source[key];
// Adopt the rule config which was found at first.
if (targetDef === void 0) {
if (Array.isArray(sourceDef)) {
target[key] = [...sourceDef];
} else {
target[key] = [sourceDef];
}
/*
* If the first found rule config is severity only and the current rule
* config has options, merge the severity and the options.
*/
} else if (
targetDef.length === 1 &&
Array.isArray(sourceDef) &&
sourceDef.length >= 2
) {
targetDef.push(...sourceDef.slice(1));
}
}
}
/**
* Create the extracted config.
* @param {ConfigArray} instance The config elements.
* @param {number[]} indices The indices to use.
* @returns {ExtractedConfig} The extracted config.
*/
function createConfig(instance, indices) {
const config = new ExtractedConfig();
const ignorePatterns = [];
// Merge elements.
for (const index of indices) {
const element = instance[index];
// Adopt the parser which was found at first.
if (!config.parser && element.parser) {
if (element.parser.error) {
throw element.parser.error;
}
config.parser = element.parser;
}
// Adopt the processor which was found at first.
if (!config.processor && element.processor) {
config.processor = element.processor;
}
// Adopt the noInlineConfig which was found at first.
if (config.noInlineConfig === void 0 && element.noInlineConfig !== void 0) {
config.noInlineConfig = element.noInlineConfig;
config.configNameOfNoInlineConfig = element.name;
}
// Adopt the reportUnusedDisableDirectives which was found at first.
if (config.reportUnusedDisableDirectives === void 0 && element.reportUnusedDisableDirectives !== void 0) {
config.reportUnusedDisableDirectives = element.reportUnusedDisableDirectives;
}
// Collect ignorePatterns
if (element.ignorePattern) {
ignorePatterns.push(element.ignorePattern);
}
// Merge others.
mergeWithoutOverwrite(config.env, element.env);
mergeWithoutOverwrite(config.globals, element.globals);
mergeWithoutOverwrite(config.parserOptions, element.parserOptions);
mergeWithoutOverwrite(config.settings, element.settings);
mergePlugins(config.plugins, element.plugins);
mergeRuleConfigs(config.rules, element.rules);
}
// Create the predicate function for ignore patterns.
if (ignorePatterns.length > 0) {
config.ignores = IgnorePattern.createIgnore(ignorePatterns.reverse());
}
return config;
}
/**
* Collect definitions.
* @template T, U
* @param {string} pluginId The plugin ID for prefix.
* @param {Record<string,T>} defs The definitions to collect.
* @param {Map<string, U>} map The map to output.
* @returns {void}
*/
function collect(pluginId, defs, map) {
if (defs) {
const prefix = pluginId && `${pluginId}/`;
for (const [key, value] of Object.entries(defs)) {
map.set(`${prefix}${key}`, value);
}
}
}
/**
* Delete the mutation methods from a given map.
* @param {Map<any, any>} map The map object to delete.
* @returns {void}
*/
function deleteMutationMethods(map) {
Object.defineProperties(map, {
clear: { configurable: true, value: void 0 },
delete: { configurable: true, value: void 0 },
set: { configurable: true, value: void 0 }
});
}
/**
* Create `envMap`, `processorMap`, `ruleMap` with the plugins in the config array.
* @param {ConfigArrayElement[]} elements The config elements.
* @param {ConfigArrayInternalSlots} slots The internal slots.
* @returns {void}
*/
function initPluginMemberMaps(elements, slots) {
const processed = new Set();
slots.envMap = new Map();
slots.processorMap = new Map();
slots.ruleMap = new Map();
for (const element of elements) {
if (!element.plugins) {
continue;
}
for (const [pluginId, value] of Object.entries(element.plugins)) {
const plugin = value.definition;
if (!plugin || processed.has(pluginId)) {
continue;
}
processed.add(pluginId);
collect(pluginId, plugin.environments, slots.envMap);
collect(pluginId, plugin.processors, slots.processorMap);
collect(pluginId, plugin.rules, slots.ruleMap);
}
}
deleteMutationMethods(slots.envMap);
deleteMutationMethods(slots.processorMap);
deleteMutationMethods(slots.ruleMap);
}
/**
* Create `envMap`, `processorMap`, `ruleMap` with the plugins in the config array.
* @param {ConfigArray} instance The config elements.
* @returns {ConfigArrayInternalSlots} The extracted config.
*/
function ensurePluginMemberMaps(instance) {
const slots = internalSlotsMap.get(instance);
if (!slots.ruleMap) {
initPluginMemberMaps(instance, slots);
}
return slots;
}
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
/**
* The Config Array.
*
* `ConfigArray` instance contains all settings, parsers, and plugins.
* You need to call `ConfigArray#extractConfig(filePath)` method in order to
* extract, merge and get only the config data which is related to an arbitrary
* file.
* @extends {Array<ConfigArrayElement>}
*/
class ConfigArray extends Array {
/**
* Get the plugin environments.
* The returned map cannot be mutated.
* @type {ReadonlyMap<string, Environment>} The plugin environments.
*/
get pluginEnvironments() {
return ensurePluginMemberMaps(this).envMap;
}
/**
* Get the plugin processors.
* The returned map cannot be mutated.
* @type {ReadonlyMap<string, Processor>} The plugin processors.
*/
get pluginProcessors() {
return ensurePluginMemberMaps(this).processorMap;
}
/**
* Get the plugin rules.
* The returned map cannot be mutated.
* @returns {ReadonlyMap<string, Rule>} The plugin rules.
*/
get pluginRules() {
return ensurePluginMemberMaps(this).ruleMap;
}
/**
* Check if this config has `root` flag.
* @returns {boolean} `true` if this config array is root.
*/
isRoot() {
for (let i = this.length - 1; i >= 0; --i) {
const root = this[i].root;
if (typeof root === "boolean") {
return root;
}
}
return false;
}
/**
* Extract the config data which is related to a given file.
* @param {string} filePath The absolute path to the target file.
* @returns {ExtractedConfig} The extracted config data.
*/
extractConfig(filePath) {
const { cache } = internalSlotsMap.get(this);
const indices = getMatchedIndices(this, filePath);
const cacheKey = indices.join(",");
if (!cache.has(cacheKey)) {
cache.set(cacheKey, createConfig(this, indices));
}
return cache.get(cacheKey);
}
/**
* Check if a given path is an additional lint target.
* @param {string} filePath The absolute path to the target file.
* @returns {boolean} `true` if the file is an additional lint target.
*/
isAdditionalTargetPath(filePath) {
for (const { criteria, type } of this) {
if (
type === "config" &&
criteria &&
!criteria.endsWithWildcard &&
criteria.test(filePath)
) {
return true;
}
}
return false;
}
}
/**
* Get the used extracted configs.
* CLIEngine will use this method to collect used deprecated rules.
* @param {ConfigArray} instance The config array object to get.
* @returns {ExtractedConfig[]} The used extracted configs.
* @private
*/
function getUsedExtractedConfigs(instance) {
const { cache } = internalSlotsMap.get(instance);
return Array.from(cache.values());
}
export {
ConfigArray,
getUsedExtractedConfigs
};

View file

@ -0,0 +1,124 @@
/**
* @fileoverview `ConfigDependency` class.
*
* `ConfigDependency` class expresses a loaded parser or plugin.
*
* If the parser or plugin was loaded successfully, it has `definition` property
* and `filePath` property. Otherwise, it has `error` property.
*
* When `JSON.stringify()` converted a `ConfigDependency` object to a JSON, it
* omits `definition` property.
*
* `ConfigArrayFactory` creates `ConfigDependency` objects when it loads parsers
* or plugins.
*
* @author Toru Nagashima <https://github.com/mysticatea>
*/
import util from "util";
/**
* The class is to store parsers or plugins.
* This class hides the loaded object from `JSON.stringify()` and `console.log`.
* @template T
*/
class ConfigDependency {
/**
* Initialize this instance.
* @param {Object} data The dependency data.
* @param {T} [data.definition] The dependency if the loading succeeded.
* @param {T} [data.original] The original, non-normalized dependency if the loading succeeded.
* @param {Error} [data.error] The error object if the loading failed.
* @param {string} [data.filePath] The actual path to the dependency if the loading succeeded.
* @param {string} data.id The ID of this dependency.
* @param {string} data.importerName The name of the config file which loads this dependency.
* @param {string} data.importerPath The path to the config file which loads this dependency.
*/
constructor({
definition = null,
original = null,
error = null,
filePath = null,
id,
importerName,
importerPath
}) {
/**
* The loaded dependency if the loading succeeded.
* @type {T|null}
*/
this.definition = definition;
/**
* The original dependency as loaded directly from disk if the loading succeeded.
* @type {T|null}
*/
this.original = original;
/**
* The error object if the loading failed.
* @type {Error|null}
*/
this.error = error;
/**
* The loaded dependency if the loading succeeded.
* @type {string|null}
*/
this.filePath = filePath;
/**
* The ID of this dependency.
* @type {string}
*/
this.id = id;
/**
* The name of the config file which loads this dependency.
* @type {string}
*/
this.importerName = importerName;
/**
* The path to the config file which loads this dependency.
* @type {string}
*/
this.importerPath = importerPath;
}
// eslint-disable-next-line jsdoc/require-description
/**
* @returns {Object} a JSON compatible object.
*/
toJSON() {
const obj = this[util.inspect.custom]();
// Display `error.message` (`Error#message` is unenumerable).
if (obj.error instanceof Error) {
obj.error = { ...obj.error, message: obj.error.message };
}
return obj;
}
// eslint-disable-next-line jsdoc/require-description
/**
* @returns {Object} an object to display by `console.log()`.
*/
[util.inspect.custom]() {
const {
definition: _ignore1, // eslint-disable-line no-unused-vars
original: _ignore2, // eslint-disable-line no-unused-vars
...obj
} = this;
return obj;
}
}
/** @typedef {ConfigDependency<import("../../shared/types").Parser>} DependentParser */
/** @typedef {ConfigDependency<import("../../shared/types").Plugin>} DependentPlugin */
export { ConfigDependency };

View file

@ -0,0 +1,145 @@
/**
* @fileoverview `ExtractedConfig` class.
*
* `ExtractedConfig` class expresses a final configuration for a specific file.
*
* It provides one method.
*
* - `toCompatibleObjectAsConfigFileContent()`
* Convert this configuration to the compatible object as the content of
* config files. It converts the loaded parser and plugins to strings.
* `CLIEngine#getConfigForFile(filePath)` method uses this method.
*
* `ConfigArray#extractConfig(filePath)` creates a `ExtractedConfig` instance.
*
* @author Toru Nagashima <https://github.com/mysticatea>
*/
import { IgnorePattern } from "./ignore-pattern.js";
// For VSCode intellisense
/** @typedef {import("../../shared/types").ConfigData} ConfigData */
/** @typedef {import("../../shared/types").GlobalConf} GlobalConf */
/** @typedef {import("../../shared/types").SeverityConf} SeverityConf */
/** @typedef {import("./config-dependency").DependentParser} DependentParser */
/** @typedef {import("./config-dependency").DependentPlugin} DependentPlugin */
/**
* Check if `xs` starts with `ys`.
* @template T
* @param {T[]} xs The array to check.
* @param {T[]} ys The array that may be the first part of `xs`.
* @returns {boolean} `true` if `xs` starts with `ys`.
*/
function startsWith(xs, ys) {
return xs.length >= ys.length && ys.every((y, i) => y === xs[i]);
}
/**
* The class for extracted config data.
*/
class ExtractedConfig {
constructor() {
/**
* The config name what `noInlineConfig` setting came from.
* @type {string}
*/
this.configNameOfNoInlineConfig = "";
/**
* Environments.
* @type {Record<string, boolean>}
*/
this.env = {};
/**
* Global variables.
* @type {Record<string, GlobalConf>}
*/
this.globals = {};
/**
* The glob patterns that ignore to lint.
* @type {(((filePath:string, dot?:boolean) => boolean) & { basePath:string; patterns:string[] }) | undefined}
*/
this.ignores = void 0;
/**
* The flag that disables directive comments.
* @type {boolean|undefined}
*/
this.noInlineConfig = void 0;
/**
* Parser definition.
* @type {DependentParser|null}
*/
this.parser = null;
/**
* Options for the parser.
* @type {Object}
*/
this.parserOptions = {};
/**
* Plugin definitions.
* @type {Record<string, DependentPlugin>}
*/
this.plugins = {};
/**
* Processor ID.
* @type {string|null}
*/
this.processor = null;
/**
* The flag that reports unused `eslint-disable` directive comments.
* @type {boolean|undefined}
*/
this.reportUnusedDisableDirectives = void 0;
/**
* Rule settings.
* @type {Record<string, [SeverityConf, ...any[]]>}
*/
this.rules = {};
/**
* Shared settings.
* @type {Object}
*/
this.settings = {};
}
/**
* Convert this config to the compatible object as a config file content.
* @returns {ConfigData} The converted object.
*/
toCompatibleObjectAsConfigFileContent() {
const {
/* eslint-disable no-unused-vars */
configNameOfNoInlineConfig: _ignore1,
processor: _ignore2,
/* eslint-enable no-unused-vars */
ignores,
...config
} = this;
config.parser = config.parser && config.parser.filePath;
config.plugins = Object.keys(config.plugins).filter(Boolean).reverse();
config.ignorePatterns = ignores ? ignores.patterns : [];
// Strip the default patterns from `ignorePatterns`.
if (startsWith(config.ignorePatterns, IgnorePattern.DefaultPatterns)) {
config.ignorePatterns =
config.ignorePatterns.slice(IgnorePattern.DefaultPatterns.length);
}
return config;
}
}
export { ExtractedConfig };

View file

@ -0,0 +1,238 @@
/**
* @fileoverview `IgnorePattern` class.
*
* `IgnorePattern` class has the set of glob patterns and the base path.
*
* It provides two static methods.
*
* - `IgnorePattern.createDefaultIgnore(cwd)`
* Create the default predicate function.
* - `IgnorePattern.createIgnore(ignorePatterns)`
* Create the predicate function from multiple `IgnorePattern` objects.
*
* It provides two properties and a method.
*
* - `patterns`
* The glob patterns that ignore to lint.
* - `basePath`
* The base path of the glob patterns. If absolute paths existed in the
* glob patterns, those are handled as relative paths to the base path.
* - `getPatternsRelativeTo(basePath)`
* Get `patterns` as modified for a given base path. It modifies the
* absolute paths in the patterns as prepending the difference of two base
* paths.
*
* `ConfigArrayFactory` creates `IgnorePattern` objects when it processes
* `ignorePatterns` properties.
*
* @author Toru Nagashima <https://github.com/mysticatea>
*/
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
import assert from "assert";
import path from "path";
import ignore from "ignore";
import debugOrig from "debug";
const debug = debugOrig("eslintrc:ignore-pattern");
/** @typedef {ReturnType<import("ignore").default>} Ignore */
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
/**
* Get the path to the common ancestor directory of given paths.
* @param {string[]} sourcePaths The paths to calculate the common ancestor.
* @returns {string} The path to the common ancestor directory.
*/
function getCommonAncestorPath(sourcePaths) {
let result = sourcePaths[0];
for (let i = 1; i < sourcePaths.length; ++i) {
const a = result;
const b = sourcePaths[i];
// Set the shorter one (it's the common ancestor if one includes the other).
result = a.length < b.length ? a : b;
// Set the common ancestor.
for (let j = 0, lastSepPos = 0; j < a.length && j < b.length; ++j) {
if (a[j] !== b[j]) {
result = a.slice(0, lastSepPos);
break;
}
if (a[j] === path.sep) {
lastSepPos = j;
}
}
}
let resolvedResult = result || path.sep;
// if Windows common ancestor is root of drive must have trailing slash to be absolute.
if (resolvedResult && resolvedResult.endsWith(":") && process.platform === "win32") {
resolvedResult += path.sep;
}
return resolvedResult;
}
/**
* Make relative path.
* @param {string} from The source path to get relative path.
* @param {string} to The destination path to get relative path.
* @returns {string} The relative path.
*/
function relative(from, to) {
const relPath = path.relative(from, to);
if (path.sep === "/") {
return relPath;
}
return relPath.split(path.sep).join("/");
}
/**
* Get the trailing slash if existed.
* @param {string} filePath The path to check.
* @returns {string} The trailing slash if existed.
*/
function dirSuffix(filePath) {
const isDir = (
filePath.endsWith(path.sep) ||
(process.platform === "win32" && filePath.endsWith("/"))
);
return isDir ? "/" : "";
}
const DefaultPatterns = Object.freeze(["/**/node_modules/*"]);
const DotPatterns = Object.freeze([".*", "!.eslintrc.*", "!../"]);
//------------------------------------------------------------------------------
// Public
//------------------------------------------------------------------------------
class IgnorePattern {
/**
* The default patterns.
* @type {string[]}
*/
static get DefaultPatterns() {
return DefaultPatterns;
}
/**
* Create the default predicate function.
* @param {string} cwd The current working directory.
* @returns {((filePath:string, dot:boolean) => boolean) & {basePath:string; patterns:string[]}}
* The preficate function.
* The first argument is an absolute path that is checked.
* The second argument is the flag to not ignore dotfiles.
* If the predicate function returned `true`, it means the path should be ignored.
*/
static createDefaultIgnore(cwd) {
return this.createIgnore([new IgnorePattern(DefaultPatterns, cwd)]);
}
/**
* Create the predicate function from multiple `IgnorePattern` objects.
* @param {IgnorePattern[]} ignorePatterns The list of ignore patterns.
* @returns {((filePath:string, dot?:boolean) => boolean) & {basePath:string; patterns:string[]}}
* The preficate function.
* The first argument is an absolute path that is checked.
* The second argument is the flag to not ignore dotfiles.
* If the predicate function returned `true`, it means the path should be ignored.
*/
static createIgnore(ignorePatterns) {
debug("Create with: %o", ignorePatterns);
const basePath = getCommonAncestorPath(ignorePatterns.map(p => p.basePath));
const patterns = [].concat(
...ignorePatterns.map(p => p.getPatternsRelativeTo(basePath))
);
const ig = ignore({ allowRelativePaths: true }).add([...DotPatterns, ...patterns]);
const dotIg = ignore({ allowRelativePaths: true }).add(patterns);
debug(" processed: %o", { basePath, patterns });
return Object.assign(
(filePath, dot = false) => {
assert(path.isAbsolute(filePath), "'filePath' should be an absolute path.");
const relPathRaw = relative(basePath, filePath);
const relPath = relPathRaw && (relPathRaw + dirSuffix(filePath));
const adoptedIg = dot ? dotIg : ig;
const result = relPath !== "" && adoptedIg.ignores(relPath);
debug("Check", { filePath, dot, relativePath: relPath, result });
return result;
},
{ basePath, patterns }
);
}
/**
* Initialize a new `IgnorePattern` instance.
* @param {string[]} patterns The glob patterns that ignore to lint.
* @param {string} basePath The base path of `patterns`.
*/
constructor(patterns, basePath) {
assert(path.isAbsolute(basePath), "'basePath' should be an absolute path.");
/**
* The glob patterns that ignore to lint.
* @type {string[]}
*/
this.patterns = patterns;
/**
* The base path of `patterns`.
* @type {string}
*/
this.basePath = basePath;
/**
* If `true` then patterns which don't start with `/` will match the paths to the outside of `basePath`. Defaults to `false`.
*
* It's set `true` for `.eslintignore`, `package.json`, and `--ignore-path` for backward compatibility.
* It's `false` as-is for `ignorePatterns` property in config files.
* @type {boolean}
*/
this.loose = false;
}
/**
* Get `patterns` as modified for a given base path. It modifies the
* absolute paths in the patterns as prepending the difference of two base
* paths.
* @param {string} newBasePath The base path.
* @returns {string[]} Modifired patterns.
*/
getPatternsRelativeTo(newBasePath) {
assert(path.isAbsolute(newBasePath), "'newBasePath' should be an absolute path.");
const { basePath, loose, patterns } = this;
if (newBasePath === basePath) {
return patterns;
}
const prefix = `/${relative(newBasePath, basePath)}`;
return patterns.map(pattern => {
const negative = pattern.startsWith("!");
const head = negative ? "!" : "";
const body = negative ? pattern.slice(1) : pattern;
if (body.startsWith("/") || body.startsWith("../")) {
return `${head}${prefix}${body}`;
}
return loose ? pattern : `${head}${prefix}/**/${body}`;
});
}
}
export { IgnorePattern };

View file

@ -0,0 +1,19 @@
/**
* @fileoverview `ConfigArray` class.
* @author Toru Nagashima <https://github.com/mysticatea>
*/
import { ConfigArray, getUsedExtractedConfigs } from "./config-array.js";
import { ConfigDependency } from "./config-dependency.js";
import { ExtractedConfig } from "./extracted-config.js";
import { IgnorePattern } from "./ignore-pattern.js";
import { OverrideTester } from "./override-tester.js";
export {
ConfigArray,
ConfigDependency,
ExtractedConfig,
IgnorePattern,
OverrideTester,
getUsedExtractedConfigs
};

View file

@ -0,0 +1,225 @@
/**
* @fileoverview `OverrideTester` class.
*
* `OverrideTester` class handles `files` property and `excludedFiles` property
* of `overrides` config.
*
* It provides one method.
*
* - `test(filePath)`
* Test if a file path matches the pair of `files` property and
* `excludedFiles` property. The `filePath` argument must be an absolute
* path.
*
* `ConfigArrayFactory` creates `OverrideTester` objects when it processes
* `overrides` properties.
*
* @author Toru Nagashima <https://github.com/mysticatea>
*/
import assert from "assert";
import path from "path";
import util from "util";
import minimatch from "minimatch";
const { Minimatch } = minimatch;
const minimatchOpts = { dot: true, matchBase: true };
/**
* @typedef {Object} Pattern
* @property {InstanceType<Minimatch>[] | null} includes The positive matchers.
* @property {InstanceType<Minimatch>[] | null} excludes The negative matchers.
*/
/**
* Normalize a given pattern to an array.
* @param {string|string[]|undefined} patterns A glob pattern or an array of glob patterns.
* @returns {string[]|null} Normalized patterns.
* @private
*/
function normalizePatterns(patterns) {
if (Array.isArray(patterns)) {
return patterns.filter(Boolean);
}
if (typeof patterns === "string" && patterns) {
return [patterns];
}
return [];
}
/**
* Create the matchers of given patterns.
* @param {string[]} patterns The patterns.
* @returns {InstanceType<Minimatch>[] | null} The matchers.
*/
function toMatcher(patterns) {
if (patterns.length === 0) {
return null;
}
return patterns.map(pattern => {
if (/^\.[/\\]/u.test(pattern)) {
return new Minimatch(
pattern.slice(2),
// `./*.js` should not match with `subdir/foo.js`
{ ...minimatchOpts, matchBase: false }
);
}
return new Minimatch(pattern, minimatchOpts);
});
}
/**
* Convert a given matcher to string.
* @param {Pattern} matchers The matchers.
* @returns {string} The string expression of the matcher.
*/
function patternToJson({ includes, excludes }) {
return {
includes: includes && includes.map(m => m.pattern),
excludes: excludes && excludes.map(m => m.pattern)
};
}
/**
* The class to test given paths are matched by the patterns.
*/
class OverrideTester {
/**
* Create a tester with given criteria.
* If there are no criteria, returns `null`.
* @param {string|string[]} files The glob patterns for included files.
* @param {string|string[]} excludedFiles The glob patterns for excluded files.
* @param {string} basePath The path to the base directory to test paths.
* @returns {OverrideTester|null} The created instance or `null`.
*/
static create(files, excludedFiles, basePath) {
const includePatterns = normalizePatterns(files);
const excludePatterns = normalizePatterns(excludedFiles);
let endsWithWildcard = false;
if (includePatterns.length === 0) {
return null;
}
// Rejects absolute paths or relative paths to parents.
for (const pattern of includePatterns) {
if (path.isAbsolute(pattern) || pattern.includes("..")) {
throw new Error(`Invalid override pattern (expected relative path not containing '..'): ${pattern}`);
}
if (pattern.endsWith("*")) {
endsWithWildcard = true;
}
}
for (const pattern of excludePatterns) {
if (path.isAbsolute(pattern) || pattern.includes("..")) {
throw new Error(`Invalid override pattern (expected relative path not containing '..'): ${pattern}`);
}
}
const includes = toMatcher(includePatterns);
const excludes = toMatcher(excludePatterns);
return new OverrideTester(
[{ includes, excludes }],
basePath,
endsWithWildcard
);
}
/**
* Combine two testers by logical and.
* If either of the testers was `null`, returns the other tester.
* The `basePath` property of the two must be the same value.
* @param {OverrideTester|null} a A tester.
* @param {OverrideTester|null} b Another tester.
* @returns {OverrideTester|null} Combined tester.
*/
static and(a, b) {
if (!b) {
return a && new OverrideTester(
a.patterns,
a.basePath,
a.endsWithWildcard
);
}
if (!a) {
return new OverrideTester(
b.patterns,
b.basePath,
b.endsWithWildcard
);
}
assert.strictEqual(a.basePath, b.basePath);
return new OverrideTester(
a.patterns.concat(b.patterns),
a.basePath,
a.endsWithWildcard || b.endsWithWildcard
);
}
/**
* Initialize this instance.
* @param {Pattern[]} patterns The matchers.
* @param {string} basePath The base path.
* @param {boolean} endsWithWildcard If `true` then a pattern ends with `*`.
*/
constructor(patterns, basePath, endsWithWildcard = false) {
/** @type {Pattern[]} */
this.patterns = patterns;
/** @type {string} */
this.basePath = basePath;
/** @type {boolean} */
this.endsWithWildcard = endsWithWildcard;
}
/**
* Test if a given path is matched or not.
* @param {string} filePath The absolute path to the target file.
* @returns {boolean} `true` if the path was matched.
*/
test(filePath) {
if (typeof filePath !== "string" || !path.isAbsolute(filePath)) {
throw new Error(`'filePath' should be an absolute path, but got ${filePath}.`);
}
const relativePath = path.relative(this.basePath, filePath);
return this.patterns.every(({ includes, excludes }) => (
(!includes || includes.some(m => m.match(relativePath))) &&
(!excludes || !excludes.some(m => m.match(relativePath)))
));
}
// eslint-disable-next-line jsdoc/require-description
/**
* @returns {Object} a JSON compatible object.
*/
toJSON() {
if (this.patterns.length === 1) {
return {
...patternToJson(this.patterns[0]),
basePath: this.basePath
};
}
return {
AND: this.patterns.map(patternToJson),
basePath: this.basePath
};
}
// eslint-disable-next-line jsdoc/require-description
/**
* @returns {Object} an object to display by `console.log()`.
*/
[util.inspect.custom]() {
return this.toJSON();
}
}
export { OverrideTester };

318
node_modules/@eslint/eslintrc/lib/flat-compat.js generated vendored Normal file
View file

@ -0,0 +1,318 @@
/**
* @fileoverview Compatibility class for flat config.
* @author Nicholas C. Zakas
*/
//-----------------------------------------------------------------------------
// Requirements
//-----------------------------------------------------------------------------
import createDebug from "debug";
import path from "path";
import environments from "../conf/environments.js";
import { ConfigArrayFactory } from "./config-array-factory.js";
//-----------------------------------------------------------------------------
// Helpers
//-----------------------------------------------------------------------------
/** @typedef {import("../../shared/types").Environment} Environment */
/** @typedef {import("../../shared/types").Processor} Processor */
const debug = createDebug("eslintrc:flat-compat");
const cafactory = Symbol("cafactory");
/**
* Translates an ESLintRC-style config object into a flag-config-style config
* object.
* @param {Object} eslintrcConfig An ESLintRC-style config object.
* @param {Object} options Options to help translate the config.
* @param {string} options.resolveConfigRelativeTo To the directory to resolve
* configs from.
* @param {string} options.resolvePluginsRelativeTo The directory to resolve
* plugins from.
* @param {ReadOnlyMap<string,Environment>} options.pluginEnvironments A map of plugin environment
* names to objects.
* @param {ReadOnlyMap<string,Processor>} options.pluginProcessors A map of plugin processor
* names to objects.
* @returns {Object} A flag-config-style config object.
*/
function translateESLintRC(eslintrcConfig, {
resolveConfigRelativeTo,
resolvePluginsRelativeTo,
pluginEnvironments,
pluginProcessors
}) {
const flatConfig = {};
const configs = [];
const languageOptions = {};
const linterOptions = {};
const keysToCopy = ["settings", "rules", "processor"];
const languageOptionsKeysToCopy = ["globals", "parser", "parserOptions"];
const linterOptionsKeysToCopy = ["noInlineConfig", "reportUnusedDisableDirectives"];
// copy over simple translations
for (const key of keysToCopy) {
if (key in eslintrcConfig && typeof eslintrcConfig[key] !== "undefined") {
flatConfig[key] = eslintrcConfig[key];
}
}
// copy over languageOptions
for (const key of languageOptionsKeysToCopy) {
if (key in eslintrcConfig && typeof eslintrcConfig[key] !== "undefined") {
// create the languageOptions key in the flat config
flatConfig.languageOptions = languageOptions;
if (key === "parser") {
debug(`Resolving parser '${languageOptions[key]}' relative to ${resolveConfigRelativeTo}`);
if (eslintrcConfig[key].error) {
throw eslintrcConfig[key].error;
}
languageOptions[key] = eslintrcConfig[key].definition;
continue;
}
// clone any object values that are in the eslintrc config
if (eslintrcConfig[key] && typeof eslintrcConfig[key] === "object") {
languageOptions[key] = {
...eslintrcConfig[key]
};
} else {
languageOptions[key] = eslintrcConfig[key];
}
}
}
// copy over linterOptions
for (const key of linterOptionsKeysToCopy) {
if (key in eslintrcConfig && typeof eslintrcConfig[key] !== "undefined") {
flatConfig.linterOptions = linterOptions;
linterOptions[key] = eslintrcConfig[key];
}
}
// move ecmaVersion a level up
if (languageOptions.parserOptions) {
if ("ecmaVersion" in languageOptions.parserOptions) {
languageOptions.ecmaVersion = languageOptions.parserOptions.ecmaVersion;
delete languageOptions.parserOptions.ecmaVersion;
}
if ("sourceType" in languageOptions.parserOptions) {
languageOptions.sourceType = languageOptions.parserOptions.sourceType;
delete languageOptions.parserOptions.sourceType;
}
// check to see if we even need parserOptions anymore and remove it if not
if (Object.keys(languageOptions.parserOptions).length === 0) {
delete languageOptions.parserOptions;
}
}
// overrides
if (eslintrcConfig.criteria) {
flatConfig.files = [absoluteFilePath => eslintrcConfig.criteria.test(absoluteFilePath)];
}
// translate plugins
if (eslintrcConfig.plugins && typeof eslintrcConfig.plugins === "object") {
debug(`Translating plugins: ${eslintrcConfig.plugins}`);
flatConfig.plugins = {};
for (const pluginName of Object.keys(eslintrcConfig.plugins)) {
debug(`Translating plugin: ${pluginName}`);
debug(`Resolving plugin '${pluginName} relative to ${resolvePluginsRelativeTo}`);
const { original: plugin, error } = eslintrcConfig.plugins[pluginName];
if (error) {
throw error;
}
flatConfig.plugins[pluginName] = plugin;
// create a config for any processors
if (plugin.processors) {
for (const processorName of Object.keys(plugin.processors)) {
if (processorName.startsWith(".")) {
debug(`Assigning processor: ${pluginName}/${processorName}`);
configs.unshift({
files: [`**/*${processorName}`],
processor: pluginProcessors.get(`${pluginName}/${processorName}`)
});
}
}
}
}
}
// translate env - must come after plugins
if (eslintrcConfig.env && typeof eslintrcConfig.env === "object") {
for (const envName of Object.keys(eslintrcConfig.env)) {
// only add environments that are true
if (eslintrcConfig.env[envName]) {
debug(`Translating environment: ${envName}`);
if (environments.has(envName)) {
// built-in environments should be defined first
configs.unshift(...translateESLintRC({
criteria: eslintrcConfig.criteria,
...environments.get(envName)
}, {
resolveConfigRelativeTo,
resolvePluginsRelativeTo
}));
} else if (pluginEnvironments.has(envName)) {
// if the environment comes from a plugin, it should come after the plugin config
configs.push(...translateESLintRC({
criteria: eslintrcConfig.criteria,
...pluginEnvironments.get(envName)
}, {
resolveConfigRelativeTo,
resolvePluginsRelativeTo
}));
}
}
}
}
// only add if there are actually keys in the config
if (Object.keys(flatConfig).length > 0) {
configs.push(flatConfig);
}
return configs;
}
//-----------------------------------------------------------------------------
// Exports
//-----------------------------------------------------------------------------
/**
* A compatibility class for working with configs.
*/
class FlatCompat {
constructor({
baseDirectory = process.cwd(),
resolvePluginsRelativeTo = baseDirectory,
recommendedConfig,
allConfig
} = {}) {
this.baseDirectory = baseDirectory;
this.resolvePluginsRelativeTo = resolvePluginsRelativeTo;
this[cafactory] = new ConfigArrayFactory({
cwd: baseDirectory,
resolvePluginsRelativeTo,
getEslintAllConfig: () => {
if (!allConfig) {
throw new TypeError("Missing parameter 'allConfig' in FlatCompat constructor.");
}
return allConfig;
},
getEslintRecommendedConfig: () => {
if (!recommendedConfig) {
throw new TypeError("Missing parameter 'recommendedConfig' in FlatCompat constructor.");
}
return recommendedConfig;
}
});
}
/**
* Translates an ESLintRC-style config into a flag-config-style config.
* @param {Object} eslintrcConfig The ESLintRC-style config object.
* @returns {Object} A flag-config-style config object.
*/
config(eslintrcConfig) {
const eslintrcArray = this[cafactory].create(eslintrcConfig, {
basePath: this.baseDirectory
});
const flatArray = [];
let hasIgnorePatterns = false;
eslintrcArray.forEach(configData => {
if (configData.type === "config") {
hasIgnorePatterns = hasIgnorePatterns || configData.ignorePattern;
flatArray.push(...translateESLintRC(configData, {
resolveConfigRelativeTo: path.join(this.baseDirectory, "__placeholder.js"),
resolvePluginsRelativeTo: path.join(this.resolvePluginsRelativeTo, "__placeholder.js"),
pluginEnvironments: eslintrcArray.pluginEnvironments,
pluginProcessors: eslintrcArray.pluginProcessors
}));
}
});
// combine ignorePatterns to emulate ESLintRC behavior better
if (hasIgnorePatterns) {
flatArray.unshift({
ignores: [filePath => {
// Compute the final config for this file.
// This filters config array elements by `files`/`excludedFiles` then merges the elements.
const finalConfig = eslintrcArray.extractConfig(filePath);
// Test the `ignorePattern` properties of the final config.
return Boolean(finalConfig.ignores) && finalConfig.ignores(filePath);
}]
});
}
return flatArray;
}
/**
* Translates the `env` section of an ESLintRC-style config.
* @param {Object} envConfig The `env` section of an ESLintRC config.
* @returns {Object[]} An array of flag-config objects representing the environments.
*/
env(envConfig) {
return this.config({
env: envConfig
});
}
/**
* Translates the `extends` section of an ESLintRC-style config.
* @param {...string} configsToExtend The names of the configs to load.
* @returns {Object[]} An array of flag-config objects representing the config.
*/
extends(...configsToExtend) {
return this.config({
extends: configsToExtend
});
}
/**
* Translates the `plugins` section of an ESLintRC-style config.
* @param {...string} plugins The names of the plugins to load.
* @returns {Object[]} An array of flag-config objects representing the plugins.
*/
plugins(...plugins) {
return this.config({
plugins
});
}
}
export { FlatCompat };

29
node_modules/@eslint/eslintrc/lib/index-universal.js generated vendored Normal file
View file

@ -0,0 +1,29 @@
/**
* @fileoverview Package exports for @eslint/eslintrc
* @author Nicholas C. Zakas
*/
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
import * as ConfigOps from "./shared/config-ops.js";
import ConfigValidator from "./shared/config-validator.js";
import * as naming from "./shared/naming.js";
import environments from "../conf/environments.js";
//-----------------------------------------------------------------------------
// Exports
//-----------------------------------------------------------------------------
const Legacy = {
environments,
// shared
ConfigOps,
ConfigValidator,
naming
};
export {
Legacy
};

56
node_modules/@eslint/eslintrc/lib/index.js generated vendored Normal file
View file

@ -0,0 +1,56 @@
/**
* @fileoverview Package exports for @eslint/eslintrc
* @author Nicholas C. Zakas
*/
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
import {
ConfigArrayFactory,
createContext as createConfigArrayFactoryContext
} from "./config-array-factory.js";
import { CascadingConfigArrayFactory } from "./cascading-config-array-factory.js";
import * as ModuleResolver from "./shared/relative-module-resolver.js";
import { ConfigArray, getUsedExtractedConfigs } from "./config-array/index.js";
import { ConfigDependency } from "./config-array/config-dependency.js";
import { ExtractedConfig } from "./config-array/extracted-config.js";
import { IgnorePattern } from "./config-array/ignore-pattern.js";
import { OverrideTester } from "./config-array/override-tester.js";
import * as ConfigOps from "./shared/config-ops.js";
import ConfigValidator from "./shared/config-validator.js";
import * as naming from "./shared/naming.js";
import { FlatCompat } from "./flat-compat.js";
import environments from "../conf/environments.js";
//-----------------------------------------------------------------------------
// Exports
//-----------------------------------------------------------------------------
const Legacy = {
ConfigArray,
createConfigArrayFactoryContext,
CascadingConfigArrayFactory,
ConfigArrayFactory,
ConfigDependency,
ExtractedConfig,
IgnorePattern,
OverrideTester,
getUsedExtractedConfigs,
environments,
// shared
ConfigOps,
ConfigValidator,
ModuleResolver,
naming
};
export {
Legacy,
FlatCompat
};

191
node_modules/@eslint/eslintrc/lib/shared/ajv.js generated vendored Normal file
View file

@ -0,0 +1,191 @@
/**
* @fileoverview The instance of Ajv validator.
* @author Evgeny Poberezkin
*/
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
import Ajv from "ajv";
//-----------------------------------------------------------------------------
// Helpers
//-----------------------------------------------------------------------------
/*
* Copied from ajv/lib/refs/json-schema-draft-04.json
* The MIT License (MIT)
* Copyright (c) 2015-2017 Evgeny Poberezkin
*/
const metaSchema = {
id: "http://json-schema.org/draft-04/schema#",
$schema: "http://json-schema.org/draft-04/schema#",
description: "Core schema meta-schema",
definitions: {
schemaArray: {
type: "array",
minItems: 1,
items: { $ref: "#" }
},
positiveInteger: {
type: "integer",
minimum: 0
},
positiveIntegerDefault0: {
allOf: [{ $ref: "#/definitions/positiveInteger" }, { default: 0 }]
},
simpleTypes: {
enum: ["array", "boolean", "integer", "null", "number", "object", "string"]
},
stringArray: {
type: "array",
items: { type: "string" },
minItems: 1,
uniqueItems: true
}
},
type: "object",
properties: {
id: {
type: "string"
},
$schema: {
type: "string"
},
title: {
type: "string"
},
description: {
type: "string"
},
default: { },
multipleOf: {
type: "number",
minimum: 0,
exclusiveMinimum: true
},
maximum: {
type: "number"
},
exclusiveMaximum: {
type: "boolean",
default: false
},
minimum: {
type: "number"
},
exclusiveMinimum: {
type: "boolean",
default: false
},
maxLength: { $ref: "#/definitions/positiveInteger" },
minLength: { $ref: "#/definitions/positiveIntegerDefault0" },
pattern: {
type: "string",
format: "regex"
},
additionalItems: {
anyOf: [
{ type: "boolean" },
{ $ref: "#" }
],
default: { }
},
items: {
anyOf: [
{ $ref: "#" },
{ $ref: "#/definitions/schemaArray" }
],
default: { }
},
maxItems: { $ref: "#/definitions/positiveInteger" },
minItems: { $ref: "#/definitions/positiveIntegerDefault0" },
uniqueItems: {
type: "boolean",
default: false
},
maxProperties: { $ref: "#/definitions/positiveInteger" },
minProperties: { $ref: "#/definitions/positiveIntegerDefault0" },
required: { $ref: "#/definitions/stringArray" },
additionalProperties: {
anyOf: [
{ type: "boolean" },
{ $ref: "#" }
],
default: { }
},
definitions: {
type: "object",
additionalProperties: { $ref: "#" },
default: { }
},
properties: {
type: "object",
additionalProperties: { $ref: "#" },
default: { }
},
patternProperties: {
type: "object",
additionalProperties: { $ref: "#" },
default: { }
},
dependencies: {
type: "object",
additionalProperties: {
anyOf: [
{ $ref: "#" },
{ $ref: "#/definitions/stringArray" }
]
}
},
enum: {
type: "array",
minItems: 1,
uniqueItems: true
},
type: {
anyOf: [
{ $ref: "#/definitions/simpleTypes" },
{
type: "array",
items: { $ref: "#/definitions/simpleTypes" },
minItems: 1,
uniqueItems: true
}
]
},
format: { type: "string" },
allOf: { $ref: "#/definitions/schemaArray" },
anyOf: { $ref: "#/definitions/schemaArray" },
oneOf: { $ref: "#/definitions/schemaArray" },
not: { $ref: "#" }
},
dependencies: {
exclusiveMaximum: ["maximum"],
exclusiveMinimum: ["minimum"]
},
default: { }
};
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
export default (additionalOptions = {}) => {
const ajv = new Ajv({
meta: false,
useDefaults: true,
validateSchema: false,
missingRefs: "ignore",
verbose: true,
schemaId: "auto",
...additionalOptions
});
ajv.addMetaSchema(metaSchema);
// eslint-disable-next-line no-underscore-dangle
ajv._opts.defaultMeta = metaSchema.id;
return ajv;
};

135
node_modules/@eslint/eslintrc/lib/shared/config-ops.js generated vendored Normal file
View file

@ -0,0 +1,135 @@
/**
* @fileoverview Config file operations. This file must be usable in the browser,
* so no Node-specific code can be here.
* @author Nicholas C. Zakas
*/
//------------------------------------------------------------------------------
// Private
//------------------------------------------------------------------------------
const RULE_SEVERITY_STRINGS = ["off", "warn", "error"],
RULE_SEVERITY = RULE_SEVERITY_STRINGS.reduce((map, value, index) => {
map[value] = index;
return map;
}, {}),
VALID_SEVERITIES = [0, 1, 2, "off", "warn", "error"];
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
/**
* Normalizes the severity value of a rule's configuration to a number
* @param {(number|string|[number, ...*]|[string, ...*])} ruleConfig A rule's configuration value, generally
* received from the user. A valid config value is either 0, 1, 2, the string "off" (treated the same as 0),
* the string "warn" (treated the same as 1), the string "error" (treated the same as 2), or an array
* whose first element is one of the above values. Strings are matched case-insensitively.
* @returns {(0|1|2)} The numeric severity value if the config value was valid, otherwise 0.
*/
function getRuleSeverity(ruleConfig) {
const severityValue = Array.isArray(ruleConfig) ? ruleConfig[0] : ruleConfig;
if (severityValue === 0 || severityValue === 1 || severityValue === 2) {
return severityValue;
}
if (typeof severityValue === "string") {
return RULE_SEVERITY[severityValue.toLowerCase()] || 0;
}
return 0;
}
/**
* Converts old-style severity settings (0, 1, 2) into new-style
* severity settings (off, warn, error) for all rules. Assumption is that severity
* values have already been validated as correct.
* @param {Object} config The config object to normalize.
* @returns {void}
*/
function normalizeToStrings(config) {
if (config.rules) {
Object.keys(config.rules).forEach(ruleId => {
const ruleConfig = config.rules[ruleId];
if (typeof ruleConfig === "number") {
config.rules[ruleId] = RULE_SEVERITY_STRINGS[ruleConfig] || RULE_SEVERITY_STRINGS[0];
} else if (Array.isArray(ruleConfig) && typeof ruleConfig[0] === "number") {
ruleConfig[0] = RULE_SEVERITY_STRINGS[ruleConfig[0]] || RULE_SEVERITY_STRINGS[0];
}
});
}
}
/**
* Determines if the severity for the given rule configuration represents an error.
* @param {int|string|Array} ruleConfig The configuration for an individual rule.
* @returns {boolean} True if the rule represents an error, false if not.
*/
function isErrorSeverity(ruleConfig) {
return getRuleSeverity(ruleConfig) === 2;
}
/**
* Checks whether a given config has valid severity or not.
* @param {number|string|Array} ruleConfig The configuration for an individual rule.
* @returns {boolean} `true` if the configuration has valid severity.
*/
function isValidSeverity(ruleConfig) {
let severity = Array.isArray(ruleConfig) ? ruleConfig[0] : ruleConfig;
if (typeof severity === "string") {
severity = severity.toLowerCase();
}
return VALID_SEVERITIES.indexOf(severity) !== -1;
}
/**
* Checks whether every rule of a given config has valid severity or not.
* @param {Object} config The configuration for rules.
* @returns {boolean} `true` if the configuration has valid severity.
*/
function isEverySeverityValid(config) {
return Object.keys(config).every(ruleId => isValidSeverity(config[ruleId]));
}
/**
* Normalizes a value for a global in a config
* @param {(boolean|string|null)} configuredValue The value given for a global in configuration or in
* a global directive comment
* @returns {("readable"|"writeable"|"off")} The value normalized as a string
* @throws Error if global value is invalid
*/
function normalizeConfigGlobal(configuredValue) {
switch (configuredValue) {
case "off":
return "off";
case true:
case "true":
case "writeable":
case "writable":
return "writable";
case null:
case false:
case "false":
case "readable":
case "readonly":
return "readonly";
default:
throw new Error(`'${configuredValue}' is not a valid configuration for a global (use 'readonly', 'writable', or 'off')`);
}
}
export {
getRuleSeverity,
normalizeToStrings,
isErrorSeverity,
isValidSeverity,
isEverySeverityValid,
normalizeConfigGlobal
};

View file

@ -0,0 +1,370 @@
/**
* @fileoverview Validates configs.
* @author Brandon Mills
*/
/* eslint class-methods-use-this: "off" */
//------------------------------------------------------------------------------
// Typedefs
//------------------------------------------------------------------------------
/** @typedef {import("../shared/types").Rule} Rule */
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
import util from "util";
import * as ConfigOps from "./config-ops.js";
import { emitDeprecationWarning } from "./deprecation-warnings.js";
import ajvOrig from "./ajv.js";
import configSchema from "../../conf/config-schema.js";
import BuiltInEnvironments from "../../conf/environments.js";
const ajv = ajvOrig();
const ruleValidators = new WeakMap();
const noop = Function.prototype;
//------------------------------------------------------------------------------
// Private
//------------------------------------------------------------------------------
let validateSchema;
const severityMap = {
error: 2,
warn: 1,
off: 0
};
const validated = new WeakSet();
// JSON schema that disallows passing any options
const noOptionsSchema = Object.freeze({
type: "array",
minItems: 0,
maxItems: 0
});
//-----------------------------------------------------------------------------
// Exports
//-----------------------------------------------------------------------------
export default class ConfigValidator {
constructor({ builtInRules = new Map() } = {}) {
this.builtInRules = builtInRules;
}
/**
* Gets a complete options schema for a rule.
* @param {Rule} rule A rule object
* @throws {TypeError} If `meta.schema` is specified but is not an array, object or `false`.
* @returns {Object|null} JSON Schema for the rule's options.
* `null` if rule wasn't passed or its `meta.schema` is `false`.
*/
getRuleOptionsSchema(rule) {
if (!rule) {
return null;
}
if (!rule.meta) {
return { ...noOptionsSchema }; // default if `meta.schema` is not specified
}
const schema = rule.meta.schema;
if (typeof schema === "undefined") {
return { ...noOptionsSchema }; // default if `meta.schema` is not specified
}
// `schema:false` is an allowed explicit opt-out of options validation for the rule
if (schema === false) {
return null;
}
if (typeof schema !== "object" || schema === null) {
throw new TypeError("Rule's `meta.schema` must be an array or object");
}
// ESLint-specific array form needs to be converted into a valid JSON Schema definition
if (Array.isArray(schema)) {
if (schema.length) {
return {
type: "array",
items: schema,
minItems: 0,
maxItems: schema.length
};
}
// `schema:[]` is an explicit way to specify that the rule does not accept any options
return { ...noOptionsSchema };
}
// `schema:<object>` is assumed to be a valid JSON Schema definition
return schema;
}
/**
* Validates a rule's severity and returns the severity value. Throws an error if the severity is invalid.
* @param {options} options The given options for the rule.
* @returns {number|string} The rule's severity value
*/
validateRuleSeverity(options) {
const severity = Array.isArray(options) ? options[0] : options;
const normSeverity = typeof severity === "string" ? severityMap[severity.toLowerCase()] : severity;
if (normSeverity === 0 || normSeverity === 1 || normSeverity === 2) {
return normSeverity;
}
throw new Error(`\tSeverity should be one of the following: 0 = off, 1 = warn, 2 = error (you passed '${util.inspect(severity).replace(/'/gu, "\"").replace(/\n/gu, "")}').\n`);
}
/**
* Validates the non-severity options passed to a rule, based on its schema.
* @param {{create: Function}} rule The rule to validate
* @param {Array} localOptions The options for the rule, excluding severity
* @returns {void}
*/
validateRuleSchema(rule, localOptions) {
if (!ruleValidators.has(rule)) {
try {
const schema = this.getRuleOptionsSchema(rule);
if (schema) {
ruleValidators.set(rule, ajv.compile(schema));
}
} catch (err) {
const errorWithCode = new Error(err.message, { cause: err });
errorWithCode.code = "ESLINT_INVALID_RULE_OPTIONS_SCHEMA";
throw errorWithCode;
}
}
const validateRule = ruleValidators.get(rule);
if (validateRule) {
validateRule(localOptions);
if (validateRule.errors) {
throw new Error(validateRule.errors.map(
error => `\tValue ${JSON.stringify(error.data)} ${error.message}.\n`
).join(""));
}
}
}
/**
* Validates a rule's options against its schema.
* @param {{create: Function}|null} rule The rule that the config is being validated for
* @param {string} ruleId The rule's unique name.
* @param {Array|number} options The given options for the rule.
* @param {string|null} source The name of the configuration source to report in any errors. If null or undefined,
* no source is prepended to the message.
* @returns {void}
*/
validateRuleOptions(rule, ruleId, options, source = null) {
try {
const severity = this.validateRuleSeverity(options);
if (severity !== 0) {
this.validateRuleSchema(rule, Array.isArray(options) ? options.slice(1) : []);
}
} catch (err) {
let enhancedMessage = err.code === "ESLINT_INVALID_RULE_OPTIONS_SCHEMA"
? `Error while processing options validation schema of rule '${ruleId}': ${err.message}`
: `Configuration for rule "${ruleId}" is invalid:\n${err.message}`;
if (typeof source === "string") {
enhancedMessage = `${source}:\n\t${enhancedMessage}`;
}
const enhancedError = new Error(enhancedMessage, { cause: err });
if (err.code) {
enhancedError.code = err.code;
}
throw enhancedError;
}
}
/**
* Validates an environment object
* @param {Object} environment The environment config object to validate.
* @param {string} source The name of the configuration source to report in any errors.
* @param {function(envId:string): Object} [getAdditionalEnv] A map from strings to loaded environments.
* @returns {void}
*/
validateEnvironment(
environment,
source,
getAdditionalEnv = noop
) {
// not having an environment is ok
if (!environment) {
return;
}
Object.keys(environment).forEach(id => {
const env = getAdditionalEnv(id) || BuiltInEnvironments.get(id) || null;
if (!env) {
const message = `${source}:\n\tEnvironment key "${id}" is unknown\n`;
throw new Error(message);
}
});
}
/**
* Validates a rules config object
* @param {Object} rulesConfig The rules config object to validate.
* @param {string} source The name of the configuration source to report in any errors.
* @param {function(ruleId:string): Object} getAdditionalRule A map from strings to loaded rules
* @returns {void}
*/
validateRules(
rulesConfig,
source,
getAdditionalRule = noop
) {
if (!rulesConfig) {
return;
}
Object.keys(rulesConfig).forEach(id => {
const rule = getAdditionalRule(id) || this.builtInRules.get(id) || null;
this.validateRuleOptions(rule, id, rulesConfig[id], source);
});
}
/**
* Validates a `globals` section of a config file
* @param {Object} globalsConfig The `globals` section
* @param {string|null} source The name of the configuration source to report in the event of an error.
* @returns {void}
*/
validateGlobals(globalsConfig, source = null) {
if (!globalsConfig) {
return;
}
Object.entries(globalsConfig)
.forEach(([configuredGlobal, configuredValue]) => {
try {
ConfigOps.normalizeConfigGlobal(configuredValue);
} catch (err) {
throw new Error(`ESLint configuration of global '${configuredGlobal}' in ${source} is invalid:\n${err.message}`);
}
});
}
/**
* Validate `processor` configuration.
* @param {string|undefined} processorName The processor name.
* @param {string} source The name of config file.
* @param {function(id:string): Processor} getProcessor The getter of defined processors.
* @returns {void}
*/
validateProcessor(processorName, source, getProcessor) {
if (processorName && !getProcessor(processorName)) {
throw new Error(`ESLint configuration of processor in '${source}' is invalid: '${processorName}' was not found.`);
}
}
/**
* Formats an array of schema validation errors.
* @param {Array} errors An array of error messages to format.
* @returns {string} Formatted error message
*/
formatErrors(errors) {
return errors.map(error => {
if (error.keyword === "additionalProperties") {
const formattedPropertyPath = error.dataPath.length ? `${error.dataPath.slice(1)}.${error.params.additionalProperty}` : error.params.additionalProperty;
return `Unexpected top-level property "${formattedPropertyPath}"`;
}
if (error.keyword === "type") {
const formattedField = error.dataPath.slice(1);
const formattedExpectedType = Array.isArray(error.schema) ? error.schema.join("/") : error.schema;
const formattedValue = JSON.stringify(error.data);
return `Property "${formattedField}" is the wrong type (expected ${formattedExpectedType} but got \`${formattedValue}\`)`;
}
const field = error.dataPath[0] === "." ? error.dataPath.slice(1) : error.dataPath;
return `"${field}" ${error.message}. Value: ${JSON.stringify(error.data)}`;
}).map(message => `\t- ${message}.\n`).join("");
}
/**
* Validates the top level properties of the config object.
* @param {Object} config The config object to validate.
* @param {string} source The name of the configuration source to report in any errors.
* @returns {void}
*/
validateConfigSchema(config, source = null) {
validateSchema = validateSchema || ajv.compile(configSchema);
if (!validateSchema(config)) {
throw new Error(`ESLint configuration in ${source} is invalid:\n${this.formatErrors(validateSchema.errors)}`);
}
if (Object.hasOwnProperty.call(config, "ecmaFeatures")) {
emitDeprecationWarning(source, "ESLINT_LEGACY_ECMAFEATURES");
}
}
/**
* Validates an entire config object.
* @param {Object} config The config object to validate.
* @param {string} source The name of the configuration source to report in any errors.
* @param {function(ruleId:string): Object} [getAdditionalRule] A map from strings to loaded rules.
* @param {function(envId:string): Object} [getAdditionalEnv] A map from strings to loaded envs.
* @returns {void}
*/
validate(config, source, getAdditionalRule, getAdditionalEnv) {
this.validateConfigSchema(config, source);
this.validateRules(config.rules, source, getAdditionalRule);
this.validateEnvironment(config.env, source, getAdditionalEnv);
this.validateGlobals(config.globals, source);
for (const override of config.overrides || []) {
this.validateRules(override.rules, source, getAdditionalRule);
this.validateEnvironment(override.env, source, getAdditionalEnv);
this.validateGlobals(config.globals, source);
}
}
/**
* Validate config array object.
* @param {ConfigArray} configArray The config array to validate.
* @returns {void}
*/
validateConfigArray(configArray) {
const getPluginEnv = Map.prototype.get.bind(configArray.pluginEnvironments);
const getPluginProcessor = Map.prototype.get.bind(configArray.pluginProcessors);
const getPluginRule = Map.prototype.get.bind(configArray.pluginRules);
// Validate.
for (const element of configArray) {
if (validated.has(element)) {
continue;
}
validated.add(element);
this.validateEnvironment(element.env, element.name, getPluginEnv);
this.validateGlobals(element.globals, element.name);
this.validateProcessor(element.processor, element.name, getPluginProcessor);
this.validateRules(element.rules, element.name, getPluginRule);
}
}
}

View file

@ -0,0 +1,63 @@
/**
* @fileoverview Provide the function that emits deprecation warnings.
* @author Toru Nagashima <http://github.com/mysticatea>
*/
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
import path from "path";
//------------------------------------------------------------------------------
// Private
//------------------------------------------------------------------------------
// Defitions for deprecation warnings.
const deprecationWarningMessages = {
ESLINT_LEGACY_ECMAFEATURES:
"The 'ecmaFeatures' config file property is deprecated and has no effect.",
ESLINT_PERSONAL_CONFIG_LOAD:
"'~/.eslintrc.*' config files have been deprecated. " +
"Please use a config file per project or the '--config' option.",
ESLINT_PERSONAL_CONFIG_SUPPRESS:
"'~/.eslintrc.*' config files have been deprecated. " +
"Please remove it or add 'root:true' to the config files in your " +
"projects in order to avoid loading '~/.eslintrc.*' accidentally."
};
const sourceFileErrorCache = new Set();
/**
* Emits a deprecation warning containing a given filepath. A new deprecation warning is emitted
* for each unique file path, but repeated invocations with the same file path have no effect.
* No warnings are emitted if the `--no-deprecation` or `--no-warnings` Node runtime flags are active.
* @param {string} source The name of the configuration source to report the warning for.
* @param {string} errorCode The warning message to show.
* @returns {void}
*/
function emitDeprecationWarning(source, errorCode) {
const cacheKey = JSON.stringify({ source, errorCode });
if (sourceFileErrorCache.has(cacheKey)) {
return;
}
sourceFileErrorCache.add(cacheKey);
const rel = path.relative(process.cwd(), source);
const message = deprecationWarningMessages[errorCode];
process.emitWarning(
`${message} (found in "${rel}")`,
"DeprecationWarning",
errorCode
);
}
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
export {
emitDeprecationWarning
};

96
node_modules/@eslint/eslintrc/lib/shared/naming.js generated vendored Normal file
View file

@ -0,0 +1,96 @@
/**
* @fileoverview Common helpers for naming of plugins, formatters and configs
*/
const NAMESPACE_REGEX = /^@.*\//iu;
/**
* Brings package name to correct format based on prefix
* @param {string} name The name of the package.
* @param {string} prefix Can be either "eslint-plugin", "eslint-config" or "eslint-formatter"
* @returns {string} Normalized name of the package
* @private
*/
function normalizePackageName(name, prefix) {
let normalizedName = name;
/**
* On Windows, name can come in with Windows slashes instead of Unix slashes.
* Normalize to Unix first to avoid errors later on.
* https://github.com/eslint/eslint/issues/5644
*/
if (normalizedName.includes("\\")) {
normalizedName = normalizedName.replace(/\\/gu, "/");
}
if (normalizedName.charAt(0) === "@") {
/**
* it's a scoped package
* package name is the prefix, or just a username
*/
const scopedPackageShortcutRegex = new RegExp(`^(@[^/]+)(?:/(?:${prefix})?)?$`, "u"),
scopedPackageNameRegex = new RegExp(`^${prefix}(-|$)`, "u");
if (scopedPackageShortcutRegex.test(normalizedName)) {
normalizedName = normalizedName.replace(scopedPackageShortcutRegex, `$1/${prefix}`);
} else if (!scopedPackageNameRegex.test(normalizedName.split("/")[1])) {
/**
* for scoped packages, insert the prefix after the first / unless
* the path is already @scope/eslint or @scope/eslint-xxx-yyy
*/
normalizedName = normalizedName.replace(/^@([^/]+)\/(.*)$/u, `@$1/${prefix}-$2`);
}
} else if (!normalizedName.startsWith(`${prefix}-`)) {
normalizedName = `${prefix}-${normalizedName}`;
}
return normalizedName;
}
/**
* Removes the prefix from a fullname.
* @param {string} fullname The term which may have the prefix.
* @param {string} prefix The prefix to remove.
* @returns {string} The term without prefix.
*/
function getShorthandName(fullname, prefix) {
if (fullname[0] === "@") {
let matchResult = new RegExp(`^(@[^/]+)/${prefix}$`, "u").exec(fullname);
if (matchResult) {
return matchResult[1];
}
matchResult = new RegExp(`^(@[^/]+)/${prefix}-(.+)$`, "u").exec(fullname);
if (matchResult) {
return `${matchResult[1]}/${matchResult[2]}`;
}
} else if (fullname.startsWith(`${prefix}-`)) {
return fullname.slice(prefix.length + 1);
}
return fullname;
}
/**
* Gets the scope (namespace) of a term.
* @param {string} term The term which may have the namespace.
* @returns {string} The namespace of the term if it has one.
*/
function getNamespaceFromTerm(term) {
const match = term.match(NAMESPACE_REGEX);
return match ? match[0] : "";
}
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
export {
normalizePackageName,
getShorthandName,
getNamespaceFromTerm
};

View file

@ -0,0 +1,42 @@
/**
* Utility for resolving a module relative to another module
* @author Teddy Katz
*/
import Module from "module";
/*
* `Module.createRequire` is added in v12.2.0. It supports URL as well.
* We only support the case where the argument is a filepath, not a URL.
*/
const createRequire = Module.createRequire;
/**
* Resolves a Node module relative to another module
* @param {string} moduleName The name of a Node module, or a path to a Node module.
* @param {string} relativeToPath An absolute path indicating the module that `moduleName` should be resolved relative to. This must be
* a file rather than a directory, but the file need not actually exist.
* @returns {string} The absolute path that would result from calling `require.resolve(moduleName)` in a file located at `relativeToPath`
*/
function resolve(moduleName, relativeToPath) {
try {
return createRequire(relativeToPath).resolve(moduleName);
} catch (error) {
// This `if` block is for older Node.js than 12.0.0. We can remove this block in the future.
if (
typeof error === "object" &&
error !== null &&
error.code === "MODULE_NOT_FOUND" &&
!error.requireStack &&
error.message.includes(moduleName)
) {
error.message += `\nRequire stack:\n- ${relativeToPath}`;
}
throw error;
}
}
export {
resolve
};

149
node_modules/@eslint/eslintrc/lib/shared/types.js generated vendored Normal file
View file

@ -0,0 +1,149 @@
/**
* @fileoverview Define common types for input completion.
* @author Toru Nagashima <https://github.com/mysticatea>
*/
/** @type {any} */
export default {};
/** @typedef {boolean | "off" | "readable" | "readonly" | "writable" | "writeable"} GlobalConf */
/** @typedef {0 | 1 | 2 | "off" | "warn" | "error"} SeverityConf */
/** @typedef {SeverityConf | [SeverityConf, ...any[]]} RuleConf */
/**
* @typedef {Object} EcmaFeatures
* @property {boolean} [globalReturn] Enabling `return` statements at the top-level.
* @property {boolean} [jsx] Enabling JSX syntax.
* @property {boolean} [impliedStrict] Enabling strict mode always.
*/
/**
* @typedef {Object} ParserOptions
* @property {EcmaFeatures} [ecmaFeatures] The optional features.
* @property {3|5|6|7|8|9|10|11|12|2015|2016|2017|2018|2019|2020|2021} [ecmaVersion] The ECMAScript version (or revision number).
* @property {"script"|"module"} [sourceType] The source code type.
*/
/**
* @typedef {Object} ConfigData
* @property {Record<string, boolean>} [env] The environment settings.
* @property {string | string[]} [extends] The path to other config files or the package name of shareable configs.
* @property {Record<string, GlobalConf>} [globals] The global variable settings.
* @property {string | string[]} [ignorePatterns] The glob patterns that ignore to lint.
* @property {boolean} [noInlineConfig] The flag that disables directive comments.
* @property {OverrideConfigData[]} [overrides] The override settings per kind of files.
* @property {string} [parser] The path to a parser or the package name of a parser.
* @property {ParserOptions} [parserOptions] The parser options.
* @property {string[]} [plugins] The plugin specifiers.
* @property {string} [processor] The processor specifier.
* @property {boolean} [reportUnusedDisableDirectives] The flag to report unused `eslint-disable` comments.
* @property {boolean} [root] The root flag.
* @property {Record<string, RuleConf>} [rules] The rule settings.
* @property {Object} [settings] The shared settings.
*/
/**
* @typedef {Object} OverrideConfigData
* @property {Record<string, boolean>} [env] The environment settings.
* @property {string | string[]} [excludedFiles] The glob pattarns for excluded files.
* @property {string | string[]} [extends] The path to other config files or the package name of shareable configs.
* @property {string | string[]} files The glob patterns for target files.
* @property {Record<string, GlobalConf>} [globals] The global variable settings.
* @property {boolean} [noInlineConfig] The flag that disables directive comments.
* @property {OverrideConfigData[]} [overrides] The override settings per kind of files.
* @property {string} [parser] The path to a parser or the package name of a parser.
* @property {ParserOptions} [parserOptions] The parser options.
* @property {string[]} [plugins] The plugin specifiers.
* @property {string} [processor] The processor specifier.
* @property {boolean} [reportUnusedDisableDirectives] The flag to report unused `eslint-disable` comments.
* @property {Record<string, RuleConf>} [rules] The rule settings.
* @property {Object} [settings] The shared settings.
*/
/**
* @typedef {Object} ParseResult
* @property {Object} ast The AST.
* @property {ScopeManager} [scopeManager] The scope manager of the AST.
* @property {Record<string, any>} [services] The services that the parser provides.
* @property {Record<string, string[]>} [visitorKeys] The visitor keys of the AST.
*/
/**
* @typedef {Object} Parser
* @property {(text:string, options:ParserOptions) => Object} parse The definition of global variables.
* @property {(text:string, options:ParserOptions) => ParseResult} [parseForESLint] The parser options that will be enabled under this environment.
*/
/**
* @typedef {Object} Environment
* @property {Record<string, GlobalConf>} [globals] The definition of global variables.
* @property {ParserOptions} [parserOptions] The parser options that will be enabled under this environment.
*/
/**
* @typedef {Object} LintMessage
* @property {number} column The 1-based column number.
* @property {number} [endColumn] The 1-based column number of the end location.
* @property {number} [endLine] The 1-based line number of the end location.
* @property {boolean} fatal If `true` then this is a fatal error.
* @property {{range:[number,number], text:string}} [fix] Information for autofix.
* @property {number} line The 1-based line number.
* @property {string} message The error message.
* @property {string|null} ruleId The ID of the rule which makes this message.
* @property {0|1|2} severity The severity of this message.
* @property {Array<{desc?: string, messageId?: string, fix: {range: [number, number], text: string}}>} [suggestions] Information for suggestions.
*/
/**
* @typedef {Object} SuggestionResult
* @property {string} desc A short description.
* @property {string} [messageId] Id referencing a message for the description.
* @property {{ text: string, range: number[] }} fix fix result info
*/
/**
* @typedef {Object} Processor
* @property {(text:string, filename:string) => Array<string | { text:string, filename:string }>} [preprocess] The function to extract code blocks.
* @property {(messagesList:LintMessage[][], filename:string) => LintMessage[]} [postprocess] The function to merge messages.
* @property {boolean} [supportsAutofix] If `true` then it means the processor supports autofix.
*/
/**
* @typedef {Object} RuleMetaDocs
* @property {string} category The category of the rule.
* @property {string} description The description of the rule.
* @property {boolean} recommended If `true` then the rule is included in `eslint:recommended` preset.
* @property {string} url The URL of the rule documentation.
*/
/**
* @typedef {Object} RuleMeta
* @property {boolean} [deprecated] If `true` then the rule has been deprecated.
* @property {RuleMetaDocs} docs The document information of the rule.
* @property {"code"|"whitespace"} [fixable] The autofix type.
* @property {Record<string,string>} [messages] The messages the rule reports.
* @property {string[]} [replacedBy] The IDs of the alternative rules.
* @property {Array|Object} schema The option schema of the rule.
* @property {"problem"|"suggestion"|"layout"} type The rule type.
*/
/**
* @typedef {Object} Rule
* @property {Function} create The factory of the rule.
* @property {RuleMeta} meta The meta data of the rule.
*/
/**
* @typedef {Object} Plugin
* @property {Record<string, ConfigData>} [configs] The definition of plugin configs.
* @property {Record<string, Environment>} [environments] The definition of plugin environments.
* @property {Record<string, Processor>} [processors] The definition of plugin processors.
* @property {Record<string, Function | Rule>} [rules] The definition of plugin rules.
*/
/**
* Information of deprecated rules.
* @typedef {Object} DeprecatedRuleInfo
* @property {string} ruleId The rule ID.
* @property {string[]} replacedBy The rule IDs that replace this deprecated rule.
*/

View file

@ -0,0 +1,20 @@
var Ajv = require('ajv');
var ajv = new Ajv({allErrors: true});
var schema = {
"properties": {
"foo": { "type": "string" },
"bar": { "type": "number", "maximum": 3 }
}
};
var validate = ajv.compile(schema);
test({"foo": "abc", "bar": 2});
test({"foo": 2, "bar": 4});
function test(data) {
var valid = validate(data);
if (valid) console.log('Valid!');
else console.log('Invalid: ' + ajv.errorsText(validate.errors));
}

22
node_modules/@eslint/eslintrc/node_modules/ajv/LICENSE generated vendored Normal file
View file

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015-2017 Evgeny Poberezkin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

1497
node_modules/@eslint/eslintrc/node_modules/ajv/README.md generated vendored Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,397 @@
declare var ajv: {
(options?: ajv.Options): ajv.Ajv;
new(options?: ajv.Options): ajv.Ajv;
ValidationError: typeof AjvErrors.ValidationError;
MissingRefError: typeof AjvErrors.MissingRefError;
$dataMetaSchema: object;
}
declare namespace AjvErrors {
class ValidationError extends Error {
constructor(errors: Array<ajv.ErrorObject>);
message: string;
errors: Array<ajv.ErrorObject>;
ajv: true;
validation: true;
}
class MissingRefError extends Error {
constructor(baseId: string, ref: string, message?: string);
static message: (baseId: string, ref: string) => string;
message: string;
missingRef: string;
missingSchema: string;
}
}
declare namespace ajv {
type ValidationError = AjvErrors.ValidationError;
type MissingRefError = AjvErrors.MissingRefError;
interface Ajv {
/**
* Validate data using schema
* Schema will be compiled and cached (using serialized JSON as key, [fast-json-stable-stringify](https://github.com/epoberezkin/fast-json-stable-stringify) is used to serialize by default).
* @param {string|object|Boolean} schemaKeyRef key, ref or schema object
* @param {Any} data to be validated
* @return {Boolean} validation result. Errors from the last validation will be available in `ajv.errors` (and also in compiled schema: `schema.errors`).
*/
validate(schemaKeyRef: object | string | boolean, data: any): boolean | PromiseLike<any>;
/**
* Create validating function for passed schema.
* @param {object|Boolean} schema schema object
* @return {Function} validating function
*/
compile(schema: object | boolean): ValidateFunction;
/**
* Creates validating function for passed schema with asynchronous loading of missing schemas.
* `loadSchema` option should be a function that accepts schema uri and node-style callback.
* @this Ajv
* @param {object|Boolean} schema schema object
* @param {Boolean} meta optional true to compile meta-schema; this parameter can be skipped
* @param {Function} callback optional node-style callback, it is always called with 2 parameters: error (or null) and validating function.
* @return {PromiseLike<ValidateFunction>} validating function
*/
compileAsync(schema: object | boolean, meta?: Boolean, callback?: (err: Error, validate: ValidateFunction) => any): PromiseLike<ValidateFunction>;
/**
* Adds schema to the instance.
* @param {object|Array} schema schema or array of schemas. If array is passed, `key` and other parameters will be ignored.
* @param {string} key Optional schema key. Can be passed to `validate` method instead of schema object or id/ref. One schema per instance can have empty `id` and `key`.
* @return {Ajv} this for method chaining
*/
addSchema(schema: Array<object> | object, key?: string): Ajv;
/**
* Add schema that will be used to validate other schemas
* options in META_IGNORE_OPTIONS are alway set to false
* @param {object} schema schema object
* @param {string} key optional schema key
* @return {Ajv} this for method chaining
*/
addMetaSchema(schema: object, key?: string): Ajv;
/**
* Validate schema
* @param {object|Boolean} schema schema to validate
* @return {Boolean} true if schema is valid
*/
validateSchema(schema: object | boolean): boolean;
/**
* Get compiled schema from the instance by `key` or `ref`.
* @param {string} keyRef `key` that was passed to `addSchema` or full schema reference (`schema.id` or resolved id).
* @return {Function} schema validating function (with property `schema`). Returns undefined if keyRef can't be resolved to an existing schema.
*/
getSchema(keyRef: string): ValidateFunction | undefined;
/**
* Remove cached schema(s).
* If no parameter is passed all schemas but meta-schemas are removed.
* If RegExp is passed all schemas with key/id matching pattern but meta-schemas are removed.
* Even if schema is referenced by other schemas it still can be removed as other schemas have local references.
* @param {string|object|RegExp|Boolean} schemaKeyRef key, ref, pattern to match key/ref or schema object
* @return {Ajv} this for method chaining
*/
removeSchema(schemaKeyRef?: object | string | RegExp | boolean): Ajv;
/**
* Add custom format
* @param {string} name format name
* @param {string|RegExp|Function} format string is converted to RegExp; function should return boolean (true when valid)
* @return {Ajv} this for method chaining
*/
addFormat(name: string, format: FormatValidator | FormatDefinition): Ajv;
/**
* Define custom keyword
* @this Ajv
* @param {string} keyword custom keyword, should be a valid identifier, should be different from all standard, custom and macro keywords.
* @param {object} definition keyword definition object with properties `type` (type(s) which the keyword applies to), `validate` or `compile`.
* @return {Ajv} this for method chaining
*/
addKeyword(keyword: string, definition: KeywordDefinition): Ajv;
/**
* Get keyword definition
* @this Ajv
* @param {string} keyword pre-defined or custom keyword.
* @return {object|Boolean} custom keyword definition, `true` if it is a predefined keyword, `false` otherwise.
*/
getKeyword(keyword: string): object | boolean;
/**
* Remove keyword
* @this Ajv
* @param {string} keyword pre-defined or custom keyword.
* @return {Ajv} this for method chaining
*/
removeKeyword(keyword: string): Ajv;
/**
* Validate keyword
* @this Ajv
* @param {object} definition keyword definition object
* @param {boolean} throwError true to throw exception if definition is invalid
* @return {boolean} validation result
*/
validateKeyword(definition: KeywordDefinition, throwError: boolean): boolean;
/**
* Convert array of error message objects to string
* @param {Array<object>} errors optional array of validation errors, if not passed errors from the instance are used.
* @param {object} options optional options with properties `separator` and `dataVar`.
* @return {string} human readable string with all errors descriptions
*/
errorsText(errors?: Array<ErrorObject> | null, options?: ErrorsTextOptions): string;
errors?: Array<ErrorObject> | null;
_opts: Options;
}
interface CustomLogger {
log(...args: any[]): any;
warn(...args: any[]): any;
error(...args: any[]): any;
}
interface ValidateFunction {
(
data: any,
dataPath?: string,
parentData?: object | Array<any>,
parentDataProperty?: string | number,
rootData?: object | Array<any>
): boolean | PromiseLike<any>;
schema?: object | boolean;
errors?: null | Array<ErrorObject>;
refs?: object;
refVal?: Array<any>;
root?: ValidateFunction | object;
$async?: true;
source?: object;
}
interface Options {
$data?: boolean;
allErrors?: boolean;
verbose?: boolean;
jsonPointers?: boolean;
uniqueItems?: boolean;
unicode?: boolean;
format?: false | string;
formats?: object;
keywords?: object;
unknownFormats?: true | string[] | 'ignore';
schemas?: Array<object> | object;
schemaId?: '$id' | 'id' | 'auto';
missingRefs?: true | 'ignore' | 'fail';
extendRefs?: true | 'ignore' | 'fail';
loadSchema?: (uri: string, cb?: (err: Error, schema: object) => void) => PromiseLike<object | boolean>;
removeAdditional?: boolean | 'all' | 'failing';
useDefaults?: boolean | 'empty' | 'shared';
coerceTypes?: boolean | 'array';
strictDefaults?: boolean | 'log';
strictKeywords?: boolean | 'log';
strictNumbers?: boolean;
async?: boolean | string;
transpile?: string | ((code: string) => string);
meta?: boolean | object;
validateSchema?: boolean | 'log';
addUsedSchema?: boolean;
inlineRefs?: boolean | number;
passContext?: boolean;
loopRequired?: number;
ownProperties?: boolean;
multipleOfPrecision?: boolean | number;
errorDataPath?: string,
messages?: boolean;
sourceCode?: boolean;
processCode?: (code: string, schema: object) => string;
cache?: object;
logger?: CustomLogger | false;
nullable?: boolean;
serialize?: ((schema: object | boolean) => any) | false;
}
type FormatValidator = string | RegExp | ((data: string) => boolean | PromiseLike<any>);
type NumberFormatValidator = ((data: number) => boolean | PromiseLike<any>);
interface NumberFormatDefinition {
type: "number",
validate: NumberFormatValidator;
compare?: (data1: number, data2: number) => number;
async?: boolean;
}
interface StringFormatDefinition {
type?: "string",
validate: FormatValidator;
compare?: (data1: string, data2: string) => number;
async?: boolean;
}
type FormatDefinition = NumberFormatDefinition | StringFormatDefinition;
interface KeywordDefinition {
type?: string | Array<string>;
async?: boolean;
$data?: boolean;
errors?: boolean | string;
metaSchema?: object;
// schema: false makes validate not to expect schema (ValidateFunction)
schema?: boolean;
statements?: boolean;
dependencies?: Array<string>;
modifying?: boolean;
valid?: boolean;
// one and only one of the following properties should be present
validate?: SchemaValidateFunction | ValidateFunction;
compile?: (schema: any, parentSchema: object, it: CompilationContext) => ValidateFunction;
macro?: (schema: any, parentSchema: object, it: CompilationContext) => object | boolean;
inline?: (it: CompilationContext, keyword: string, schema: any, parentSchema: object) => string;
}
interface CompilationContext {
level: number;
dataLevel: number;
dataPathArr: string[];
schema: any;
schemaPath: string;
baseId: string;
async: boolean;
opts: Options;
formats: {
[index: string]: FormatDefinition | undefined;
};
keywords: {
[index: string]: KeywordDefinition | undefined;
};
compositeRule: boolean;
validate: (schema: object) => boolean;
util: {
copy(obj: any, target?: any): any;
toHash(source: string[]): { [index: string]: true | undefined };
equal(obj: any, target: any): boolean;
getProperty(str: string): string;
schemaHasRules(schema: object, rules: any): string;
escapeQuotes(str: string): string;
toQuotedString(str: string): string;
getData(jsonPointer: string, dataLevel: number, paths: string[]): string;
escapeJsonPointer(str: string): string;
unescapeJsonPointer(str: string): string;
escapeFragment(str: string): string;
unescapeFragment(str: string): string;
};
self: Ajv;
}
interface SchemaValidateFunction {
(
schema: any,
data: any,
parentSchema?: object,
dataPath?: string,
parentData?: object | Array<any>,
parentDataProperty?: string | number,
rootData?: object | Array<any>
): boolean | PromiseLike<any>;
errors?: Array<ErrorObject>;
}
interface ErrorsTextOptions {
separator?: string;
dataVar?: string;
}
interface ErrorObject {
keyword: string;
dataPath: string;
schemaPath: string;
params: ErrorParameters;
// Added to validation errors of propertyNames keyword schema
propertyName?: string;
// Excluded if messages set to false.
message?: string;
// These are added with the `verbose` option.
schema?: any;
parentSchema?: object;
data?: any;
}
type ErrorParameters = RefParams | LimitParams | AdditionalPropertiesParams |
DependenciesParams | FormatParams | ComparisonParams |
MultipleOfParams | PatternParams | RequiredParams |
TypeParams | UniqueItemsParams | CustomParams |
PatternRequiredParams | PropertyNamesParams |
IfParams | SwitchParams | NoParams | EnumParams;
interface RefParams {
ref: string;
}
interface LimitParams {
limit: number;
}
interface AdditionalPropertiesParams {
additionalProperty: string;
}
interface DependenciesParams {
property: string;
missingProperty: string;
depsCount: number;
deps: string;
}
interface FormatParams {
format: string
}
interface ComparisonParams {
comparison: string;
limit: number | string;
exclusive: boolean;
}
interface MultipleOfParams {
multipleOf: number;
}
interface PatternParams {
pattern: string;
}
interface RequiredParams {
missingProperty: string;
}
interface TypeParams {
type: string;
}
interface UniqueItemsParams {
i: number;
j: number;
}
interface CustomParams {
keyword: string;
}
interface PatternRequiredParams {
missingPattern: string;
}
interface PropertyNamesParams {
propertyName: string;
}
interface IfParams {
failingKeyword: string;
}
interface SwitchParams {
caseIndex: number;
}
interface NoParams { }
interface EnumParams {
allowedValues: Array<any>;
}
}
export = ajv;

View file

@ -0,0 +1,506 @@
'use strict';
var compileSchema = require('./compile')
, resolve = require('./compile/resolve')
, Cache = require('./cache')
, SchemaObject = require('./compile/schema_obj')
, stableStringify = require('fast-json-stable-stringify')
, formats = require('./compile/formats')
, rules = require('./compile/rules')
, $dataMetaSchema = require('./data')
, util = require('./compile/util');
module.exports = Ajv;
Ajv.prototype.validate = validate;
Ajv.prototype.compile = compile;
Ajv.prototype.addSchema = addSchema;
Ajv.prototype.addMetaSchema = addMetaSchema;
Ajv.prototype.validateSchema = validateSchema;
Ajv.prototype.getSchema = getSchema;
Ajv.prototype.removeSchema = removeSchema;
Ajv.prototype.addFormat = addFormat;
Ajv.prototype.errorsText = errorsText;
Ajv.prototype._addSchema = _addSchema;
Ajv.prototype._compile = _compile;
Ajv.prototype.compileAsync = require('./compile/async');
var customKeyword = require('./keyword');
Ajv.prototype.addKeyword = customKeyword.add;
Ajv.prototype.getKeyword = customKeyword.get;
Ajv.prototype.removeKeyword = customKeyword.remove;
Ajv.prototype.validateKeyword = customKeyword.validate;
var errorClasses = require('./compile/error_classes');
Ajv.ValidationError = errorClasses.Validation;
Ajv.MissingRefError = errorClasses.MissingRef;
Ajv.$dataMetaSchema = $dataMetaSchema;
var META_SCHEMA_ID = 'http://json-schema.org/draft-07/schema';
var META_IGNORE_OPTIONS = [ 'removeAdditional', 'useDefaults', 'coerceTypes', 'strictDefaults' ];
var META_SUPPORT_DATA = ['/properties'];
/**
* Creates validator instance.
* Usage: `Ajv(opts)`
* @param {Object} opts optional options
* @return {Object} ajv instance
*/
function Ajv(opts) {
if (!(this instanceof Ajv)) return new Ajv(opts);
opts = this._opts = util.copy(opts) || {};
setLogger(this);
this._schemas = {};
this._refs = {};
this._fragments = {};
this._formats = formats(opts.format);
this._cache = opts.cache || new Cache;
this._loadingSchemas = {};
this._compilations = [];
this.RULES = rules();
this._getId = chooseGetId(opts);
opts.loopRequired = opts.loopRequired || Infinity;
if (opts.errorDataPath == 'property') opts._errorDataPathProperty = true;
if (opts.serialize === undefined) opts.serialize = stableStringify;
this._metaOpts = getMetaSchemaOptions(this);
if (opts.formats) addInitialFormats(this);
if (opts.keywords) addInitialKeywords(this);
addDefaultMetaSchema(this);
if (typeof opts.meta == 'object') this.addMetaSchema(opts.meta);
if (opts.nullable) this.addKeyword('nullable', {metaSchema: {type: 'boolean'}});
addInitialSchemas(this);
}
/**
* Validate data using schema
* Schema will be compiled and cached (using serialized JSON as key. [fast-json-stable-stringify](https://github.com/epoberezkin/fast-json-stable-stringify) is used to serialize.
* @this Ajv
* @param {String|Object} schemaKeyRef key, ref or schema object
* @param {Any} data to be validated
* @return {Boolean} validation result. Errors from the last validation will be available in `ajv.errors` (and also in compiled schema: `schema.errors`).
*/
function validate(schemaKeyRef, data) {
var v;
if (typeof schemaKeyRef == 'string') {
v = this.getSchema(schemaKeyRef);
if (!v) throw new Error('no schema with key or ref "' + schemaKeyRef + '"');
} else {
var schemaObj = this._addSchema(schemaKeyRef);
v = schemaObj.validate || this._compile(schemaObj);
}
var valid = v(data);
if (v.$async !== true) this.errors = v.errors;
return valid;
}
/**
* Create validating function for passed schema.
* @this Ajv
* @param {Object} schema schema object
* @param {Boolean} _meta true if schema is a meta-schema. Used internally to compile meta schemas of custom keywords.
* @return {Function} validating function
*/
function compile(schema, _meta) {
var schemaObj = this._addSchema(schema, undefined, _meta);
return schemaObj.validate || this._compile(schemaObj);
}
/**
* Adds schema to the instance.
* @this Ajv
* @param {Object|Array} schema schema or array of schemas. If array is passed, `key` and other parameters will be ignored.
* @param {String} key Optional schema key. Can be passed to `validate` method instead of schema object or id/ref. One schema per instance can have empty `id` and `key`.
* @param {Boolean} _skipValidation true to skip schema validation. Used internally, option validateSchema should be used instead.
* @param {Boolean} _meta true if schema is a meta-schema. Used internally, addMetaSchema should be used instead.
* @return {Ajv} this for method chaining
*/
function addSchema(schema, key, _skipValidation, _meta) {
if (Array.isArray(schema)){
for (var i=0; i<schema.length; i++) this.addSchema(schema[i], undefined, _skipValidation, _meta);
return this;
}
var id = this._getId(schema);
if (id !== undefined && typeof id != 'string')
throw new Error('schema id must be string');
key = resolve.normalizeId(key || id);
checkUnique(this, key);
this._schemas[key] = this._addSchema(schema, _skipValidation, _meta, true);
return this;
}
/**
* Add schema that will be used to validate other schemas
* options in META_IGNORE_OPTIONS are alway set to false
* @this Ajv
* @param {Object} schema schema object
* @param {String} key optional schema key
* @param {Boolean} skipValidation true to skip schema validation, can be used to override validateSchema option for meta-schema
* @return {Ajv} this for method chaining
*/
function addMetaSchema(schema, key, skipValidation) {
this.addSchema(schema, key, skipValidation, true);
return this;
}
/**
* Validate schema
* @this Ajv
* @param {Object} schema schema to validate
* @param {Boolean} throwOrLogError pass true to throw (or log) an error if invalid
* @return {Boolean} true if schema is valid
*/
function validateSchema(schema, throwOrLogError) {
var $schema = schema.$schema;
if ($schema !== undefined && typeof $schema != 'string')
throw new Error('$schema must be a string');
$schema = $schema || this._opts.defaultMeta || defaultMeta(this);
if (!$schema) {
this.logger.warn('meta-schema not available');
this.errors = null;
return true;
}
var valid = this.validate($schema, schema);
if (!valid && throwOrLogError) {
var message = 'schema is invalid: ' + this.errorsText();
if (this._opts.validateSchema == 'log') this.logger.error(message);
else throw new Error(message);
}
return valid;
}
function defaultMeta(self) {
var meta = self._opts.meta;
self._opts.defaultMeta = typeof meta == 'object'
? self._getId(meta) || meta
: self.getSchema(META_SCHEMA_ID)
? META_SCHEMA_ID
: undefined;
return self._opts.defaultMeta;
}
/**
* Get compiled schema from the instance by `key` or `ref`.
* @this Ajv
* @param {String} keyRef `key` that was passed to `addSchema` or full schema reference (`schema.id` or resolved id).
* @return {Function} schema validating function (with property `schema`).
*/
function getSchema(keyRef) {
var schemaObj = _getSchemaObj(this, keyRef);
switch (typeof schemaObj) {
case 'object': return schemaObj.validate || this._compile(schemaObj);
case 'string': return this.getSchema(schemaObj);
case 'undefined': return _getSchemaFragment(this, keyRef);
}
}
function _getSchemaFragment(self, ref) {
var res = resolve.schema.call(self, { schema: {} }, ref);
if (res) {
var schema = res.schema
, root = res.root
, baseId = res.baseId;
var v = compileSchema.call(self, schema, root, undefined, baseId);
self._fragments[ref] = new SchemaObject({
ref: ref,
fragment: true,
schema: schema,
root: root,
baseId: baseId,
validate: v
});
return v;
}
}
function _getSchemaObj(self, keyRef) {
keyRef = resolve.normalizeId(keyRef);
return self._schemas[keyRef] || self._refs[keyRef] || self._fragments[keyRef];
}
/**
* Remove cached schema(s).
* If no parameter is passed all schemas but meta-schemas are removed.
* If RegExp is passed all schemas with key/id matching pattern but meta-schemas are removed.
* Even if schema is referenced by other schemas it still can be removed as other schemas have local references.
* @this Ajv
* @param {String|Object|RegExp} schemaKeyRef key, ref, pattern to match key/ref or schema object
* @return {Ajv} this for method chaining
*/
function removeSchema(schemaKeyRef) {
if (schemaKeyRef instanceof RegExp) {
_removeAllSchemas(this, this._schemas, schemaKeyRef);
_removeAllSchemas(this, this._refs, schemaKeyRef);
return this;
}
switch (typeof schemaKeyRef) {
case 'undefined':
_removeAllSchemas(this, this._schemas);
_removeAllSchemas(this, this._refs);
this._cache.clear();
return this;
case 'string':
var schemaObj = _getSchemaObj(this, schemaKeyRef);
if (schemaObj) this._cache.del(schemaObj.cacheKey);
delete this._schemas[schemaKeyRef];
delete this._refs[schemaKeyRef];
return this;
case 'object':
var serialize = this._opts.serialize;
var cacheKey = serialize ? serialize(schemaKeyRef) : schemaKeyRef;
this._cache.del(cacheKey);
var id = this._getId(schemaKeyRef);
if (id) {
id = resolve.normalizeId(id);
delete this._schemas[id];
delete this._refs[id];
}
}
return this;
}
function _removeAllSchemas(self, schemas, regex) {
for (var keyRef in schemas) {
var schemaObj = schemas[keyRef];
if (!schemaObj.meta && (!regex || regex.test(keyRef))) {
self._cache.del(schemaObj.cacheKey);
delete schemas[keyRef];
}
}
}
/* @this Ajv */
function _addSchema(schema, skipValidation, meta, shouldAddSchema) {
if (typeof schema != 'object' && typeof schema != 'boolean')
throw new Error('schema should be object or boolean');
var serialize = this._opts.serialize;
var cacheKey = serialize ? serialize(schema) : schema;
var cached = this._cache.get(cacheKey);
if (cached) return cached;
shouldAddSchema = shouldAddSchema || this._opts.addUsedSchema !== false;
var id = resolve.normalizeId(this._getId(schema));
if (id && shouldAddSchema) checkUnique(this, id);
var willValidate = this._opts.validateSchema !== false && !skipValidation;
var recursiveMeta;
if (willValidate && !(recursiveMeta = id && id == resolve.normalizeId(schema.$schema)))
this.validateSchema(schema, true);
var localRefs = resolve.ids.call(this, schema);
var schemaObj = new SchemaObject({
id: id,
schema: schema,
localRefs: localRefs,
cacheKey: cacheKey,
meta: meta
});
if (id[0] != '#' && shouldAddSchema) this._refs[id] = schemaObj;
this._cache.put(cacheKey, schemaObj);
if (willValidate && recursiveMeta) this.validateSchema(schema, true);
return schemaObj;
}
/* @this Ajv */
function _compile(schemaObj, root) {
if (schemaObj.compiling) {
schemaObj.validate = callValidate;
callValidate.schema = schemaObj.schema;
callValidate.errors = null;
callValidate.root = root ? root : callValidate;
if (schemaObj.schema.$async === true)
callValidate.$async = true;
return callValidate;
}
schemaObj.compiling = true;
var currentOpts;
if (schemaObj.meta) {
currentOpts = this._opts;
this._opts = this._metaOpts;
}
var v;
try { v = compileSchema.call(this, schemaObj.schema, root, schemaObj.localRefs); }
catch(e) {
delete schemaObj.validate;
throw e;
}
finally {
schemaObj.compiling = false;
if (schemaObj.meta) this._opts = currentOpts;
}
schemaObj.validate = v;
schemaObj.refs = v.refs;
schemaObj.refVal = v.refVal;
schemaObj.root = v.root;
return v;
/* @this {*} - custom context, see passContext option */
function callValidate() {
/* jshint validthis: true */
var _validate = schemaObj.validate;
var result = _validate.apply(this, arguments);
callValidate.errors = _validate.errors;
return result;
}
}
function chooseGetId(opts) {
switch (opts.schemaId) {
case 'auto': return _get$IdOrId;
case 'id': return _getId;
default: return _get$Id;
}
}
/* @this Ajv */
function _getId(schema) {
if (schema.$id) this.logger.warn('schema $id ignored', schema.$id);
return schema.id;
}
/* @this Ajv */
function _get$Id(schema) {
if (schema.id) this.logger.warn('schema id ignored', schema.id);
return schema.$id;
}
function _get$IdOrId(schema) {
if (schema.$id && schema.id && schema.$id != schema.id)
throw new Error('schema $id is different from id');
return schema.$id || schema.id;
}
/**
* Convert array of error message objects to string
* @this Ajv
* @param {Array<Object>} errors optional array of validation errors, if not passed errors from the instance are used.
* @param {Object} options optional options with properties `separator` and `dataVar`.
* @return {String} human readable string with all errors descriptions
*/
function errorsText(errors, options) {
errors = errors || this.errors;
if (!errors) return 'No errors';
options = options || {};
var separator = options.separator === undefined ? ', ' : options.separator;
var dataVar = options.dataVar === undefined ? 'data' : options.dataVar;
var text = '';
for (var i=0; i<errors.length; i++) {
var e = errors[i];
if (e) text += dataVar + e.dataPath + ' ' + e.message + separator;
}
return text.slice(0, -separator.length);
}
/**
* Add custom format
* @this Ajv
* @param {String} name format name
* @param {String|RegExp|Function} format string is converted to RegExp; function should return boolean (true when valid)
* @return {Ajv} this for method chaining
*/
function addFormat(name, format) {
if (typeof format == 'string') format = new RegExp(format);
this._formats[name] = format;
return this;
}
function addDefaultMetaSchema(self) {
var $dataSchema;
if (self._opts.$data) {
$dataSchema = require('./refs/data.json');
self.addMetaSchema($dataSchema, $dataSchema.$id, true);
}
if (self._opts.meta === false) return;
var metaSchema = require('./refs/json-schema-draft-07.json');
if (self._opts.$data) metaSchema = $dataMetaSchema(metaSchema, META_SUPPORT_DATA);
self.addMetaSchema(metaSchema, META_SCHEMA_ID, true);
self._refs['http://json-schema.org/schema'] = META_SCHEMA_ID;
}
function addInitialSchemas(self) {
var optsSchemas = self._opts.schemas;
if (!optsSchemas) return;
if (Array.isArray(optsSchemas)) self.addSchema(optsSchemas);
else for (var key in optsSchemas) self.addSchema(optsSchemas[key], key);
}
function addInitialFormats(self) {
for (var name in self._opts.formats) {
var format = self._opts.formats[name];
self.addFormat(name, format);
}
}
function addInitialKeywords(self) {
for (var name in self._opts.keywords) {
var keyword = self._opts.keywords[name];
self.addKeyword(name, keyword);
}
}
function checkUnique(self, id) {
if (self._schemas[id] || self._refs[id])
throw new Error('schema with key or id "' + id + '" already exists');
}
function getMetaSchemaOptions(self) {
var metaOpts = util.copy(self._opts);
for (var i=0; i<META_IGNORE_OPTIONS.length; i++)
delete metaOpts[META_IGNORE_OPTIONS[i]];
return metaOpts;
}
function setLogger(self) {
var logger = self._opts.logger;
if (logger === false) {
self.logger = {log: noop, warn: noop, error: noop};
} else {
if (logger === undefined) logger = console;
if (!(typeof logger == 'object' && logger.log && logger.warn && logger.error))
throw new Error('logger must implement log, warn and error methods');
self.logger = logger;
}
}
function noop() {}

View file

@ -0,0 +1,26 @@
'use strict';
var Cache = module.exports = function Cache() {
this._cache = {};
};
Cache.prototype.put = function Cache_put(key, value) {
this._cache[key] = value;
};
Cache.prototype.get = function Cache_get(key) {
return this._cache[key];
};
Cache.prototype.del = function Cache_del(key) {
delete this._cache[key];
};
Cache.prototype.clear = function Cache_clear() {
this._cache = {};
};

View file

@ -0,0 +1,90 @@
'use strict';
var MissingRefError = require('./error_classes').MissingRef;
module.exports = compileAsync;
/**
* Creates validating function for passed schema with asynchronous loading of missing schemas.
* `loadSchema` option should be a function that accepts schema uri and returns promise that resolves with the schema.
* @this Ajv
* @param {Object} schema schema object
* @param {Boolean} meta optional true to compile meta-schema; this parameter can be skipped
* @param {Function} callback an optional node-style callback, it is called with 2 parameters: error (or null) and validating function.
* @return {Promise} promise that resolves with a validating function.
*/
function compileAsync(schema, meta, callback) {
/* eslint no-shadow: 0 */
/* global Promise */
/* jshint validthis: true */
var self = this;
if (typeof this._opts.loadSchema != 'function')
throw new Error('options.loadSchema should be a function');
if (typeof meta == 'function') {
callback = meta;
meta = undefined;
}
var p = loadMetaSchemaOf(schema).then(function () {
var schemaObj = self._addSchema(schema, undefined, meta);
return schemaObj.validate || _compileAsync(schemaObj);
});
if (callback) {
p.then(
function(v) { callback(null, v); },
callback
);
}
return p;
function loadMetaSchemaOf(sch) {
var $schema = sch.$schema;
return $schema && !self.getSchema($schema)
? compileAsync.call(self, { $ref: $schema }, true)
: Promise.resolve();
}
function _compileAsync(schemaObj) {
try { return self._compile(schemaObj); }
catch(e) {
if (e instanceof MissingRefError) return loadMissingSchema(e);
throw e;
}
function loadMissingSchema(e) {
var ref = e.missingSchema;
if (added(ref)) throw new Error('Schema ' + ref + ' is loaded but ' + e.missingRef + ' cannot be resolved');
var schemaPromise = self._loadingSchemas[ref];
if (!schemaPromise) {
schemaPromise = self._loadingSchemas[ref] = self._opts.loadSchema(ref);
schemaPromise.then(removePromise, removePromise);
}
return schemaPromise.then(function (sch) {
if (!added(ref)) {
return loadMetaSchemaOf(sch).then(function () {
if (!added(ref)) self.addSchema(sch, ref, undefined, meta);
});
}
}).then(function() {
return _compileAsync(schemaObj);
});
function removePromise() {
delete self._loadingSchemas[ref];
}
function added(ref) {
return self._refs[ref] || self._schemas[ref];
}
}
}
}

View file

@ -0,0 +1,5 @@
'use strict';
// do NOT remove this file - it would break pre-compiled schemas
// https://github.com/ajv-validator/ajv/issues/889
module.exports = require('fast-deep-equal');

View file

@ -0,0 +1,34 @@
'use strict';
var resolve = require('./resolve');
module.exports = {
Validation: errorSubclass(ValidationError),
MissingRef: errorSubclass(MissingRefError)
};
function ValidationError(errors) {
this.message = 'validation failed';
this.errors = errors;
this.ajv = this.validation = true;
}
MissingRefError.message = function (baseId, ref) {
return 'can\'t resolve reference ' + ref + ' from id ' + baseId;
};
function MissingRefError(baseId, ref, message) {
this.message = message || MissingRefError.message(baseId, ref);
this.missingRef = resolve.url(baseId, ref);
this.missingSchema = resolve.normalizeId(resolve.fullPath(this.missingRef));
}
function errorSubclass(Subclass) {
Subclass.prototype = Object.create(Error.prototype);
Subclass.prototype.constructor = Subclass;
return Subclass;
}

View file

@ -0,0 +1,142 @@
'use strict';
var util = require('./util');
var DATE = /^(\d\d\d\d)-(\d\d)-(\d\d)$/;
var DAYS = [0,31,28,31,30,31,30,31,31,30,31,30,31];
var TIME = /^(\d\d):(\d\d):(\d\d)(\.\d+)?(z|[+-]\d\d(?::?\d\d)?)?$/i;
var HOSTNAME = /^(?=.{1,253}\.?$)[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[-0-9a-z]{0,61}[0-9a-z])?)*\.?$/i;
var URI = /^(?:[a-z][a-z0-9+\-.]*:)(?:\/?\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|[Vv][0-9a-f]+\.[a-z0-9\-._~!$&'()*+,;=:]+)\]|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)|(?:[a-z0-9\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\d*)?(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)(?:\?(?:[a-z0-9\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$/i;
var URIREF = /^(?:[a-z][a-z0-9+\-.]*:)?(?:\/?\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|[Vv][0-9a-f]+\.[a-z0-9\-._~!$&'()*+,;=:]+)\]|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)|(?:[a-z0-9\-._~!$&'"()*+,;=]|%[0-9a-f]{2})*)(?::\d*)?(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*|\/(?:(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*)?(?:\?(?:[a-z0-9\-._~!$&'"()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\-._~!$&'"()*+,;=:@/?]|%[0-9a-f]{2})*)?$/i;
// uri-template: https://tools.ietf.org/html/rfc6570
var URITEMPLATE = /^(?:(?:[^\x00-\x20"'<>%\\^`{|}]|%[0-9a-f]{2})|\{[+#./;?&=,!@|]?(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\*)?(?:,(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\*)?)*\})*$/i;
// For the source: https://gist.github.com/dperini/729294
// For test cases: https://mathiasbynens.be/demo/url-regex
// @todo Delete current URL in favour of the commented out URL rule when this issue is fixed https://github.com/eslint/eslint/issues/7983.
// var URL = /^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u{00a1}-\u{ffff}0-9]+-)*[a-z\u{00a1}-\u{ffff}0-9]+)(?:\.(?:[a-z\u{00a1}-\u{ffff}0-9]+-)*[a-z\u{00a1}-\u{ffff}0-9]+)*(?:\.(?:[a-z\u{00a1}-\u{ffff}]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?$/iu;
var URL = /^(?:(?:http[s\u017F]?|ftp):\/\/)(?:(?:[\0-\x08\x0E-\x1F!-\x9F\xA1-\u167F\u1681-\u1FFF\u200B-\u2027\u202A-\u202E\u2030-\u205E\u2060-\u2FFF\u3001-\uD7FF\uE000-\uFEFE\uFF00-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+(?::(?:[\0-\x08\x0E-\x1F!-\x9F\xA1-\u167F\u1681-\u1FFF\u200B-\u2027\u202A-\u202E\u2030-\u205E\u2060-\u2FFF\u3001-\uD7FF\uE000-\uFEFE\uFF00-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])*)?@)?(?:(?!10(?:\.[0-9]{1,3}){3})(?!127(?:\.[0-9]{1,3}){3})(?!169\.254(?:\.[0-9]{1,3}){2})(?!192\.168(?:\.[0-9]{1,3}){2})(?!172\.(?:1[6-9]|2[0-9]|3[01])(?:\.[0-9]{1,3}){2})(?:[1-9][0-9]?|1[0-9][0-9]|2[01][0-9]|22[0-3])(?:\.(?:1?[0-9]{1,2}|2[0-4][0-9]|25[0-5])){2}(?:\.(?:[1-9][0-9]?|1[0-9][0-9]|2[0-4][0-9]|25[0-4]))|(?:(?:(?:[0-9a-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+-)*(?:[0-9a-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+)(?:\.(?:(?:[0-9a-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+-)*(?:[0-9a-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+)*(?:\.(?:(?:[a-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]){2,})))(?::[0-9]{2,5})?(?:\/(?:[\0-\x08\x0E-\x1F!-\x9F\xA1-\u167F\u1681-\u1FFF\u200B-\u2027\u202A-\u202E\u2030-\u205E\u2060-\u2FFF\u3001-\uD7FF\uE000-\uFEFE\uFF00-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])*)?$/i;
var UUID = /^(?:urn:uuid:)?[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/i;
var JSON_POINTER = /^(?:\/(?:[^~/]|~0|~1)*)*$/;
var JSON_POINTER_URI_FRAGMENT = /^#(?:\/(?:[a-z0-9_\-.!$&'()*+,;:=@]|%[0-9a-f]{2}|~0|~1)*)*$/i;
var RELATIVE_JSON_POINTER = /^(?:0|[1-9][0-9]*)(?:#|(?:\/(?:[^~/]|~0|~1)*)*)$/;
module.exports = formats;
function formats(mode) {
mode = mode == 'full' ? 'full' : 'fast';
return util.copy(formats[mode]);
}
formats.fast = {
// date: http://tools.ietf.org/html/rfc3339#section-5.6
date: /^\d\d\d\d-[0-1]\d-[0-3]\d$/,
// date-time: http://tools.ietf.org/html/rfc3339#section-5.6
time: /^(?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)(?:\.\d+)?(?:z|[+-]\d\d(?::?\d\d)?)?$/i,
'date-time': /^\d\d\d\d-[0-1]\d-[0-3]\d[t\s](?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)(?:\.\d+)?(?:z|[+-]\d\d(?::?\d\d)?)$/i,
// uri: https://github.com/mafintosh/is-my-json-valid/blob/master/formats.js
uri: /^(?:[a-z][a-z0-9+\-.]*:)(?:\/?\/)?[^\s]*$/i,
'uri-reference': /^(?:(?:[a-z][a-z0-9+\-.]*:)?\/?\/)?(?:[^\\\s#][^\s#]*)?(?:#[^\\\s]*)?$/i,
'uri-template': URITEMPLATE,
url: URL,
// email (sources from jsen validator):
// http://stackoverflow.com/questions/201323/using-a-regular-expression-to-validate-an-email-address#answer-8829363
// http://www.w3.org/TR/html5/forms.html#valid-e-mail-address (search for 'willful violation')
email: /^[a-z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$/i,
hostname: HOSTNAME,
// optimized https://www.safaribooksonline.com/library/view/regular-expressions-cookbook/9780596802837/ch07s16.html
ipv4: /^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/,
// optimized http://stackoverflow.com/questions/53497/regular-expression-that-matches-valid-ipv6-addresses
ipv6: /^\s*(?:(?:(?:[0-9a-f]{1,4}:){7}(?:[0-9a-f]{1,4}|:))|(?:(?:[0-9a-f]{1,4}:){6}(?::[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){5}(?:(?:(?::[0-9a-f]{1,4}){1,2})|:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){4}(?:(?:(?::[0-9a-f]{1,4}){1,3})|(?:(?::[0-9a-f]{1,4})?:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){3}(?:(?:(?::[0-9a-f]{1,4}){1,4})|(?:(?::[0-9a-f]{1,4}){0,2}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){2}(?:(?:(?::[0-9a-f]{1,4}){1,5})|(?:(?::[0-9a-f]{1,4}){0,3}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){1}(?:(?:(?::[0-9a-f]{1,4}){1,6})|(?:(?::[0-9a-f]{1,4}){0,4}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?::(?:(?:(?::[0-9a-f]{1,4}){1,7})|(?:(?::[0-9a-f]{1,4}){0,5}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(?:%.+)?\s*$/i,
regex: regex,
// uuid: http://tools.ietf.org/html/rfc4122
uuid: UUID,
// JSON-pointer: https://tools.ietf.org/html/rfc6901
// uri fragment: https://tools.ietf.org/html/rfc3986#appendix-A
'json-pointer': JSON_POINTER,
'json-pointer-uri-fragment': JSON_POINTER_URI_FRAGMENT,
// relative JSON-pointer: http://tools.ietf.org/html/draft-luff-relative-json-pointer-00
'relative-json-pointer': RELATIVE_JSON_POINTER
};
formats.full = {
date: date,
time: time,
'date-time': date_time,
uri: uri,
'uri-reference': URIREF,
'uri-template': URITEMPLATE,
url: URL,
email: /^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i,
hostname: HOSTNAME,
ipv4: /^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/,
ipv6: /^\s*(?:(?:(?:[0-9a-f]{1,4}:){7}(?:[0-9a-f]{1,4}|:))|(?:(?:[0-9a-f]{1,4}:){6}(?::[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){5}(?:(?:(?::[0-9a-f]{1,4}){1,2})|:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){4}(?:(?:(?::[0-9a-f]{1,4}){1,3})|(?:(?::[0-9a-f]{1,4})?:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){3}(?:(?:(?::[0-9a-f]{1,4}){1,4})|(?:(?::[0-9a-f]{1,4}){0,2}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){2}(?:(?:(?::[0-9a-f]{1,4}){1,5})|(?:(?::[0-9a-f]{1,4}){0,3}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){1}(?:(?:(?::[0-9a-f]{1,4}){1,6})|(?:(?::[0-9a-f]{1,4}){0,4}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?::(?:(?:(?::[0-9a-f]{1,4}){1,7})|(?:(?::[0-9a-f]{1,4}){0,5}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(?:%.+)?\s*$/i,
regex: regex,
uuid: UUID,
'json-pointer': JSON_POINTER,
'json-pointer-uri-fragment': JSON_POINTER_URI_FRAGMENT,
'relative-json-pointer': RELATIVE_JSON_POINTER
};
function isLeapYear(year) {
// https://tools.ietf.org/html/rfc3339#appendix-C
return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
}
function date(str) {
// full-date from http://tools.ietf.org/html/rfc3339#section-5.6
var matches = str.match(DATE);
if (!matches) return false;
var year = +matches[1];
var month = +matches[2];
var day = +matches[3];
return month >= 1 && month <= 12 && day >= 1 &&
day <= (month == 2 && isLeapYear(year) ? 29 : DAYS[month]);
}
function time(str, full) {
var matches = str.match(TIME);
if (!matches) return false;
var hour = matches[1];
var minute = matches[2];
var second = matches[3];
var timeZone = matches[5];
return ((hour <= 23 && minute <= 59 && second <= 59) ||
(hour == 23 && minute == 59 && second == 60)) &&
(!full || timeZone);
}
var DATE_TIME_SEPARATOR = /t|\s/i;
function date_time(str) {
// http://tools.ietf.org/html/rfc3339#section-5.6
var dateTime = str.split(DATE_TIME_SEPARATOR);
return dateTime.length == 2 && date(dateTime[0]) && time(dateTime[1], true);
}
var NOT_URI_FRAGMENT = /\/|:/;
function uri(str) {
// http://jmrware.com/articles/2009/uri_regexp/URI_regex.html + optional protocol + required "."
return NOT_URI_FRAGMENT.test(str) && URI.test(str);
}
var Z_ANCHOR = /[^\\]\\Z/;
function regex(str) {
if (Z_ANCHOR.test(str)) return false;
try {
new RegExp(str);
return true;
} catch(e) {
return false;
}
}

View file

@ -0,0 +1,387 @@
'use strict';
var resolve = require('./resolve')
, util = require('./util')
, errorClasses = require('./error_classes')
, stableStringify = require('fast-json-stable-stringify');
var validateGenerator = require('../dotjs/validate');
/**
* Functions below are used inside compiled validations function
*/
var ucs2length = util.ucs2length;
var equal = require('fast-deep-equal');
// this error is thrown by async schemas to return validation errors via exception
var ValidationError = errorClasses.Validation;
module.exports = compile;
/**
* Compiles schema to validation function
* @this Ajv
* @param {Object} schema schema object
* @param {Object} root object with information about the root schema for this schema
* @param {Object} localRefs the hash of local references inside the schema (created by resolve.id), used for inline resolution
* @param {String} baseId base ID for IDs in the schema
* @return {Function} validation function
*/
function compile(schema, root, localRefs, baseId) {
/* jshint validthis: true, evil: true */
/* eslint no-shadow: 0 */
var self = this
, opts = this._opts
, refVal = [ undefined ]
, refs = {}
, patterns = []
, patternsHash = {}
, defaults = []
, defaultsHash = {}
, customRules = [];
root = root || { schema: schema, refVal: refVal, refs: refs };
var c = checkCompiling.call(this, schema, root, baseId);
var compilation = this._compilations[c.index];
if (c.compiling) return (compilation.callValidate = callValidate);
var formats = this._formats;
var RULES = this.RULES;
try {
var v = localCompile(schema, root, localRefs, baseId);
compilation.validate = v;
var cv = compilation.callValidate;
if (cv) {
cv.schema = v.schema;
cv.errors = null;
cv.refs = v.refs;
cv.refVal = v.refVal;
cv.root = v.root;
cv.$async = v.$async;
if (opts.sourceCode) cv.source = v.source;
}
return v;
} finally {
endCompiling.call(this, schema, root, baseId);
}
/* @this {*} - custom context, see passContext option */
function callValidate() {
/* jshint validthis: true */
var validate = compilation.validate;
var result = validate.apply(this, arguments);
callValidate.errors = validate.errors;
return result;
}
function localCompile(_schema, _root, localRefs, baseId) {
var isRoot = !_root || (_root && _root.schema == _schema);
if (_root.schema != root.schema)
return compile.call(self, _schema, _root, localRefs, baseId);
var $async = _schema.$async === true;
var sourceCode = validateGenerator({
isTop: true,
schema: _schema,
isRoot: isRoot,
baseId: baseId,
root: _root,
schemaPath: '',
errSchemaPath: '#',
errorPath: '""',
MissingRefError: errorClasses.MissingRef,
RULES: RULES,
validate: validateGenerator,
util: util,
resolve: resolve,
resolveRef: resolveRef,
usePattern: usePattern,
useDefault: useDefault,
useCustomRule: useCustomRule,
opts: opts,
formats: formats,
logger: self.logger,
self: self
});
sourceCode = vars(refVal, refValCode) + vars(patterns, patternCode)
+ vars(defaults, defaultCode) + vars(customRules, customRuleCode)
+ sourceCode;
if (opts.processCode) sourceCode = opts.processCode(sourceCode, _schema);
// console.log('\n\n\n *** \n', JSON.stringify(sourceCode));
var validate;
try {
var makeValidate = new Function(
'self',
'RULES',
'formats',
'root',
'refVal',
'defaults',
'customRules',
'equal',
'ucs2length',
'ValidationError',
sourceCode
);
validate = makeValidate(
self,
RULES,
formats,
root,
refVal,
defaults,
customRules,
equal,
ucs2length,
ValidationError
);
refVal[0] = validate;
} catch(e) {
self.logger.error('Error compiling schema, function code:', sourceCode);
throw e;
}
validate.schema = _schema;
validate.errors = null;
validate.refs = refs;
validate.refVal = refVal;
validate.root = isRoot ? validate : _root;
if ($async) validate.$async = true;
if (opts.sourceCode === true) {
validate.source = {
code: sourceCode,
patterns: patterns,
defaults: defaults
};
}
return validate;
}
function resolveRef(baseId, ref, isRoot) {
ref = resolve.url(baseId, ref);
var refIndex = refs[ref];
var _refVal, refCode;
if (refIndex !== undefined) {
_refVal = refVal[refIndex];
refCode = 'refVal[' + refIndex + ']';
return resolvedRef(_refVal, refCode);
}
if (!isRoot && root.refs) {
var rootRefId = root.refs[ref];
if (rootRefId !== undefined) {
_refVal = root.refVal[rootRefId];
refCode = addLocalRef(ref, _refVal);
return resolvedRef(_refVal, refCode);
}
}
refCode = addLocalRef(ref);
var v = resolve.call(self, localCompile, root, ref);
if (v === undefined) {
var localSchema = localRefs && localRefs[ref];
if (localSchema) {
v = resolve.inlineRef(localSchema, opts.inlineRefs)
? localSchema
: compile.call(self, localSchema, root, localRefs, baseId);
}
}
if (v === undefined) {
removeLocalRef(ref);
} else {
replaceLocalRef(ref, v);
return resolvedRef(v, refCode);
}
}
function addLocalRef(ref, v) {
var refId = refVal.length;
refVal[refId] = v;
refs[ref] = refId;
return 'refVal' + refId;
}
function removeLocalRef(ref) {
delete refs[ref];
}
function replaceLocalRef(ref, v) {
var refId = refs[ref];
refVal[refId] = v;
}
function resolvedRef(refVal, code) {
return typeof refVal == 'object' || typeof refVal == 'boolean'
? { code: code, schema: refVal, inline: true }
: { code: code, $async: refVal && !!refVal.$async };
}
function usePattern(regexStr) {
var index = patternsHash[regexStr];
if (index === undefined) {
index = patternsHash[regexStr] = patterns.length;
patterns[index] = regexStr;
}
return 'pattern' + index;
}
function useDefault(value) {
switch (typeof value) {
case 'boolean':
case 'number':
return '' + value;
case 'string':
return util.toQuotedString(value);
case 'object':
if (value === null) return 'null';
var valueStr = stableStringify(value);
var index = defaultsHash[valueStr];
if (index === undefined) {
index = defaultsHash[valueStr] = defaults.length;
defaults[index] = value;
}
return 'default' + index;
}
}
function useCustomRule(rule, schema, parentSchema, it) {
if (self._opts.validateSchema !== false) {
var deps = rule.definition.dependencies;
if (deps && !deps.every(function(keyword) {
return Object.prototype.hasOwnProperty.call(parentSchema, keyword);
}))
throw new Error('parent schema must have all required keywords: ' + deps.join(','));
var validateSchema = rule.definition.validateSchema;
if (validateSchema) {
var valid = validateSchema(schema);
if (!valid) {
var message = 'keyword schema is invalid: ' + self.errorsText(validateSchema.errors);
if (self._opts.validateSchema == 'log') self.logger.error(message);
else throw new Error(message);
}
}
}
var compile = rule.definition.compile
, inline = rule.definition.inline
, macro = rule.definition.macro;
var validate;
if (compile) {
validate = compile.call(self, schema, parentSchema, it);
} else if (macro) {
validate = macro.call(self, schema, parentSchema, it);
if (opts.validateSchema !== false) self.validateSchema(validate, true);
} else if (inline) {
validate = inline.call(self, it, rule.keyword, schema, parentSchema);
} else {
validate = rule.definition.validate;
if (!validate) return;
}
if (validate === undefined)
throw new Error('custom keyword "' + rule.keyword + '"failed to compile');
var index = customRules.length;
customRules[index] = validate;
return {
code: 'customRule' + index,
validate: validate
};
}
}
/**
* Checks if the schema is currently compiled
* @this Ajv
* @param {Object} schema schema to compile
* @param {Object} root root object
* @param {String} baseId base schema ID
* @return {Object} object with properties "index" (compilation index) and "compiling" (boolean)
*/
function checkCompiling(schema, root, baseId) {
/* jshint validthis: true */
var index = compIndex.call(this, schema, root, baseId);
if (index >= 0) return { index: index, compiling: true };
index = this._compilations.length;
this._compilations[index] = {
schema: schema,
root: root,
baseId: baseId
};
return { index: index, compiling: false };
}
/**
* Removes the schema from the currently compiled list
* @this Ajv
* @param {Object} schema schema to compile
* @param {Object} root root object
* @param {String} baseId base schema ID
*/
function endCompiling(schema, root, baseId) {
/* jshint validthis: true */
var i = compIndex.call(this, schema, root, baseId);
if (i >= 0) this._compilations.splice(i, 1);
}
/**
* Index of schema compilation in the currently compiled list
* @this Ajv
* @param {Object} schema schema to compile
* @param {Object} root root object
* @param {String} baseId base schema ID
* @return {Integer} compilation index
*/
function compIndex(schema, root, baseId) {
/* jshint validthis: true */
for (var i=0; i<this._compilations.length; i++) {
var c = this._compilations[i];
if (c.schema == schema && c.root == root && c.baseId == baseId) return i;
}
return -1;
}
function patternCode(i, patterns) {
return 'var pattern' + i + ' = new RegExp(' + util.toQuotedString(patterns[i]) + ');';
}
function defaultCode(i) {
return 'var default' + i + ' = defaults[' + i + '];';
}
function refValCode(i, refVal) {
return refVal[i] === undefined ? '' : 'var refVal' + i + ' = refVal[' + i + '];';
}
function customRuleCode(i) {
return 'var customRule' + i + ' = customRules[' + i + '];';
}
function vars(arr, statement) {
if (!arr.length) return '';
var code = '';
for (var i=0; i<arr.length; i++)
code += statement(i, arr);
return code;
}

View file

@ -0,0 +1,270 @@
'use strict';
var URI = require('uri-js')
, equal = require('fast-deep-equal')
, util = require('./util')
, SchemaObject = require('./schema_obj')
, traverse = require('json-schema-traverse');
module.exports = resolve;
resolve.normalizeId = normalizeId;
resolve.fullPath = getFullPath;
resolve.url = resolveUrl;
resolve.ids = resolveIds;
resolve.inlineRef = inlineRef;
resolve.schema = resolveSchema;
/**
* [resolve and compile the references ($ref)]
* @this Ajv
* @param {Function} compile reference to schema compilation funciton (localCompile)
* @param {Object} root object with information about the root schema for the current schema
* @param {String} ref reference to resolve
* @return {Object|Function} schema object (if the schema can be inlined) or validation function
*/
function resolve(compile, root, ref) {
/* jshint validthis: true */
var refVal = this._refs[ref];
if (typeof refVal == 'string') {
if (this._refs[refVal]) refVal = this._refs[refVal];
else return resolve.call(this, compile, root, refVal);
}
refVal = refVal || this._schemas[ref];
if (refVal instanceof SchemaObject) {
return inlineRef(refVal.schema, this._opts.inlineRefs)
? refVal.schema
: refVal.validate || this._compile(refVal);
}
var res = resolveSchema.call(this, root, ref);
var schema, v, baseId;
if (res) {
schema = res.schema;
root = res.root;
baseId = res.baseId;
}
if (schema instanceof SchemaObject) {
v = schema.validate || compile.call(this, schema.schema, root, undefined, baseId);
} else if (schema !== undefined) {
v = inlineRef(schema, this._opts.inlineRefs)
? schema
: compile.call(this, schema, root, undefined, baseId);
}
return v;
}
/**
* Resolve schema, its root and baseId
* @this Ajv
* @param {Object} root root object with properties schema, refVal, refs
* @param {String} ref reference to resolve
* @return {Object} object with properties schema, root, baseId
*/
function resolveSchema(root, ref) {
/* jshint validthis: true */
var p = URI.parse(ref)
, refPath = _getFullPath(p)
, baseId = getFullPath(this._getId(root.schema));
if (Object.keys(root.schema).length === 0 || refPath !== baseId) {
var id = normalizeId(refPath);
var refVal = this._refs[id];
if (typeof refVal == 'string') {
return resolveRecursive.call(this, root, refVal, p);
} else if (refVal instanceof SchemaObject) {
if (!refVal.validate) this._compile(refVal);
root = refVal;
} else {
refVal = this._schemas[id];
if (refVal instanceof SchemaObject) {
if (!refVal.validate) this._compile(refVal);
if (id == normalizeId(ref))
return { schema: refVal, root: root, baseId: baseId };
root = refVal;
} else {
return;
}
}
if (!root.schema) return;
baseId = getFullPath(this._getId(root.schema));
}
return getJsonPointer.call(this, p, baseId, root.schema, root);
}
/* @this Ajv */
function resolveRecursive(root, ref, parsedRef) {
/* jshint validthis: true */
var res = resolveSchema.call(this, root, ref);
if (res) {
var schema = res.schema;
var baseId = res.baseId;
root = res.root;
var id = this._getId(schema);
if (id) baseId = resolveUrl(baseId, id);
return getJsonPointer.call(this, parsedRef, baseId, schema, root);
}
}
var PREVENT_SCOPE_CHANGE = util.toHash(['properties', 'patternProperties', 'enum', 'dependencies', 'definitions']);
/* @this Ajv */
function getJsonPointer(parsedRef, baseId, schema, root) {
/* jshint validthis: true */
parsedRef.fragment = parsedRef.fragment || '';
if (parsedRef.fragment.slice(0,1) != '/') return;
var parts = parsedRef.fragment.split('/');
for (var i = 1; i < parts.length; i++) {
var part = parts[i];
if (part) {
part = util.unescapeFragment(part);
schema = schema[part];
if (schema === undefined) break;
var id;
if (!PREVENT_SCOPE_CHANGE[part]) {
id = this._getId(schema);
if (id) baseId = resolveUrl(baseId, id);
if (schema.$ref) {
var $ref = resolveUrl(baseId, schema.$ref);
var res = resolveSchema.call(this, root, $ref);
if (res) {
schema = res.schema;
root = res.root;
baseId = res.baseId;
}
}
}
}
}
if (schema !== undefined && schema !== root.schema)
return { schema: schema, root: root, baseId: baseId };
}
var SIMPLE_INLINED = util.toHash([
'type', 'format', 'pattern',
'maxLength', 'minLength',
'maxProperties', 'minProperties',
'maxItems', 'minItems',
'maximum', 'minimum',
'uniqueItems', 'multipleOf',
'required', 'enum'
]);
function inlineRef(schema, limit) {
if (limit === false) return false;
if (limit === undefined || limit === true) return checkNoRef(schema);
else if (limit) return countKeys(schema) <= limit;
}
function checkNoRef(schema) {
var item;
if (Array.isArray(schema)) {
for (var i=0; i<schema.length; i++) {
item = schema[i];
if (typeof item == 'object' && !checkNoRef(item)) return false;
}
} else {
for (var key in schema) {
if (key == '$ref') return false;
item = schema[key];
if (typeof item == 'object' && !checkNoRef(item)) return false;
}
}
return true;
}
function countKeys(schema) {
var count = 0, item;
if (Array.isArray(schema)) {
for (var i=0; i<schema.length; i++) {
item = schema[i];
if (typeof item == 'object') count += countKeys(item);
if (count == Infinity) return Infinity;
}
} else {
for (var key in schema) {
if (key == '$ref') return Infinity;
if (SIMPLE_INLINED[key]) {
count++;
} else {
item = schema[key];
if (typeof item == 'object') count += countKeys(item) + 1;
if (count == Infinity) return Infinity;
}
}
}
return count;
}
function getFullPath(id, normalize) {
if (normalize !== false) id = normalizeId(id);
var p = URI.parse(id);
return _getFullPath(p);
}
function _getFullPath(p) {
return URI.serialize(p).split('#')[0] + '#';
}
var TRAILING_SLASH_HASH = /#\/?$/;
function normalizeId(id) {
return id ? id.replace(TRAILING_SLASH_HASH, '') : '';
}
function resolveUrl(baseId, id) {
id = normalizeId(id);
return URI.resolve(baseId, id);
}
/* @this Ajv */
function resolveIds(schema) {
var schemaId = normalizeId(this._getId(schema));
var baseIds = {'': schemaId};
var fullPaths = {'': getFullPath(schemaId, false)};
var localRefs = {};
var self = this;
traverse(schema, {allKeys: true}, function(sch, jsonPtr, rootSchema, parentJsonPtr, parentKeyword, parentSchema, keyIndex) {
if (jsonPtr === '') return;
var id = self._getId(sch);
var baseId = baseIds[parentJsonPtr];
var fullPath = fullPaths[parentJsonPtr] + '/' + parentKeyword;
if (keyIndex !== undefined)
fullPath += '/' + (typeof keyIndex == 'number' ? keyIndex : util.escapeFragment(keyIndex));
if (typeof id == 'string') {
id = baseId = normalizeId(baseId ? URI.resolve(baseId, id) : id);
var refVal = self._refs[id];
if (typeof refVal == 'string') refVal = self._refs[refVal];
if (refVal && refVal.schema) {
if (!equal(sch, refVal.schema))
throw new Error('id "' + id + '" resolves to more than one schema');
} else if (id != normalizeId(fullPath)) {
if (id[0] == '#') {
if (localRefs[id] && !equal(sch, localRefs[id]))
throw new Error('id "' + id + '" resolves to more than one schema');
localRefs[id] = sch;
} else {
self._refs[id] = fullPath;
}
}
}
baseIds[jsonPtr] = baseId;
fullPaths[jsonPtr] = fullPath;
});
return localRefs;
}

View file

@ -0,0 +1,66 @@
'use strict';
var ruleModules = require('../dotjs')
, toHash = require('./util').toHash;
module.exports = function rules() {
var RULES = [
{ type: 'number',
rules: [ { 'maximum': ['exclusiveMaximum'] },
{ 'minimum': ['exclusiveMinimum'] }, 'multipleOf', 'format'] },
{ type: 'string',
rules: [ 'maxLength', 'minLength', 'pattern', 'format' ] },
{ type: 'array',
rules: [ 'maxItems', 'minItems', 'items', 'contains', 'uniqueItems' ] },
{ type: 'object',
rules: [ 'maxProperties', 'minProperties', 'required', 'dependencies', 'propertyNames',
{ 'properties': ['additionalProperties', 'patternProperties'] } ] },
{ rules: [ '$ref', 'const', 'enum', 'not', 'anyOf', 'oneOf', 'allOf', 'if' ] }
];
var ALL = [ 'type', '$comment' ];
var KEYWORDS = [
'$schema', '$id', 'id', '$data', '$async', 'title',
'description', 'default', 'definitions',
'examples', 'readOnly', 'writeOnly',
'contentMediaType', 'contentEncoding',
'additionalItems', 'then', 'else'
];
var TYPES = [ 'number', 'integer', 'string', 'array', 'object', 'boolean', 'null' ];
RULES.all = toHash(ALL);
RULES.types = toHash(TYPES);
RULES.forEach(function (group) {
group.rules = group.rules.map(function (keyword) {
var implKeywords;
if (typeof keyword == 'object') {
var key = Object.keys(keyword)[0];
implKeywords = keyword[key];
keyword = key;
implKeywords.forEach(function (k) {
ALL.push(k);
RULES.all[k] = true;
});
}
ALL.push(keyword);
var rule = RULES.all[keyword] = {
keyword: keyword,
code: ruleModules[keyword],
implements: implKeywords
};
return rule;
});
RULES.all.$comment = {
keyword: '$comment',
code: ruleModules.$comment
};
if (group.type) RULES.types[group.type] = group;
});
RULES.keywords = toHash(ALL.concat(KEYWORDS));
RULES.custom = {};
return RULES;
};

View file

@ -0,0 +1,9 @@
'use strict';
var util = require('./util');
module.exports = SchemaObject;
function SchemaObject(obj) {
util.copy(obj, this);
}

View file

@ -0,0 +1,20 @@
'use strict';
// https://mathiasbynens.be/notes/javascript-encoding
// https://github.com/bestiejs/punycode.js - punycode.ucs2.decode
module.exports = function ucs2length(str) {
var length = 0
, len = str.length
, pos = 0
, value;
while (pos < len) {
length++;
value = str.charCodeAt(pos++);
if (value >= 0xD800 && value <= 0xDBFF && pos < len) {
// high surrogate, and there is a next character
value = str.charCodeAt(pos);
if ((value & 0xFC00) == 0xDC00) pos++; // low surrogate
}
}
return length;
};

View file

@ -0,0 +1,239 @@
'use strict';
module.exports = {
copy: copy,
checkDataType: checkDataType,
checkDataTypes: checkDataTypes,
coerceToTypes: coerceToTypes,
toHash: toHash,
getProperty: getProperty,
escapeQuotes: escapeQuotes,
equal: require('fast-deep-equal'),
ucs2length: require('./ucs2length'),
varOccurences: varOccurences,
varReplace: varReplace,
schemaHasRules: schemaHasRules,
schemaHasRulesExcept: schemaHasRulesExcept,
schemaUnknownRules: schemaUnknownRules,
toQuotedString: toQuotedString,
getPathExpr: getPathExpr,
getPath: getPath,
getData: getData,
unescapeFragment: unescapeFragment,
unescapeJsonPointer: unescapeJsonPointer,
escapeFragment: escapeFragment,
escapeJsonPointer: escapeJsonPointer
};
function copy(o, to) {
to = to || {};
for (var key in o) to[key] = o[key];
return to;
}
function checkDataType(dataType, data, strictNumbers, negate) {
var EQUAL = negate ? ' !== ' : ' === '
, AND = negate ? ' || ' : ' && '
, OK = negate ? '!' : ''
, NOT = negate ? '' : '!';
switch (dataType) {
case 'null': return data + EQUAL + 'null';
case 'array': return OK + 'Array.isArray(' + data + ')';
case 'object': return '(' + OK + data + AND +
'typeof ' + data + EQUAL + '"object"' + AND +
NOT + 'Array.isArray(' + data + '))';
case 'integer': return '(typeof ' + data + EQUAL + '"number"' + AND +
NOT + '(' + data + ' % 1)' +
AND + data + EQUAL + data +
(strictNumbers ? (AND + OK + 'isFinite(' + data + ')') : '') + ')';
case 'number': return '(typeof ' + data + EQUAL + '"' + dataType + '"' +
(strictNumbers ? (AND + OK + 'isFinite(' + data + ')') : '') + ')';
default: return 'typeof ' + data + EQUAL + '"' + dataType + '"';
}
}
function checkDataTypes(dataTypes, data, strictNumbers) {
switch (dataTypes.length) {
case 1: return checkDataType(dataTypes[0], data, strictNumbers, true);
default:
var code = '';
var types = toHash(dataTypes);
if (types.array && types.object) {
code = types.null ? '(': '(!' + data + ' || ';
code += 'typeof ' + data + ' !== "object")';
delete types.null;
delete types.array;
delete types.object;
}
if (types.number) delete types.integer;
for (var t in types)
code += (code ? ' && ' : '' ) + checkDataType(t, data, strictNumbers, true);
return code;
}
}
var COERCE_TO_TYPES = toHash([ 'string', 'number', 'integer', 'boolean', 'null' ]);
function coerceToTypes(optionCoerceTypes, dataTypes) {
if (Array.isArray(dataTypes)) {
var types = [];
for (var i=0; i<dataTypes.length; i++) {
var t = dataTypes[i];
if (COERCE_TO_TYPES[t]) types[types.length] = t;
else if (optionCoerceTypes === 'array' && t === 'array') types[types.length] = t;
}
if (types.length) return types;
} else if (COERCE_TO_TYPES[dataTypes]) {
return [dataTypes];
} else if (optionCoerceTypes === 'array' && dataTypes === 'array') {
return ['array'];
}
}
function toHash(arr) {
var hash = {};
for (var i=0; i<arr.length; i++) hash[arr[i]] = true;
return hash;
}
var IDENTIFIER = /^[a-z$_][a-z$_0-9]*$/i;
var SINGLE_QUOTE = /'|\\/g;
function getProperty(key) {
return typeof key == 'number'
? '[' + key + ']'
: IDENTIFIER.test(key)
? '.' + key
: "['" + escapeQuotes(key) + "']";
}
function escapeQuotes(str) {
return str.replace(SINGLE_QUOTE, '\\$&')
.replace(/\n/g, '\\n')
.replace(/\r/g, '\\r')
.replace(/\f/g, '\\f')
.replace(/\t/g, '\\t');
}
function varOccurences(str, dataVar) {
dataVar += '[^0-9]';
var matches = str.match(new RegExp(dataVar, 'g'));
return matches ? matches.length : 0;
}
function varReplace(str, dataVar, expr) {
dataVar += '([^0-9])';
expr = expr.replace(/\$/g, '$$$$');
return str.replace(new RegExp(dataVar, 'g'), expr + '$1');
}
function schemaHasRules(schema, rules) {
if (typeof schema == 'boolean') return !schema;
for (var key in schema) if (rules[key]) return true;
}
function schemaHasRulesExcept(schema, rules, exceptKeyword) {
if (typeof schema == 'boolean') return !schema && exceptKeyword != 'not';
for (var key in schema) if (key != exceptKeyword && rules[key]) return true;
}
function schemaUnknownRules(schema, rules) {
if (typeof schema == 'boolean') return;
for (var key in schema) if (!rules[key]) return key;
}
function toQuotedString(str) {
return '\'' + escapeQuotes(str) + '\'';
}
function getPathExpr(currentPath, expr, jsonPointers, isNumber) {
var path = jsonPointers // false by default
? '\'/\' + ' + expr + (isNumber ? '' : '.replace(/~/g, \'~0\').replace(/\\//g, \'~1\')')
: (isNumber ? '\'[\' + ' + expr + ' + \']\'' : '\'[\\\'\' + ' + expr + ' + \'\\\']\'');
return joinPaths(currentPath, path);
}
function getPath(currentPath, prop, jsonPointers) {
var path = jsonPointers // false by default
? toQuotedString('/' + escapeJsonPointer(prop))
: toQuotedString(getProperty(prop));
return joinPaths(currentPath, path);
}
var JSON_POINTER = /^\/(?:[^~]|~0|~1)*$/;
var RELATIVE_JSON_POINTER = /^([0-9]+)(#|\/(?:[^~]|~0|~1)*)?$/;
function getData($data, lvl, paths) {
var up, jsonPointer, data, matches;
if ($data === '') return 'rootData';
if ($data[0] == '/') {
if (!JSON_POINTER.test($data)) throw new Error('Invalid JSON-pointer: ' + $data);
jsonPointer = $data;
data = 'rootData';
} else {
matches = $data.match(RELATIVE_JSON_POINTER);
if (!matches) throw new Error('Invalid JSON-pointer: ' + $data);
up = +matches[1];
jsonPointer = matches[2];
if (jsonPointer == '#') {
if (up >= lvl) throw new Error('Cannot access property/index ' + up + ' levels up, current level is ' + lvl);
return paths[lvl - up];
}
if (up > lvl) throw new Error('Cannot access data ' + up + ' levels up, current level is ' + lvl);
data = 'data' + ((lvl - up) || '');
if (!jsonPointer) return data;
}
var expr = data;
var segments = jsonPointer.split('/');
for (var i=0; i<segments.length; i++) {
var segment = segments[i];
if (segment) {
data += getProperty(unescapeJsonPointer(segment));
expr += ' && ' + data;
}
}
return expr;
}
function joinPaths (a, b) {
if (a == '""') return b;
return (a + ' + ' + b).replace(/([^\\])' \+ '/g, '$1');
}
function unescapeFragment(str) {
return unescapeJsonPointer(decodeURIComponent(str));
}
function escapeFragment(str) {
return encodeURIComponent(escapeJsonPointer(str));
}
function escapeJsonPointer(str) {
return str.replace(/~/g, '~0').replace(/\//g, '~1');
}
function unescapeJsonPointer(str) {
return str.replace(/~1/g, '/').replace(/~0/g, '~');
}

View file

@ -0,0 +1,49 @@
'use strict';
var KEYWORDS = [
'multipleOf',
'maximum',
'exclusiveMaximum',
'minimum',
'exclusiveMinimum',
'maxLength',
'minLength',
'pattern',
'additionalItems',
'maxItems',
'minItems',
'uniqueItems',
'maxProperties',
'minProperties',
'required',
'additionalProperties',
'enum',
'format',
'const'
];
module.exports = function (metaSchema, keywordsJsonPointers) {
for (var i=0; i<keywordsJsonPointers.length; i++) {
metaSchema = JSON.parse(JSON.stringify(metaSchema));
var segments = keywordsJsonPointers[i].split('/');
var keywords = metaSchema;
var j;
for (j=1; j<segments.length; j++)
keywords = keywords[segments[j]];
for (j=0; j<KEYWORDS.length; j++) {
var key = KEYWORDS[j];
var schema = keywords[key];
if (schema) {
keywords[key] = {
anyOf: [
schema,
{ $ref: 'https://raw.githubusercontent.com/ajv-validator/ajv/master/lib/refs/data.json#' }
]
};
}
}
}
return metaSchema;
};

View file

@ -0,0 +1,37 @@
'use strict';
var metaSchema = require('./refs/json-schema-draft-07.json');
module.exports = {
$id: 'https://github.com/ajv-validator/ajv/blob/master/lib/definition_schema.js',
definitions: {
simpleTypes: metaSchema.definitions.simpleTypes
},
type: 'object',
dependencies: {
schema: ['validate'],
$data: ['validate'],
statements: ['inline'],
valid: {not: {required: ['macro']}}
},
properties: {
type: metaSchema.properties.type,
schema: {type: 'boolean'},
statements: {type: 'boolean'},
dependencies: {
type: 'array',
items: {type: 'string'}
},
metaSchema: {type: 'object'},
modifying: {type: 'boolean'},
valid: {type: 'boolean'},
$data: {type: 'boolean'},
async: {type: 'boolean'},
errors: {
anyOf: [
{type: 'boolean'},
{const: 'full'}
]
}
}
};

View file

@ -0,0 +1,113 @@
{{# def.definitions }}
{{# def.errors }}
{{# def.setupKeyword }}
{{# def.$data }}
{{## def.setExclusiveLimit:
$exclusive = true;
$errorKeyword = $exclusiveKeyword;
$errSchemaPath = it.errSchemaPath + '/' + $exclusiveKeyword;
#}}
{{
var $isMax = $keyword == 'maximum'
, $exclusiveKeyword = $isMax ? 'exclusiveMaximum' : 'exclusiveMinimum'
, $schemaExcl = it.schema[$exclusiveKeyword]
, $isDataExcl = it.opts.$data && $schemaExcl && $schemaExcl.$data
, $op = $isMax ? '<' : '>'
, $notOp = $isMax ? '>' : '<'
, $errorKeyword = undefined;
if (!($isData || typeof $schema == 'number' || $schema === undefined)) {
throw new Error($keyword + ' must be number');
}
if (!($isDataExcl || $schemaExcl === undefined
|| typeof $schemaExcl == 'number'
|| typeof $schemaExcl == 'boolean')) {
throw new Error($exclusiveKeyword + ' must be number or boolean');
}
}}
{{? $isDataExcl }}
{{
var $schemaValueExcl = it.util.getData($schemaExcl.$data, $dataLvl, it.dataPathArr)
, $exclusive = 'exclusive' + $lvl
, $exclType = 'exclType' + $lvl
, $exclIsNumber = 'exclIsNumber' + $lvl
, $opExpr = 'op' + $lvl
, $opStr = '\' + ' + $opExpr + ' + \'';
}}
var schemaExcl{{=$lvl}} = {{=$schemaValueExcl}};
{{ $schemaValueExcl = 'schemaExcl' + $lvl; }}
var {{=$exclusive}};
var {{=$exclType}} = typeof {{=$schemaValueExcl}};
if ({{=$exclType}} != 'boolean' && {{=$exclType}} != 'undefined' && {{=$exclType}} != 'number') {
{{ var $errorKeyword = $exclusiveKeyword; }}
{{# def.error:'_exclusiveLimit' }}
} else if ({{# def.$dataNotType:'number' }}
{{=$exclType}} == 'number'
? (
({{=$exclusive}} = {{=$schemaValue}} === undefined || {{=$schemaValueExcl}} {{=$op}}= {{=$schemaValue}})
? {{=$data}} {{=$notOp}}= {{=$schemaValueExcl}}
: {{=$data}} {{=$notOp}} {{=$schemaValue}}
)
: (
({{=$exclusive}} = {{=$schemaValueExcl}} === true)
? {{=$data}} {{=$notOp}}= {{=$schemaValue}}
: {{=$data}} {{=$notOp}} {{=$schemaValue}}
)
|| {{=$data}} !== {{=$data}}) {
var op{{=$lvl}} = {{=$exclusive}} ? '{{=$op}}' : '{{=$op}}=';
{{
if ($schema === undefined) {
$errorKeyword = $exclusiveKeyword;
$errSchemaPath = it.errSchemaPath + '/' + $exclusiveKeyword;
$schemaValue = $schemaValueExcl;
$isData = $isDataExcl;
}
}}
{{??}}
{{
var $exclIsNumber = typeof $schemaExcl == 'number'
, $opStr = $op; /*used in error*/
}}
{{? $exclIsNumber && $isData }}
{{ var $opExpr = '\'' + $opStr + '\''; /*used in error*/ }}
if ({{# def.$dataNotType:'number' }}
( {{=$schemaValue}} === undefined
|| {{=$schemaExcl}} {{=$op}}= {{=$schemaValue}}
? {{=$data}} {{=$notOp}}= {{=$schemaExcl}}
: {{=$data}} {{=$notOp}} {{=$schemaValue}} )
|| {{=$data}} !== {{=$data}}) {
{{??}}
{{
if ($exclIsNumber && $schema === undefined) {
{{# def.setExclusiveLimit }}
$schemaValue = $schemaExcl;
$notOp += '=';
} else {
if ($exclIsNumber)
$schemaValue = Math[$isMax ? 'min' : 'max']($schemaExcl, $schema);
if ($schemaExcl === ($exclIsNumber ? $schemaValue : true)) {
{{# def.setExclusiveLimit }}
$notOp += '=';
} else {
$exclusive = false;
$opStr += '=';
}
}
var $opExpr = '\'' + $opStr + '\''; /*used in error*/
}}
if ({{# def.$dataNotType:'number' }}
{{=$data}} {{=$notOp}} {{=$schemaValue}}
|| {{=$data}} !== {{=$data}}) {
{{?}}
{{?}}
{{ $errorKeyword = $errorKeyword || $keyword; }}
{{# def.error:'_limit' }}
} {{? $breakOnError }} else { {{?}}

View file

@ -0,0 +1,12 @@
{{# def.definitions }}
{{# def.errors }}
{{# def.setupKeyword }}
{{# def.$data }}
{{# def.numberKeyword }}
{{ var $op = $keyword == 'maxItems' ? '>' : '<'; }}
if ({{# def.$dataNotType:'number' }} {{=$data}}.length {{=$op}} {{=$schemaValue}}) {
{{ var $errorKeyword = $keyword; }}
{{# def.error:'_limitItems' }}
} {{? $breakOnError }} else { {{?}}

View file

@ -0,0 +1,12 @@
{{# def.definitions }}
{{# def.errors }}
{{# def.setupKeyword }}
{{# def.$data }}
{{# def.numberKeyword }}
{{ var $op = $keyword == 'maxLength' ? '>' : '<'; }}
if ({{# def.$dataNotType:'number' }} {{# def.strLength }} {{=$op}} {{=$schemaValue}}) {
{{ var $errorKeyword = $keyword; }}
{{# def.error:'_limitLength' }}
} {{? $breakOnError }} else { {{?}}

View file

@ -0,0 +1,12 @@
{{# def.definitions }}
{{# def.errors }}
{{# def.setupKeyword }}
{{# def.$data }}
{{# def.numberKeyword }}
{{ var $op = $keyword == 'maxProperties' ? '>' : '<'; }}
if ({{# def.$dataNotType:'number' }} Object.keys({{=$data}}).length {{=$op}} {{=$schemaValue}}) {
{{ var $errorKeyword = $keyword; }}
{{# def.error:'_limitProperties' }}
} {{? $breakOnError }} else { {{?}}

View file

@ -0,0 +1,32 @@
{{# def.definitions }}
{{# def.errors }}
{{# def.setupKeyword }}
{{# def.setupNextLevel }}
{{
var $currentBaseId = $it.baseId
, $allSchemasEmpty = true;
}}
{{~ $schema:$sch:$i }}
{{? {{# def.nonEmptySchema:$sch }} }}
{{
$allSchemasEmpty = false;
$it.schema = $sch;
$it.schemaPath = $schemaPath + '[' + $i + ']';
$it.errSchemaPath = $errSchemaPath + '/' + $i;
}}
{{# def.insertSubschemaCode }}
{{# def.ifResultValid }}
{{?}}
{{~}}
{{? $breakOnError }}
{{? $allSchemasEmpty }}
if (true) {
{{??}}
{{= $closingBraces.slice(0,-1) }}
{{?}}
{{?}}

View file

@ -0,0 +1,46 @@
{{# def.definitions }}
{{# def.errors }}
{{# def.setupKeyword }}
{{# def.setupNextLevel }}
{{
var $noEmptySchema = $schema.every(function($sch) {
return {{# def.nonEmptySchema:$sch }};
});
}}
{{? $noEmptySchema }}
{{ var $currentBaseId = $it.baseId; }}
var {{=$errs}} = errors;
var {{=$valid}} = false;
{{# def.setCompositeRule }}
{{~ $schema:$sch:$i }}
{{
$it.schema = $sch;
$it.schemaPath = $schemaPath + '[' + $i + ']';
$it.errSchemaPath = $errSchemaPath + '/' + $i;
}}
{{# def.insertSubschemaCode }}
{{=$valid}} = {{=$valid}} || {{=$nextValid}};
if (!{{=$valid}}) {
{{ $closingBraces += '}'; }}
{{~}}
{{# def.resetCompositeRule }}
{{= $closingBraces }}
if (!{{=$valid}}) {
{{# def.extraError:'anyOf' }}
} else {
{{# def.resetErrors }}
{{? it.opts.allErrors }} } {{?}}
{{??}}
{{? $breakOnError }}
if (true) {
{{?}}
{{?}}

View file

@ -0,0 +1,51 @@
{{## def.coerceType:
{{
var $dataType = 'dataType' + $lvl
, $coerced = 'coerced' + $lvl;
}}
var {{=$dataType}} = typeof {{=$data}};
var {{=$coerced}} = undefined;
{{? it.opts.coerceTypes == 'array' }}
if ({{=$dataType}} == 'object' && Array.isArray({{=$data}}) && {{=$data}}.length == 1) {
{{=$data}} = {{=$data}}[0];
{{=$dataType}} = typeof {{=$data}};
if ({{=it.util.checkDataType(it.schema.type, $data, it.opts.strictNumbers)}}) {{=$coerced}} = {{=$data}};
}
{{?}}
if ({{=$coerced}} !== undefined) ;
{{~ $coerceToTypes:$type:$i }}
{{? $type == 'string' }}
else if ({{=$dataType}} == 'number' || {{=$dataType}} == 'boolean')
{{=$coerced}} = '' + {{=$data}};
else if ({{=$data}} === null) {{=$coerced}} = '';
{{?? $type == 'number' || $type == 'integer' }}
else if ({{=$dataType}} == 'boolean' || {{=$data}} === null
|| ({{=$dataType}} == 'string' && {{=$data}} && {{=$data}} == +{{=$data}}
{{? $type == 'integer' }} && !({{=$data}} % 1){{?}}))
{{=$coerced}} = +{{=$data}};
{{?? $type == 'boolean' }}
else if ({{=$data}} === 'false' || {{=$data}} === 0 || {{=$data}} === null)
{{=$coerced}} = false;
else if ({{=$data}} === 'true' || {{=$data}} === 1)
{{=$coerced}} = true;
{{?? $type == 'null' }}
else if ({{=$data}} === '' || {{=$data}} === 0 || {{=$data}} === false)
{{=$coerced}} = null;
{{?? it.opts.coerceTypes == 'array' && $type == 'array' }}
else if ({{=$dataType}} == 'string' || {{=$dataType}} == 'number' || {{=$dataType}} == 'boolean' || {{=$data}} == null)
{{=$coerced}} = [{{=$data}}];
{{?}}
{{~}}
else {
{{# def.error:'type' }}
}
if ({{=$coerced}} !== undefined) {
{{# def.setParentData }}
{{=$data}} = {{=$coerced}};
{{? !$dataLvl }}if ({{=$parentData}} !== undefined){{?}}
{{=$parentData}}[{{=$parentDataProperty}}] = {{=$coerced}};
}
#}}

View file

@ -0,0 +1,9 @@
{{# def.definitions }}
{{# def.setupKeyword }}
{{ var $comment = it.util.toQuotedString($schema); }}
{{? it.opts.$comment === true }}
console.log({{=$comment}});
{{?? typeof it.opts.$comment == 'function' }}
self._opts.$comment({{=$comment}}, {{=it.util.toQuotedString($errSchemaPath)}}, validate.root.schema);
{{?}}

View file

@ -0,0 +1,11 @@
{{# def.definitions }}
{{# def.errors }}
{{# def.setupKeyword }}
{{# def.$data }}
{{? !$isData }}
var schema{{=$lvl}} = validate.schema{{=$schemaPath}};
{{?}}
var {{=$valid}} = equal({{=$data}}, schema{{=$lvl}});
{{# def.checkError:'const' }}
{{? $breakOnError }} else { {{?}}

View file

@ -0,0 +1,55 @@
{{# def.definitions }}
{{# def.errors }}
{{# def.setupKeyword }}
{{# def.setupNextLevel }}
{{
var $idx = 'i' + $lvl
, $dataNxt = $it.dataLevel = it.dataLevel + 1
, $nextData = 'data' + $dataNxt
, $currentBaseId = it.baseId
, $nonEmptySchema = {{# def.nonEmptySchema:$schema }};
}}
var {{=$errs}} = errors;
var {{=$valid}};
{{? $nonEmptySchema }}
{{# def.setCompositeRule }}
{{
$it.schema = $schema;
$it.schemaPath = $schemaPath;
$it.errSchemaPath = $errSchemaPath;
}}
var {{=$nextValid}} = false;
for (var {{=$idx}} = 0; {{=$idx}} < {{=$data}}.length; {{=$idx}}++) {
{{
$it.errorPath = it.util.getPathExpr(it.errorPath, $idx, it.opts.jsonPointers, true);
var $passData = $data + '[' + $idx + ']';
$it.dataPathArr[$dataNxt] = $idx;
}}
{{# def.generateSubschemaCode }}
{{# def.optimizeValidate }}
if ({{=$nextValid}}) break;
}
{{# def.resetCompositeRule }}
{{= $closingBraces }}
if (!{{=$nextValid}}) {
{{??}}
if ({{=$data}}.length == 0) {
{{?}}
{{# def.error:'contains' }}
} else {
{{? $nonEmptySchema }}
{{# def.resetErrors }}
{{?}}
{{? it.opts.allErrors }} } {{?}}

View file

@ -0,0 +1,191 @@
{{# def.definitions }}
{{# def.errors }}
{{# def.setupKeyword }}
{{# def.$data }}
{{
var $rule = this
, $definition = 'definition' + $lvl
, $rDef = $rule.definition
, $closingBraces = '';
var $validate = $rDef.validate;
var $compile, $inline, $macro, $ruleValidate, $validateCode;
}}
{{? $isData && $rDef.$data }}
{{
$validateCode = 'keywordValidate' + $lvl;
var $validateSchema = $rDef.validateSchema;
}}
var {{=$definition}} = RULES.custom['{{=$keyword}}'].definition;
var {{=$validateCode}} = {{=$definition}}.validate;
{{??}}
{{
$ruleValidate = it.useCustomRule($rule, $schema, it.schema, it);
if (!$ruleValidate) return;
$schemaValue = 'validate.schema' + $schemaPath;
$validateCode = $ruleValidate.code;
$compile = $rDef.compile;
$inline = $rDef.inline;
$macro = $rDef.macro;
}}
{{?}}
{{
var $ruleErrs = $validateCode + '.errors'
, $i = 'i' + $lvl
, $ruleErr = 'ruleErr' + $lvl
, $asyncKeyword = $rDef.async;
if ($asyncKeyword && !it.async)
throw new Error('async keyword in sync schema');
}}
{{? !($inline || $macro) }}{{=$ruleErrs}} = null;{{?}}
var {{=$errs}} = errors;
var {{=$valid}};
{{## def.callRuleValidate:
{{=$validateCode}}.call(
{{? it.opts.passContext }}this{{??}}self{{?}}
{{? $compile || $rDef.schema === false }}
, {{=$data}}
{{??}}
, {{=$schemaValue}}
, {{=$data}}
, validate.schema{{=it.schemaPath}}
{{?}}
, {{# def.dataPath }}
{{# def.passParentData }}
, rootData
)
#}}
{{## def.extendErrors:_inline:
for (var {{=$i}}={{=$errs}}; {{=$i}}<errors; {{=$i}}++) {
var {{=$ruleErr}} = vErrors[{{=$i}}];
if ({{=$ruleErr}}.dataPath === undefined)
{{=$ruleErr}}.dataPath = (dataPath || '') + {{= it.errorPath }};
{{# _inline ? 'if (\{\{=$ruleErr\}\}.schemaPath === undefined) {' : '' }}
{{=$ruleErr}}.schemaPath = "{{=$errSchemaPath}}";
{{# _inline ? '}' : '' }}
{{? it.opts.verbose }}
{{=$ruleErr}}.schema = {{=$schemaValue}};
{{=$ruleErr}}.data = {{=$data}};
{{?}}
}
#}}
{{? $isData && $rDef.$data }}
{{ $closingBraces += '}'; }}
if ({{=$schemaValue}} === undefined) {
{{=$valid}} = true;
} else {
{{? $validateSchema }}
{{ $closingBraces += '}'; }}
{{=$valid}} = {{=$definition}}.validateSchema({{=$schemaValue}});
if ({{=$valid}}) {
{{?}}
{{?}}
{{? $inline }}
{{? $rDef.statements }}
{{= $ruleValidate.validate }}
{{??}}
{{=$valid}} = {{= $ruleValidate.validate }};
{{?}}
{{?? $macro }}
{{# def.setupNextLevel }}
{{
$it.schema = $ruleValidate.validate;
$it.schemaPath = '';
}}
{{# def.setCompositeRule }}
{{ var $code = it.validate($it).replace(/validate\.schema/g, $validateCode); }}
{{# def.resetCompositeRule }}
{{= $code }}
{{??}}
{{# def.beginDefOut}}
{{# def.callRuleValidate }}
{{# def.storeDefOut:def_callRuleValidate }}
{{? $rDef.errors === false }}
{{=$valid}} = {{? $asyncKeyword }}await {{?}}{{= def_callRuleValidate }};
{{??}}
{{? $asyncKeyword }}
{{ $ruleErrs = 'customErrors' + $lvl; }}
var {{=$ruleErrs}} = null;
try {
{{=$valid}} = await {{= def_callRuleValidate }};
} catch (e) {
{{=$valid}} = false;
if (e instanceof ValidationError) {{=$ruleErrs}} = e.errors;
else throw e;
}
{{??}}
{{=$ruleErrs}} = null;
{{=$valid}} = {{= def_callRuleValidate }};
{{?}}
{{?}}
{{?}}
{{? $rDef.modifying }}
if ({{=$parentData}}) {{=$data}} = {{=$parentData}}[{{=$parentDataProperty}}];
{{?}}
{{= $closingBraces }}
{{## def.notValidationResult:
{{? $rDef.valid === undefined }}
!{{? $macro }}{{=$nextValid}}{{??}}{{=$valid}}{{?}}
{{??}}
{{= !$rDef.valid }}
{{?}}
#}}
{{? $rDef.valid }}
{{? $breakOnError }} if (true) { {{?}}
{{??}}
if ({{# def.notValidationResult }}) {
{{ $errorKeyword = $rule.keyword; }}
{{# def.beginDefOut}}
{{# def.error:'custom' }}
{{# def.storeDefOut:def_customError }}
{{? $inline }}
{{? $rDef.errors }}
{{? $rDef.errors != 'full' }}
{{# def.extendErrors:true }}
{{?}}
{{??}}
{{? $rDef.errors === false}}
{{= def_customError }}
{{??}}
if ({{=$errs}} == errors) {
{{= def_customError }}
} else {
{{# def.extendErrors:true }}
}
{{?}}
{{?}}
{{?? $macro }}
{{# def.extraError:'custom' }}
{{??}}
{{? $rDef.errors === false}}
{{= def_customError }}
{{??}}
if (Array.isArray({{=$ruleErrs}})) {
if (vErrors === null) vErrors = {{=$ruleErrs}};
else vErrors = vErrors.concat({{=$ruleErrs}});
errors = vErrors.length;
{{# def.extendErrors:false }}
} else {
{{= def_customError }}
}
{{?}}
{{?}}
} {{? $breakOnError }} else { {{?}}
{{?}}

View file

@ -0,0 +1,47 @@
{{## def.assignDefault:
{{? it.compositeRule }}
{{
if (it.opts.strictDefaults) {
var $defaultMsg = 'default is ignored for: ' + $passData;
if (it.opts.strictDefaults === 'log') it.logger.warn($defaultMsg);
else throw new Error($defaultMsg);
}
}}
{{??}}
if ({{=$passData}} === undefined
{{? it.opts.useDefaults == 'empty' }}
|| {{=$passData}} === null
|| {{=$passData}} === ''
{{?}}
)
{{=$passData}} = {{? it.opts.useDefaults == 'shared' }}
{{= it.useDefault($sch.default) }}
{{??}}
{{= JSON.stringify($sch.default) }}
{{?}};
{{?}}
#}}
{{## def.defaultProperties:
{{
var $schema = it.schema.properties
, $schemaKeys = Object.keys($schema); }}
{{~ $schemaKeys:$propertyKey }}
{{ var $sch = $schema[$propertyKey]; }}
{{? $sch.default !== undefined }}
{{ var $passData = $data + it.util.getProperty($propertyKey); }}
{{# def.assignDefault }}
{{?}}
{{~}}
#}}
{{## def.defaultItems:
{{~ it.schema.items:$sch:$i }}
{{? $sch.default !== undefined }}
{{ var $passData = $data + '[' + $i + ']'; }}
{{# def.assignDefault }}
{{?}}
{{~}}
#}}

View file

@ -0,0 +1,203 @@
{{## def.setupKeyword:
{{
var $lvl = it.level;
var $dataLvl = it.dataLevel;
var $schema = it.schema[$keyword];
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
var $breakOnError = !it.opts.allErrors;
var $errorKeyword;
var $data = 'data' + ($dataLvl || '');
var $valid = 'valid' + $lvl;
var $errs = 'errs__' + $lvl;
}}
#}}
{{## def.setCompositeRule:
{{
var $wasComposite = it.compositeRule;
it.compositeRule = $it.compositeRule = true;
}}
#}}
{{## def.resetCompositeRule:
{{ it.compositeRule = $it.compositeRule = $wasComposite; }}
#}}
{{## def.setupNextLevel:
{{
var $it = it.util.copy(it);
var $closingBraces = '';
$it.level++;
var $nextValid = 'valid' + $it.level;
}}
#}}
{{## def.ifValid:
{{? $breakOnError }}
if ({{=$valid}}) {
{{ $closingBraces += '}'; }}
{{?}}
#}}
{{## def.ifResultValid:
{{? $breakOnError }}
if ({{=$nextValid}}) {
{{ $closingBraces += '}'; }}
{{?}}
#}}
{{## def.elseIfValid:
{{? $breakOnError }}
{{ $closingBraces += '}'; }}
else {
{{?}}
#}}
{{## def.nonEmptySchema:_schema:
(it.opts.strictKeywords
? (typeof _schema == 'object' && Object.keys(_schema).length > 0)
|| _schema === false
: it.util.schemaHasRules(_schema, it.RULES.all))
#}}
{{## def.strLength:
{{? it.opts.unicode === false }}
{{=$data}}.length
{{??}}
ucs2length({{=$data}})
{{?}}
#}}
{{## def.willOptimize:
it.util.varOccurences($code, $nextData) < 2
#}}
{{## def.generateSubschemaCode:
{{
var $code = it.validate($it);
$it.baseId = $currentBaseId;
}}
#}}
{{## def.insertSubschemaCode:
{{= it.validate($it) }}
{{ $it.baseId = $currentBaseId; }}
#}}
{{## def._optimizeValidate:
it.util.varReplace($code, $nextData, $passData)
#}}
{{## def.optimizeValidate:
{{? {{# def.willOptimize}} }}
{{= {{# def._optimizeValidate }} }}
{{??}}
var {{=$nextData}} = {{=$passData}};
{{= $code }}
{{?}}
#}}
{{## def.$data:
{{
var $isData = it.opts.$data && $schema && $schema.$data
, $schemaValue;
}}
{{? $isData }}
var schema{{=$lvl}} = {{= it.util.getData($schema.$data, $dataLvl, it.dataPathArr) }};
{{ $schemaValue = 'schema' + $lvl; }}
{{??}}
{{ $schemaValue = $schema; }}
{{?}}
#}}
{{## def.$dataNotType:_type:
{{?$isData}} ({{=$schemaValue}} !== undefined && typeof {{=$schemaValue}} != _type) || {{?}}
#}}
{{## def.check$dataIsArray:
if (schema{{=$lvl}} === undefined) {{=$valid}} = true;
else if (!Array.isArray(schema{{=$lvl}})) {{=$valid}} = false;
else {
#}}
{{## def.numberKeyword:
{{? !($isData || typeof $schema == 'number') }}
{{ throw new Error($keyword + ' must be number'); }}
{{?}}
#}}
{{## def.beginDefOut:
{{
var $$outStack = $$outStack || [];
$$outStack.push(out);
out = '';
}}
#}}
{{## def.storeDefOut:_variable:
{{
var _variable = out;
out = $$outStack.pop();
}}
#}}
{{## def.dataPath:(dataPath || ''){{? it.errorPath != '""'}} + {{= it.errorPath }}{{?}}#}}
{{## def.setParentData:
{{
var $parentData = $dataLvl ? 'data' + (($dataLvl-1)||'') : 'parentData'
, $parentDataProperty = $dataLvl ? it.dataPathArr[$dataLvl] : 'parentDataProperty';
}}
#}}
{{## def.passParentData:
{{# def.setParentData }}
, {{= $parentData }}
, {{= $parentDataProperty }}
#}}
{{## def.iterateProperties:
{{? $ownProperties }}
{{=$dataProperties}} = {{=$dataProperties}} || Object.keys({{=$data}});
for (var {{=$idx}}=0; {{=$idx}}<{{=$dataProperties}}.length; {{=$idx}}++) {
var {{=$key}} = {{=$dataProperties}}[{{=$idx}}];
{{??}}
for (var {{=$key}} in {{=$data}}) {
{{?}}
#}}
{{## def.noPropertyInData:
{{=$useData}} === undefined
{{? $ownProperties }}
|| !{{# def.isOwnProperty }}
{{?}}
#}}
{{## def.isOwnProperty:
Object.prototype.hasOwnProperty.call({{=$data}}, '{{=it.util.escapeQuotes($propertyKey)}}')
#}}

View file

@ -0,0 +1,79 @@
{{# def.definitions }}
{{# def.errors }}
{{# def.missing }}
{{# def.setupKeyword }}
{{# def.setupNextLevel }}
{{## def.propertyInData:
{{=$data}}{{= it.util.getProperty($property) }} !== undefined
{{? $ownProperties }}
&& Object.prototype.hasOwnProperty.call({{=$data}}, '{{=it.util.escapeQuotes($property)}}')
{{?}}
#}}
{{
var $schemaDeps = {}
, $propertyDeps = {}
, $ownProperties = it.opts.ownProperties;
for ($property in $schema) {
if ($property == '__proto__') continue;
var $sch = $schema[$property];
var $deps = Array.isArray($sch) ? $propertyDeps : $schemaDeps;
$deps[$property] = $sch;
}
}}
var {{=$errs}} = errors;
{{ var $currentErrorPath = it.errorPath; }}
var missing{{=$lvl}};
{{ for (var $property in $propertyDeps) { }}
{{ $deps = $propertyDeps[$property]; }}
{{? $deps.length }}
if ({{# def.propertyInData }}
{{? $breakOnError }}
&& ({{# def.checkMissingProperty:$deps }})) {
{{# def.errorMissingProperty:'dependencies' }}
{{??}}
) {
{{~ $deps:$propertyKey }}
{{# def.allErrorsMissingProperty:'dependencies' }}
{{~}}
{{?}}
} {{# def.elseIfValid }}
{{?}}
{{ } }}
{{
it.errorPath = $currentErrorPath;
var $currentBaseId = $it.baseId;
}}
{{ for (var $property in $schemaDeps) { }}
{{ var $sch = $schemaDeps[$property]; }}
{{? {{# def.nonEmptySchema:$sch }} }}
{{=$nextValid}} = true;
if ({{# def.propertyInData }}) {
{{
$it.schema = $sch;
$it.schemaPath = $schemaPath + it.util.getProperty($property);
$it.errSchemaPath = $errSchemaPath + '/' + it.util.escapeFragment($property);
}}
{{# def.insertSubschemaCode }}
}
{{# def.ifResultValid }}
{{?}}
{{ } }}
{{? $breakOnError }}
{{= $closingBraces }}
if ({{=$errs}} == errors) {
{{?}}

View file

@ -0,0 +1,30 @@
{{# def.definitions }}
{{# def.errors }}
{{# def.setupKeyword }}
{{# def.$data }}
{{
var $i = 'i' + $lvl
, $vSchema = 'schema' + $lvl;
}}
{{? !$isData }}
var {{=$vSchema}} = validate.schema{{=$schemaPath}};
{{?}}
var {{=$valid}};
{{?$isData}}{{# def.check$dataIsArray }}{{?}}
{{=$valid}} = false;
for (var {{=$i}}=0; {{=$i}}<{{=$vSchema}}.length; {{=$i}}++)
if (equal({{=$data}}, {{=$vSchema}}[{{=$i}}])) {
{{=$valid}} = true;
break;
}
{{? $isData }} } {{?}}
{{# def.checkError:'enum' }}
{{? $breakOnError }} else { {{?}}

View file

@ -0,0 +1,194 @@
{{# def.definitions }}
{{## def._error:_rule:
{{ 'istanbul ignore else'; }}
{{? it.createErrors !== false }}
{
keyword: '{{= $errorKeyword || _rule }}'
, dataPath: (dataPath || '') + {{= it.errorPath }}
, schemaPath: {{=it.util.toQuotedString($errSchemaPath)}}
, params: {{# def._errorParams[_rule] }}
{{? it.opts.messages !== false }}
, message: {{# def._errorMessages[_rule] }}
{{?}}
{{? it.opts.verbose }}
, schema: {{# def._errorSchemas[_rule] }}
, parentSchema: validate.schema{{=it.schemaPath}}
, data: {{=$data}}
{{?}}
}
{{??}}
{}
{{?}}
#}}
{{## def._addError:_rule:
if (vErrors === null) vErrors = [err];
else vErrors.push(err);
errors++;
#}}
{{## def.addError:_rule:
var err = {{# def._error:_rule }};
{{# def._addError:_rule }}
#}}
{{## def.error:_rule:
{{# def.beginDefOut}}
{{# def._error:_rule }}
{{# def.storeDefOut:__err }}
{{? !it.compositeRule && $breakOnError }}
{{ 'istanbul ignore if'; }}
{{? it.async }}
throw new ValidationError([{{=__err}}]);
{{??}}
validate.errors = [{{=__err}}];
return false;
{{?}}
{{??}}
var err = {{=__err}};
{{# def._addError:_rule }}
{{?}}
#}}
{{## def.extraError:_rule:
{{# def.addError:_rule}}
{{? !it.compositeRule && $breakOnError }}
{{ 'istanbul ignore if'; }}
{{? it.async }}
throw new ValidationError(vErrors);
{{??}}
validate.errors = vErrors;
return false;
{{?}}
{{?}}
#}}
{{## def.checkError:_rule:
if (!{{=$valid}}) {
{{# def.error:_rule }}
}
#}}
{{## def.resetErrors:
errors = {{=$errs}};
if (vErrors !== null) {
if ({{=$errs}}) vErrors.length = {{=$errs}};
else vErrors = null;
}
#}}
{{## def.concatSchema:{{?$isData}}' + {{=$schemaValue}} + '{{??}}{{=$schema}}{{?}}#}}
{{## def.appendSchema:{{?$isData}}' + {{=$schemaValue}}{{??}}{{=$schemaValue}}'{{?}}#}}
{{## def.concatSchemaEQ:{{?$isData}}' + {{=$schemaValue}} + '{{??}}{{=it.util.escapeQuotes($schema)}}{{?}}#}}
{{## def._errorMessages = {
'false schema': "'boolean schema is false'",
$ref: "'can\\\'t resolve reference {{=it.util.escapeQuotes($schema)}}'",
additionalItems: "'should NOT have more than {{=$schema.length}} items'",
additionalProperties: "'{{? it.opts._errorDataPathProperty }}is an invalid additional property{{??}}should NOT have additional properties{{?}}'",
anyOf: "'should match some schema in anyOf'",
const: "'should be equal to constant'",
contains: "'should contain a valid item'",
dependencies: "'should have {{? $deps.length == 1 }}property {{= it.util.escapeQuotes($deps[0]) }}{{??}}properties {{= it.util.escapeQuotes($deps.join(\", \")) }}{{?}} when property {{= it.util.escapeQuotes($property) }} is present'",
'enum': "'should be equal to one of the allowed values'",
format: "'should match format \"{{#def.concatSchemaEQ}}\"'",
'if': "'should match \"' + {{=$ifClause}} + '\" schema'",
_limit: "'should be {{=$opStr}} {{#def.appendSchema}}",
_exclusiveLimit: "'{{=$exclusiveKeyword}} should be boolean'",
_limitItems: "'should NOT have {{?$keyword=='maxItems'}}more{{??}}fewer{{?}} than {{#def.concatSchema}} items'",
_limitLength: "'should NOT be {{?$keyword=='maxLength'}}longer{{??}}shorter{{?}} than {{#def.concatSchema}} characters'",
_limitProperties:"'should NOT have {{?$keyword=='maxProperties'}}more{{??}}fewer{{?}} than {{#def.concatSchema}} properties'",
multipleOf: "'should be multiple of {{#def.appendSchema}}",
not: "'should NOT be valid'",
oneOf: "'should match exactly one schema in oneOf'",
pattern: "'should match pattern \"{{#def.concatSchemaEQ}}\"'",
propertyNames: "'property name \\'{{=$invalidName}}\\' is invalid'",
required: "'{{? it.opts._errorDataPathProperty }}is a required property{{??}}should have required property \\'{{=$missingProperty}}\\'{{?}}'",
type: "'should be {{? $typeIsArray }}{{= $typeSchema.join(\",\") }}{{??}}{{=$typeSchema}}{{?}}'",
uniqueItems: "'should NOT have duplicate items (items ## ' + j + ' and ' + i + ' are identical)'",
custom: "'should pass \"{{=$rule.keyword}}\" keyword validation'",
patternRequired: "'should have property matching pattern \\'{{=$missingPattern}}\\''",
switch: "'should pass \"switch\" keyword validation'",
_formatLimit: "'should be {{=$opStr}} \"{{#def.concatSchemaEQ}}\"'",
_formatExclusiveLimit: "'{{=$exclusiveKeyword}} should be boolean'"
} #}}
{{## def.schemaRefOrVal: {{?$isData}}validate.schema{{=$schemaPath}}{{??}}{{=$schema}}{{?}} #}}
{{## def.schemaRefOrQS: {{?$isData}}validate.schema{{=$schemaPath}}{{??}}{{=it.util.toQuotedString($schema)}}{{?}} #}}
{{## def._errorSchemas = {
'false schema': "false",
$ref: "{{=it.util.toQuotedString($schema)}}",
additionalItems: "false",
additionalProperties: "false",
anyOf: "validate.schema{{=$schemaPath}}",
const: "validate.schema{{=$schemaPath}}",
contains: "validate.schema{{=$schemaPath}}",
dependencies: "validate.schema{{=$schemaPath}}",
'enum': "validate.schema{{=$schemaPath}}",
format: "{{#def.schemaRefOrQS}}",
'if': "validate.schema{{=$schemaPath}}",
_limit: "{{#def.schemaRefOrVal}}",
_exclusiveLimit: "validate.schema{{=$schemaPath}}",
_limitItems: "{{#def.schemaRefOrVal}}",
_limitLength: "{{#def.schemaRefOrVal}}",
_limitProperties:"{{#def.schemaRefOrVal}}",
multipleOf: "{{#def.schemaRefOrVal}}",
not: "validate.schema{{=$schemaPath}}",
oneOf: "validate.schema{{=$schemaPath}}",
pattern: "{{#def.schemaRefOrQS}}",
propertyNames: "validate.schema{{=$schemaPath}}",
required: "validate.schema{{=$schemaPath}}",
type: "validate.schema{{=$schemaPath}}",
uniqueItems: "{{#def.schemaRefOrVal}}",
custom: "validate.schema{{=$schemaPath}}",
patternRequired: "validate.schema{{=$schemaPath}}",
switch: "validate.schema{{=$schemaPath}}",
_formatLimit: "{{#def.schemaRefOrQS}}",
_formatExclusiveLimit: "validate.schema{{=$schemaPath}}"
} #}}
{{## def.schemaValueQS: {{?$isData}}{{=$schemaValue}}{{??}}{{=it.util.toQuotedString($schema)}}{{?}} #}}
{{## def._errorParams = {
'false schema': "{}",
$ref: "{ ref: '{{=it.util.escapeQuotes($schema)}}' }",
additionalItems: "{ limit: {{=$schema.length}} }",
additionalProperties: "{ additionalProperty: '{{=$additionalProperty}}' }",
anyOf: "{}",
const: "{ allowedValue: schema{{=$lvl}} }",
contains: "{}",
dependencies: "{ property: '{{= it.util.escapeQuotes($property) }}', missingProperty: '{{=$missingProperty}}', depsCount: {{=$deps.length}}, deps: '{{= it.util.escapeQuotes($deps.length==1 ? $deps[0] : $deps.join(\", \")) }}' }",
'enum': "{ allowedValues: schema{{=$lvl}} }",
format: "{ format: {{#def.schemaValueQS}} }",
'if': "{ failingKeyword: {{=$ifClause}} }",
_limit: "{ comparison: {{=$opExpr}}, limit: {{=$schemaValue}}, exclusive: {{=$exclusive}} }",
_exclusiveLimit: "{}",
_limitItems: "{ limit: {{=$schemaValue}} }",
_limitLength: "{ limit: {{=$schemaValue}} }",
_limitProperties:"{ limit: {{=$schemaValue}} }",
multipleOf: "{ multipleOf: {{=$schemaValue}} }",
not: "{}",
oneOf: "{ passingSchemas: {{=$passingSchemas}} }",
pattern: "{ pattern: {{#def.schemaValueQS}} }",
propertyNames: "{ propertyName: '{{=$invalidName}}' }",
required: "{ missingProperty: '{{=$missingProperty}}' }",
type: "{ type: '{{? $typeIsArray }}{{= $typeSchema.join(\",\") }}{{??}}{{=$typeSchema}}{{?}}' }",
uniqueItems: "{ i: i, j: j }",
custom: "{ keyword: '{{=$rule.keyword}}' }",
patternRequired: "{ missingPattern: '{{=$missingPattern}}' }",
switch: "{ caseIndex: {{=$caseIndex}} }",
_formatLimit: "{ comparison: {{=$opExpr}}, limit: {{#def.schemaValueQS}}, exclusive: {{=$exclusive}} }",
_formatExclusiveLimit: "{}"
} #}}

View file

@ -0,0 +1,106 @@
{{# def.definitions }}
{{# def.errors }}
{{# def.setupKeyword }}
{{## def.skipFormat:
{{? $breakOnError }} if (true) { {{?}}
{{ return out; }}
#}}
{{? it.opts.format === false }}{{# def.skipFormat }}{{?}}
{{# def.$data }}
{{## def.$dataCheckFormat:
{{# def.$dataNotType:'string' }}
({{? $unknownFormats != 'ignore' }}
({{=$schemaValue}} && !{{=$format}}
{{? $allowUnknown }}
&& self._opts.unknownFormats.indexOf({{=$schemaValue}}) == -1
{{?}}) ||
{{?}}
({{=$format}} && {{=$formatType}} == '{{=$ruleType}}'
&& !(typeof {{=$format}} == 'function'
? {{? it.async}}
(async{{=$lvl}} ? await {{=$format}}({{=$data}}) : {{=$format}}({{=$data}}))
{{??}}
{{=$format}}({{=$data}})
{{?}}
: {{=$format}}.test({{=$data}}))))
#}}
{{## def.checkFormat:
{{
var $formatRef = 'formats' + it.util.getProperty($schema);
if ($isObject) $formatRef += '.validate';
}}
{{? typeof $format == 'function' }}
{{=$formatRef}}({{=$data}})
{{??}}
{{=$formatRef}}.test({{=$data}})
{{?}}
#}}
{{
var $unknownFormats = it.opts.unknownFormats
, $allowUnknown = Array.isArray($unknownFormats);
}}
{{? $isData }}
{{
var $format = 'format' + $lvl
, $isObject = 'isObject' + $lvl
, $formatType = 'formatType' + $lvl;
}}
var {{=$format}} = formats[{{=$schemaValue}}];
var {{=$isObject}} = typeof {{=$format}} == 'object'
&& !({{=$format}} instanceof RegExp)
&& {{=$format}}.validate;
var {{=$formatType}} = {{=$isObject}} && {{=$format}}.type || 'string';
if ({{=$isObject}}) {
{{? it.async}}
var async{{=$lvl}} = {{=$format}}.async;
{{?}}
{{=$format}} = {{=$format}}.validate;
}
if ({{# def.$dataCheckFormat }}) {
{{??}}
{{ var $format = it.formats[$schema]; }}
{{? !$format }}
{{? $unknownFormats == 'ignore' }}
{{ it.logger.warn('unknown format "' + $schema + '" ignored in schema at path "' + it.errSchemaPath + '"'); }}
{{# def.skipFormat }}
{{?? $allowUnknown && $unknownFormats.indexOf($schema) >= 0 }}
{{# def.skipFormat }}
{{??}}
{{ throw new Error('unknown format "' + $schema + '" is used in schema at path "' + it.errSchemaPath + '"'); }}
{{?}}
{{?}}
{{
var $isObject = typeof $format == 'object'
&& !($format instanceof RegExp)
&& $format.validate;
var $formatType = $isObject && $format.type || 'string';
if ($isObject) {
var $async = $format.async === true;
$format = $format.validate;
}
}}
{{? $formatType != $ruleType }}
{{# def.skipFormat }}
{{?}}
{{? $async }}
{{
if (!it.async) throw new Error('async format in sync schema');
var $formatRef = 'formats' + it.util.getProperty($schema) + '.validate';
}}
if (!(await {{=$formatRef}}({{=$data}}))) {
{{??}}
if (!{{# def.checkFormat }}) {
{{?}}
{{?}}
{{# def.error:'format' }}
} {{? $breakOnError }} else { {{?}}

View file

@ -0,0 +1,73 @@
{{# def.definitions }}
{{# def.errors }}
{{# def.setupKeyword }}
{{# def.setupNextLevel }}
{{## def.validateIfClause:_clause:
{{
$it.schema = it.schema['_clause'];
$it.schemaPath = it.schemaPath + '._clause';
$it.errSchemaPath = it.errSchemaPath + '/_clause';
}}
{{# def.insertSubschemaCode }}
{{=$valid}} = {{=$nextValid}};
{{? $thenPresent && $elsePresent }}
{{ $ifClause = 'ifClause' + $lvl; }}
var {{=$ifClause}} = '_clause';
{{??}}
{{ $ifClause = '\'_clause\''; }}
{{?}}
#}}
{{
var $thenSch = it.schema['then']
, $elseSch = it.schema['else']
, $thenPresent = $thenSch !== undefined && {{# def.nonEmptySchema:$thenSch }}
, $elsePresent = $elseSch !== undefined && {{# def.nonEmptySchema:$elseSch }}
, $currentBaseId = $it.baseId;
}}
{{? $thenPresent || $elsePresent }}
{{
var $ifClause;
$it.createErrors = false;
$it.schema = $schema;
$it.schemaPath = $schemaPath;
$it.errSchemaPath = $errSchemaPath;
}}
var {{=$errs}} = errors;
var {{=$valid}} = true;
{{# def.setCompositeRule }}
{{# def.insertSubschemaCode }}
{{ $it.createErrors = true; }}
{{# def.resetErrors }}
{{# def.resetCompositeRule }}
{{? $thenPresent }}
if ({{=$nextValid}}) {
{{# def.validateIfClause:then }}
}
{{? $elsePresent }}
else {
{{?}}
{{??}}
if (!{{=$nextValid}}) {
{{?}}
{{? $elsePresent }}
{{# def.validateIfClause:else }}
}
{{?}}
if (!{{=$valid}}) {
{{# def.extraError:'if' }}
}
{{? $breakOnError }} else { {{?}}
{{??}}
{{? $breakOnError }}
if (true) {
{{?}}
{{?}}

View file

@ -0,0 +1,98 @@
{{# def.definitions }}
{{# def.errors }}
{{# def.setupKeyword }}
{{# def.setupNextLevel }}
{{## def.validateItems:startFrom:
for (var {{=$idx}} = {{=startFrom}}; {{=$idx}} < {{=$data}}.length; {{=$idx}}++) {
{{
$it.errorPath = it.util.getPathExpr(it.errorPath, $idx, it.opts.jsonPointers, true);
var $passData = $data + '[' + $idx + ']';
$it.dataPathArr[$dataNxt] = $idx;
}}
{{# def.generateSubschemaCode }}
{{# def.optimizeValidate }}
{{? $breakOnError }}
if (!{{=$nextValid}}) break;
{{?}}
}
#}}
{{
var $idx = 'i' + $lvl
, $dataNxt = $it.dataLevel = it.dataLevel + 1
, $nextData = 'data' + $dataNxt
, $currentBaseId = it.baseId;
}}
var {{=$errs}} = errors;
var {{=$valid}};
{{? Array.isArray($schema) }}
{{ /* 'items' is an array of schemas */}}
{{ var $additionalItems = it.schema.additionalItems; }}
{{? $additionalItems === false }}
{{=$valid}} = {{=$data}}.length <= {{= $schema.length }};
{{
var $currErrSchemaPath = $errSchemaPath;
$errSchemaPath = it.errSchemaPath + '/additionalItems';
}}
{{# def.checkError:'additionalItems' }}
{{ $errSchemaPath = $currErrSchemaPath; }}
{{# def.elseIfValid}}
{{?}}
{{~ $schema:$sch:$i }}
{{? {{# def.nonEmptySchema:$sch }} }}
{{=$nextValid}} = true;
if ({{=$data}}.length > {{=$i}}) {
{{
var $passData = $data + '[' + $i + ']';
$it.schema = $sch;
$it.schemaPath = $schemaPath + '[' + $i + ']';
$it.errSchemaPath = $errSchemaPath + '/' + $i;
$it.errorPath = it.util.getPathExpr(it.errorPath, $i, it.opts.jsonPointers, true);
$it.dataPathArr[$dataNxt] = $i;
}}
{{# def.generateSubschemaCode }}
{{# def.optimizeValidate }}
}
{{# def.ifResultValid }}
{{?}}
{{~}}
{{? typeof $additionalItems == 'object' && {{# def.nonEmptySchema:$additionalItems }} }}
{{
$it.schema = $additionalItems;
$it.schemaPath = it.schemaPath + '.additionalItems';
$it.errSchemaPath = it.errSchemaPath + '/additionalItems';
}}
{{=$nextValid}} = true;
if ({{=$data}}.length > {{= $schema.length }}) {
{{# def.validateItems: $schema.length }}
}
{{# def.ifResultValid }}
{{?}}
{{?? {{# def.nonEmptySchema:$schema }} }}
{{ /* 'items' is a single schema */}}
{{
$it.schema = $schema;
$it.schemaPath = $schemaPath;
$it.errSchemaPath = $errSchemaPath;
}}
{{# def.validateItems: 0 }}
{{?}}
{{? $breakOnError }}
{{= $closingBraces }}
if ({{=$errs}} == errors) {
{{?}}

View file

@ -0,0 +1,39 @@
{{## def.checkMissingProperty:_properties:
{{~ _properties:$propertyKey:$i }}
{{?$i}} || {{?}}
{{
var $prop = it.util.getProperty($propertyKey)
, $useData = $data + $prop;
}}
( ({{# def.noPropertyInData }}) && (missing{{=$lvl}} = {{= it.util.toQuotedString(it.opts.jsonPointers ? $propertyKey : $prop) }}) )
{{~}}
#}}
{{## def.errorMissingProperty:_error:
{{
var $propertyPath = 'missing' + $lvl
, $missingProperty = '\' + ' + $propertyPath + ' + \'';
if (it.opts._errorDataPathProperty) {
it.errorPath = it.opts.jsonPointers
? it.util.getPathExpr($currentErrorPath, $propertyPath, true)
: $currentErrorPath + ' + ' + $propertyPath;
}
}}
{{# def.error:_error }}
#}}
{{## def.allErrorsMissingProperty:_error:
{{
var $prop = it.util.getProperty($propertyKey)
, $missingProperty = it.util.escapeQuotes($propertyKey)
, $useData = $data + $prop;
if (it.opts._errorDataPathProperty) {
it.errorPath = it.util.getPath($currentErrorPath, $propertyKey, it.opts.jsonPointers);
}
}}
if ({{# def.noPropertyInData }}) {
{{# def.addError:_error }}
}
#}}

View file

@ -0,0 +1,22 @@
{{# def.definitions }}
{{# def.errors }}
{{# def.setupKeyword }}
{{# def.$data }}
{{# def.numberKeyword }}
var division{{=$lvl}};
if ({{?$isData}}
{{=$schemaValue}} !== undefined && (
typeof {{=$schemaValue}} != 'number' ||
{{?}}
(division{{=$lvl}} = {{=$data}} / {{=$schemaValue}},
{{? it.opts.multipleOfPrecision }}
Math.abs(Math.round(division{{=$lvl}}) - division{{=$lvl}}) > 1e-{{=it.opts.multipleOfPrecision}}
{{??}}
division{{=$lvl}} !== parseInt(division{{=$lvl}})
{{?}}
)
{{?$isData}} ) {{?}} ) {
{{# def.error:'multipleOf' }}
} {{? $breakOnError }} else { {{?}}

View file

@ -0,0 +1,43 @@
{{# def.definitions }}
{{# def.errors }}
{{# def.setupKeyword }}
{{# def.setupNextLevel }}
{{? {{# def.nonEmptySchema:$schema }} }}
{{
$it.schema = $schema;
$it.schemaPath = $schemaPath;
$it.errSchemaPath = $errSchemaPath;
}}
var {{=$errs}} = errors;
{{# def.setCompositeRule }}
{{
$it.createErrors = false;
var $allErrorsOption;
if ($it.opts.allErrors) {
$allErrorsOption = $it.opts.allErrors;
$it.opts.allErrors = false;
}
}}
{{= it.validate($it) }}
{{
$it.createErrors = true;
if ($allErrorsOption) $it.opts.allErrors = $allErrorsOption;
}}
{{# def.resetCompositeRule }}
if ({{=$nextValid}}) {
{{# def.error:'not' }}
} else {
{{# def.resetErrors }}
{{? it.opts.allErrors }} } {{?}}
{{??}}
{{# def.addError:'not' }}
{{? $breakOnError}}
if (false) {
{{?}}
{{?}}

View file

@ -0,0 +1,54 @@
{{# def.definitions }}
{{# def.errors }}
{{# def.setupKeyword }}
{{# def.setupNextLevel }}
{{
var $currentBaseId = $it.baseId
, $prevValid = 'prevValid' + $lvl
, $passingSchemas = 'passingSchemas' + $lvl;
}}
var {{=$errs}} = errors
, {{=$prevValid}} = false
, {{=$valid}} = false
, {{=$passingSchemas}} = null;
{{# def.setCompositeRule }}
{{~ $schema:$sch:$i }}
{{? {{# def.nonEmptySchema:$sch }} }}
{{
$it.schema = $sch;
$it.schemaPath = $schemaPath + '[' + $i + ']';
$it.errSchemaPath = $errSchemaPath + '/' + $i;
}}
{{# def.insertSubschemaCode }}
{{??}}
var {{=$nextValid}} = true;
{{?}}
{{? $i }}
if ({{=$nextValid}} && {{=$prevValid}}) {
{{=$valid}} = false;
{{=$passingSchemas}} = [{{=$passingSchemas}}, {{=$i}}];
} else {
{{ $closingBraces += '}'; }}
{{?}}
if ({{=$nextValid}}) {
{{=$valid}} = {{=$prevValid}} = true;
{{=$passingSchemas}} = {{=$i}};
}
{{~}}
{{# def.resetCompositeRule }}
{{= $closingBraces }}
if (!{{=$valid}}) {
{{# def.extraError:'oneOf' }}
} else {
{{# def.resetErrors }}
{{? it.opts.allErrors }} } {{?}}

View file

@ -0,0 +1,14 @@
{{# def.definitions }}
{{# def.errors }}
{{# def.setupKeyword }}
{{# def.$data }}
{{
var $regexp = $isData
? '(new RegExp(' + $schemaValue + '))'
: it.usePattern($schema);
}}
if ({{# def.$dataNotType:'string' }} !{{=$regexp}}.test({{=$data}}) ) {
{{# def.error:'pattern' }}
} {{? $breakOnError }} else { {{?}}

View file

@ -0,0 +1,245 @@
{{# def.definitions }}
{{# def.errors }}
{{# def.setupKeyword }}
{{# def.setupNextLevel }}
{{## def.validateAdditional:
{{ /* additionalProperties is schema */
$it.schema = $aProperties;
$it.schemaPath = it.schemaPath + '.additionalProperties';
$it.errSchemaPath = it.errSchemaPath + '/additionalProperties';
$it.errorPath = it.opts._errorDataPathProperty
? it.errorPath
: it.util.getPathExpr(it.errorPath, $key, it.opts.jsonPointers);
var $passData = $data + '[' + $key + ']';
$it.dataPathArr[$dataNxt] = $key;
}}
{{# def.generateSubschemaCode }}
{{# def.optimizeValidate }}
#}}
{{
var $key = 'key' + $lvl
, $idx = 'idx' + $lvl
, $dataNxt = $it.dataLevel = it.dataLevel + 1
, $nextData = 'data' + $dataNxt
, $dataProperties = 'dataProperties' + $lvl;
var $schemaKeys = Object.keys($schema || {}).filter(notProto)
, $pProperties = it.schema.patternProperties || {}
, $pPropertyKeys = Object.keys($pProperties).filter(notProto)
, $aProperties = it.schema.additionalProperties
, $someProperties = $schemaKeys.length || $pPropertyKeys.length
, $noAdditional = $aProperties === false
, $additionalIsSchema = typeof $aProperties == 'object'
&& Object.keys($aProperties).length
, $removeAdditional = it.opts.removeAdditional
, $checkAdditional = $noAdditional || $additionalIsSchema || $removeAdditional
, $ownProperties = it.opts.ownProperties
, $currentBaseId = it.baseId;
var $required = it.schema.required;
if ($required && !(it.opts.$data && $required.$data) && $required.length < it.opts.loopRequired) {
var $requiredHash = it.util.toHash($required);
}
function notProto(p) { return p !== '__proto__'; }
}}
var {{=$errs}} = errors;
var {{=$nextValid}} = true;
{{? $ownProperties }}
var {{=$dataProperties}} = undefined;
{{?}}
{{? $checkAdditional }}
{{# def.iterateProperties }}
{{? $someProperties }}
var isAdditional{{=$lvl}} = !(false
{{? $schemaKeys.length }}
{{? $schemaKeys.length > 8 }}
|| validate.schema{{=$schemaPath}}.hasOwnProperty({{=$key}})
{{??}}
{{~ $schemaKeys:$propertyKey }}
|| {{=$key}} == {{= it.util.toQuotedString($propertyKey) }}
{{~}}
{{?}}
{{?}}
{{? $pPropertyKeys.length }}
{{~ $pPropertyKeys:$pProperty:$i }}
|| {{= it.usePattern($pProperty) }}.test({{=$key}})
{{~}}
{{?}}
);
if (isAdditional{{=$lvl}}) {
{{?}}
{{? $removeAdditional == 'all' }}
delete {{=$data}}[{{=$key}}];
{{??}}
{{
var $currentErrorPath = it.errorPath;
var $additionalProperty = '\' + ' + $key + ' + \'';
if (it.opts._errorDataPathProperty) {
it.errorPath = it.util.getPathExpr(it.errorPath, $key, it.opts.jsonPointers);
}
}}
{{? $noAdditional }}
{{? $removeAdditional }}
delete {{=$data}}[{{=$key}}];
{{??}}
{{=$nextValid}} = false;
{{
var $currErrSchemaPath = $errSchemaPath;
$errSchemaPath = it.errSchemaPath + '/additionalProperties';
}}
{{# def.error:'additionalProperties' }}
{{ $errSchemaPath = $currErrSchemaPath; }}
{{? $breakOnError }} break; {{?}}
{{?}}
{{?? $additionalIsSchema }}
{{? $removeAdditional == 'failing' }}
var {{=$errs}} = errors;
{{# def.setCompositeRule }}
{{# def.validateAdditional }}
if (!{{=$nextValid}}) {
errors = {{=$errs}};
if (validate.errors !== null) {
if (errors) validate.errors.length = errors;
else validate.errors = null;
}
delete {{=$data}}[{{=$key}}];
}
{{# def.resetCompositeRule }}
{{??}}
{{# def.validateAdditional }}
{{? $breakOnError }} if (!{{=$nextValid}}) break; {{?}}
{{?}}
{{?}}
{{ it.errorPath = $currentErrorPath; }}
{{?}}
{{? $someProperties }}
}
{{?}}
}
{{# def.ifResultValid }}
{{?}}
{{ var $useDefaults = it.opts.useDefaults && !it.compositeRule; }}
{{? $schemaKeys.length }}
{{~ $schemaKeys:$propertyKey }}
{{ var $sch = $schema[$propertyKey]; }}
{{? {{# def.nonEmptySchema:$sch}} }}
{{
var $prop = it.util.getProperty($propertyKey)
, $passData = $data + $prop
, $hasDefault = $useDefaults && $sch.default !== undefined;
$it.schema = $sch;
$it.schemaPath = $schemaPath + $prop;
$it.errSchemaPath = $errSchemaPath + '/' + it.util.escapeFragment($propertyKey);
$it.errorPath = it.util.getPath(it.errorPath, $propertyKey, it.opts.jsonPointers);
$it.dataPathArr[$dataNxt] = it.util.toQuotedString($propertyKey);
}}
{{# def.generateSubschemaCode }}
{{? {{# def.willOptimize }} }}
{{
$code = {{# def._optimizeValidate }};
var $useData = $passData;
}}
{{??}}
{{ var $useData = $nextData; }}
var {{=$nextData}} = {{=$passData}};
{{?}}
{{? $hasDefault }}
{{= $code }}
{{??}}
{{? $requiredHash && $requiredHash[$propertyKey] }}
if ({{# def.noPropertyInData }}) {
{{=$nextValid}} = false;
{{
var $currentErrorPath = it.errorPath
, $currErrSchemaPath = $errSchemaPath
, $missingProperty = it.util.escapeQuotes($propertyKey);
if (it.opts._errorDataPathProperty) {
it.errorPath = it.util.getPath($currentErrorPath, $propertyKey, it.opts.jsonPointers);
}
$errSchemaPath = it.errSchemaPath + '/required';
}}
{{# def.error:'required' }}
{{ $errSchemaPath = $currErrSchemaPath; }}
{{ it.errorPath = $currentErrorPath; }}
} else {
{{??}}
{{? $breakOnError }}
if ({{# def.noPropertyInData }}) {
{{=$nextValid}} = true;
} else {
{{??}}
if ({{=$useData}} !== undefined
{{? $ownProperties }}
&& {{# def.isOwnProperty }}
{{?}}
) {
{{?}}
{{?}}
{{= $code }}
}
{{?}} {{ /* $hasDefault */ }}
{{?}} {{ /* def.nonEmptySchema */ }}
{{# def.ifResultValid }}
{{~}}
{{?}}
{{? $pPropertyKeys.length }}
{{~ $pPropertyKeys:$pProperty }}
{{ var $sch = $pProperties[$pProperty]; }}
{{? {{# def.nonEmptySchema:$sch}} }}
{{
$it.schema = $sch;
$it.schemaPath = it.schemaPath + '.patternProperties' + it.util.getProperty($pProperty);
$it.errSchemaPath = it.errSchemaPath + '/patternProperties/'
+ it.util.escapeFragment($pProperty);
}}
{{# def.iterateProperties }}
if ({{= it.usePattern($pProperty) }}.test({{=$key}})) {
{{
$it.errorPath = it.util.getPathExpr(it.errorPath, $key, it.opts.jsonPointers);
var $passData = $data + '[' + $key + ']';
$it.dataPathArr[$dataNxt] = $key;
}}
{{# def.generateSubschemaCode }}
{{# def.optimizeValidate }}
{{? $breakOnError }} if (!{{=$nextValid}}) break; {{?}}
}
{{? $breakOnError }} else {{=$nextValid}} = true; {{?}}
}
{{# def.ifResultValid }}
{{?}} {{ /* def.nonEmptySchema */ }}
{{~}}
{{?}}
{{? $breakOnError }}
{{= $closingBraces }}
if ({{=$errs}} == errors) {
{{?}}

View file

@ -0,0 +1,52 @@
{{# def.definitions }}
{{# def.errors }}
{{# def.setupKeyword }}
{{# def.setupNextLevel }}
var {{=$errs}} = errors;
{{? {{# def.nonEmptySchema:$schema }} }}
{{
$it.schema = $schema;
$it.schemaPath = $schemaPath;
$it.errSchemaPath = $errSchemaPath;
}}
{{
var $key = 'key' + $lvl
, $idx = 'idx' + $lvl
, $i = 'i' + $lvl
, $invalidName = '\' + ' + $key + ' + \''
, $dataNxt = $it.dataLevel = it.dataLevel + 1
, $nextData = 'data' + $dataNxt
, $dataProperties = 'dataProperties' + $lvl
, $ownProperties = it.opts.ownProperties
, $currentBaseId = it.baseId;
}}
{{? $ownProperties }}
var {{=$dataProperties}} = undefined;
{{?}}
{{# def.iterateProperties }}
var startErrs{{=$lvl}} = errors;
{{ var $passData = $key; }}
{{# def.setCompositeRule }}
{{# def.generateSubschemaCode }}
{{# def.optimizeValidate }}
{{# def.resetCompositeRule }}
if (!{{=$nextValid}}) {
for (var {{=$i}}=startErrs{{=$lvl}}; {{=$i}}<errors; {{=$i}}++) {
vErrors[{{=$i}}].propertyName = {{=$key}};
}
{{# def.extraError:'propertyNames' }}
{{? $breakOnError }} break; {{?}}
}
}
{{?}}
{{? $breakOnError }}
{{= $closingBraces }}
if ({{=$errs}} == errors) {
{{?}}

View file

@ -0,0 +1,85 @@
{{# def.definitions }}
{{# def.errors }}
{{# def.setupKeyword }}
{{## def._validateRef:_v:
{{? it.opts.passContext }}
{{=_v}}.call(this,
{{??}}
{{=_v}}(
{{?}}
{{=$data}}, {{# def.dataPath }}{{# def.passParentData }}, rootData)
#}}
{{ var $async, $refCode; }}
{{? $schema == '#' || $schema == '#/' }}
{{
if (it.isRoot) {
$async = it.async;
$refCode = 'validate';
} else {
$async = it.root.schema.$async === true;
$refCode = 'root.refVal[0]';
}
}}
{{??}}
{{ var $refVal = it.resolveRef(it.baseId, $schema, it.isRoot); }}
{{? $refVal === undefined }}
{{ var $message = it.MissingRefError.message(it.baseId, $schema); }}
{{? it.opts.missingRefs == 'fail' }}
{{ it.logger.error($message); }}
{{# def.error:'$ref' }}
{{? $breakOnError }} if (false) { {{?}}
{{?? it.opts.missingRefs == 'ignore' }}
{{ it.logger.warn($message); }}
{{? $breakOnError }} if (true) { {{?}}
{{??}}
{{ throw new it.MissingRefError(it.baseId, $schema, $message); }}
{{?}}
{{?? $refVal.inline }}
{{# def.setupNextLevel }}
{{
$it.schema = $refVal.schema;
$it.schemaPath = '';
$it.errSchemaPath = $schema;
}}
{{ var $code = it.validate($it).replace(/validate\.schema/g, $refVal.code); }}
{{= $code }}
{{? $breakOnError}}
if ({{=$nextValid}}) {
{{?}}
{{??}}
{{
$async = $refVal.$async === true || (it.async && $refVal.$async !== false);
$refCode = $refVal.code;
}}
{{?}}
{{?}}
{{? $refCode }}
{{# def.beginDefOut}}
{{# def._validateRef:$refCode }}
{{# def.storeDefOut:__callValidate }}
{{? $async }}
{{ if (!it.async) throw new Error('async schema referenced by sync schema'); }}
{{? $breakOnError }} var {{=$valid}}; {{?}}
try {
await {{=__callValidate}};
{{? $breakOnError }} {{=$valid}} = true; {{?}}
} catch (e) {
if (!(e instanceof ValidationError)) throw e;
if (vErrors === null) vErrors = e.errors;
else vErrors = vErrors.concat(e.errors);
errors = vErrors.length;
{{? $breakOnError }} {{=$valid}} = false; {{?}}
}
{{? $breakOnError }} if ({{=$valid}}) { {{?}}
{{??}}
if (!{{=__callValidate}}) {
if (vErrors === null) vErrors = {{=$refCode}}.errors;
else vErrors = vErrors.concat({{=$refCode}}.errors);
errors = vErrors.length;
} {{? $breakOnError }} else { {{?}}
{{?}}
{{?}}

View file

@ -0,0 +1,108 @@
{{# def.definitions }}
{{# def.errors }}
{{# def.missing }}
{{# def.setupKeyword }}
{{# def.$data }}
{{ var $vSchema = 'schema' + $lvl; }}
{{## def.setupLoop:
{{? !$isData }}
var {{=$vSchema}} = validate.schema{{=$schemaPath}};
{{?}}
{{
var $i = 'i' + $lvl
, $propertyPath = 'schema' + $lvl + '[' + $i + ']'
, $missingProperty = '\' + ' + $propertyPath + ' + \'';
if (it.opts._errorDataPathProperty) {
it.errorPath = it.util.getPathExpr($currentErrorPath, $propertyPath, it.opts.jsonPointers);
}
}}
#}}
{{## def.isRequiredOwnProperty:
Object.prototype.hasOwnProperty.call({{=$data}}, {{=$vSchema}}[{{=$i}}])
#}}
{{? !$isData }}
{{? $schema.length < it.opts.loopRequired &&
it.schema.properties && Object.keys(it.schema.properties).length }}
{{ var $required = []; }}
{{~ $schema:$property }}
{{ var $propertySch = it.schema.properties[$property]; }}
{{? !($propertySch && {{# def.nonEmptySchema:$propertySch}}) }}
{{ $required[$required.length] = $property; }}
{{?}}
{{~}}
{{??}}
{{ var $required = $schema; }}
{{?}}
{{?}}
{{? $isData || $required.length }}
{{
var $currentErrorPath = it.errorPath
, $loopRequired = $isData || $required.length >= it.opts.loopRequired
, $ownProperties = it.opts.ownProperties;
}}
{{? $breakOnError }}
var missing{{=$lvl}};
{{? $loopRequired }}
{{# def.setupLoop }}
var {{=$valid}} = true;
{{?$isData}}{{# def.check$dataIsArray }}{{?}}
for (var {{=$i}} = 0; {{=$i}} < {{=$vSchema}}.length; {{=$i}}++) {
{{=$valid}} = {{=$data}}[{{=$vSchema}}[{{=$i}}]] !== undefined
{{? $ownProperties }}
&& {{# def.isRequiredOwnProperty }}
{{?}};
if (!{{=$valid}}) break;
}
{{? $isData }} } {{?}}
{{# def.checkError:'required' }}
else {
{{??}}
if ({{# def.checkMissingProperty:$required }}) {
{{# def.errorMissingProperty:'required' }}
} else {
{{?}}
{{??}}
{{? $loopRequired }}
{{# def.setupLoop }}
{{? $isData }}
if ({{=$vSchema}} && !Array.isArray({{=$vSchema}})) {
{{# def.addError:'required' }}
} else if ({{=$vSchema}} !== undefined) {
{{?}}
for (var {{=$i}} = 0; {{=$i}} < {{=$vSchema}}.length; {{=$i}}++) {
if ({{=$data}}[{{=$vSchema}}[{{=$i}}]] === undefined
{{? $ownProperties }}
|| !{{# def.isRequiredOwnProperty }}
{{?}}) {
{{# def.addError:'required' }}
}
}
{{? $isData }} } {{?}}
{{??}}
{{~ $required:$propertyKey }}
{{# def.allErrorsMissingProperty:'required' }}
{{~}}
{{?}}
{{?}}
{{ it.errorPath = $currentErrorPath; }}
{{?? $breakOnError }}
if (true) {
{{?}}

View file

@ -0,0 +1,62 @@
{{# def.definitions }}
{{# def.errors }}
{{# def.setupKeyword }}
{{# def.$data }}
{{? ($schema || $isData) && it.opts.uniqueItems !== false }}
{{? $isData }}
var {{=$valid}};
if ({{=$schemaValue}} === false || {{=$schemaValue}} === undefined)
{{=$valid}} = true;
else if (typeof {{=$schemaValue}} != 'boolean')
{{=$valid}} = false;
else {
{{?}}
var i = {{=$data}}.length
, {{=$valid}} = true
, j;
if (i > 1) {
{{
var $itemType = it.schema.items && it.schema.items.type
, $typeIsArray = Array.isArray($itemType);
}}
{{? !$itemType || $itemType == 'object' || $itemType == 'array' ||
($typeIsArray && ($itemType.indexOf('object') >= 0 || $itemType.indexOf('array') >= 0)) }}
outer:
for (;i--;) {
for (j = i; j--;) {
if (equal({{=$data}}[i], {{=$data}}[j])) {
{{=$valid}} = false;
break outer;
}
}
}
{{??}}
var itemIndices = {}, item;
for (;i--;) {
var item = {{=$data}}[i];
{{ var $method = 'checkDataType' + ($typeIsArray ? 's' : ''); }}
if ({{= it.util[$method]($itemType, 'item', it.opts.strictNumbers, true) }}) continue;
{{? $typeIsArray}}
if (typeof item == 'string') item = '"' + item;
{{?}}
if (typeof itemIndices[item] == 'number') {
{{=$valid}} = false;
j = itemIndices[item];
break;
}
itemIndices[item] = i;
}
{{?}}
}
{{? $isData }} } {{?}}
if (!{{=$valid}}) {
{{# def.error:'uniqueItems' }}
} {{? $breakOnError }} else { {{?}}
{{??}}
{{? $breakOnError }} if (true) { {{?}}
{{?}}

View file

@ -0,0 +1,276 @@
{{# def.definitions }}
{{# def.errors }}
{{# def.defaults }}
{{# def.coerce }}
{{ /**
* schema compilation (render) time:
* it = { schema, RULES, _validate, opts }
* it.validate - this template function,
* it is used recursively to generate code for subschemas
*
* runtime:
* "validate" is a variable name to which this function will be assigned
* validateRef etc. are defined in the parent scope in index.js
*/ }}
{{
var $async = it.schema.$async === true
, $refKeywords = it.util.schemaHasRulesExcept(it.schema, it.RULES.all, '$ref')
, $id = it.self._getId(it.schema);
}}
{{
if (it.opts.strictKeywords) {
var $unknownKwd = it.util.schemaUnknownRules(it.schema, it.RULES.keywords);
if ($unknownKwd) {
var $keywordsMsg = 'unknown keyword: ' + $unknownKwd;
if (it.opts.strictKeywords === 'log') it.logger.warn($keywordsMsg);
else throw new Error($keywordsMsg);
}
}
}}
{{? it.isTop }}
var validate = {{?$async}}{{it.async = true;}}async {{?}}function(data, dataPath, parentData, parentDataProperty, rootData) {
'use strict';
{{? $id && (it.opts.sourceCode || it.opts.processCode) }}
{{= '/\*# sourceURL=' + $id + ' */' }}
{{?}}
{{?}}
{{? typeof it.schema == 'boolean' || !($refKeywords || it.schema.$ref) }}
{{ var $keyword = 'false schema'; }}
{{# def.setupKeyword }}
{{? it.schema === false}}
{{? it.isTop}}
{{ $breakOnError = true; }}
{{??}}
var {{=$valid}} = false;
{{?}}
{{# def.error:'false schema' }}
{{??}}
{{? it.isTop}}
{{? $async }}
return data;
{{??}}
validate.errors = null;
return true;
{{?}}
{{??}}
var {{=$valid}} = true;
{{?}}
{{?}}
{{? it.isTop}}
};
return validate;
{{?}}
{{ return out; }}
{{?}}
{{? it.isTop }}
{{
var $top = it.isTop
, $lvl = it.level = 0
, $dataLvl = it.dataLevel = 0
, $data = 'data';
it.rootId = it.resolve.fullPath(it.self._getId(it.root.schema));
it.baseId = it.baseId || it.rootId;
delete it.isTop;
it.dataPathArr = [""];
if (it.schema.default !== undefined && it.opts.useDefaults && it.opts.strictDefaults) {
var $defaultMsg = 'default is ignored in the schema root';
if (it.opts.strictDefaults === 'log') it.logger.warn($defaultMsg);
else throw new Error($defaultMsg);
}
}}
var vErrors = null; {{ /* don't edit, used in replace */ }}
var errors = 0; {{ /* don't edit, used in replace */ }}
if (rootData === undefined) rootData = data; {{ /* don't edit, used in replace */ }}
{{??}}
{{
var $lvl = it.level
, $dataLvl = it.dataLevel
, $data = 'data' + ($dataLvl || '');
if ($id) it.baseId = it.resolve.url(it.baseId, $id);
if ($async && !it.async) throw new Error('async schema in sync schema');
}}
var errs_{{=$lvl}} = errors;
{{?}}
{{
var $valid = 'valid' + $lvl
, $breakOnError = !it.opts.allErrors
, $closingBraces1 = ''
, $closingBraces2 = '';
var $errorKeyword;
var $typeSchema = it.schema.type
, $typeIsArray = Array.isArray($typeSchema);
if ($typeSchema && it.opts.nullable && it.schema.nullable === true) {
if ($typeIsArray) {
if ($typeSchema.indexOf('null') == -1)
$typeSchema = $typeSchema.concat('null');
} else if ($typeSchema != 'null') {
$typeSchema = [$typeSchema, 'null'];
$typeIsArray = true;
}
}
if ($typeIsArray && $typeSchema.length == 1) {
$typeSchema = $typeSchema[0];
$typeIsArray = false;
}
}}
{{## def.checkType:
{{
var $schemaPath = it.schemaPath + '.type'
, $errSchemaPath = it.errSchemaPath + '/type'
, $method = $typeIsArray ? 'checkDataTypes' : 'checkDataType';
}}
if ({{= it.util[$method]($typeSchema, $data, it.opts.strictNumbers, true) }}) {
#}}
{{? it.schema.$ref && $refKeywords }}
{{? it.opts.extendRefs == 'fail' }}
{{ throw new Error('$ref: validation keywords used in schema at path "' + it.errSchemaPath + '" (see option extendRefs)'); }}
{{?? it.opts.extendRefs !== true }}
{{
$refKeywords = false;
it.logger.warn('$ref: keywords ignored in schema at path "' + it.errSchemaPath + '"');
}}
{{?}}
{{?}}
{{? it.schema.$comment && it.opts.$comment }}
{{= it.RULES.all.$comment.code(it, '$comment') }}
{{?}}
{{? $typeSchema }}
{{? it.opts.coerceTypes }}
{{ var $coerceToTypes = it.util.coerceToTypes(it.opts.coerceTypes, $typeSchema); }}
{{?}}
{{ var $rulesGroup = it.RULES.types[$typeSchema]; }}
{{? $coerceToTypes || $typeIsArray || $rulesGroup === true ||
($rulesGroup && !$shouldUseGroup($rulesGroup)) }}
{{
var $schemaPath = it.schemaPath + '.type'
, $errSchemaPath = it.errSchemaPath + '/type';
}}
{{# def.checkType }}
{{? $coerceToTypes }}
{{# def.coerceType }}
{{??}}
{{# def.error:'type' }}
{{?}}
}
{{?}}
{{?}}
{{? it.schema.$ref && !$refKeywords }}
{{= it.RULES.all.$ref.code(it, '$ref') }}
{{? $breakOnError }}
}
if (errors === {{?$top}}0{{??}}errs_{{=$lvl}}{{?}}) {
{{ $closingBraces2 += '}'; }}
{{?}}
{{??}}
{{~ it.RULES:$rulesGroup }}
{{? $shouldUseGroup($rulesGroup) }}
{{? $rulesGroup.type }}
if ({{= it.util.checkDataType($rulesGroup.type, $data, it.opts.strictNumbers) }}) {
{{?}}
{{? it.opts.useDefaults }}
{{? $rulesGroup.type == 'object' && it.schema.properties }}
{{# def.defaultProperties }}
{{?? $rulesGroup.type == 'array' && Array.isArray(it.schema.items) }}
{{# def.defaultItems }}
{{?}}
{{?}}
{{~ $rulesGroup.rules:$rule }}
{{? $shouldUseRule($rule) }}
{{ var $code = $rule.code(it, $rule.keyword, $rulesGroup.type); }}
{{? $code }}
{{= $code }}
{{? $breakOnError }}
{{ $closingBraces1 += '}'; }}
{{?}}
{{?}}
{{?}}
{{~}}
{{? $breakOnError }}
{{= $closingBraces1 }}
{{ $closingBraces1 = ''; }}
{{?}}
{{? $rulesGroup.type }}
}
{{? $typeSchema && $typeSchema === $rulesGroup.type && !$coerceToTypes }}
else {
{{
var $schemaPath = it.schemaPath + '.type'
, $errSchemaPath = it.errSchemaPath + '/type';
}}
{{# def.error:'type' }}
}
{{?}}
{{?}}
{{? $breakOnError }}
if (errors === {{?$top}}0{{??}}errs_{{=$lvl}}{{?}}) {
{{ $closingBraces2 += '}'; }}
{{?}}
{{?}}
{{~}}
{{?}}
{{? $breakOnError }} {{= $closingBraces2 }} {{?}}
{{? $top }}
{{? $async }}
if (errors === 0) return data; {{ /* don't edit, used in replace */ }}
else throw new ValidationError(vErrors); {{ /* don't edit, used in replace */ }}
{{??}}
validate.errors = vErrors; {{ /* don't edit, used in replace */ }}
return errors === 0; {{ /* don't edit, used in replace */ }}
{{?}}
};
return validate;
{{??}}
var {{=$valid}} = errors === errs_{{=$lvl}};
{{?}}
{{
function $shouldUseGroup($rulesGroup) {
var rules = $rulesGroup.rules;
for (var i=0; i < rules.length; i++)
if ($shouldUseRule(rules[i]))
return true;
}
function $shouldUseRule($rule) {
return it.schema[$rule.keyword] !== undefined ||
($rule.implements && $ruleImplementsSomeKeyword($rule));
}
function $ruleImplementsSomeKeyword($rule) {
var impl = $rule.implements;
for (var i=0; i < impl.length; i++)
if (it.schema[impl[i]] !== undefined)
return true;
}
}}

View file

@ -0,0 +1,3 @@
These files are compiled dot templates from dot folder.
Do NOT edit them directly, edit the templates and run `npm run build` from main ajv folder.

View file

@ -0,0 +1,163 @@
'use strict';
module.exports = function generate__limit(it, $keyword, $ruleType) {
var out = ' ';
var $lvl = it.level;
var $dataLvl = it.dataLevel;
var $schema = it.schema[$keyword];
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
var $breakOnError = !it.opts.allErrors;
var $errorKeyword;
var $data = 'data' + ($dataLvl || '');
var $isData = it.opts.$data && $schema && $schema.$data,
$schemaValue;
if ($isData) {
out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; ';
$schemaValue = 'schema' + $lvl;
} else {
$schemaValue = $schema;
}
var $isMax = $keyword == 'maximum',
$exclusiveKeyword = $isMax ? 'exclusiveMaximum' : 'exclusiveMinimum',
$schemaExcl = it.schema[$exclusiveKeyword],
$isDataExcl = it.opts.$data && $schemaExcl && $schemaExcl.$data,
$op = $isMax ? '<' : '>',
$notOp = $isMax ? '>' : '<',
$errorKeyword = undefined;
if (!($isData || typeof $schema == 'number' || $schema === undefined)) {
throw new Error($keyword + ' must be number');
}
if (!($isDataExcl || $schemaExcl === undefined || typeof $schemaExcl == 'number' || typeof $schemaExcl == 'boolean')) {
throw new Error($exclusiveKeyword + ' must be number or boolean');
}
if ($isDataExcl) {
var $schemaValueExcl = it.util.getData($schemaExcl.$data, $dataLvl, it.dataPathArr),
$exclusive = 'exclusive' + $lvl,
$exclType = 'exclType' + $lvl,
$exclIsNumber = 'exclIsNumber' + $lvl,
$opExpr = 'op' + $lvl,
$opStr = '\' + ' + $opExpr + ' + \'';
out += ' var schemaExcl' + ($lvl) + ' = ' + ($schemaValueExcl) + '; ';
$schemaValueExcl = 'schemaExcl' + $lvl;
out += ' var ' + ($exclusive) + '; var ' + ($exclType) + ' = typeof ' + ($schemaValueExcl) + '; if (' + ($exclType) + ' != \'boolean\' && ' + ($exclType) + ' != \'undefined\' && ' + ($exclType) + ' != \'number\') { ';
var $errorKeyword = $exclusiveKeyword;
var $$outStack = $$outStack || [];
$$outStack.push(out);
out = ''; /* istanbul ignore else */
if (it.createErrors !== false) {
out += ' { keyword: \'' + ($errorKeyword || '_exclusiveLimit') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: {} ';
if (it.opts.messages !== false) {
out += ' , message: \'' + ($exclusiveKeyword) + ' should be boolean\' ';
}
if (it.opts.verbose) {
out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
}
out += ' } ';
} else {
out += ' {} ';
}
var __err = out;
out = $$outStack.pop();
if (!it.compositeRule && $breakOnError) {
/* istanbul ignore if */
if (it.async) {
out += ' throw new ValidationError([' + (__err) + ']); ';
} else {
out += ' validate.errors = [' + (__err) + ']; return false; ';
}
} else {
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
}
out += ' } else if ( ';
if ($isData) {
out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'number\') || ';
}
out += ' ' + ($exclType) + ' == \'number\' ? ( (' + ($exclusive) + ' = ' + ($schemaValue) + ' === undefined || ' + ($schemaValueExcl) + ' ' + ($op) + '= ' + ($schemaValue) + ') ? ' + ($data) + ' ' + ($notOp) + '= ' + ($schemaValueExcl) + ' : ' + ($data) + ' ' + ($notOp) + ' ' + ($schemaValue) + ' ) : ( (' + ($exclusive) + ' = ' + ($schemaValueExcl) + ' === true) ? ' + ($data) + ' ' + ($notOp) + '= ' + ($schemaValue) + ' : ' + ($data) + ' ' + ($notOp) + ' ' + ($schemaValue) + ' ) || ' + ($data) + ' !== ' + ($data) + ') { var op' + ($lvl) + ' = ' + ($exclusive) + ' ? \'' + ($op) + '\' : \'' + ($op) + '=\'; ';
if ($schema === undefined) {
$errorKeyword = $exclusiveKeyword;
$errSchemaPath = it.errSchemaPath + '/' + $exclusiveKeyword;
$schemaValue = $schemaValueExcl;
$isData = $isDataExcl;
}
} else {
var $exclIsNumber = typeof $schemaExcl == 'number',
$opStr = $op;
if ($exclIsNumber && $isData) {
var $opExpr = '\'' + $opStr + '\'';
out += ' if ( ';
if ($isData) {
out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'number\') || ';
}
out += ' ( ' + ($schemaValue) + ' === undefined || ' + ($schemaExcl) + ' ' + ($op) + '= ' + ($schemaValue) + ' ? ' + ($data) + ' ' + ($notOp) + '= ' + ($schemaExcl) + ' : ' + ($data) + ' ' + ($notOp) + ' ' + ($schemaValue) + ' ) || ' + ($data) + ' !== ' + ($data) + ') { ';
} else {
if ($exclIsNumber && $schema === undefined) {
$exclusive = true;
$errorKeyword = $exclusiveKeyword;
$errSchemaPath = it.errSchemaPath + '/' + $exclusiveKeyword;
$schemaValue = $schemaExcl;
$notOp += '=';
} else {
if ($exclIsNumber) $schemaValue = Math[$isMax ? 'min' : 'max']($schemaExcl, $schema);
if ($schemaExcl === ($exclIsNumber ? $schemaValue : true)) {
$exclusive = true;
$errorKeyword = $exclusiveKeyword;
$errSchemaPath = it.errSchemaPath + '/' + $exclusiveKeyword;
$notOp += '=';
} else {
$exclusive = false;
$opStr += '=';
}
}
var $opExpr = '\'' + $opStr + '\'';
out += ' if ( ';
if ($isData) {
out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'number\') || ';
}
out += ' ' + ($data) + ' ' + ($notOp) + ' ' + ($schemaValue) + ' || ' + ($data) + ' !== ' + ($data) + ') { ';
}
}
$errorKeyword = $errorKeyword || $keyword;
var $$outStack = $$outStack || [];
$$outStack.push(out);
out = ''; /* istanbul ignore else */
if (it.createErrors !== false) {
out += ' { keyword: \'' + ($errorKeyword || '_limit') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { comparison: ' + ($opExpr) + ', limit: ' + ($schemaValue) + ', exclusive: ' + ($exclusive) + ' } ';
if (it.opts.messages !== false) {
out += ' , message: \'should be ' + ($opStr) + ' ';
if ($isData) {
out += '\' + ' + ($schemaValue);
} else {
out += '' + ($schemaValue) + '\'';
}
}
if (it.opts.verbose) {
out += ' , schema: ';
if ($isData) {
out += 'validate.schema' + ($schemaPath);
} else {
out += '' + ($schema);
}
out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
}
out += ' } ';
} else {
out += ' {} ';
}
var __err = out;
out = $$outStack.pop();
if (!it.compositeRule && $breakOnError) {
/* istanbul ignore if */
if (it.async) {
out += ' throw new ValidationError([' + (__err) + ']); ';
} else {
out += ' validate.errors = [' + (__err) + ']; return false; ';
}
} else {
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
}
out += ' } ';
if ($breakOnError) {
out += ' else { ';
}
return out;
}

View file

@ -0,0 +1,80 @@
'use strict';
module.exports = function generate__limitItems(it, $keyword, $ruleType) {
var out = ' ';
var $lvl = it.level;
var $dataLvl = it.dataLevel;
var $schema = it.schema[$keyword];
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
var $breakOnError = !it.opts.allErrors;
var $errorKeyword;
var $data = 'data' + ($dataLvl || '');
var $isData = it.opts.$data && $schema && $schema.$data,
$schemaValue;
if ($isData) {
out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; ';
$schemaValue = 'schema' + $lvl;
} else {
$schemaValue = $schema;
}
if (!($isData || typeof $schema == 'number')) {
throw new Error($keyword + ' must be number');
}
var $op = $keyword == 'maxItems' ? '>' : '<';
out += 'if ( ';
if ($isData) {
out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'number\') || ';
}
out += ' ' + ($data) + '.length ' + ($op) + ' ' + ($schemaValue) + ') { ';
var $errorKeyword = $keyword;
var $$outStack = $$outStack || [];
$$outStack.push(out);
out = ''; /* istanbul ignore else */
if (it.createErrors !== false) {
out += ' { keyword: \'' + ($errorKeyword || '_limitItems') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { limit: ' + ($schemaValue) + ' } ';
if (it.opts.messages !== false) {
out += ' , message: \'should NOT have ';
if ($keyword == 'maxItems') {
out += 'more';
} else {
out += 'fewer';
}
out += ' than ';
if ($isData) {
out += '\' + ' + ($schemaValue) + ' + \'';
} else {
out += '' + ($schema);
}
out += ' items\' ';
}
if (it.opts.verbose) {
out += ' , schema: ';
if ($isData) {
out += 'validate.schema' + ($schemaPath);
} else {
out += '' + ($schema);
}
out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
}
out += ' } ';
} else {
out += ' {} ';
}
var __err = out;
out = $$outStack.pop();
if (!it.compositeRule && $breakOnError) {
/* istanbul ignore if */
if (it.async) {
out += ' throw new ValidationError([' + (__err) + ']); ';
} else {
out += ' validate.errors = [' + (__err) + ']; return false; ';
}
} else {
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
}
out += '} ';
if ($breakOnError) {
out += ' else { ';
}
return out;
}

View file

@ -0,0 +1,85 @@
'use strict';
module.exports = function generate__limitLength(it, $keyword, $ruleType) {
var out = ' ';
var $lvl = it.level;
var $dataLvl = it.dataLevel;
var $schema = it.schema[$keyword];
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
var $breakOnError = !it.opts.allErrors;
var $errorKeyword;
var $data = 'data' + ($dataLvl || '');
var $isData = it.opts.$data && $schema && $schema.$data,
$schemaValue;
if ($isData) {
out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; ';
$schemaValue = 'schema' + $lvl;
} else {
$schemaValue = $schema;
}
if (!($isData || typeof $schema == 'number')) {
throw new Error($keyword + ' must be number');
}
var $op = $keyword == 'maxLength' ? '>' : '<';
out += 'if ( ';
if ($isData) {
out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'number\') || ';
}
if (it.opts.unicode === false) {
out += ' ' + ($data) + '.length ';
} else {
out += ' ucs2length(' + ($data) + ') ';
}
out += ' ' + ($op) + ' ' + ($schemaValue) + ') { ';
var $errorKeyword = $keyword;
var $$outStack = $$outStack || [];
$$outStack.push(out);
out = ''; /* istanbul ignore else */
if (it.createErrors !== false) {
out += ' { keyword: \'' + ($errorKeyword || '_limitLength') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { limit: ' + ($schemaValue) + ' } ';
if (it.opts.messages !== false) {
out += ' , message: \'should NOT be ';
if ($keyword == 'maxLength') {
out += 'longer';
} else {
out += 'shorter';
}
out += ' than ';
if ($isData) {
out += '\' + ' + ($schemaValue) + ' + \'';
} else {
out += '' + ($schema);
}
out += ' characters\' ';
}
if (it.opts.verbose) {
out += ' , schema: ';
if ($isData) {
out += 'validate.schema' + ($schemaPath);
} else {
out += '' + ($schema);
}
out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
}
out += ' } ';
} else {
out += ' {} ';
}
var __err = out;
out = $$outStack.pop();
if (!it.compositeRule && $breakOnError) {
/* istanbul ignore if */
if (it.async) {
out += ' throw new ValidationError([' + (__err) + ']); ';
} else {
out += ' validate.errors = [' + (__err) + ']; return false; ';
}
} else {
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
}
out += '} ';
if ($breakOnError) {
out += ' else { ';
}
return out;
}

View file

@ -0,0 +1,80 @@
'use strict';
module.exports = function generate__limitProperties(it, $keyword, $ruleType) {
var out = ' ';
var $lvl = it.level;
var $dataLvl = it.dataLevel;
var $schema = it.schema[$keyword];
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
var $breakOnError = !it.opts.allErrors;
var $errorKeyword;
var $data = 'data' + ($dataLvl || '');
var $isData = it.opts.$data && $schema && $schema.$data,
$schemaValue;
if ($isData) {
out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; ';
$schemaValue = 'schema' + $lvl;
} else {
$schemaValue = $schema;
}
if (!($isData || typeof $schema == 'number')) {
throw new Error($keyword + ' must be number');
}
var $op = $keyword == 'maxProperties' ? '>' : '<';
out += 'if ( ';
if ($isData) {
out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'number\') || ';
}
out += ' Object.keys(' + ($data) + ').length ' + ($op) + ' ' + ($schemaValue) + ') { ';
var $errorKeyword = $keyword;
var $$outStack = $$outStack || [];
$$outStack.push(out);
out = ''; /* istanbul ignore else */
if (it.createErrors !== false) {
out += ' { keyword: \'' + ($errorKeyword || '_limitProperties') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { limit: ' + ($schemaValue) + ' } ';
if (it.opts.messages !== false) {
out += ' , message: \'should NOT have ';
if ($keyword == 'maxProperties') {
out += 'more';
} else {
out += 'fewer';
}
out += ' than ';
if ($isData) {
out += '\' + ' + ($schemaValue) + ' + \'';
} else {
out += '' + ($schema);
}
out += ' properties\' ';
}
if (it.opts.verbose) {
out += ' , schema: ';
if ($isData) {
out += 'validate.schema' + ($schemaPath);
} else {
out += '' + ($schema);
}
out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
}
out += ' } ';
} else {
out += ' {} ';
}
var __err = out;
out = $$outStack.pop();
if (!it.compositeRule && $breakOnError) {
/* istanbul ignore if */
if (it.async) {
out += ' throw new ValidationError([' + (__err) + ']); ';
} else {
out += ' validate.errors = [' + (__err) + ']; return false; ';
}
} else {
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
}
out += '} ';
if ($breakOnError) {
out += ' else { ';
}
return out;
}

View file

@ -0,0 +1,42 @@
'use strict';
module.exports = function generate_allOf(it, $keyword, $ruleType) {
var out = ' ';
var $schema = it.schema[$keyword];
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
var $breakOnError = !it.opts.allErrors;
var $it = it.util.copy(it);
var $closingBraces = '';
$it.level++;
var $nextValid = 'valid' + $it.level;
var $currentBaseId = $it.baseId,
$allSchemasEmpty = true;
var arr1 = $schema;
if (arr1) {
var $sch, $i = -1,
l1 = arr1.length - 1;
while ($i < l1) {
$sch = arr1[$i += 1];
if ((it.opts.strictKeywords ? (typeof $sch == 'object' && Object.keys($sch).length > 0) || $sch === false : it.util.schemaHasRules($sch, it.RULES.all))) {
$allSchemasEmpty = false;
$it.schema = $sch;
$it.schemaPath = $schemaPath + '[' + $i + ']';
$it.errSchemaPath = $errSchemaPath + '/' + $i;
out += ' ' + (it.validate($it)) + ' ';
$it.baseId = $currentBaseId;
if ($breakOnError) {
out += ' if (' + ($nextValid) + ') { ';
$closingBraces += '}';
}
}
}
}
if ($breakOnError) {
if ($allSchemasEmpty) {
out += ' if (true) { ';
} else {
out += ' ' + ($closingBraces.slice(0, -1)) + ' ';
}
}
return out;
}

View file

@ -0,0 +1,73 @@
'use strict';
module.exports = function generate_anyOf(it, $keyword, $ruleType) {
var out = ' ';
var $lvl = it.level;
var $dataLvl = it.dataLevel;
var $schema = it.schema[$keyword];
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
var $breakOnError = !it.opts.allErrors;
var $data = 'data' + ($dataLvl || '');
var $valid = 'valid' + $lvl;
var $errs = 'errs__' + $lvl;
var $it = it.util.copy(it);
var $closingBraces = '';
$it.level++;
var $nextValid = 'valid' + $it.level;
var $noEmptySchema = $schema.every(function($sch) {
return (it.opts.strictKeywords ? (typeof $sch == 'object' && Object.keys($sch).length > 0) || $sch === false : it.util.schemaHasRules($sch, it.RULES.all));
});
if ($noEmptySchema) {
var $currentBaseId = $it.baseId;
out += ' var ' + ($errs) + ' = errors; var ' + ($valid) + ' = false; ';
var $wasComposite = it.compositeRule;
it.compositeRule = $it.compositeRule = true;
var arr1 = $schema;
if (arr1) {
var $sch, $i = -1,
l1 = arr1.length - 1;
while ($i < l1) {
$sch = arr1[$i += 1];
$it.schema = $sch;
$it.schemaPath = $schemaPath + '[' + $i + ']';
$it.errSchemaPath = $errSchemaPath + '/' + $i;
out += ' ' + (it.validate($it)) + ' ';
$it.baseId = $currentBaseId;
out += ' ' + ($valid) + ' = ' + ($valid) + ' || ' + ($nextValid) + '; if (!' + ($valid) + ') { ';
$closingBraces += '}';
}
}
it.compositeRule = $it.compositeRule = $wasComposite;
out += ' ' + ($closingBraces) + ' if (!' + ($valid) + ') { var err = '; /* istanbul ignore else */
if (it.createErrors !== false) {
out += ' { keyword: \'' + ('anyOf') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: {} ';
if (it.opts.messages !== false) {
out += ' , message: \'should match some schema in anyOf\' ';
}
if (it.opts.verbose) {
out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
}
out += ' } ';
} else {
out += ' {} ';
}
out += '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
if (!it.compositeRule && $breakOnError) {
/* istanbul ignore if */
if (it.async) {
out += ' throw new ValidationError(vErrors); ';
} else {
out += ' validate.errors = vErrors; return false; ';
}
}
out += ' } else { errors = ' + ($errs) + '; if (vErrors !== null) { if (' + ($errs) + ') vErrors.length = ' + ($errs) + '; else vErrors = null; } ';
if (it.opts.allErrors) {
out += ' } ';
}
} else {
if ($breakOnError) {
out += ' if (true) { ';
}
}
return out;
}

View file

@ -0,0 +1,14 @@
'use strict';
module.exports = function generate_comment(it, $keyword, $ruleType) {
var out = ' ';
var $schema = it.schema[$keyword];
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
var $breakOnError = !it.opts.allErrors;
var $comment = it.util.toQuotedString($schema);
if (it.opts.$comment === true) {
out += ' console.log(' + ($comment) + ');';
} else if (typeof it.opts.$comment == 'function') {
out += ' self._opts.$comment(' + ($comment) + ', ' + (it.util.toQuotedString($errSchemaPath)) + ', validate.root.schema);';
}
return out;
}

View file

@ -0,0 +1,56 @@
'use strict';
module.exports = function generate_const(it, $keyword, $ruleType) {
var out = ' ';
var $lvl = it.level;
var $dataLvl = it.dataLevel;
var $schema = it.schema[$keyword];
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
var $breakOnError = !it.opts.allErrors;
var $data = 'data' + ($dataLvl || '');
var $valid = 'valid' + $lvl;
var $isData = it.opts.$data && $schema && $schema.$data,
$schemaValue;
if ($isData) {
out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; ';
$schemaValue = 'schema' + $lvl;
} else {
$schemaValue = $schema;
}
if (!$isData) {
out += ' var schema' + ($lvl) + ' = validate.schema' + ($schemaPath) + ';';
}
out += 'var ' + ($valid) + ' = equal(' + ($data) + ', schema' + ($lvl) + '); if (!' + ($valid) + ') { ';
var $$outStack = $$outStack || [];
$$outStack.push(out);
out = ''; /* istanbul ignore else */
if (it.createErrors !== false) {
out += ' { keyword: \'' + ('const') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { allowedValue: schema' + ($lvl) + ' } ';
if (it.opts.messages !== false) {
out += ' , message: \'should be equal to constant\' ';
}
if (it.opts.verbose) {
out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
}
out += ' } ';
} else {
out += ' {} ';
}
var __err = out;
out = $$outStack.pop();
if (!it.compositeRule && $breakOnError) {
/* istanbul ignore if */
if (it.async) {
out += ' throw new ValidationError([' + (__err) + ']); ';
} else {
out += ' validate.errors = [' + (__err) + ']; return false; ';
}
} else {
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
}
out += ' }';
if ($breakOnError) {
out += ' else { ';
}
return out;
}

View file

@ -0,0 +1,81 @@
'use strict';
module.exports = function generate_contains(it, $keyword, $ruleType) {
var out = ' ';
var $lvl = it.level;
var $dataLvl = it.dataLevel;
var $schema = it.schema[$keyword];
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
var $breakOnError = !it.opts.allErrors;
var $data = 'data' + ($dataLvl || '');
var $valid = 'valid' + $lvl;
var $errs = 'errs__' + $lvl;
var $it = it.util.copy(it);
var $closingBraces = '';
$it.level++;
var $nextValid = 'valid' + $it.level;
var $idx = 'i' + $lvl,
$dataNxt = $it.dataLevel = it.dataLevel + 1,
$nextData = 'data' + $dataNxt,
$currentBaseId = it.baseId,
$nonEmptySchema = (it.opts.strictKeywords ? (typeof $schema == 'object' && Object.keys($schema).length > 0) || $schema === false : it.util.schemaHasRules($schema, it.RULES.all));
out += 'var ' + ($errs) + ' = errors;var ' + ($valid) + ';';
if ($nonEmptySchema) {
var $wasComposite = it.compositeRule;
it.compositeRule = $it.compositeRule = true;
$it.schema = $schema;
$it.schemaPath = $schemaPath;
$it.errSchemaPath = $errSchemaPath;
out += ' var ' + ($nextValid) + ' = false; for (var ' + ($idx) + ' = 0; ' + ($idx) + ' < ' + ($data) + '.length; ' + ($idx) + '++) { ';
$it.errorPath = it.util.getPathExpr(it.errorPath, $idx, it.opts.jsonPointers, true);
var $passData = $data + '[' + $idx + ']';
$it.dataPathArr[$dataNxt] = $idx;
var $code = it.validate($it);
$it.baseId = $currentBaseId;
if (it.util.varOccurences($code, $nextData) < 2) {
out += ' ' + (it.util.varReplace($code, $nextData, $passData)) + ' ';
} else {
out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ' + ($code) + ' ';
}
out += ' if (' + ($nextValid) + ') break; } ';
it.compositeRule = $it.compositeRule = $wasComposite;
out += ' ' + ($closingBraces) + ' if (!' + ($nextValid) + ') {';
} else {
out += ' if (' + ($data) + '.length == 0) {';
}
var $$outStack = $$outStack || [];
$$outStack.push(out);
out = ''; /* istanbul ignore else */
if (it.createErrors !== false) {
out += ' { keyword: \'' + ('contains') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: {} ';
if (it.opts.messages !== false) {
out += ' , message: \'should contain a valid item\' ';
}
if (it.opts.verbose) {
out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
}
out += ' } ';
} else {
out += ' {} ';
}
var __err = out;
out = $$outStack.pop();
if (!it.compositeRule && $breakOnError) {
/* istanbul ignore if */
if (it.async) {
out += ' throw new ValidationError([' + (__err) + ']); ';
} else {
out += ' validate.errors = [' + (__err) + ']; return false; ';
}
} else {
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
}
out += ' } else { ';
if ($nonEmptySchema) {
out += ' errors = ' + ($errs) + '; if (vErrors !== null) { if (' + ($errs) + ') vErrors.length = ' + ($errs) + '; else vErrors = null; } ';
}
if (it.opts.allErrors) {
out += ' } ';
}
return out;
}

View file

@ -0,0 +1,228 @@
'use strict';
module.exports = function generate_custom(it, $keyword, $ruleType) {
var out = ' ';
var $lvl = it.level;
var $dataLvl = it.dataLevel;
var $schema = it.schema[$keyword];
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
var $breakOnError = !it.opts.allErrors;
var $errorKeyword;
var $data = 'data' + ($dataLvl || '');
var $valid = 'valid' + $lvl;
var $errs = 'errs__' + $lvl;
var $isData = it.opts.$data && $schema && $schema.$data,
$schemaValue;
if ($isData) {
out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; ';
$schemaValue = 'schema' + $lvl;
} else {
$schemaValue = $schema;
}
var $rule = this,
$definition = 'definition' + $lvl,
$rDef = $rule.definition,
$closingBraces = '';
var $compile, $inline, $macro, $ruleValidate, $validateCode;
if ($isData && $rDef.$data) {
$validateCode = 'keywordValidate' + $lvl;
var $validateSchema = $rDef.validateSchema;
out += ' var ' + ($definition) + ' = RULES.custom[\'' + ($keyword) + '\'].definition; var ' + ($validateCode) + ' = ' + ($definition) + '.validate;';
} else {
$ruleValidate = it.useCustomRule($rule, $schema, it.schema, it);
if (!$ruleValidate) return;
$schemaValue = 'validate.schema' + $schemaPath;
$validateCode = $ruleValidate.code;
$compile = $rDef.compile;
$inline = $rDef.inline;
$macro = $rDef.macro;
}
var $ruleErrs = $validateCode + '.errors',
$i = 'i' + $lvl,
$ruleErr = 'ruleErr' + $lvl,
$asyncKeyword = $rDef.async;
if ($asyncKeyword && !it.async) throw new Error('async keyword in sync schema');
if (!($inline || $macro)) {
out += '' + ($ruleErrs) + ' = null;';
}
out += 'var ' + ($errs) + ' = errors;var ' + ($valid) + ';';
if ($isData && $rDef.$data) {
$closingBraces += '}';
out += ' if (' + ($schemaValue) + ' === undefined) { ' + ($valid) + ' = true; } else { ';
if ($validateSchema) {
$closingBraces += '}';
out += ' ' + ($valid) + ' = ' + ($definition) + '.validateSchema(' + ($schemaValue) + '); if (' + ($valid) + ') { ';
}
}
if ($inline) {
if ($rDef.statements) {
out += ' ' + ($ruleValidate.validate) + ' ';
} else {
out += ' ' + ($valid) + ' = ' + ($ruleValidate.validate) + '; ';
}
} else if ($macro) {
var $it = it.util.copy(it);
var $closingBraces = '';
$it.level++;
var $nextValid = 'valid' + $it.level;
$it.schema = $ruleValidate.validate;
$it.schemaPath = '';
var $wasComposite = it.compositeRule;
it.compositeRule = $it.compositeRule = true;
var $code = it.validate($it).replace(/validate\.schema/g, $validateCode);
it.compositeRule = $it.compositeRule = $wasComposite;
out += ' ' + ($code);
} else {
var $$outStack = $$outStack || [];
$$outStack.push(out);
out = '';
out += ' ' + ($validateCode) + '.call( ';
if (it.opts.passContext) {
out += 'this';
} else {
out += 'self';
}
if ($compile || $rDef.schema === false) {
out += ' , ' + ($data) + ' ';
} else {
out += ' , ' + ($schemaValue) + ' , ' + ($data) + ' , validate.schema' + (it.schemaPath) + ' ';
}
out += ' , (dataPath || \'\')';
if (it.errorPath != '""') {
out += ' + ' + (it.errorPath);
}
var $parentData = $dataLvl ? 'data' + (($dataLvl - 1) || '') : 'parentData',
$parentDataProperty = $dataLvl ? it.dataPathArr[$dataLvl] : 'parentDataProperty';
out += ' , ' + ($parentData) + ' , ' + ($parentDataProperty) + ' , rootData ) ';
var def_callRuleValidate = out;
out = $$outStack.pop();
if ($rDef.errors === false) {
out += ' ' + ($valid) + ' = ';
if ($asyncKeyword) {
out += 'await ';
}
out += '' + (def_callRuleValidate) + '; ';
} else {
if ($asyncKeyword) {
$ruleErrs = 'customErrors' + $lvl;
out += ' var ' + ($ruleErrs) + ' = null; try { ' + ($valid) + ' = await ' + (def_callRuleValidate) + '; } catch (e) { ' + ($valid) + ' = false; if (e instanceof ValidationError) ' + ($ruleErrs) + ' = e.errors; else throw e; } ';
} else {
out += ' ' + ($ruleErrs) + ' = null; ' + ($valid) + ' = ' + (def_callRuleValidate) + '; ';
}
}
}
if ($rDef.modifying) {
out += ' if (' + ($parentData) + ') ' + ($data) + ' = ' + ($parentData) + '[' + ($parentDataProperty) + '];';
}
out += '' + ($closingBraces);
if ($rDef.valid) {
if ($breakOnError) {
out += ' if (true) { ';
}
} else {
out += ' if ( ';
if ($rDef.valid === undefined) {
out += ' !';
if ($macro) {
out += '' + ($nextValid);
} else {
out += '' + ($valid);
}
} else {
out += ' ' + (!$rDef.valid) + ' ';
}
out += ') { ';
$errorKeyword = $rule.keyword;
var $$outStack = $$outStack || [];
$$outStack.push(out);
out = '';
var $$outStack = $$outStack || [];
$$outStack.push(out);
out = ''; /* istanbul ignore else */
if (it.createErrors !== false) {
out += ' { keyword: \'' + ($errorKeyword || 'custom') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { keyword: \'' + ($rule.keyword) + '\' } ';
if (it.opts.messages !== false) {
out += ' , message: \'should pass "' + ($rule.keyword) + '" keyword validation\' ';
}
if (it.opts.verbose) {
out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
}
out += ' } ';
} else {
out += ' {} ';
}
var __err = out;
out = $$outStack.pop();
if (!it.compositeRule && $breakOnError) {
/* istanbul ignore if */
if (it.async) {
out += ' throw new ValidationError([' + (__err) + ']); ';
} else {
out += ' validate.errors = [' + (__err) + ']; return false; ';
}
} else {
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
}
var def_customError = out;
out = $$outStack.pop();
if ($inline) {
if ($rDef.errors) {
if ($rDef.errors != 'full') {
out += ' for (var ' + ($i) + '=' + ($errs) + '; ' + ($i) + '<errors; ' + ($i) + '++) { var ' + ($ruleErr) + ' = vErrors[' + ($i) + ']; if (' + ($ruleErr) + '.dataPath === undefined) ' + ($ruleErr) + '.dataPath = (dataPath || \'\') + ' + (it.errorPath) + '; if (' + ($ruleErr) + '.schemaPath === undefined) { ' + ($ruleErr) + '.schemaPath = "' + ($errSchemaPath) + '"; } ';
if (it.opts.verbose) {
out += ' ' + ($ruleErr) + '.schema = ' + ($schemaValue) + '; ' + ($ruleErr) + '.data = ' + ($data) + '; ';
}
out += ' } ';
}
} else {
if ($rDef.errors === false) {
out += ' ' + (def_customError) + ' ';
} else {
out += ' if (' + ($errs) + ' == errors) { ' + (def_customError) + ' } else { for (var ' + ($i) + '=' + ($errs) + '; ' + ($i) + '<errors; ' + ($i) + '++) { var ' + ($ruleErr) + ' = vErrors[' + ($i) + ']; if (' + ($ruleErr) + '.dataPath === undefined) ' + ($ruleErr) + '.dataPath = (dataPath || \'\') + ' + (it.errorPath) + '; if (' + ($ruleErr) + '.schemaPath === undefined) { ' + ($ruleErr) + '.schemaPath = "' + ($errSchemaPath) + '"; } ';
if (it.opts.verbose) {
out += ' ' + ($ruleErr) + '.schema = ' + ($schemaValue) + '; ' + ($ruleErr) + '.data = ' + ($data) + '; ';
}
out += ' } } ';
}
}
} else if ($macro) {
out += ' var err = '; /* istanbul ignore else */
if (it.createErrors !== false) {
out += ' { keyword: \'' + ($errorKeyword || 'custom') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { keyword: \'' + ($rule.keyword) + '\' } ';
if (it.opts.messages !== false) {
out += ' , message: \'should pass "' + ($rule.keyword) + '" keyword validation\' ';
}
if (it.opts.verbose) {
out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
}
out += ' } ';
} else {
out += ' {} ';
}
out += '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
if (!it.compositeRule && $breakOnError) {
/* istanbul ignore if */
if (it.async) {
out += ' throw new ValidationError(vErrors); ';
} else {
out += ' validate.errors = vErrors; return false; ';
}
}
} else {
if ($rDef.errors === false) {
out += ' ' + (def_customError) + ' ';
} else {
out += ' if (Array.isArray(' + ($ruleErrs) + ')) { if (vErrors === null) vErrors = ' + ($ruleErrs) + '; else vErrors = vErrors.concat(' + ($ruleErrs) + '); errors = vErrors.length; for (var ' + ($i) + '=' + ($errs) + '; ' + ($i) + '<errors; ' + ($i) + '++) { var ' + ($ruleErr) + ' = vErrors[' + ($i) + ']; if (' + ($ruleErr) + '.dataPath === undefined) ' + ($ruleErr) + '.dataPath = (dataPath || \'\') + ' + (it.errorPath) + '; ' + ($ruleErr) + '.schemaPath = "' + ($errSchemaPath) + '"; ';
if (it.opts.verbose) {
out += ' ' + ($ruleErr) + '.schema = ' + ($schemaValue) + '; ' + ($ruleErr) + '.data = ' + ($data) + '; ';
}
out += ' } } else { ' + (def_customError) + ' } ';
}
}
out += ' } ';
if ($breakOnError) {
out += ' else { ';
}
}
return out;
}

View file

@ -0,0 +1,168 @@
'use strict';
module.exports = function generate_dependencies(it, $keyword, $ruleType) {
var out = ' ';
var $lvl = it.level;
var $dataLvl = it.dataLevel;
var $schema = it.schema[$keyword];
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
var $breakOnError = !it.opts.allErrors;
var $data = 'data' + ($dataLvl || '');
var $errs = 'errs__' + $lvl;
var $it = it.util.copy(it);
var $closingBraces = '';
$it.level++;
var $nextValid = 'valid' + $it.level;
var $schemaDeps = {},
$propertyDeps = {},
$ownProperties = it.opts.ownProperties;
for ($property in $schema) {
if ($property == '__proto__') continue;
var $sch = $schema[$property];
var $deps = Array.isArray($sch) ? $propertyDeps : $schemaDeps;
$deps[$property] = $sch;
}
out += 'var ' + ($errs) + ' = errors;';
var $currentErrorPath = it.errorPath;
out += 'var missing' + ($lvl) + ';';
for (var $property in $propertyDeps) {
$deps = $propertyDeps[$property];
if ($deps.length) {
out += ' if ( ' + ($data) + (it.util.getProperty($property)) + ' !== undefined ';
if ($ownProperties) {
out += ' && Object.prototype.hasOwnProperty.call(' + ($data) + ', \'' + (it.util.escapeQuotes($property)) + '\') ';
}
if ($breakOnError) {
out += ' && ( ';
var arr1 = $deps;
if (arr1) {
var $propertyKey, $i = -1,
l1 = arr1.length - 1;
while ($i < l1) {
$propertyKey = arr1[$i += 1];
if ($i) {
out += ' || ';
}
var $prop = it.util.getProperty($propertyKey),
$useData = $data + $prop;
out += ' ( ( ' + ($useData) + ' === undefined ';
if ($ownProperties) {
out += ' || ! Object.prototype.hasOwnProperty.call(' + ($data) + ', \'' + (it.util.escapeQuotes($propertyKey)) + '\') ';
}
out += ') && (missing' + ($lvl) + ' = ' + (it.util.toQuotedString(it.opts.jsonPointers ? $propertyKey : $prop)) + ') ) ';
}
}
out += ')) { ';
var $propertyPath = 'missing' + $lvl,
$missingProperty = '\' + ' + $propertyPath + ' + \'';
if (it.opts._errorDataPathProperty) {
it.errorPath = it.opts.jsonPointers ? it.util.getPathExpr($currentErrorPath, $propertyPath, true) : $currentErrorPath + ' + ' + $propertyPath;
}
var $$outStack = $$outStack || [];
$$outStack.push(out);
out = ''; /* istanbul ignore else */
if (it.createErrors !== false) {
out += ' { keyword: \'' + ('dependencies') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { property: \'' + (it.util.escapeQuotes($property)) + '\', missingProperty: \'' + ($missingProperty) + '\', depsCount: ' + ($deps.length) + ', deps: \'' + (it.util.escapeQuotes($deps.length == 1 ? $deps[0] : $deps.join(", "))) + '\' } ';
if (it.opts.messages !== false) {
out += ' , message: \'should have ';
if ($deps.length == 1) {
out += 'property ' + (it.util.escapeQuotes($deps[0]));
} else {
out += 'properties ' + (it.util.escapeQuotes($deps.join(", ")));
}
out += ' when property ' + (it.util.escapeQuotes($property)) + ' is present\' ';
}
if (it.opts.verbose) {
out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
}
out += ' } ';
} else {
out += ' {} ';
}
var __err = out;
out = $$outStack.pop();
if (!it.compositeRule && $breakOnError) {
/* istanbul ignore if */
if (it.async) {
out += ' throw new ValidationError([' + (__err) + ']); ';
} else {
out += ' validate.errors = [' + (__err) + ']; return false; ';
}
} else {
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
}
} else {
out += ' ) { ';
var arr2 = $deps;
if (arr2) {
var $propertyKey, i2 = -1,
l2 = arr2.length - 1;
while (i2 < l2) {
$propertyKey = arr2[i2 += 1];
var $prop = it.util.getProperty($propertyKey),
$missingProperty = it.util.escapeQuotes($propertyKey),
$useData = $data + $prop;
if (it.opts._errorDataPathProperty) {
it.errorPath = it.util.getPath($currentErrorPath, $propertyKey, it.opts.jsonPointers);
}
out += ' if ( ' + ($useData) + ' === undefined ';
if ($ownProperties) {
out += ' || ! Object.prototype.hasOwnProperty.call(' + ($data) + ', \'' + (it.util.escapeQuotes($propertyKey)) + '\') ';
}
out += ') { var err = '; /* istanbul ignore else */
if (it.createErrors !== false) {
out += ' { keyword: \'' + ('dependencies') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { property: \'' + (it.util.escapeQuotes($property)) + '\', missingProperty: \'' + ($missingProperty) + '\', depsCount: ' + ($deps.length) + ', deps: \'' + (it.util.escapeQuotes($deps.length == 1 ? $deps[0] : $deps.join(", "))) + '\' } ';
if (it.opts.messages !== false) {
out += ' , message: \'should have ';
if ($deps.length == 1) {
out += 'property ' + (it.util.escapeQuotes($deps[0]));
} else {
out += 'properties ' + (it.util.escapeQuotes($deps.join(", ")));
}
out += ' when property ' + (it.util.escapeQuotes($property)) + ' is present\' ';
}
if (it.opts.verbose) {
out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
}
out += ' } ';
} else {
out += ' {} ';
}
out += '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; } ';
}
}
}
out += ' } ';
if ($breakOnError) {
$closingBraces += '}';
out += ' else { ';
}
}
}
it.errorPath = $currentErrorPath;
var $currentBaseId = $it.baseId;
for (var $property in $schemaDeps) {
var $sch = $schemaDeps[$property];
if ((it.opts.strictKeywords ? (typeof $sch == 'object' && Object.keys($sch).length > 0) || $sch === false : it.util.schemaHasRules($sch, it.RULES.all))) {
out += ' ' + ($nextValid) + ' = true; if ( ' + ($data) + (it.util.getProperty($property)) + ' !== undefined ';
if ($ownProperties) {
out += ' && Object.prototype.hasOwnProperty.call(' + ($data) + ', \'' + (it.util.escapeQuotes($property)) + '\') ';
}
out += ') { ';
$it.schema = $sch;
$it.schemaPath = $schemaPath + it.util.getProperty($property);
$it.errSchemaPath = $errSchemaPath + '/' + it.util.escapeFragment($property);
out += ' ' + (it.validate($it)) + ' ';
$it.baseId = $currentBaseId;
out += ' } ';
if ($breakOnError) {
out += ' if (' + ($nextValid) + ') { ';
$closingBraces += '}';
}
}
}
if ($breakOnError) {
out += ' ' + ($closingBraces) + ' if (' + ($errs) + ' == errors) {';
}
return out;
}

View file

@ -0,0 +1,66 @@
'use strict';
module.exports = function generate_enum(it, $keyword, $ruleType) {
var out = ' ';
var $lvl = it.level;
var $dataLvl = it.dataLevel;
var $schema = it.schema[$keyword];
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
var $breakOnError = !it.opts.allErrors;
var $data = 'data' + ($dataLvl || '');
var $valid = 'valid' + $lvl;
var $isData = it.opts.$data && $schema && $schema.$data,
$schemaValue;
if ($isData) {
out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; ';
$schemaValue = 'schema' + $lvl;
} else {
$schemaValue = $schema;
}
var $i = 'i' + $lvl,
$vSchema = 'schema' + $lvl;
if (!$isData) {
out += ' var ' + ($vSchema) + ' = validate.schema' + ($schemaPath) + ';';
}
out += 'var ' + ($valid) + ';';
if ($isData) {
out += ' if (schema' + ($lvl) + ' === undefined) ' + ($valid) + ' = true; else if (!Array.isArray(schema' + ($lvl) + ')) ' + ($valid) + ' = false; else {';
}
out += '' + ($valid) + ' = false;for (var ' + ($i) + '=0; ' + ($i) + '<' + ($vSchema) + '.length; ' + ($i) + '++) if (equal(' + ($data) + ', ' + ($vSchema) + '[' + ($i) + '])) { ' + ($valid) + ' = true; break; }';
if ($isData) {
out += ' } ';
}
out += ' if (!' + ($valid) + ') { ';
var $$outStack = $$outStack || [];
$$outStack.push(out);
out = ''; /* istanbul ignore else */
if (it.createErrors !== false) {
out += ' { keyword: \'' + ('enum') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { allowedValues: schema' + ($lvl) + ' } ';
if (it.opts.messages !== false) {
out += ' , message: \'should be equal to one of the allowed values\' ';
}
if (it.opts.verbose) {
out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
}
out += ' } ';
} else {
out += ' {} ';
}
var __err = out;
out = $$outStack.pop();
if (!it.compositeRule && $breakOnError) {
/* istanbul ignore if */
if (it.async) {
out += ' throw new ValidationError([' + (__err) + ']); ';
} else {
out += ' validate.errors = [' + (__err) + ']; return false; ';
}
} else {
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
}
out += ' }';
if ($breakOnError) {
out += ' else { ';
}
return out;
}

View file

@ -0,0 +1,150 @@
'use strict';
module.exports = function generate_format(it, $keyword, $ruleType) {
var out = ' ';
var $lvl = it.level;
var $dataLvl = it.dataLevel;
var $schema = it.schema[$keyword];
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
var $breakOnError = !it.opts.allErrors;
var $data = 'data' + ($dataLvl || '');
if (it.opts.format === false) {
if ($breakOnError) {
out += ' if (true) { ';
}
return out;
}
var $isData = it.opts.$data && $schema && $schema.$data,
$schemaValue;
if ($isData) {
out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; ';
$schemaValue = 'schema' + $lvl;
} else {
$schemaValue = $schema;
}
var $unknownFormats = it.opts.unknownFormats,
$allowUnknown = Array.isArray($unknownFormats);
if ($isData) {
var $format = 'format' + $lvl,
$isObject = 'isObject' + $lvl,
$formatType = 'formatType' + $lvl;
out += ' var ' + ($format) + ' = formats[' + ($schemaValue) + ']; var ' + ($isObject) + ' = typeof ' + ($format) + ' == \'object\' && !(' + ($format) + ' instanceof RegExp) && ' + ($format) + '.validate; var ' + ($formatType) + ' = ' + ($isObject) + ' && ' + ($format) + '.type || \'string\'; if (' + ($isObject) + ') { ';
if (it.async) {
out += ' var async' + ($lvl) + ' = ' + ($format) + '.async; ';
}
out += ' ' + ($format) + ' = ' + ($format) + '.validate; } if ( ';
if ($isData) {
out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'string\') || ';
}
out += ' (';
if ($unknownFormats != 'ignore') {
out += ' (' + ($schemaValue) + ' && !' + ($format) + ' ';
if ($allowUnknown) {
out += ' && self._opts.unknownFormats.indexOf(' + ($schemaValue) + ') == -1 ';
}
out += ') || ';
}
out += ' (' + ($format) + ' && ' + ($formatType) + ' == \'' + ($ruleType) + '\' && !(typeof ' + ($format) + ' == \'function\' ? ';
if (it.async) {
out += ' (async' + ($lvl) + ' ? await ' + ($format) + '(' + ($data) + ') : ' + ($format) + '(' + ($data) + ')) ';
} else {
out += ' ' + ($format) + '(' + ($data) + ') ';
}
out += ' : ' + ($format) + '.test(' + ($data) + '))))) {';
} else {
var $format = it.formats[$schema];
if (!$format) {
if ($unknownFormats == 'ignore') {
it.logger.warn('unknown format "' + $schema + '" ignored in schema at path "' + it.errSchemaPath + '"');
if ($breakOnError) {
out += ' if (true) { ';
}
return out;
} else if ($allowUnknown && $unknownFormats.indexOf($schema) >= 0) {
if ($breakOnError) {
out += ' if (true) { ';
}
return out;
} else {
throw new Error('unknown format "' + $schema + '" is used in schema at path "' + it.errSchemaPath + '"');
}
}
var $isObject = typeof $format == 'object' && !($format instanceof RegExp) && $format.validate;
var $formatType = $isObject && $format.type || 'string';
if ($isObject) {
var $async = $format.async === true;
$format = $format.validate;
}
if ($formatType != $ruleType) {
if ($breakOnError) {
out += ' if (true) { ';
}
return out;
}
if ($async) {
if (!it.async) throw new Error('async format in sync schema');
var $formatRef = 'formats' + it.util.getProperty($schema) + '.validate';
out += ' if (!(await ' + ($formatRef) + '(' + ($data) + '))) { ';
} else {
out += ' if (! ';
var $formatRef = 'formats' + it.util.getProperty($schema);
if ($isObject) $formatRef += '.validate';
if (typeof $format == 'function') {
out += ' ' + ($formatRef) + '(' + ($data) + ') ';
} else {
out += ' ' + ($formatRef) + '.test(' + ($data) + ') ';
}
out += ') { ';
}
}
var $$outStack = $$outStack || [];
$$outStack.push(out);
out = ''; /* istanbul ignore else */
if (it.createErrors !== false) {
out += ' { keyword: \'' + ('format') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { format: ';
if ($isData) {
out += '' + ($schemaValue);
} else {
out += '' + (it.util.toQuotedString($schema));
}
out += ' } ';
if (it.opts.messages !== false) {
out += ' , message: \'should match format "';
if ($isData) {
out += '\' + ' + ($schemaValue) + ' + \'';
} else {
out += '' + (it.util.escapeQuotes($schema));
}
out += '"\' ';
}
if (it.opts.verbose) {
out += ' , schema: ';
if ($isData) {
out += 'validate.schema' + ($schemaPath);
} else {
out += '' + (it.util.toQuotedString($schema));
}
out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
}
out += ' } ';
} else {
out += ' {} ';
}
var __err = out;
out = $$outStack.pop();
if (!it.compositeRule && $breakOnError) {
/* istanbul ignore if */
if (it.async) {
out += ' throw new ValidationError([' + (__err) + ']); ';
} else {
out += ' validate.errors = [' + (__err) + ']; return false; ';
}
} else {
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
}
out += ' } ';
if ($breakOnError) {
out += ' else { ';
}
return out;
}

View file

@ -0,0 +1,103 @@
'use strict';
module.exports = function generate_if(it, $keyword, $ruleType) {
var out = ' ';
var $lvl = it.level;
var $dataLvl = it.dataLevel;
var $schema = it.schema[$keyword];
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
var $breakOnError = !it.opts.allErrors;
var $data = 'data' + ($dataLvl || '');
var $valid = 'valid' + $lvl;
var $errs = 'errs__' + $lvl;
var $it = it.util.copy(it);
$it.level++;
var $nextValid = 'valid' + $it.level;
var $thenSch = it.schema['then'],
$elseSch = it.schema['else'],
$thenPresent = $thenSch !== undefined && (it.opts.strictKeywords ? (typeof $thenSch == 'object' && Object.keys($thenSch).length > 0) || $thenSch === false : it.util.schemaHasRules($thenSch, it.RULES.all)),
$elsePresent = $elseSch !== undefined && (it.opts.strictKeywords ? (typeof $elseSch == 'object' && Object.keys($elseSch).length > 0) || $elseSch === false : it.util.schemaHasRules($elseSch, it.RULES.all)),
$currentBaseId = $it.baseId;
if ($thenPresent || $elsePresent) {
var $ifClause;
$it.createErrors = false;
$it.schema = $schema;
$it.schemaPath = $schemaPath;
$it.errSchemaPath = $errSchemaPath;
out += ' var ' + ($errs) + ' = errors; var ' + ($valid) + ' = true; ';
var $wasComposite = it.compositeRule;
it.compositeRule = $it.compositeRule = true;
out += ' ' + (it.validate($it)) + ' ';
$it.baseId = $currentBaseId;
$it.createErrors = true;
out += ' errors = ' + ($errs) + '; if (vErrors !== null) { if (' + ($errs) + ') vErrors.length = ' + ($errs) + '; else vErrors = null; } ';
it.compositeRule = $it.compositeRule = $wasComposite;
if ($thenPresent) {
out += ' if (' + ($nextValid) + ') { ';
$it.schema = it.schema['then'];
$it.schemaPath = it.schemaPath + '.then';
$it.errSchemaPath = it.errSchemaPath + '/then';
out += ' ' + (it.validate($it)) + ' ';
$it.baseId = $currentBaseId;
out += ' ' + ($valid) + ' = ' + ($nextValid) + '; ';
if ($thenPresent && $elsePresent) {
$ifClause = 'ifClause' + $lvl;
out += ' var ' + ($ifClause) + ' = \'then\'; ';
} else {
$ifClause = '\'then\'';
}
out += ' } ';
if ($elsePresent) {
out += ' else { ';
}
} else {
out += ' if (!' + ($nextValid) + ') { ';
}
if ($elsePresent) {
$it.schema = it.schema['else'];
$it.schemaPath = it.schemaPath + '.else';
$it.errSchemaPath = it.errSchemaPath + '/else';
out += ' ' + (it.validate($it)) + ' ';
$it.baseId = $currentBaseId;
out += ' ' + ($valid) + ' = ' + ($nextValid) + '; ';
if ($thenPresent && $elsePresent) {
$ifClause = 'ifClause' + $lvl;
out += ' var ' + ($ifClause) + ' = \'else\'; ';
} else {
$ifClause = '\'else\'';
}
out += ' } ';
}
out += ' if (!' + ($valid) + ') { var err = '; /* istanbul ignore else */
if (it.createErrors !== false) {
out += ' { keyword: \'' + ('if') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { failingKeyword: ' + ($ifClause) + ' } ';
if (it.opts.messages !== false) {
out += ' , message: \'should match "\' + ' + ($ifClause) + ' + \'" schema\' ';
}
if (it.opts.verbose) {
out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
}
out += ' } ';
} else {
out += ' {} ';
}
out += '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
if (!it.compositeRule && $breakOnError) {
/* istanbul ignore if */
if (it.async) {
out += ' throw new ValidationError(vErrors); ';
} else {
out += ' validate.errors = vErrors; return false; ';
}
}
out += ' } ';
if ($breakOnError) {
out += ' else { ';
}
} else {
if ($breakOnError) {
out += ' if (true) { ';
}
}
return out;
}

View file

@ -0,0 +1,33 @@
'use strict';
//all requires must be explicit because browserify won't work with dynamic requires
module.exports = {
'$ref': require('./ref'),
allOf: require('./allOf'),
anyOf: require('./anyOf'),
'$comment': require('./comment'),
const: require('./const'),
contains: require('./contains'),
dependencies: require('./dependencies'),
'enum': require('./enum'),
format: require('./format'),
'if': require('./if'),
items: require('./items'),
maximum: require('./_limit'),
minimum: require('./_limit'),
maxItems: require('./_limitItems'),
minItems: require('./_limitItems'),
maxLength: require('./_limitLength'),
minLength: require('./_limitLength'),
maxProperties: require('./_limitProperties'),
minProperties: require('./_limitProperties'),
multipleOf: require('./multipleOf'),
not: require('./not'),
oneOf: require('./oneOf'),
pattern: require('./pattern'),
properties: require('./properties'),
propertyNames: require('./propertyNames'),
required: require('./required'),
uniqueItems: require('./uniqueItems'),
validate: require('./validate')
};

View file

@ -0,0 +1,140 @@
'use strict';
module.exports = function generate_items(it, $keyword, $ruleType) {
var out = ' ';
var $lvl = it.level;
var $dataLvl = it.dataLevel;
var $schema = it.schema[$keyword];
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
var $breakOnError = !it.opts.allErrors;
var $data = 'data' + ($dataLvl || '');
var $valid = 'valid' + $lvl;
var $errs = 'errs__' + $lvl;
var $it = it.util.copy(it);
var $closingBraces = '';
$it.level++;
var $nextValid = 'valid' + $it.level;
var $idx = 'i' + $lvl,
$dataNxt = $it.dataLevel = it.dataLevel + 1,
$nextData = 'data' + $dataNxt,
$currentBaseId = it.baseId;
out += 'var ' + ($errs) + ' = errors;var ' + ($valid) + ';';
if (Array.isArray($schema)) {
var $additionalItems = it.schema.additionalItems;
if ($additionalItems === false) {
out += ' ' + ($valid) + ' = ' + ($data) + '.length <= ' + ($schema.length) + '; ';
var $currErrSchemaPath = $errSchemaPath;
$errSchemaPath = it.errSchemaPath + '/additionalItems';
out += ' if (!' + ($valid) + ') { ';
var $$outStack = $$outStack || [];
$$outStack.push(out);
out = ''; /* istanbul ignore else */
if (it.createErrors !== false) {
out += ' { keyword: \'' + ('additionalItems') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { limit: ' + ($schema.length) + ' } ';
if (it.opts.messages !== false) {
out += ' , message: \'should NOT have more than ' + ($schema.length) + ' items\' ';
}
if (it.opts.verbose) {
out += ' , schema: false , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
}
out += ' } ';
} else {
out += ' {} ';
}
var __err = out;
out = $$outStack.pop();
if (!it.compositeRule && $breakOnError) {
/* istanbul ignore if */
if (it.async) {
out += ' throw new ValidationError([' + (__err) + ']); ';
} else {
out += ' validate.errors = [' + (__err) + ']; return false; ';
}
} else {
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
}
out += ' } ';
$errSchemaPath = $currErrSchemaPath;
if ($breakOnError) {
$closingBraces += '}';
out += ' else { ';
}
}
var arr1 = $schema;
if (arr1) {
var $sch, $i = -1,
l1 = arr1.length - 1;
while ($i < l1) {
$sch = arr1[$i += 1];
if ((it.opts.strictKeywords ? (typeof $sch == 'object' && Object.keys($sch).length > 0) || $sch === false : it.util.schemaHasRules($sch, it.RULES.all))) {
out += ' ' + ($nextValid) + ' = true; if (' + ($data) + '.length > ' + ($i) + ') { ';
var $passData = $data + '[' + $i + ']';
$it.schema = $sch;
$it.schemaPath = $schemaPath + '[' + $i + ']';
$it.errSchemaPath = $errSchemaPath + '/' + $i;
$it.errorPath = it.util.getPathExpr(it.errorPath, $i, it.opts.jsonPointers, true);
$it.dataPathArr[$dataNxt] = $i;
var $code = it.validate($it);
$it.baseId = $currentBaseId;
if (it.util.varOccurences($code, $nextData) < 2) {
out += ' ' + (it.util.varReplace($code, $nextData, $passData)) + ' ';
} else {
out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ' + ($code) + ' ';
}
out += ' } ';
if ($breakOnError) {
out += ' if (' + ($nextValid) + ') { ';
$closingBraces += '}';
}
}
}
}
if (typeof $additionalItems == 'object' && (it.opts.strictKeywords ? (typeof $additionalItems == 'object' && Object.keys($additionalItems).length > 0) || $additionalItems === false : it.util.schemaHasRules($additionalItems, it.RULES.all))) {
$it.schema = $additionalItems;
$it.schemaPath = it.schemaPath + '.additionalItems';
$it.errSchemaPath = it.errSchemaPath + '/additionalItems';
out += ' ' + ($nextValid) + ' = true; if (' + ($data) + '.length > ' + ($schema.length) + ') { for (var ' + ($idx) + ' = ' + ($schema.length) + '; ' + ($idx) + ' < ' + ($data) + '.length; ' + ($idx) + '++) { ';
$it.errorPath = it.util.getPathExpr(it.errorPath, $idx, it.opts.jsonPointers, true);
var $passData = $data + '[' + $idx + ']';
$it.dataPathArr[$dataNxt] = $idx;
var $code = it.validate($it);
$it.baseId = $currentBaseId;
if (it.util.varOccurences($code, $nextData) < 2) {
out += ' ' + (it.util.varReplace($code, $nextData, $passData)) + ' ';
} else {
out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ' + ($code) + ' ';
}
if ($breakOnError) {
out += ' if (!' + ($nextValid) + ') break; ';
}
out += ' } } ';
if ($breakOnError) {
out += ' if (' + ($nextValid) + ') { ';
$closingBraces += '}';
}
}
} else if ((it.opts.strictKeywords ? (typeof $schema == 'object' && Object.keys($schema).length > 0) || $schema === false : it.util.schemaHasRules($schema, it.RULES.all))) {
$it.schema = $schema;
$it.schemaPath = $schemaPath;
$it.errSchemaPath = $errSchemaPath;
out += ' for (var ' + ($idx) + ' = ' + (0) + '; ' + ($idx) + ' < ' + ($data) + '.length; ' + ($idx) + '++) { ';
$it.errorPath = it.util.getPathExpr(it.errorPath, $idx, it.opts.jsonPointers, true);
var $passData = $data + '[' + $idx + ']';
$it.dataPathArr[$dataNxt] = $idx;
var $code = it.validate($it);
$it.baseId = $currentBaseId;
if (it.util.varOccurences($code, $nextData) < 2) {
out += ' ' + (it.util.varReplace($code, $nextData, $passData)) + ' ';
} else {
out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ' + ($code) + ' ';
}
if ($breakOnError) {
out += ' if (!' + ($nextValid) + ') break; ';
}
out += ' }';
}
if ($breakOnError) {
out += ' ' + ($closingBraces) + ' if (' + ($errs) + ' == errors) {';
}
return out;
}

View file

@ -0,0 +1,80 @@
'use strict';
module.exports = function generate_multipleOf(it, $keyword, $ruleType) {
var out = ' ';
var $lvl = it.level;
var $dataLvl = it.dataLevel;
var $schema = it.schema[$keyword];
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
var $breakOnError = !it.opts.allErrors;
var $data = 'data' + ($dataLvl || '');
var $isData = it.opts.$data && $schema && $schema.$data,
$schemaValue;
if ($isData) {
out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; ';
$schemaValue = 'schema' + $lvl;
} else {
$schemaValue = $schema;
}
if (!($isData || typeof $schema == 'number')) {
throw new Error($keyword + ' must be number');
}
out += 'var division' + ($lvl) + ';if (';
if ($isData) {
out += ' ' + ($schemaValue) + ' !== undefined && ( typeof ' + ($schemaValue) + ' != \'number\' || ';
}
out += ' (division' + ($lvl) + ' = ' + ($data) + ' / ' + ($schemaValue) + ', ';
if (it.opts.multipleOfPrecision) {
out += ' Math.abs(Math.round(division' + ($lvl) + ') - division' + ($lvl) + ') > 1e-' + (it.opts.multipleOfPrecision) + ' ';
} else {
out += ' division' + ($lvl) + ' !== parseInt(division' + ($lvl) + ') ';
}
out += ' ) ';
if ($isData) {
out += ' ) ';
}
out += ' ) { ';
var $$outStack = $$outStack || [];
$$outStack.push(out);
out = ''; /* istanbul ignore else */
if (it.createErrors !== false) {
out += ' { keyword: \'' + ('multipleOf') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { multipleOf: ' + ($schemaValue) + ' } ';
if (it.opts.messages !== false) {
out += ' , message: \'should be multiple of ';
if ($isData) {
out += '\' + ' + ($schemaValue);
} else {
out += '' + ($schemaValue) + '\'';
}
}
if (it.opts.verbose) {
out += ' , schema: ';
if ($isData) {
out += 'validate.schema' + ($schemaPath);
} else {
out += '' + ($schema);
}
out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
}
out += ' } ';
} else {
out += ' {} ';
}
var __err = out;
out = $$outStack.pop();
if (!it.compositeRule && $breakOnError) {
/* istanbul ignore if */
if (it.async) {
out += ' throw new ValidationError([' + (__err) + ']); ';
} else {
out += ' validate.errors = [' + (__err) + ']; return false; ';
}
} else {
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
}
out += '} ';
if ($breakOnError) {
out += ' else { ';
}
return out;
}

View file

@ -0,0 +1,84 @@
'use strict';
module.exports = function generate_not(it, $keyword, $ruleType) {
var out = ' ';
var $lvl = it.level;
var $dataLvl = it.dataLevel;
var $schema = it.schema[$keyword];
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
var $breakOnError = !it.opts.allErrors;
var $data = 'data' + ($dataLvl || '');
var $errs = 'errs__' + $lvl;
var $it = it.util.copy(it);
$it.level++;
var $nextValid = 'valid' + $it.level;
if ((it.opts.strictKeywords ? (typeof $schema == 'object' && Object.keys($schema).length > 0) || $schema === false : it.util.schemaHasRules($schema, it.RULES.all))) {
$it.schema = $schema;
$it.schemaPath = $schemaPath;
$it.errSchemaPath = $errSchemaPath;
out += ' var ' + ($errs) + ' = errors; ';
var $wasComposite = it.compositeRule;
it.compositeRule = $it.compositeRule = true;
$it.createErrors = false;
var $allErrorsOption;
if ($it.opts.allErrors) {
$allErrorsOption = $it.opts.allErrors;
$it.opts.allErrors = false;
}
out += ' ' + (it.validate($it)) + ' ';
$it.createErrors = true;
if ($allErrorsOption) $it.opts.allErrors = $allErrorsOption;
it.compositeRule = $it.compositeRule = $wasComposite;
out += ' if (' + ($nextValid) + ') { ';
var $$outStack = $$outStack || [];
$$outStack.push(out);
out = ''; /* istanbul ignore else */
if (it.createErrors !== false) {
out += ' { keyword: \'' + ('not') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: {} ';
if (it.opts.messages !== false) {
out += ' , message: \'should NOT be valid\' ';
}
if (it.opts.verbose) {
out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
}
out += ' } ';
} else {
out += ' {} ';
}
var __err = out;
out = $$outStack.pop();
if (!it.compositeRule && $breakOnError) {
/* istanbul ignore if */
if (it.async) {
out += ' throw new ValidationError([' + (__err) + ']); ';
} else {
out += ' validate.errors = [' + (__err) + ']; return false; ';
}
} else {
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
}
out += ' } else { errors = ' + ($errs) + '; if (vErrors !== null) { if (' + ($errs) + ') vErrors.length = ' + ($errs) + '; else vErrors = null; } ';
if (it.opts.allErrors) {
out += ' } ';
}
} else {
out += ' var err = '; /* istanbul ignore else */
if (it.createErrors !== false) {
out += ' { keyword: \'' + ('not') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: {} ';
if (it.opts.messages !== false) {
out += ' , message: \'should NOT be valid\' ';
}
if (it.opts.verbose) {
out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
}
out += ' } ';
} else {
out += ' {} ';
}
out += '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
if ($breakOnError) {
out += ' if (false) { ';
}
}
return out;
}

View file

@ -0,0 +1,73 @@
'use strict';
module.exports = function generate_oneOf(it, $keyword, $ruleType) {
var out = ' ';
var $lvl = it.level;
var $dataLvl = it.dataLevel;
var $schema = it.schema[$keyword];
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
var $breakOnError = !it.opts.allErrors;
var $data = 'data' + ($dataLvl || '');
var $valid = 'valid' + $lvl;
var $errs = 'errs__' + $lvl;
var $it = it.util.copy(it);
var $closingBraces = '';
$it.level++;
var $nextValid = 'valid' + $it.level;
var $currentBaseId = $it.baseId,
$prevValid = 'prevValid' + $lvl,
$passingSchemas = 'passingSchemas' + $lvl;
out += 'var ' + ($errs) + ' = errors , ' + ($prevValid) + ' = false , ' + ($valid) + ' = false , ' + ($passingSchemas) + ' = null; ';
var $wasComposite = it.compositeRule;
it.compositeRule = $it.compositeRule = true;
var arr1 = $schema;
if (arr1) {
var $sch, $i = -1,
l1 = arr1.length - 1;
while ($i < l1) {
$sch = arr1[$i += 1];
if ((it.opts.strictKeywords ? (typeof $sch == 'object' && Object.keys($sch).length > 0) || $sch === false : it.util.schemaHasRules($sch, it.RULES.all))) {
$it.schema = $sch;
$it.schemaPath = $schemaPath + '[' + $i + ']';
$it.errSchemaPath = $errSchemaPath + '/' + $i;
out += ' ' + (it.validate($it)) + ' ';
$it.baseId = $currentBaseId;
} else {
out += ' var ' + ($nextValid) + ' = true; ';
}
if ($i) {
out += ' if (' + ($nextValid) + ' && ' + ($prevValid) + ') { ' + ($valid) + ' = false; ' + ($passingSchemas) + ' = [' + ($passingSchemas) + ', ' + ($i) + ']; } else { ';
$closingBraces += '}';
}
out += ' if (' + ($nextValid) + ') { ' + ($valid) + ' = ' + ($prevValid) + ' = true; ' + ($passingSchemas) + ' = ' + ($i) + '; }';
}
}
it.compositeRule = $it.compositeRule = $wasComposite;
out += '' + ($closingBraces) + 'if (!' + ($valid) + ') { var err = '; /* istanbul ignore else */
if (it.createErrors !== false) {
out += ' { keyword: \'' + ('oneOf') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { passingSchemas: ' + ($passingSchemas) + ' } ';
if (it.opts.messages !== false) {
out += ' , message: \'should match exactly one schema in oneOf\' ';
}
if (it.opts.verbose) {
out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
}
out += ' } ';
} else {
out += ' {} ';
}
out += '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
if (!it.compositeRule && $breakOnError) {
/* istanbul ignore if */
if (it.async) {
out += ' throw new ValidationError(vErrors); ';
} else {
out += ' validate.errors = vErrors; return false; ';
}
}
out += '} else { errors = ' + ($errs) + '; if (vErrors !== null) { if (' + ($errs) + ') vErrors.length = ' + ($errs) + '; else vErrors = null; }';
if (it.opts.allErrors) {
out += ' } ';
}
return out;
}

View file

@ -0,0 +1,75 @@
'use strict';
module.exports = function generate_pattern(it, $keyword, $ruleType) {
var out = ' ';
var $lvl = it.level;
var $dataLvl = it.dataLevel;
var $schema = it.schema[$keyword];
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
var $breakOnError = !it.opts.allErrors;
var $data = 'data' + ($dataLvl || '');
var $isData = it.opts.$data && $schema && $schema.$data,
$schemaValue;
if ($isData) {
out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; ';
$schemaValue = 'schema' + $lvl;
} else {
$schemaValue = $schema;
}
var $regexp = $isData ? '(new RegExp(' + $schemaValue + '))' : it.usePattern($schema);
out += 'if ( ';
if ($isData) {
out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'string\') || ';
}
out += ' !' + ($regexp) + '.test(' + ($data) + ') ) { ';
var $$outStack = $$outStack || [];
$$outStack.push(out);
out = ''; /* istanbul ignore else */
if (it.createErrors !== false) {
out += ' { keyword: \'' + ('pattern') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { pattern: ';
if ($isData) {
out += '' + ($schemaValue);
} else {
out += '' + (it.util.toQuotedString($schema));
}
out += ' } ';
if (it.opts.messages !== false) {
out += ' , message: \'should match pattern "';
if ($isData) {
out += '\' + ' + ($schemaValue) + ' + \'';
} else {
out += '' + (it.util.escapeQuotes($schema));
}
out += '"\' ';
}
if (it.opts.verbose) {
out += ' , schema: ';
if ($isData) {
out += 'validate.schema' + ($schemaPath);
} else {
out += '' + (it.util.toQuotedString($schema));
}
out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
}
out += ' } ';
} else {
out += ' {} ';
}
var __err = out;
out = $$outStack.pop();
if (!it.compositeRule && $breakOnError) {
/* istanbul ignore if */
if (it.async) {
out += ' throw new ValidationError([' + (__err) + ']); ';
} else {
out += ' validate.errors = [' + (__err) + ']; return false; ';
}
} else {
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
}
out += '} ';
if ($breakOnError) {
out += ' else { ';
}
return out;
}

View file

@ -0,0 +1,335 @@
'use strict';
module.exports = function generate_properties(it, $keyword, $ruleType) {
var out = ' ';
var $lvl = it.level;
var $dataLvl = it.dataLevel;
var $schema = it.schema[$keyword];
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
var $breakOnError = !it.opts.allErrors;
var $data = 'data' + ($dataLvl || '');
var $errs = 'errs__' + $lvl;
var $it = it.util.copy(it);
var $closingBraces = '';
$it.level++;
var $nextValid = 'valid' + $it.level;
var $key = 'key' + $lvl,
$idx = 'idx' + $lvl,
$dataNxt = $it.dataLevel = it.dataLevel + 1,
$nextData = 'data' + $dataNxt,
$dataProperties = 'dataProperties' + $lvl;
var $schemaKeys = Object.keys($schema || {}).filter(notProto),
$pProperties = it.schema.patternProperties || {},
$pPropertyKeys = Object.keys($pProperties).filter(notProto),
$aProperties = it.schema.additionalProperties,
$someProperties = $schemaKeys.length || $pPropertyKeys.length,
$noAdditional = $aProperties === false,
$additionalIsSchema = typeof $aProperties == 'object' && Object.keys($aProperties).length,
$removeAdditional = it.opts.removeAdditional,
$checkAdditional = $noAdditional || $additionalIsSchema || $removeAdditional,
$ownProperties = it.opts.ownProperties,
$currentBaseId = it.baseId;
var $required = it.schema.required;
if ($required && !(it.opts.$data && $required.$data) && $required.length < it.opts.loopRequired) {
var $requiredHash = it.util.toHash($required);
}
function notProto(p) {
return p !== '__proto__';
}
out += 'var ' + ($errs) + ' = errors;var ' + ($nextValid) + ' = true;';
if ($ownProperties) {
out += ' var ' + ($dataProperties) + ' = undefined;';
}
if ($checkAdditional) {
if ($ownProperties) {
out += ' ' + ($dataProperties) + ' = ' + ($dataProperties) + ' || Object.keys(' + ($data) + '); for (var ' + ($idx) + '=0; ' + ($idx) + '<' + ($dataProperties) + '.length; ' + ($idx) + '++) { var ' + ($key) + ' = ' + ($dataProperties) + '[' + ($idx) + ']; ';
} else {
out += ' for (var ' + ($key) + ' in ' + ($data) + ') { ';
}
if ($someProperties) {
out += ' var isAdditional' + ($lvl) + ' = !(false ';
if ($schemaKeys.length) {
if ($schemaKeys.length > 8) {
out += ' || validate.schema' + ($schemaPath) + '.hasOwnProperty(' + ($key) + ') ';
} else {
var arr1 = $schemaKeys;
if (arr1) {
var $propertyKey, i1 = -1,
l1 = arr1.length - 1;
while (i1 < l1) {
$propertyKey = arr1[i1 += 1];
out += ' || ' + ($key) + ' == ' + (it.util.toQuotedString($propertyKey)) + ' ';
}
}
}
}
if ($pPropertyKeys.length) {
var arr2 = $pPropertyKeys;
if (arr2) {
var $pProperty, $i = -1,
l2 = arr2.length - 1;
while ($i < l2) {
$pProperty = arr2[$i += 1];
out += ' || ' + (it.usePattern($pProperty)) + '.test(' + ($key) + ') ';
}
}
}
out += ' ); if (isAdditional' + ($lvl) + ') { ';
}
if ($removeAdditional == 'all') {
out += ' delete ' + ($data) + '[' + ($key) + ']; ';
} else {
var $currentErrorPath = it.errorPath;
var $additionalProperty = '\' + ' + $key + ' + \'';
if (it.opts._errorDataPathProperty) {
it.errorPath = it.util.getPathExpr(it.errorPath, $key, it.opts.jsonPointers);
}
if ($noAdditional) {
if ($removeAdditional) {
out += ' delete ' + ($data) + '[' + ($key) + ']; ';
} else {
out += ' ' + ($nextValid) + ' = false; ';
var $currErrSchemaPath = $errSchemaPath;
$errSchemaPath = it.errSchemaPath + '/additionalProperties';
var $$outStack = $$outStack || [];
$$outStack.push(out);
out = ''; /* istanbul ignore else */
if (it.createErrors !== false) {
out += ' { keyword: \'' + ('additionalProperties') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { additionalProperty: \'' + ($additionalProperty) + '\' } ';
if (it.opts.messages !== false) {
out += ' , message: \'';
if (it.opts._errorDataPathProperty) {
out += 'is an invalid additional property';
} else {
out += 'should NOT have additional properties';
}
out += '\' ';
}
if (it.opts.verbose) {
out += ' , schema: false , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
}
out += ' } ';
} else {
out += ' {} ';
}
var __err = out;
out = $$outStack.pop();
if (!it.compositeRule && $breakOnError) {
/* istanbul ignore if */
if (it.async) {
out += ' throw new ValidationError([' + (__err) + ']); ';
} else {
out += ' validate.errors = [' + (__err) + ']; return false; ';
}
} else {
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
}
$errSchemaPath = $currErrSchemaPath;
if ($breakOnError) {
out += ' break; ';
}
}
} else if ($additionalIsSchema) {
if ($removeAdditional == 'failing') {
out += ' var ' + ($errs) + ' = errors; ';
var $wasComposite = it.compositeRule;
it.compositeRule = $it.compositeRule = true;
$it.schema = $aProperties;
$it.schemaPath = it.schemaPath + '.additionalProperties';
$it.errSchemaPath = it.errSchemaPath + '/additionalProperties';
$it.errorPath = it.opts._errorDataPathProperty ? it.errorPath : it.util.getPathExpr(it.errorPath, $key, it.opts.jsonPointers);
var $passData = $data + '[' + $key + ']';
$it.dataPathArr[$dataNxt] = $key;
var $code = it.validate($it);
$it.baseId = $currentBaseId;
if (it.util.varOccurences($code, $nextData) < 2) {
out += ' ' + (it.util.varReplace($code, $nextData, $passData)) + ' ';
} else {
out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ' + ($code) + ' ';
}
out += ' if (!' + ($nextValid) + ') { errors = ' + ($errs) + '; if (validate.errors !== null) { if (errors) validate.errors.length = errors; else validate.errors = null; } delete ' + ($data) + '[' + ($key) + ']; } ';
it.compositeRule = $it.compositeRule = $wasComposite;
} else {
$it.schema = $aProperties;
$it.schemaPath = it.schemaPath + '.additionalProperties';
$it.errSchemaPath = it.errSchemaPath + '/additionalProperties';
$it.errorPath = it.opts._errorDataPathProperty ? it.errorPath : it.util.getPathExpr(it.errorPath, $key, it.opts.jsonPointers);
var $passData = $data + '[' + $key + ']';
$it.dataPathArr[$dataNxt] = $key;
var $code = it.validate($it);
$it.baseId = $currentBaseId;
if (it.util.varOccurences($code, $nextData) < 2) {
out += ' ' + (it.util.varReplace($code, $nextData, $passData)) + ' ';
} else {
out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ' + ($code) + ' ';
}
if ($breakOnError) {
out += ' if (!' + ($nextValid) + ') break; ';
}
}
}
it.errorPath = $currentErrorPath;
}
if ($someProperties) {
out += ' } ';
}
out += ' } ';
if ($breakOnError) {
out += ' if (' + ($nextValid) + ') { ';
$closingBraces += '}';
}
}
var $useDefaults = it.opts.useDefaults && !it.compositeRule;
if ($schemaKeys.length) {
var arr3 = $schemaKeys;
if (arr3) {
var $propertyKey, i3 = -1,
l3 = arr3.length - 1;
while (i3 < l3) {
$propertyKey = arr3[i3 += 1];
var $sch = $schema[$propertyKey];
if ((it.opts.strictKeywords ? (typeof $sch == 'object' && Object.keys($sch).length > 0) || $sch === false : it.util.schemaHasRules($sch, it.RULES.all))) {
var $prop = it.util.getProperty($propertyKey),
$passData = $data + $prop,
$hasDefault = $useDefaults && $sch.default !== undefined;
$it.schema = $sch;
$it.schemaPath = $schemaPath + $prop;
$it.errSchemaPath = $errSchemaPath + '/' + it.util.escapeFragment($propertyKey);
$it.errorPath = it.util.getPath(it.errorPath, $propertyKey, it.opts.jsonPointers);
$it.dataPathArr[$dataNxt] = it.util.toQuotedString($propertyKey);
var $code = it.validate($it);
$it.baseId = $currentBaseId;
if (it.util.varOccurences($code, $nextData) < 2) {
$code = it.util.varReplace($code, $nextData, $passData);
var $useData = $passData;
} else {
var $useData = $nextData;
out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ';
}
if ($hasDefault) {
out += ' ' + ($code) + ' ';
} else {
if ($requiredHash && $requiredHash[$propertyKey]) {
out += ' if ( ' + ($useData) + ' === undefined ';
if ($ownProperties) {
out += ' || ! Object.prototype.hasOwnProperty.call(' + ($data) + ', \'' + (it.util.escapeQuotes($propertyKey)) + '\') ';
}
out += ') { ' + ($nextValid) + ' = false; ';
var $currentErrorPath = it.errorPath,
$currErrSchemaPath = $errSchemaPath,
$missingProperty = it.util.escapeQuotes($propertyKey);
if (it.opts._errorDataPathProperty) {
it.errorPath = it.util.getPath($currentErrorPath, $propertyKey, it.opts.jsonPointers);
}
$errSchemaPath = it.errSchemaPath + '/required';
var $$outStack = $$outStack || [];
$$outStack.push(out);
out = ''; /* istanbul ignore else */
if (it.createErrors !== false) {
out += ' { keyword: \'' + ('required') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { missingProperty: \'' + ($missingProperty) + '\' } ';
if (it.opts.messages !== false) {
out += ' , message: \'';
if (it.opts._errorDataPathProperty) {
out += 'is a required property';
} else {
out += 'should have required property \\\'' + ($missingProperty) + '\\\'';
}
out += '\' ';
}
if (it.opts.verbose) {
out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
}
out += ' } ';
} else {
out += ' {} ';
}
var __err = out;
out = $$outStack.pop();
if (!it.compositeRule && $breakOnError) {
/* istanbul ignore if */
if (it.async) {
out += ' throw new ValidationError([' + (__err) + ']); ';
} else {
out += ' validate.errors = [' + (__err) + ']; return false; ';
}
} else {
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
}
$errSchemaPath = $currErrSchemaPath;
it.errorPath = $currentErrorPath;
out += ' } else { ';
} else {
if ($breakOnError) {
out += ' if ( ' + ($useData) + ' === undefined ';
if ($ownProperties) {
out += ' || ! Object.prototype.hasOwnProperty.call(' + ($data) + ', \'' + (it.util.escapeQuotes($propertyKey)) + '\') ';
}
out += ') { ' + ($nextValid) + ' = true; } else { ';
} else {
out += ' if (' + ($useData) + ' !== undefined ';
if ($ownProperties) {
out += ' && Object.prototype.hasOwnProperty.call(' + ($data) + ', \'' + (it.util.escapeQuotes($propertyKey)) + '\') ';
}
out += ' ) { ';
}
}
out += ' ' + ($code) + ' } ';
}
}
if ($breakOnError) {
out += ' if (' + ($nextValid) + ') { ';
$closingBraces += '}';
}
}
}
}
if ($pPropertyKeys.length) {
var arr4 = $pPropertyKeys;
if (arr4) {
var $pProperty, i4 = -1,
l4 = arr4.length - 1;
while (i4 < l4) {
$pProperty = arr4[i4 += 1];
var $sch = $pProperties[$pProperty];
if ((it.opts.strictKeywords ? (typeof $sch == 'object' && Object.keys($sch).length > 0) || $sch === false : it.util.schemaHasRules($sch, it.RULES.all))) {
$it.schema = $sch;
$it.schemaPath = it.schemaPath + '.patternProperties' + it.util.getProperty($pProperty);
$it.errSchemaPath = it.errSchemaPath + '/patternProperties/' + it.util.escapeFragment($pProperty);
if ($ownProperties) {
out += ' ' + ($dataProperties) + ' = ' + ($dataProperties) + ' || Object.keys(' + ($data) + '); for (var ' + ($idx) + '=0; ' + ($idx) + '<' + ($dataProperties) + '.length; ' + ($idx) + '++) { var ' + ($key) + ' = ' + ($dataProperties) + '[' + ($idx) + ']; ';
} else {
out += ' for (var ' + ($key) + ' in ' + ($data) + ') { ';
}
out += ' if (' + (it.usePattern($pProperty)) + '.test(' + ($key) + ')) { ';
$it.errorPath = it.util.getPathExpr(it.errorPath, $key, it.opts.jsonPointers);
var $passData = $data + '[' + $key + ']';
$it.dataPathArr[$dataNxt] = $key;
var $code = it.validate($it);
$it.baseId = $currentBaseId;
if (it.util.varOccurences($code, $nextData) < 2) {
out += ' ' + (it.util.varReplace($code, $nextData, $passData)) + ' ';
} else {
out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ' + ($code) + ' ';
}
if ($breakOnError) {
out += ' if (!' + ($nextValid) + ') break; ';
}
out += ' } ';
if ($breakOnError) {
out += ' else ' + ($nextValid) + ' = true; ';
}
out += ' } ';
if ($breakOnError) {
out += ' if (' + ($nextValid) + ') { ';
$closingBraces += '}';
}
}
}
}
}
if ($breakOnError) {
out += ' ' + ($closingBraces) + ' if (' + ($errs) + ' == errors) {';
}
return out;
}

View file

@ -0,0 +1,81 @@
'use strict';
module.exports = function generate_propertyNames(it, $keyword, $ruleType) {
var out = ' ';
var $lvl = it.level;
var $dataLvl = it.dataLevel;
var $schema = it.schema[$keyword];
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
var $breakOnError = !it.opts.allErrors;
var $data = 'data' + ($dataLvl || '');
var $errs = 'errs__' + $lvl;
var $it = it.util.copy(it);
var $closingBraces = '';
$it.level++;
var $nextValid = 'valid' + $it.level;
out += 'var ' + ($errs) + ' = errors;';
if ((it.opts.strictKeywords ? (typeof $schema == 'object' && Object.keys($schema).length > 0) || $schema === false : it.util.schemaHasRules($schema, it.RULES.all))) {
$it.schema = $schema;
$it.schemaPath = $schemaPath;
$it.errSchemaPath = $errSchemaPath;
var $key = 'key' + $lvl,
$idx = 'idx' + $lvl,
$i = 'i' + $lvl,
$invalidName = '\' + ' + $key + ' + \'',
$dataNxt = $it.dataLevel = it.dataLevel + 1,
$nextData = 'data' + $dataNxt,
$dataProperties = 'dataProperties' + $lvl,
$ownProperties = it.opts.ownProperties,
$currentBaseId = it.baseId;
if ($ownProperties) {
out += ' var ' + ($dataProperties) + ' = undefined; ';
}
if ($ownProperties) {
out += ' ' + ($dataProperties) + ' = ' + ($dataProperties) + ' || Object.keys(' + ($data) + '); for (var ' + ($idx) + '=0; ' + ($idx) + '<' + ($dataProperties) + '.length; ' + ($idx) + '++) { var ' + ($key) + ' = ' + ($dataProperties) + '[' + ($idx) + ']; ';
} else {
out += ' for (var ' + ($key) + ' in ' + ($data) + ') { ';
}
out += ' var startErrs' + ($lvl) + ' = errors; ';
var $passData = $key;
var $wasComposite = it.compositeRule;
it.compositeRule = $it.compositeRule = true;
var $code = it.validate($it);
$it.baseId = $currentBaseId;
if (it.util.varOccurences($code, $nextData) < 2) {
out += ' ' + (it.util.varReplace($code, $nextData, $passData)) + ' ';
} else {
out += ' var ' + ($nextData) + ' = ' + ($passData) + '; ' + ($code) + ' ';
}
it.compositeRule = $it.compositeRule = $wasComposite;
out += ' if (!' + ($nextValid) + ') { for (var ' + ($i) + '=startErrs' + ($lvl) + '; ' + ($i) + '<errors; ' + ($i) + '++) { vErrors[' + ($i) + '].propertyName = ' + ($key) + '; } var err = '; /* istanbul ignore else */
if (it.createErrors !== false) {
out += ' { keyword: \'' + ('propertyNames') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { propertyName: \'' + ($invalidName) + '\' } ';
if (it.opts.messages !== false) {
out += ' , message: \'property name \\\'' + ($invalidName) + '\\\' is invalid\' ';
}
if (it.opts.verbose) {
out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
}
out += ' } ';
} else {
out += ' {} ';
}
out += '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
if (!it.compositeRule && $breakOnError) {
/* istanbul ignore if */
if (it.async) {
out += ' throw new ValidationError(vErrors); ';
} else {
out += ' validate.errors = vErrors; return false; ';
}
}
if ($breakOnError) {
out += ' break; ';
}
out += ' } }';
}
if ($breakOnError) {
out += ' ' + ($closingBraces) + ' if (' + ($errs) + ' == errors) {';
}
return out;
}

Some files were not shown because too many files have changed in this diff Show more