node_modules
Ajv JSON schema validator
The fastest JSON validator for Node.js and browser.
Supports JSON Schema draft-04/06/07/2019-09/2020-12 (draft-04 support requires ajv-draft-04 package) and JSON Type Definition RFC8927.
Ajv sponsors#
Contributing#
More than 100 people contributed to Ajv, and we would love to have you join the development. We welcome implementing new features that will benefit many users and ideas to improve our documentation.
Please review Contributing guidelines and Code components.
Documentation#
All documentation is available on the Ajv website.
Some useful site links:
- Getting started
- JSON Schema vs JSON Type Definition
- API reference
- Strict mode
- Standalone validation code
- Security considerations
- Command line interface
- Frequently Asked Questions
Please sponsor Ajv development#
Since I asked to support Ajv development 40 people and 6 organizations contributed via GitHub and OpenCollective - this support helped receiving the MOSS grant!
Your continuing support is very important - the funds will be used to develop and maintain Ajv once the next major version is released.
Please sponsor Ajv via:
- GitHub sponsors page (GitHub will match it)
- Ajv Open Collective
Thank you.
Open Collective sponsors#
Performance#
Ajv generates code to turn JSON Schemas into super-fast validation functions that are efficient for v8 optimization.
Currently Ajv is the fastest and the most standard compliant validator according to these benchmarks:
- json-schema-benchmark - 50% faster than the second place
- jsck benchmark - 20-190% faster
- z-schema benchmark
- themis benchmark
Performance of different validators by json-schema-benchmark:
Features#
- Ajv implements JSON Schema draft-06/07/2019-09/2020-12 standards (draft-04 is supported in v6):
- all validation keywords (see JSON Schema validation keywords)
- OpenAPI extensions:
- NEW: keyword discriminator.
- keyword nullable.
- full support of remote references (remote schemas have to be added with
addSchemaor compiled to be available) - support of recursive references between schemas
- correct string lengths for strings with unicode pairs
- JSON Schema formats (with ajv-formats plugin).
- validates schemas against meta-schema
- NEW: supports JSON Type Definition:
- all keywords (see JSON Type Definition schema forms)
- meta-schema for JTD schemas
- "union" keyword and user-defined keywords (can be used inside "metadata" member of the schema)
- supports browsers and Node.js 10.x - current
- asynchronous loading of referenced schemas during compilation
- "All errors" validation mode with option allErrors
- error messages with parameters describing error reasons to allow error message generation
- i18n error messages support with ajv-i18n package
- removing-additional-properties
- assigning defaults to missing properties and items
- coercing data to the types specified in
typekeywords - user-defined keywords
- additional extension keywords with ajv-keywords package
- $data reference to use values from the validated data as values for the schema keywords
- asynchronous validation of user-defined formats and keywords
Install#
To install version 8:
npm install ajv
Getting started#
Try it in the Node.js REPL: https://runkit.com/npm/ajv
In JavaScript:
// or ESM/TypeScript import
import Ajv from "ajv"
// Node.js require:
const Ajv = require("ajv")
const ajv = new Ajv() // options can be passed, e.g. {allErrors: true}
const schema = {
type: "object",
properties: {
foo: {type: "integer"},
bar: {type: "string"},
},
required: ["foo"],
additionalProperties: false,
}
const data = {
foo: 1,
bar: "abc",
}
const validate = ajv.compile(schema)
const valid = validate(data)
if (!valid) console.log(validate.errors)Learn how to use Ajv and see more examples in the Guide: getting started
Changes history#
See https://github.com/ajv-validator/ajv/releases
Please note: Changes in version 8.0.0
Code of conduct#
Please review and follow the Code of conduct.
Please report any unacceptable behaviour to ajv.validator@gmail.com - it will be reviewed by the project team.
Security contact#
To report a security vulnerability, please use the Tidelift security contact. Tidelift will coordinate the fix and disclosure. Please do NOT report security vulnerabilities via GitHub issues.
Open-source software support#
Ajv is a part of Tidelift subscription - it provides a centralised support to open-source software users, in addition to the support provided by software maintainers.
License#
MIT # ajv-formats
JSON Schema formats for Ajv
Usage#
// ESM/TypeScript import
import Ajv from "ajv"
import addFormats from "ajv-formats"
// Node.js require:
const Ajv = require("ajv")
const addFormats = require("ajv-formats")
const ajv = new Ajv()
addFormats(ajv)Formats#
The package defines these formats:
- date: full-date according to RFC3339.
- time: time (time-zone is mandatory).
- date-time: date-time (time-zone is mandatory).
- iso-time: time with optional time-zone.
- iso-date-time: date-time with optional time-zone.
- duration: duration from RFC3339
- uri: full URI.
- uri-reference: URI reference, including full and relative URIs.
- uri-template: URI template according to RFC6570
- url (deprecated): URL record.
- email: email address.
- hostname: host name according to RFC1034.
- ipv4: IP address v4.
- ipv6: IP address v6.
- regex: tests whether a string is a valid regular expression by passing it to RegExp constructor.
- uuid: Universally Unique IDentifier according to RFC4122.
- json-pointer: JSON-pointer according to RFC6901.
- relative-json-pointer: relative JSON-pointer according to this draft.
- byte: base64 encoded data according to the openApi 3.0.0 specification
- int32: signed 32 bits integer according to the openApi 3.0.0 specification
- int64: signed 64 bits according to the openApi 3.0.0 specification
- float: float according to the openApi 3.0.0 specification
- double: double according to the openApi 3.0.0 specification
- password: password string according to the openApi 3.0.0 specification
- binary: binary string according to the openApi 3.0.0 specification
See regular expressions used for format validation and the sources that were used in formats.ts.
Please note: JSON Schema draft-07 also defines formats iri, iri-reference, idn-hostname and idn-email for URLs, hostnames and emails with international characters. These formats are available in ajv-formats-draft2019 plugin.
Keywords to compare values: formatMaximum / formatMinimum and formatExclusiveMaximum / formatExclusiveMinimum#
These keywords allow to define minimum/maximum constraints when the format keyword defines ordering (compare function in format definition).
These keywords are added to ajv instance when ajv-formats is used without options or with option keywords: true.
These keywords apply only to strings. If the data is not a string, the validation succeeds.
The value of keywords formatMaximum/formatMinimum and formatExclusiveMaximum/formatExclusiveMinimum should be a string or $data reference. This value is the maximum (minimum) allowed value for the data to be valid as determined by format keyword. If format keyword is not present schema compilation will throw exception.
When these keyword are added, they also add comparison functions to formats "date", "time" and "date-time". User-defined formats also can have comparison functions. See addFormat method.
require("ajv-formats")(ajv)
const schema = {
type: "string",
format: "date",
formatMinimum: "2016-02-06",
formatExclusiveMaximum: "2016-12-27",
}
const validDataList = ["2016-02-06", "2016-12-26"]
const invalidDataList = ["2016-02-05", "2016-12-27", "abc"]Options#
Options can be passed via the second parameter. Options value can be
- The list of format names that will be added to ajv instance:
addFormats(ajv, ["date", "time"])Please note: when ajv encounters an undefined format it throws exception (unless ajv instance was configured with strict: false option). To allow specific undefined formats they have to be passed to ajv instance via formats option with true value:
const ajv = new Ajv((formats: {date: true, time: true})) // to ignore "date" and "time" formats in schemas.- Format validation mode (default is
"full") with optional list of format names andkeywordsoption to add additional format comparison keywords:
addFormats(ajv, {mode: "fast"})or
addFormats(ajv, {mode: "fast", formats: ["date", "time"], keywords: true})In "fast" mode the following formats are simplified: "date", "time", "date-time", "iso-time", "iso-date-time", "uri", "uri-reference", "email". For example, "date", "time" and "date-time" do not validate ranges in "fast" mode, only string structure, and other formats have simplified regular expressions.
Tests#
npm install
git submodule update --init
npm testLicense#
MIT # ajv-formats-draft2019
An AJV plugin adding support for draft2019 formats missing from AJV.
Currently, iri, iri-reference, idn-email, idn-hostname, and duration
formats are supported. duration was added in draft 2019. The uuid format was
added in draft2019, but is already supported by the ajv-formats package.
Using international formats with pre-draft2019 JSON schemas#
The idn-email and idn-hostname formats are implemented per RFC 1123, however
earlier JSON schemas specify RFC 1034. This is probably just fine, but you have
been warned...
Installation#
npm install --save ajv-formats-draft2019Usage#
The default export is an apply function that patches an existing instance of
ajv.
const Ajv = require('ajv');
const apply = require('ajv-formats-draft2019');
const ajv = new Ajv();
apply(ajv); // returns ajv instance, allowing chaining
let schema = {
type: 'string',
format: 'idn-email',
};
ajv.validate(schema, 'квіточка@пошта.укр'); // returns trueThe apply function also accepts a second optional parameter to specify which
formats to add to the ajv instance.
const Ajv = require('ajv');
const apply = require('ajv-formats-draft2019');
const ajv = new Ajv();
// Install only the idn-email and iri formats
apply(ajv, { formats: ['idn-email', 'iri'] });The module also provides an alternate entrypoint ajv-formats-draft2019/formats
that works with the ajv constructor to add the formats to new instances.
const Ajv = require('ajv');
const formats = require('ajv-formats-draft2019/formats');
const ajv = new Ajv({ formats });
let schema = {
type: 'string',
format: 'idn-email',
};
ajv.validate(schema, 'квіточка@пошта.укр'); // returns trueUsing the ajv-formats-draft2019/formats entry point also allows cherry picking
formats. Note the approach below only works for formats that don't contain a
hypen - in the name. This approach may yield smaller packed bundles since it
allows tree-shaking to remove unwanted validators and related dependencies.
const Ajv = require('ajv');
const { duration, iri } = require('ajv-formats-draft2019/formats');
const ajv = new Ajv({ formats: { duration, iri } });International formats#
The library also provides an idn export to load only the international formats
(ie. iri, iri-reference, idn-hostname and idn-email).
const Ajv = require('ajv');
const formats = require('ajv-formats-draft2019/idn');
const ajv = new Ajv({ formats });Formats#
iri#
The string is parsed with 'uri-js' and the scheme is checked against the list of
known IANA schemes. If it's a 'mailto' schemes, all of the to: addresses are
validated, otherwise we check there IRI includes a path and is an absolute
reference.
iri-reference#
All valid IRIs are valid. Fragments must have a valid path and of type "relative", "same-document" or "uri". If there is a scheme, it must be valid.
Validating a IRI references is challenging since the syntax is so permissive. Basically, any URL-safe string is a valid IRI syntactically. I struggled to find negative test cases when writing the unit tests for IRI-references. Consider:
google.comis NOT a valid IRI because it does not include a scheme.file.txtis a valid IRI-reference/this:thatis a valid IRI-referencethis:thatis a NOT a valid IRI-reference
idn-email#
smtp-address-parser is
used to check the validity of the email.
idn-hostname#
The hostname is converted to ascii with punycode and checked for a valid tld.
duration#
The string is checked against a regex.
Releases#
v1.6.1#
- Updated
schemesdependency, adding support formodbus+tcpandmqttin URIs.
v1.6.0#
- Fix tests to work with AJV v7+ and how
ajvis exported, rather than changes to this library.
v1.5.0#
- Upgrade dependencies
v1.4.4#
-
The last release that's compatible with Node 8.
-
Fixed a bug when validated
mailto:IRIs. 2.20.3 / 2019-10-11 ==================- Support Node.js 0.10 (Revert #1059)
- Ran "npm unpublish commander@2.20.2". There is no 2.20.2.
2.20.1 / 2019-09-29#
- Improve executable subcommand tracking
- Update dev dependencies
2.20.0 / 2019-04-02#
- fix: resolve symbolic links completely when hunting for subcommands (#935)
- Update index.d.ts (#930)
- Update Readme.md (#924)
- Remove --save option as it isn't required anymore (#918)
- Add link to the license file (#900)
- Added example of receiving args from options (#858)
- Added missing semicolon (#882)
- Add extension to .eslintrc (#876)
2.19.0 / 2018-10-02#
- Removed newline after Options and Commands headers (#864)
- Bugfix - Error output (#862)
- Fix to change default value to string (#856)
2.18.0 / 2018-09-07#
- Standardize help output (#853)
- chmod 644 travis.yml (#851)
- add support for execute typescript subcommand via ts-node (#849)
2.17.1 / 2018-08-07#
- Fix bug in command emit (#844)
2.17.0 / 2018-08-03#
- fixed newline output after help information (#833)
- Fix to emit the action even without command (#778)
- npm update (#823)
2.16.0 / 2018-06-29#
- Remove Makefile and
test/run(#821) - Make 'npm test' run on Windows (#820)
- Add badge to display install size (#807)
- chore: cache node_modules (#814)
- chore: remove Node.js 4 (EOL), add Node.js 10 (#813)
- fixed typo in readme (#812)
- Fix types (#804)
- Update eslint to resolve vulnerabilities in lodash (#799)
- updated readme with custom event listeners. (#791)
- fix tests (#794)
2.15.0 / 2018-03-07#
- Update downloads badge to point to graph of downloads over time instead of duplicating link to npm
- Arguments description
2.14.1 / 2018-02-07#
- Fix typing of help function
2.14.0 / 2018-02-05#
- only register the option:version event once
- Fixes issue #727: Passing empty string for option on command is set to undefined
- enable eqeqeq rule
- resolves #754 add linter configuration to project
- resolves #560 respect custom name for version option
- document how to override the version flag
- document using options per command
2.13.0 / 2018-01-09#
- Do not print default for --no-
- remove trailing spaces in command help
- Update CI's Node.js to LTS and latest version
- typedefs: Command and Option types added to commander namespace
2.12.2 / 2017-11-28#
- fix: typings are not shipped
2.12.1 / 2017-11-23#
- Move @types/node to dev dependency
2.12.0 / 2017-11-22#
- add attributeName() method to Option objects
- Documentation updated for options with --no prefix
- typings:
outputHelptakes a string as the first parameter - typings: use overloads
- feat(typings): update to match js api
- Print default value in option help
- Fix translation error
- Fail when using same command and alias (#491)
- feat(typings): add help callback
- fix bug when description is add after command with options (#662)
- Format js code
- Rename History.md to CHANGELOG.md (#668)
- feat(typings): add typings to support TypeScript (#646)
- use current node
2.11.0 / 2017-07-03#
- Fix help section order and padding (#652)
- feature: support for signals to subcommands (#632)
- Fixed #37, --help should not display first (#447)
- Fix translation errors. (#570)
- Add package-lock.json
- Remove engines
- Upgrade package version
- Prefix events to prevent conflicts between commands and options (#494)
- Removing dependency on graceful-readlink
- Support setting name in #name function and make it chainable
- Add .vscode directory to .gitignore (Visual Studio Code metadata)
- Updated link to ruby commander in readme files
2.10.0 / 2017-06-19#
- Update .travis.yml. drop support for older node.js versions.
- Fix require arguments in README.md
- On SemVer you do not start from 0.0.1
- Add missing semi colon in readme
- Add save param to npm install
- node v6 travis test
- Update Readme_zh-CN.md
- Allow literal '--' to be passed-through as an argument
- Test subcommand alias help
- link build badge to master branch
- Support the alias of Git style sub-command
- added keyword commander for better search result on npm
- Fix Sub-Subcommands
- test node.js stable
- Fixes TypeError when a command has an option called
--description - Update README.md to make it beginner friendly and elaborate on the difference between angled and square brackets.
- Add chinese Readme file
2.9.0 / 2015-10-13#
- Add option
isDefaultto set default subcommand #415 @Qix- - Add callback to allow filtering or post-processing of help text #434 @djulien
- Fix
undefinedtext in help information close #414 #416 @zhiyelee
2.8.1 / 2015-04-22#
- Back out
support multiline descriptionClose #396 #397
2.8.0 / 2015-04-07#
- Add
process.execArgsupport, execution args like--harmonywill be passed to sub-commands #387 @DigitalIO @zhiyelee - Fix bug in Git-style sub-commands #372 @zhiyelee
- Allow commands to be hidden from help #383 @tonylukasavage
- When git-style sub-commands are in use, yet none are called, display help #382 @claylo
- Add ability to specify arguments syntax for top-level command #258 @rrthomas
- Support multiline descriptions #208 @zxqfox
2.7.1 / 2015-03-11#
- Revert #347 (fix collisions when option and first arg have same name) which causes a bug in #367.
2.7.0 / 2015-03-09#
- Fix git-style bug when installed globally. Close #335 #349 @zhiyelee
- Fix collisions when option and first arg have same name. Close #346 #347 @tonylukasavage
- Add support for camelCase on
opts(). Close #353 @nkzawa - Add node.js 0.12 and io.js to travis.yml
- Allow RegEx options. #337 @palanik
- Fixes exit code when sub-command failing. Close #260 #332 @pirelenito
- git-style
binfiles in $PATH make sense. Close #196 #327 @zhiyelee
2.6.0 / 2014-12-30#
- added
Command#allowUnknownOptionmethod. Close #138 #318 @doozr @zhiyelee - Add application description to the help msg. Close #112 @dalssoft
2.5.1 / 2014-12-15#
- fixed two bugs incurred by variadic arguments. Close #291 @Quentin01 #302 @zhiyelee
2.5.0 / 2014-10-24#
- add support for variadic arguments. Closes #277 @whitlockjc
2.4.0 / 2014-10-17#
- fixed a bug on executing the coercion function of subcommands option. Closes #270
- added
Command.prototype.nameto retrieve command name. Closes #264 #266 @tonylukasavage - added
Command.prototype.optsto retrieve all the options as a simple object of key-value pairs. Closes #262 @tonylukasavage - fixed a bug on subcommand name. Closes #248 @jonathandelgado
- fixed function normalize doesn’t honor option terminator. Closes #216 @abbr
2.3.0 / 2014-07-16#
- add command alias'. Closes PR #210
- fix: Typos. Closes #99
- fix: Unused fs module. Closes #217
2.2.0 / 2014-03-29#
- add passing of previous option value
- fix: support subcommands on windows. Closes #142
- Now the defaultValue passed as the second argument of the coercion function.
2.1.0 / 2013-11-21#
- add: allow cflag style option params, unit test, fixes #174
2.0.0 / 2013-07-18#
- remove input methods (.prompt, .confirm, etc)
1.3.2 / 2013-07-18#
- add support for sub-commands to co-exist with the original command
1.3.1 / 2013-07-18#
- add quick .runningCommand hack so you can opt-out of other logic when running a sub command
1.3.0 / 2013-07-09#
- add EACCES error handling
- fix sub-command --help
1.2.0 / 2013-06-13#
- allow "-" hyphen as an option argument
- support for RegExp coercion
1.1.1 / 2012-11-20#
- add more sub-command padding
- fix .usage() when args are present. Closes #106
1.1.0 / 2012-11-16#
- add git-style executable subcommand support. Closes #94
1.0.5 / 2012-10-09#
- fix
--nameclobbering. Closes #92 - fix examples/help. Closes #89
1.0.4 / 2012-09-03#
- add
outputHelp()method.
1.0.3 / 2012-08-30#
- remove invalid .version() defaulting
1.0.2 / 2012-08-24#
- add
--foo=barsupport [arv] - fix password on node 0.8.8. Make backward compatible with 0.6 [focusaurus]
1.0.1 / 2012-08-03#
- fix issue #56
- fix tty.setRawMode(mode) was moved to tty.ReadStream#setRawMode() (i.e. process.stdin.setRawMode())
1.0.0 / 2012-07-05#
- add support for optional option descriptions
- add defaulting of
.version()to package.json's version
0.6.1 / 2012-06-01#
- Added: append (yes or no) on confirmation
- Added: allow node.js v0.7.x
0.6.0 / 2012-04-10#
- Added
.prompt(obj, callback)support. Closes #49 - Added default support to .choose(). Closes #41
- Fixed the choice example
0.5.1 / 2011-12-20#
- Fixed
password()for recent nodes. Closes #36
0.5.0 / 2011-12-04#
- Added sub-command option support [itay]
0.4.3 / 2011-12-04#
- Fixed custom help ordering. Closes #32
0.4.2 / 2011-11-24#
- Added travis support
- Fixed: line-buffered input automatically trimmed. Closes #31
0.4.1 / 2011-11-18#
- Removed listening for "close" on --help
0.4.0 / 2011-11-15#
- Added support for
--. Closes #24
0.3.3 / 2011-11-14#
- Fixed: wait for close event when writing help info [Jerry Hamlet]
0.3.2 / 2011-11-01#
- Fixed long flag definitions with values [felixge]
0.3.1 / 2011-10-31#
- Changed
--versionshort flag to-Vfrom-v - Changed
.version()so it's configurable [felixge]
0.3.0 / 2011-10-31#
- Added support for long flags only. Closes #18
0.2.1 / 2011-10-24#
- "node": ">= 0.4.x < 0.7.0". Closes #20
0.2.0 / 2011-09-26#
- Allow for defaults that are not just boolean. Default peassignment only occurs for --no-*, optional, and required arguments. [Jim Isaacs]
0.1.0 / 2011-08-24#
- Added support for custom
--helpoutput
0.0.5 / 2011-08-18#
- Changed: when the user enters nothing prompt for password again
- Fixed issue with passwords beginning with numbers [NuckChorris]
0.0.4 / 2011-08-15#
- Fixed
Commander#args
0.0.3 / 2011-08-15#
- Added default option value support
0.0.2 / 2011-08-15#
- Added mask support to
Command#password(str[, mask], fn) - Added
Command#password(str, fn)
0.0.1 / 2010-01-03#
- Initial release # Commander.js
The complete solution for node.js command-line interfaces, inspired by Ruby's commander.
API documentation
Installation#
$ npm install commander
Option parsing#
Options with commander are defined with the .option() method, also serving as documentation for the options. The example below parses args and options from process.argv, leaving remaining args as the program.args array which were not consumed by options.
#!/usr/bin/env node
/**
* Module dependencies.
*/
var program = require('commander');
program
.version('0.1.0')
.option('-p, --peppers', 'Add peppers')
.option('-P, --pineapple', 'Add pineapple')
.option('-b, --bbq-sauce', 'Add bbq sauce')
.option('-c, --cheese [type]', 'Add the specified type of cheese [marble]', 'marble')
.parse(process.argv);
console.log('you ordered a pizza with:');
if (program.peppers) console.log(' - peppers');
if (program.pineapple) console.log(' - pineapple');
if (program.bbqSauce) console.log(' - bbq');
console.log(' - %s cheese', program.cheese);Short flags may be passed as a single arg, for example -abc is equivalent to -a -b -c. Multi-word options such as "--template-engine" are camel-cased, becoming program.templateEngine etc.
Note that multi-word options starting with --no prefix negate the boolean value of the following word. For example, --no-sauce sets the value of program.sauce to false.
#!/usr/bin/env node
/**
* Module dependencies.
*/
var program = require('commander');
program
.option('--no-sauce', 'Remove sauce')
.parse(process.argv);
console.log('you ordered a pizza');
if (program.sauce) console.log(' with sauce');
else console.log(' without sauce');To get string arguments from options you will need to use angle brackets <> for required inputs or square brackets [] for optional inputs.
e.g. .option('-m --myarg [myVar]', 'my super cool description')
Then to access the input if it was passed in.
e.g. var myInput = program.myarg
NOTE: If you pass a argument without using brackets the example above will return true and not the value passed in.
Version option#
Calling the version implicitly adds the -V and --version options to the command.
When either of these options is present, the command prints the version number and exits.
$ ./examples/pizza -V
0.0.1
If you want your program to respond to the -v option instead of the -V option, simply pass custom flags to the version method using the same syntax as the option method.
program
.version('0.0.1', '-v, --version')The version flags can be named anything, but the long option is required.
Command-specific options#
You can attach options to a command.
#!/usr/bin/env node
var program = require('commander');
program
.command('rm <dir>')
.option('-r, --recursive', 'Remove recursively')
.action(function (dir, cmd) {
console.log('remove ' + dir + (cmd.recursive ? ' recursively' : ''))
})
program.parse(process.argv)A command's options are validated when the command is used. Any unknown options will be reported as an error. However, if an action-based command does not define an action, then the options are not validated.
Coercion#
function range(val) {
return val.split('..').map(Number);
}
function list(val) {
return val.split(',');
}
function collect(val, memo) {
memo.push(val);
return memo;
}
function increaseVerbosity(v, total) {
return total + 1;
}
program
.version('0.1.0')
.usage('[options] <file ...>')
.option('-i, --integer <n>', 'An integer argument', parseInt)
.option('-f, --float <n>', 'A float argument', parseFloat)
.option('-r, --range <a>..<b>', 'A range', range)
.option('-l, --list <items>', 'A list', list)
.option('-o, --optional [value]', 'An optional value')
.option('-c, --collect [value]', 'A repeatable value', collect, [])
.option('-v, --verbose', 'A value that can be increased', increaseVerbosity, 0)
.parse(process.argv);
console.log(' int: %j', program.integer);
console.log(' float: %j', program.float);
console.log(' optional: %j', program.optional);
program.range = program.range || [];
console.log(' range: %j..%j', program.range[0], program.range[1]);
console.log(' list: %j', program.list);
console.log(' collect: %j', program.collect);
console.log(' verbosity: %j', program.verbose);
console.log(' args: %j', program.args);Regular Expression#
program
.version('0.1.0')
.option('-s --size <size>', 'Pizza size', /^(large|medium|small)$/i, 'medium')
.option('-d --drink [drink]', 'Drink', /^(coke|pepsi|izze)$/i)
.parse(process.argv);
console.log(' size: %j', program.size);
console.log(' drink: %j', program.drink);Variadic arguments#
The last argument of a command can be variadic, and only the last argument. To make an argument variadic you have to
append ... to the argument name. Here is an example:
#!/usr/bin/env node
/**
* Module dependencies.
*/
var program = require('commander');
program
.version('0.1.0')
.command('rmdir <dir> [otherDirs...]')
.action(function (dir, otherDirs) {
console.log('rmdir %s', dir);
if (otherDirs) {
otherDirs.forEach(function (oDir) {
console.log('rmdir %s', oDir);
});
}
});
program.parse(process.argv);An Array is used for the value of a variadic argument. This applies to program.args as well as the argument passed
to your action as demonstrated above.
Specify the argument syntax#
#!/usr/bin/env node
var program = require('commander');
program
.version('0.1.0')
.arguments('<cmd> [env]')
.action(function (cmd, env) {
cmdValue = cmd;
envValue = env;
});
program.parse(process.argv);
if (typeof cmdValue === 'undefined') {
console.error('no command given!');
process.exit(1);
}
console.log('command:', cmdValue);
console.log('environment:', envValue || "no environment given");Angled brackets (e.g. <cmd>) indicate required input. Square brackets (e.g. [env]) indicate optional input.
Git-style sub-commands#
// file: ./examples/pm
var program = require('commander');
program
.version('0.1.0')
.command('install [name]', 'install one or more packages')
.command('search [query]', 'search with optional query')
.command('list', 'list packages installed', {isDefault: true})
.parse(process.argv);When .command() is invoked with a description argument, no .action(callback) should be called to handle sub-commands, otherwise there will be an error. This tells commander that you're going to use separate executables for sub-commands, much like git(1) and other popular tools.
The commander will try to search the executables in the directory of the entry script (like ./examples/pm) with the name program-command, like pm-install, pm-search.
Options can be passed with the call to .command(). Specifying true for opts.noHelp will remove the subcommand from the generated help output. Specifying true for opts.isDefault will run the subcommand if no other subcommand is specified.
If the program is designed to be installed globally, make sure the executables have proper modes, like 755.
--harmony#
You can enable --harmony option in two ways:
- Use
#! /usr/bin/env node --harmonyin the sub-commands scripts. Note some os version don’t support this pattern. - Use the
--harmonyoption when call the command, likenode --harmony examples/pm publish. The--harmonyoption will be preserved when spawning sub-command process.
Automated --help#
The help information is auto-generated based on the information commander already knows about your program, so the following --help info is for free:
$ ./examples/pizza --help
Usage: pizza [options]
An application for pizzas ordering
Options:
-h, --help output usage information
-V, --version output the version number
-p, --peppers Add peppers
-P, --pineapple Add pineapple
-b, --bbq Add bbq sauce
-c, --cheese <type> Add the specified type of cheese [marble]
-C, --no-cheese You do not want any cheese
Custom help#
You can display arbitrary -h, --help information
by listening for "--help". Commander will automatically
exit once you are done so that the remainder of your program
does not execute causing undesired behaviors, for example
in the following executable "stuff" will not output when
--help is used.
#!/usr/bin/env node
/**
* Module dependencies.
*/
var program = require('commander');
program
.version('0.1.0')
.option('-f, --foo', 'enable some foo')
.option('-b, --bar', 'enable some bar')
.option('-B, --baz', 'enable some baz');
// must be before .parse() since
// node's emit() is immediate
program.on('--help', function(){
console.log('')
console.log('Examples:');
console.log(' $ custom-help --help');
console.log(' $ custom-help -h');
});
program.parse(process.argv);
console.log('stuff');Yields the following help output when node script-name.js -h or node script-name.js --help are run:
Usage: custom-help [options]
Options:
-h, --help output usage information
-V, --version output the version number
-f, --foo enable some foo
-b, --bar enable some bar
-B, --baz enable some baz
Examples:
$ custom-help --help
$ custom-help -h
.outputHelp(cb)#
Output help information without exiting. Optional callback cb allows post-processing of help text before it is displayed.
If you want to display help by default (e.g. if no command was provided), you can use something like:
var program = require('commander');
var colors = require('colors');
program
.version('0.1.0')
.command('getstream [url]', 'get stream URL')
.parse(process.argv);
if (!process.argv.slice(2).length) {
program.outputHelp(make_red);
}
function make_red(txt) {
return colors.red(txt); //display the help text in red on the console
}.help(cb)#
Output help information and exit immediately. Optional callback cb allows post-processing of help text before it is displayed.
Custom event listeners#
You can execute custom actions by listening to command and option events.
program.on('option:verbose', function () {
process.env.VERBOSE = this.verbose;
});
// error on unknown commands
program.on('command:*', function () {
console.error('Invalid command: %s\nSee --help for a list of available commands.', program.args.join(' '));
process.exit(1);
});Examples#
var program = require('commander');
program
.version('0.1.0')
.option('-C, --chdir <path>', 'change the working directory')
.option('-c, --config <path>', 'set config path. defaults to ./deploy.conf')
.option('-T, --no-tests', 'ignore test hook');
program
.command('setup [env]')
.description('run setup commands for all envs')
.option("-s, --setup_mode [mode]", "Which setup mode to use")
.action(function(env, options){
var mode = options.setup_mode || "normal";
env = env || 'all';
console.log('setup for %s env(s) with %s mode', env, mode);
});
program
.command('exec <cmd>')
.alias('ex')
.description('execute the given remote cmd')
.option("-e, --exec_mode <mode>", "Which exec mode to use")
.action(function(cmd, options){
console.log('exec "%s" using %s mode', cmd, options.exec_mode);
}).on('--help', function() {
console.log('');
console.log('Examples:');
console.log('');
console.log(' $ deploy exec sequential');
console.log(' $ deploy exec async');
});
program
.command('*')
.action(function(env){
console.log('deploying "%s"', env);
});
program.parse(process.argv);More Demos can be found in the examples directory.
License#
MIT discontinuous-range#
DiscontinuousRange(1, 10).subtract(4, 6); // [ 1-3, 7-10 ]
this is a pretty simple module, but it exists to service another project so this'll be pretty lacking documentation. reading the test to see how this works may help. otherwise, here's an example that I think pretty much sums it up
###Example
var all_numbers = new DiscontinuousRange(1, 100);
var bad_numbers = DiscontinuousRange(13).add(8).add(60,80);
var good_numbers = all_numbers.clone().subtract(bad_numbers);
console.log(good_numbers.toString()); //[ 1-7, 9-12, 14-59, 81-100 ]
var random_good_number = good_numbers.index(Math.floor(Math.random() * good_numbers.length));
3.0.2 / 2018-07-19#
- [Fix] Prevent merging
__proto__property (#48) - [Dev Deps] update
eslint,@ljharb/eslint-config,tape - [Tests] up to
nodev10.7,v9.11,v8.11,v7.10,v6.14,v4.9; usenvm install-latest-npm
3.0.1 / 2017-04-27#
- [Fix] deep extending should work with a non-object (#46)
- [Dev Deps] update
tape,eslint,@ljharb/eslint-config - [Tests] up to
nodev7.9,v6.10,v4.8; improve matrix - [Docs] Switch from vb.teelaun.ch to versionbadg.es for the npm version badge SVG.
- [Docs] Add example to readme (#34)
3.0.0 / 2015-07-01#
- [Possible breaking change] Use global "strict" directive (#32)
- [Tests]
intis an ES3 reserved word - [Tests] Test up to
io.jsv2.3 - [Tests] Add
npm run eslint - [Dev Deps] Update
covert,jscs
2.0.1 / 2015-04-25#
- Use an inline
isArraycheck, for ES3 browsers. (#27) - Some old browsers fail when an identifier is
toString - Test latest
nodeandio.jsversions ontravis-ci; speed up builds - Add license info to package.json (#25)
- Update
tape,jscs - Adding a CHANGELOG
2.0.0 / 2014-10-01#
- Increase code coverage to 100%; run code coverage as part of tests
- Add
npm run lint; Run linter as part of tests - Remove nodeType and setInterval checks in isPlainObject
- Updating
tape,jscs,covert - General style and README cleanup
1.3.0 / 2014-06-20#
- Add component.json for browser support (#18)
- Use SVG for badges in README (#16)
- Updating
tape,covert - Updating travis-ci to work with multiple node versions
- Fix
deep === falsebug (returning target as {}) (#14) - Fixing constructor checks in isPlainObject
- Adding additional test coverage
- Adding
npm run coverage - Add LICENSE (#13)
- Adding a warning about
false, per #11 - General style and whitespace cleanup
1.2.1 / 2013-09-14#
- Fixing hasOwnProperty bugs that would only have shown up in specific browsers. Fixes #8
- Updating
tape
1.2.0 / 2013-09-02#
- Updating the README: add badges
- Adding a missing variable reference.
- Using
tapeinstead ofbusterfor tests; add more tests (#7) - Adding node 0.10 to Travis CI (#6)
- Enabling "npm test" and cleaning up package.json (#5)
- Add Travis CI.
1.1.3 / 2012-12-06#
- Added unit tests.
- Ensure extend function is named. (Looks nicer in a stack trace.)
- README cleanup.
1.1.1 / 2012-11-07#
- README cleanup.
- Added installation instructions.
- Added a missing semicolon
1.0.0 / 2012-04-08#
- Initial commit
extend() for Node.js
#
node-extend is a port of the classic extend() method from jQuery. It behaves as you expect. It is simple, tried and true.
Notes:
- Since Node.js >= 4,
Object.assignnow offers the same functionality natively (but without the "deep copy" option). See ECMAScript 2015 (ES6) in Node.js. - Some native implementations of
Object.assignin both Node.js and many browsers (since NPM modules are for the browser too) may not be fully spec-compliant. Checkobject.assignmodule for a compliant candidate.
Installation#
This package is available on npm as: extend
npm install extendUsage#
Syntax: extend ( [deep], target, object1, [objectN] )
Extend one object with one or more others, returning the modified object.
Example:
var extend = require('extend');
extend(targetObject, object1, object2);Keep in mind that the target object will be modified, and will be returned from extend().
If a boolean true is specified as the first argument, extend performs a deep copy, recursively copying any objects it finds. Otherwise, the copy will share structure with the original object(s).
Undefined properties are not copied. However, properties inherited from the object's prototype will be copied over.
Warning: passing false as the first argument is not supported.
Arguments#
deepBoolean (optional) If set, the merge becomes recursive (i.e. deep copy).targetObject The object to extend.object1Object The object that will be merged into the first.objectNObject (Optional) More objects to merge into the first.
License#
node-extend is licensed under the MIT License.
Acknowledgements#
All credit to the jQuery authors for perfecting this amazing utility.
Ported to Node.js by Stefan Thomas with contributions by Jonathan Buchanan and Jordan Harband.
# fast-deep-equal The fastest deep equal with ES6 Map, Set and Typed arrays support.
Install#
npm install fast-deep-equalFeatures#
- ES5 compatible
- works in node.js (8+) and browsers (IE9+)
- checks equality of Date and RegExp objects by value.
ES6 equal (require('fast-deep-equal/es6')) also supports:
- Maps
- Sets
- Typed arrays
Usage#
var equal = require('fast-deep-equal');
console.log(equal({foo: 'bar'}, {foo: 'bar'})); // trueTo support ES6 Maps, Sets and Typed arrays equality use:
var equal = require('fast-deep-equal/es6');
console.log(equal(Int16Array([1, 2]), Int16Array([1, 2]))); // trueTo use with React (avoiding the traversal of React elements' _owner property that contains circular references and is not needed when comparing the elements - borrowed from react-fast-compare):
var equal = require('fast-deep-equal/react');
var equal = require('fast-deep-equal/es6/react');Performance benchmark#
Node.js v12.6.0:
fast-deep-equal x 261,950 ops/sec ±0.52% (89 runs sampled)
fast-deep-equal/es6 x 212,991 ops/sec ±0.34% (92 runs sampled)
fast-equals x 230,957 ops/sec ±0.83% (85 runs sampled)
nano-equal x 187,995 ops/sec ±0.53% (88 runs sampled)
shallow-equal-fuzzy x 138,302 ops/sec ±0.49% (90 runs sampled)
underscore.isEqual x 74,423 ops/sec ±0.38% (89 runs sampled)
lodash.isEqual x 36,637 ops/sec ±0.72% (90 runs sampled)
deep-equal x 2,310 ops/sec ±0.37% (90 runs sampled)
deep-eql x 35,312 ops/sec ±0.67% (91 runs sampled)
ramda.equals x 12,054 ops/sec ±0.40% (91 runs sampled)
util.isDeepStrictEqual x 46,440 ops/sec ±0.43% (90 runs sampled)
assert.deepStrictEqual x 456 ops/sec ±0.71% (88 runs sampled)
The fastest is fast-deep-equal
To run benchmark (requires node.js 6+):
npm run benchmarkPlease note: this benchmark runs against the available test cases. To choose the most performant library for your application, it is recommended to benchmark against your data and to NOT expect this benchmark to reflect the performance difference in your application.
Enterprise support#
fast-deep-equal package is a part of Tidelift enterprise subscription - it provides a centralised commercial support to open-source software users, in addition to the support provided by software maintainers.
Security contact#
To report a security vulnerability, please use the Tidelift security contact. Tidelift will coordinate the fix and disclosure. Please do NOT report security vulnerability via GitHub issues.
License#
MIT # fast-uri
Dependency-free RFC 3986 URI toolbox.
Usage#
Options#
All of the above functions can accept an additional options argument that is an object that can contain one or more of the following properties:
-
scheme(string) Indicates the scheme that the URI should be treated as, overriding the URI's normal scheme parsing behavior. -
reference(string) If set to"suffix", it indicates that the URI is in the suffix format and the parser will use the option'sschemeproperty to determine the URI's scheme. -
tolerant(boolean, false) If set totrue, the parser will relax URI resolving rules. -
absolutePath(boolean, false) If set totrue, the serializer will not resolve a relativepathcomponent. -
unicodeSupport(boolean, false) If set totrue, the parser will unescape non-ASCII characters in the parsed output as per RFC 3987. -
domainHost(boolean, false) If set totrue, the library will treat thehostcomponent as a domain name, and convert IDNs (International Domain Names) as per RFC 5891.
Parse#
const uri = require('fast-uri')
uri.parse('uri://user:pass@example.com:123/one/two.three?q1=a1&q2=a2#body')
// Output
{
scheme: "uri",
userinfo: "user:pass",
host: "example.com",
port: 123,
path: "/one/two.three",
query: "q1=a1&q2=a2",
fragment: "body"
}Serialize#
const uri = require('fast-uri')
uri.serialize({scheme: "http", host: "example.com", fragment: "footer"})
// Output
"http://example.com/#footer"
Resolve#
const uri = require('fast-uri')
uri.resolve("uri://a/b/c/d?q", "../../g")
// Output
"uri://a/g"Equal#
const uri = require('fast-uri')
uri.equal("example://a/b/c/%7Bfoo%7D", "eXAMPLE://a/./b/../b/%63/%7bfoo%7d")
// Output
trueScheme supports#
fast-uri supports inserting custom scheme-dependent processing rules. Currently, fast-uri has built-in support for the following schemes:
Benchmarks#
fast-uri benchmark
┌─────────┬──────────────────────────────────────────┬──────────────────┬──────────────────┬────────────────────────┬────────────────────────┬─────────┐
│ (index) │ Task name │ Latency avg (ns) │ Latency med (ns) │ Throughput avg (ops/s) │ Throughput med (ops/s) │ Samples │
├─────────┼──────────────────────────────────────────┼──────────────────┼──────────────────┼────────────────────────┼────────────────────────┼─────────┤
│ 0 │ 'fast-uri: parse domain' │ '951.31 ± 0.75%' │ '875.00 ± 11.00' │ '1122538 ± 0.01%' │ '1142857 ± 14550' │ 1051187 │
│ 1 │ 'fast-uri: parse IPv4' │ '443.44 ± 0.22%' │ '406.00 ± 3.00' │ '2422762 ± 0.01%' │ '2463054 ± 18335' │ 2255105 │
│ 2 │ 'fast-uri: parse IPv6' │ '1241.6 ± 1.74%' │ '1131.0 ± 30.00' │ '875177 ± 0.02%' │ '884173 ± 24092' │ 805399 │
│ 3 │ 'fast-uri: parse URN' │ '689.19 ± 4.29%' │ '618.00 ± 9.00' │ '1598373 ± 0.01%' │ '1618123 ± 23913' │ 1450972 │
│ 4 │ 'fast-uri: parse URN uuid' │ '1025.4 ± 2.02%' │ '921.00 ± 19.00' │ '1072419 ± 0.02%' │ '1085776 ± 22871' │ 975236 │
│ 5 │ 'fast-uri: serialize uri' │ '1028.5 ± 0.53%' │ '933.00 ± 43.00' │ '1063310 ± 0.02%' │ '1071811 ± 50523' │ 972249 │
│ 6 │ 'fast-uri: serialize long uri with dots' │ '1805.1 ± 0.52%' │ '1627.0 ± 17.00' │ '602620 ± 0.02%' │ '614628 ± 6490' │ 553997 │
│ 7 │ 'fast-uri: serialize IPv6' │ '2569.4 ± 2.69%' │ '2302.0 ± 21.00' │ '426080 ± 0.03%' │ '434405 ± 3999' │ 389194 │
│ 8 │ 'fast-uri: serialize ws' │ '979.39 ± 0.43%' │ '882.00 ± 8.00' │ '1111665 ± 0.02%' │ '1133787 ± 10378' │ 1021045 │
│ 9 │ 'fast-uri: resolve' │ '2208.2 ± 1.08%' │ '1980.0 ± 24.00' │ '495001 ± 0.03%' │ '505051 ± 6049' │ 452848 │
└─────────┴──────────────────────────────────────────┴──────────────────┴──────────────────┴────────────────────────┴────────────────────────┴─────────┘
uri-js benchmark
┌─────────┬───────────────────────────────────────┬──────────────────┬──────────────────┬────────────────────────┬────────────────────────┬─────────┐
│ (index) │ Task name │ Latency avg (ns) │ Latency med (ns) │ Throughput avg (ops/s) │ Throughput med (ops/s) │ Samples │
├─────────┼───────────────────────────────────────┼──────────────────┼──────────────────┼────────────────────────┼────────────────────────┼─────────┤
│ 0 │ 'urijs: parse domain' │ '3618.3 ± 0.43%' │ '3314.0 ± 33.00' │ '294875 ± 0.04%' │ '301750 ± 2975' │ 276375 │
│ 1 │ 'urijs: parse IPv4' │ '4024.1 ± 0.41%' │ '3751.0 ± 25.00' │ '261981 ± 0.04%' │ '266596 ± 1789' │ 248506 │
│ 2 │ 'urijs: parse IPv6' │ '5417.2 ± 0.46%' │ '4968.0 ± 43.00' │ '196023 ± 0.05%' │ '201288 ± 1727' │ 184598 │
│ 3 │ 'urijs: parse URN' │ '1324.2 ± 0.23%' │ '1229.0 ± 17.00' │ '801535 ± 0.02%' │ '813670 ± 11413' │ 755185 │
│ 4 │ 'urijs: parse URN uuid' │ '1822.0 ± 3.08%' │ '1655.0 ± 15.00' │ '594433 ± 0.02%' │ '604230 ± 5427' │ 548843 │
│ 5 │ 'urijs: serialize uri' │ '4196.8 ± 0.36%' │ '3908.0 ± 27.00' │ '251146 ± 0.04%' │ '255885 ± 1756' │ 238276 │
│ 6 │ 'urijs: serialize long uri with dots' │ '8331.0 ± 1.30%' │ '7658.0 ± 72.00' │ '126440 ± 0.07%' │ '130582 ± 1239' │ 120034 │
│ 7 │ 'urijs: serialize IPv6' │ '5685.5 ± 0.30%' │ '5366.0 ± 33.00' │ '182632 ± 0.05%' │ '186359 ± 1153' │ 175886 │
│ 8 │ 'urijs: serialize ws' │ '4159.3 ± 0.20%' │ '3899.0 ± 28.00' │ '250459 ± 0.04%' │ '256476 ± 1855' │ 240423 │
│ 9 │ 'urijs: resolve' │ '6729.9 ± 0.39%' │ '6261.0 ± 37.00' │ '156361 ± 0.06%' │ '159719 ± 949' │ 148591 │
└─────────┴───────────────────────────────────────┴──────────────────┴──────────────────┴────────────────────────┴────────────────────────┴─────────┘
WHATWG URL benchmark
┌─────────┬────────────────────────────┬──────────────────┬──────────────────┬────────────────────────┬────────────────────────┬─────────┐
│ (index) │ Task name │ Latency avg (ns) │ Latency med (ns) │ Throughput avg (ops/s) │ Throughput med (ops/s) │ Samples │
├─────────┼────────────────────────────┼──────────────────┼──────────────────┼────────────────────────┼────────────────────────┼─────────┤
│ 0 │ 'WHATWG URL: parse domain' │ '475.22 ± 0.20%' │ '444.00 ± 5.00' │ '2217599 ± 0.01%' │ '2252252 ± 25652' │ 2104289 │
│ 1 │ 'WHATWG URL: parse URN' │ '384.78 ± 0.85%' │ '350.00 ± 5.00' │ '2809071 ± 0.01%' │ '2857143 ± 41408' │ 2598885 │
└─────────┴────────────────────────────┴──────────────────┴──────────────────┴────────────────────────┴────────────────────────┴─────────┘
TODO#
- Support MailTo
- Be 100% iso compatible with uri-js
License#
Licensed under BSD-3-Clause. # json-schema-traverse Traverse JSON Schema passing each schema object to callback
Install#
npm install json-schema-traverse
Usage#
const traverse = require('json-schema-traverse');
const schema = {
properties: {
foo: {type: 'string'},
bar: {type: 'integer'}
}
};
traverse(schema, {cb});
// cb is called 3 times with:
// 1. root schema
// 2. {type: 'string'}
// 3. {type: 'integer'}
// Or:
traverse(schema, {cb: {pre, post}});
// pre is called 3 times with:
// 1. root schema
// 2. {type: 'string'}
// 3. {type: 'integer'}
//
// post is called 3 times with:
// 1. {type: 'string'}
// 2. {type: 'integer'}
// 3. root schema
Callback function cb is called for each schema object (not including draft-06 boolean schemas), including the root schema, in pre-order traversal. Schema references ($ref) are not resolved, they are passed as is. Alternatively, you can pass a {pre, post} object as cb, and then pre will be called before traversing child elements, and post will be called after all child elements have been traversed.
Callback is passed these parameters:
- schema: the current schema object
- JSON pointer: from the root schema to the current schema object
- root schema: the schema passed to
traverseobject - parent JSON pointer: from the root schema to the parent schema object (see below)
- parent keyword: the keyword inside which this schema appears (e.g.
properties,anyOf, etc.) - parent schema: not necessarily parent object/array; in the example above the parent schema for
{type: 'string'}is the root schema - index/property: index or property name in the array/object containing multiple schemas; in the example above for
{type: 'string'}the property name is'foo'
Traverse objects in all unknown keywords#
const traverse = require('json-schema-traverse');
const schema = {
mySchema: {
minimum: 1,
maximum: 2
}
};
traverse(schema, {allKeys: true, cb});
// cb is called 2 times with:
// 1. root schema
// 2. mySchemaWithout option allKeys: true callback will be called only with root schema.
Enterprise support#
json-schema-traverse package is a part of Tidelift enterprise subscription - it provides a centralised commercial support to open-source software users, in addition to the support provided by software maintainers.
Security contact#
To report a security vulnerability, please use the Tidelift security contact. Tidelift will coordinate the fix and disclosure. Please do NOT report security vulnerability via GitHub issues.
License#
Moo!#
Moo is a highly-optimised tokenizer/lexer generator. Use it to tokenize your strings, before parsing 'em with a parser like nearley or whatever else you're into.
- Fast
- Convenient
- uses Regular Expressions
- tracks Line Numbers
- handles Keywords
- supports States
- custom Errors
- is even Iterable
- has no dependencies
- 4KB minified + gzipped
- Moo!
Is it fast?#
Yup! Flying-cows-and-singed-steak fast.
Moo is the fastest JS tokenizer around. It's ~2–10x faster than most other tokenizers; it's a couple orders of magnitude faster than some of the slower ones.
Define your tokens using regular expressions. Moo will compile 'em down to a single RegExp for performance. It uses the new ES6 sticky flag where possible to make things faster; otherwise it falls back to an almost-as-efficient workaround. (For more than you ever wanted to know about this, read adventures in the land of substrings and RegExps.)
You might be able to go faster still by writing your lexer by hand rather than using RegExps, but that's icky.
Oh, and it avoids parsing RegExps by itself. Because that would be horrible.
Usage#
First, you need to do the needful: $ npm install moo, or whatever will ship this code to your computer. Alternatively, grab the moo.js file by itself and slap it into your web page via a <script> tag; moo is completely standalone.
Then you can start roasting your very own lexer/tokenizer:
const moo = require('moo')
let lexer = moo.compile({
WS: /[ \t]+/,
comment: /\/\/.*?$/,
number: /0|[1-9][0-9]*/,
string: /"(?:\\["\\]|[^\n"\\])*"/,
lparen: '(',
rparen: ')',
keyword: ['while', 'if', 'else', 'moo', 'cows'],
NL: { match: /\n/, lineBreaks: true },
})And now throw some text at it:
lexer.reset('while (10) cows\nmoo')
lexer.next() // -> { type: 'keyword', value: 'while' }
lexer.next() // -> { type: 'WS', value: ' ' }
lexer.next() // -> { type: 'lparen', value: '(' }
lexer.next() // -> { type: 'number', value: '10' }
// ...When you reach the end of Moo's internal buffer, next() will return undefined. You can always reset() it and feed it more data when that happens.
On Regular Expressions#
RegExps are nifty for making tokenizers, but they can be a bit of a pain. Here are some things to be aware of:
-
You often want to use non-greedy quantifiers: e.g.
*?instead of*. Otherwise your tokens will be longer than you expect:let lexer = moo.compile({ string: /".*"/, // greedy quantifier * // ... }) lexer.reset('"foo" "bar"') lexer.next() // -> { type: 'string', value: 'foo" "bar' }Better:
let lexer = moo.compile({ string: /".*?"/, // non-greedy quantifier *? // ... }) lexer.reset('"foo" "bar"') lexer.next() // -> { type: 'string', value: 'foo' } lexer.next() // -> { type: 'space', value: ' ' } lexer.next() // -> { type: 'string', value: 'bar' } -
The order of your rules matters. Earlier ones will take precedence.
moo.compile({ identifier: /[a-z0-9]+/, number: /[0-9]+/, }).reset('42').next() // -> { type: 'identifier', value: '42' } moo.compile({ number: /[0-9]+/, identifier: /[a-z0-9]+/, }).reset('42').next() // -> { type: 'number', value: '42' } -
Moo uses multiline RegExps. This has a few quirks: for example, the dot
/./doesn't include newlines. Use[^]instead if you want to match newlines too. -
Since an excluding character ranges like
/[^ ]/(which matches anything but a space) will include newlines, you have to be careful not to include them by accident! In particular, the whitespace metacharacter\sincludes newlines.
Line Numbers#
Moo tracks detailed information about the input for you.
It will track line numbers, as long as you apply the lineBreaks: true option to any rules which might contain newlines. Moo will try to warn you if you forget to do this.
Note that this is false by default, for performance reasons: counting the number of lines in a matched token has a small cost. For optimal performance, only match newlines inside a dedicated token:
newline: {match: '\n', lineBreaks: true},Token Info#
Token objects (returned from next()) have the following attributes:
type: the name of the group, as passed to compile.text: the string that was matched.value: the string that was matched, transformed by yourvaluefunction (if any).offset: the number of bytes from the start of the buffer where the match starts.lineBreaks: the number of line breaks found in the match. (Always zero if this rule haslineBreaks: false.)line: the line number of the beginning of the match, starting from 1.col: the column where the match begins, starting from 1.
Value vs. Text#
The value is the same as the text, unless you provide a value transform.
const moo = require('moo')
const lexer = moo.compile({
ws: /[ \t]+/,
string: {match: /"(?:\\["\\]|[^\n"\\])*"/, value: s => s.slice(1, -1)},
})
lexer.reset('"test"')
lexer.next() /* { value: 'test', text: '"test"', ... } */Reset#
Calling reset() on your lexer will empty its internal buffer, and set the line, column, and offset counts back to their initial value.
If you don't want this, you can save() the state, and later pass it as the second argument to reset() to explicitly control the internal state of the lexer.
lexer.reset('some line\n')
let info = lexer.save() // -> { line: 10 }
lexer.next() // -> { line: 10 }
lexer.next() // -> { line: 11 }
// ...
lexer.reset('a different line\n', info)
lexer.next() // -> { line: 10 }Keywords#
Moo makes it convenient to define literals.
moo.compile({
lparen: '(',
rparen: ')',
keyword: ['while', 'if', 'else', 'moo', 'cows'],
})It'll automatically compile them into regular expressions, escaping them where necessary.
Keywords should be written using the keywords transform.
moo.compile({
IDEN: {match: /[a-zA-Z]+/, type: moo.keywords({
KW: ['while', 'if', 'else', 'moo', 'cows'],
})},
SPACE: {match: /\s+/, lineBreaks: true},
})Why?#
You need to do this to ensure the longest match principle applies, even in edge cases.
Imagine trying to parse the input className with the following rules:
keyword: ['class'],
identifier: /[a-zA-Z]+/,You'll get two tokens — ['class', 'Name'] -- which is not what you want! If you swap the order of the rules, you'll fix this example; but now you'll lex class wrong (as an identifier).
The keywords helper checks matches against the list of keywords; if any of them match, it uses the type 'keyword' instead of 'identifier' (for this example).
Keyword Types#
Keywords can also have individual types.
let lexer = moo.compile({
name: {match: /[a-zA-Z]+/, type: moo.keywords({
'kw-class': 'class',
'kw-def': 'def',
'kw-if': 'if',
})},
// ...
})
lexer.reset('def foo')
lexer.next() // -> { type: 'kw-def', value: 'def' }
lexer.next() // space
lexer.next() // -> { type: 'name', value: 'foo' }You can use Object.fromEntries to easily construct keyword objects:
Object.fromEntries(['class', 'def', 'if'].map(k => ['kw-' + k, k]))States#
Moo allows you to define multiple lexer states. Each state defines its own separate set of token rules. Your lexer will start off in the first state given to moo.states({}).
Rules can be annotated with next, push, and pop, to change the current state after that token is matched. A "stack" of past states is kept, which is used by push and pop.
next: 'bar'moves to the state namedbar. (The stack is not changed.)push: 'bar'moves to the state namedbar, and pushes the old state onto the stack.pop: 1removes one state from the top of the stack, and moves to that state. (Only1is supported.)
Only rules from the current state can be matched. You need to copy your rule into all the states you want it to be matched in.
For example, to tokenize JS-style string interpolation such as a${{c: d}}e, you might use:
let lexer = moo.states({
main: {
strstart: {match: '`', push: 'lit'},
ident: /\w+/,
lbrace: {match: '{', push: 'main'},
rbrace: {match: '}', pop: 1},
colon: ':',
space: {match: /\s+/, lineBreaks: true},
},
lit: {
interp: {match: '${', push: 'main'},
escape: /\\./,
strend: {match: '`', pop: 1},
const: {match: /(?:[^$`]|\$(?!\{))+/, lineBreaks: true},
},
})
// <= `a${{c: d}}e`
// => strstart const interp lbrace ident colon space ident rbrace rbrace const strendThe rbrace rule is annotated with pop, so it moves from the main state into either lit or main, depending on the stack.
Errors#
If none of your rules match, Moo will throw an Error; since it doesn't know what else to do.
If you prefer, you can have moo return an error token instead of throwing an exception. The error token will contain the whole of the rest of the buffer.
moo.compile({
// ...
myError: moo.error,
})
moo.reset('invalid')
moo.next() // -> { type: 'myError', value: 'invalid', text: 'invalid', offset: 0, lineBreaks: 0, line: 1, col: 1 }
moo.next() // -> undefinedYou can have a token type that both matches tokens and contains error values.
moo.compile({
// ...
myError: {match: /[\$?`]/, error: true},
})Formatting errors#
If you want to throw an error from your parser, you might find formatError helpful. Call it with the offending token:
throw new Error(lexer.formatError(token, "invalid syntax"))It returns a string with a pretty error message.
Error: invalid syntax at line 2 col 15:
totally valid `syntax`
^
Iteration#
Iterators: we got 'em.
for (let here of lexer) {
// here = { type: 'number', value: '123', ... }
}Create an array of tokens.
let tokens = Array.from(lexer);Use itt's iteration tools with Moo.
for (let [here, next] of itt(lexer).lookahead()) { // pass a number if you need more tokens
// enjoy!
}Transform#
Moo doesn't allow capturing groups, but you can supply a transform function, value(), which will be called on the value before storing it in the Token object.
moo.compile({
STRING: [
{match: /"""[^]*?"""/, lineBreaks: true, value: x => x.slice(3, -3)},
{match: /"(?:\\["\\rn]|[^"\\])*?"/, lineBreaks: true, value: x => x.slice(1, -1)},
{match: /'(?:\\['\\rn]|[^'\\])*?'/, lineBreaks: true, value: x => x.slice(1, -1)},
],
// ...
})Contributing#
Do check the FAQ.
Before submitting an issue, remember...
# nearley ↗️
nearley is a simple, fast and powerful parsing toolkit. It consists of:
- A powerful, modular DSL for describing languages
- An efficient, lightweight Earley parser
- Loads of tools, editor plug-ins, and other goodies!
nearley is a streaming parser with support for catching errors gracefully and providing all parsings for ambiguous grammars. It is compatible with a variety of lexers (we recommend moo). It comes with tools for creating tests, railroad diagrams and fuzzers from your grammars, and has support for a variety of editors and platforms. It works in both node and the browser.
Unlike most other parser generators, nearley can handle any grammar you can define in BNF (and more!). In particular, while most existing JS parsers such as PEGjs and Jison choke on certain grammars (e.g. left recursive ones), nearley handles them easily and efficiently by using the Earley parsing algorithm.
nearley is used by a wide variety of projects:
- artificial intelligence and
- computational linguistics classes at universities;
- file format parsers;
- data-driven markup languages;
- compilers for real-world programming languages;
- and nearley itself! The nearley compiler is bootstrapped.
nearley is an npm staff pick.
Documentation#
Please visit our website https://nearley.js.org to get started! You will find a tutorial, detailed reference documents, and links to several real-world examples to get inspired.
Contributing#
Please read this document before working on nearley. If you are interested in contributing but unsure where to start, take a look at the issues labeled "up for grabs" on the issue tracker, or message a maintainer (@kach or @tjvr on Github).
nearley is MIT licensed.
A big thanks to Nathan Dinsmore for teaching me how to Earley, Aria Stewart for helping structure nearley into a mature module, and Robin Windels for bootstrapping the grammar. Additionally, Jacob Edelman wrote an experimental JavaScript parser with nearley and contributed ideas for EBNF support. Joshua T. Corbin refactored the compiler to be much, much prettier. Bojidar Marinov implemented postprocessors-in-other-languages. Shachar Itzhaky fixed a subtle bug with nullables.
Citing nearley#
If you are citing nearley in academic work, please use the following BibTeX entry.
@misc{nearley,
author = "Kartik Chandra and Tim Radvan",
title = "{nearley}: a parsing toolkit for {JavaScript}",
year = {2014},
doi = {10.5281/zenodo.3897993},
url = {https://github.com/kach/nearley}
}Punycode.js is a robust Punycode converter that fully complies to RFC 3492 and RFC 5891.
This JavaScript library is the result of comparing, optimizing and documenting different open-source implementations of the Punycode algorithm:
- The C example code from RFC 3492
punycode.cby Markus W. Scherer (IBM)punycode.cby Ben Noordhuis- JavaScript implementation by some
punycode.jsby Ben Noordhuis (note: not fully compliant)
This project was bundled with Node.js from v0.6.2+ until v7 (soft-deprecated).
This project provides a CommonJS module that uses ES2015+ features and JavaScript module, which work in modern Node.js versions and browsers. For the old Punycode.js version that offers the same functionality in a UMD build with support for older pre-ES2015 runtimes, including Rhino, Ringo, and Narwhal, see v1.4.1.
Installation#
Via npm:
npm install punycode --saveIn Node.js:
⚠️ Note that userland modules don't hide core modules. For example,
require('punycode')still imports the deprecated core module even if you executednpm install punycode. Userequire('punycode/')to import userland modules rather than core modules.
const punycode = require('punycode/');API#
punycode.decode(string)#
Converts a Punycode string of ASCII symbols to a string of Unicode symbols.
// decode domain name parts
punycode.decode('maana-pta'); // 'mañana'
punycode.decode('--dqo34k'); // '☃-⌘'punycode.encode(string)#
Converts a string of Unicode symbols to a Punycode string of ASCII symbols.
// encode domain name parts
punycode.encode('mañana'); // 'maana-pta'
punycode.encode('☃-⌘'); // '--dqo34k'punycode.toUnicode(input)#
Converts a Punycode string representing a domain name or an email address to Unicode. Only the Punycoded parts of the input will be converted, i.e. it doesn’t matter if you call it on a string that has already been converted to Unicode.
// decode domain names
punycode.toUnicode('xn--maana-pta.com');
// → 'mañana.com'
punycode.toUnicode('xn----dqo34k.com');
// → '☃-⌘.com'
// decode email addresses
punycode.toUnicode('джумла@xn--p-8sbkgc5ag7bhce.xn--ba-lmcq');
// → 'джумла@джpумлатест.bрфa'punycode.toASCII(input)#
Converts a lowercased Unicode string representing a domain name or an email address to Punycode. Only the non-ASCII parts of the input will be converted, i.e. it doesn’t matter if you call it with a domain that’s already in ASCII.
// encode domain names
punycode.toASCII('mañana.com');
// → 'xn--maana-pta.com'
punycode.toASCII('☃-⌘.com');
// → 'xn----dqo34k.com'
// encode email addresses
punycode.toASCII('джумла@джpумлатест.bрфa');
// → 'джумла@xn--p-8sbkgc5ag7bhce.xn--ba-lmcq'punycode.ucs2#
punycode.ucs2.decode(string)#
Creates an array containing the numeric code point values of each Unicode symbol in the string. While JavaScript uses UCS-2 internally, this function will convert a pair of surrogate halves (each of which UCS-2 exposes as separate characters) into a single code point, matching UTF-16.
punycode.ucs2.decode('abc');
// → [0x61, 0x62, 0x63]
// surrogate pair for U+1D306 TETRAGRAM FOR CENTRE:
punycode.ucs2.decode('\uD834\uDF06');
// → [0x1D306]punycode.ucs2.encode(codePoints)#
Creates a string based on an array of numeric code point values.
punycode.ucs2.encode([0x61, 0x62, 0x63]);
// → 'abc'
punycode.ucs2.encode([0x1D306]);
// → '\uD834\uDF06'punycode.version#
A string representing the current Punycode.js version number.
For maintainers#
How to publish a new release#
-
On the
mainbranch, bump the version number inpackage.json:npm version patch -m 'Release v%s'Instead of
patch, useminorormajoras needed.Note that this produces a Git commit + tag.
-
Push the release commit and tag:
git push && git push --tagsOur CI then automatically publishes the new release to npm, under both the
punycodeandpunycode.jsnames.
Author#
| Mathias Bynens |
License#
Punycode.js is available under the MIT license. Railroad-diagram Generator#
This is a small js library for generating railroad diagrams (like what JSON.org uses) using SVG.
Railroad diagrams are a way of visually representing a grammar in a form that is more readable than using regular expressions or BNF. I think (though I haven't given it a lot of thought yet) that if it's easy to write a context-free grammar for the language, the corresponding railroad diagram will be easy as well.
There are several railroad-diagram generators out there, but none of them had the visual appeal I wanted. Here's an example of how they look! And here's an online generator for you to play with and get SVG code from!
The library now exists in a Python port as well! See the information further down.
Details#
To use the library, just include the js and css files, and then call the Diagram() function. Its arguments are the components of the diagram (Diagram is a special form of Sequence). An alternative to Diagram() is ComplexDiagram() which is used to describe a complex type diagram. Components are either leaves or containers.
The leaves:
- Terminal(text) or a bare string - represents literal text
- NonTerminal(text) - represents an instruction or another production
- Comment(text) - a comment
- Skip() - an empty line
The containers:
- Sequence(children) - like simple concatenation in a regex
- Choice(index, children) - like | in a regex. The index argument specifies which child is the "normal" choice and should go in the middle
- Optional(child, skip) - like ? in a regex. A shorthand for
Choice(1, [Skip(), child]). If the optionalskipparameter has the value"skip", it instead puts the Skip() in the straight-line path, for when the "normal" behavior is to omit the item. - OneOrMore(child, repeat) - like + in a regex. The 'repeat' argument is optional, and specifies something that must go between the repetitions.
- ZeroOrMore(child, repeat, skip) - like * in a regex. A shorthand for
Optional(OneOrMore(child, repeat)). The optionalskipparameter is identical to Optional().
For convenience, each component can be called with or without new.
If called without new,
the container components become n-ary;
that is, you can say either new Sequence([A, B]) or just Sequence(A,B).
After constructing a Diagram, call .format(...padding) on it, specifying 0-4 padding values (just like CSS) for some additional "breathing space" around the diagram (the paddings default to 20px).
The result can either be .toString()'d for the markup, or .toSVG()'d for an <svg> element, which can then be immediately inserted to the document. As a convenience, Diagram also has an .addTo(element) method, which immediately converts it to SVG and appends it to the referenced element with default paddings. element defaults to document.body.
Options#
There are a few options you can tweak, at the bottom of the file. Just tweak either until the diagram looks like what you want. You can also change the CSS file - feel free to tweak to your heart's content. Note, though, that if you change the text sizes in the CSS, you'll have to go adjust the metrics for the leaf nodes as well.
- VERTICAL_SEPARATION - sets the minimum amount of vertical separation between two items. Note that the stroke width isn't counted when computing the separation; this shouldn't be relevant unless you have a very small separation or very large stroke width.
- ARC_RADIUS - the radius of the arcs used in the branching containers like Choice. This has a relatively large effect on the size of non-trivial diagrams. Both tight and loose values look good, depending on what you're going for.
- DIAGRAM_CLASS - the class set on the root
<svg>element of each diagram, for use in the CSS stylesheet. - STROKE_ODD_PIXEL_LENGTH - the default stylesheet uses odd pixel lengths for 'stroke'. Due to rasterization artifacts, they look best when the item has been translated half a pixel in both directions. If you change the styling to use a stroke with even pixel lengths, you'll want to set this variable to
false. - INTERNAL_ALIGNMENT - when some branches of a container are narrower than others, this determines how they're aligned in the extra space. Defaults to "center", but can be set to "left" or "right".
Caveats#
At this early stage, the generator is feature-complete and works as intended, but still has several TODOs:
- The font-sizes are hard-coded right now, and the font handling in general is very dumb - I'm just guessing at some metrics that are probably "good enough" rather than measuring things properly.
Python Port#
In addition to the canonical JS version, the library now exists as a Python library as well.
Using it is basically identical. The config variables are globals in the file, and so may be adjusted either manually or via tweaking from inside your program.
The main difference from the JS port is how you extract the string from the Diagram. You'll find a writeSvg(writerFunc) method on Diagram, which takes a callback of one argument and passes it the string form of the diagram. For example, it can be used like Diagram(...).writeSvg(sys.stdout.write) to write to stdout. Note: the callback will be called multiple times as it builds up the string, not just once with the whole thing. If you need it all at once, consider something like a StringIO as an easy way to collect it into a single string.
License#
This document and all associated files in the github project are licensed under CC0
.
This means you can reuse, remix, or otherwise appropriate this project for your own use without restriction.
(The actual legal meaning can be found at the above link.)
Don't ask me for permission to use any part of this project, just use it.
I would appreciate attribution, but that is not required by the license.
# randexp.js
randexp will generate a random string that matches a given RegExp Javascript object.
Usage#
var RandExp = require('randexp');
// supports grouping and piping
new RandExp(/hello+ (world|to you)/).gen();
// => hellooooooooooooooooooo world
// sets and ranges and references
new RandExp(/<([a-z]\w{0,20})>foo<\1>/).gen();
// => <m5xhdg>foo<m5xhdg>
// wildcard
new RandExp(/random stuff: .+/).gen();
// => random stuff: l3m;Hf9XYbI [YPaxV>U*4-_F!WXQh9>;rH3i l!8.zoh?[utt1OWFQrE ^~8zEQm]~tK
// ignore case
new RandExp(/xxx xtreme dragon warrior xxx/i).gen();
// => xxx xtReME dRAGON warRiOR xXX
// dynamic regexp shortcut
new RandExp('(sun|mon|tue|wednes|thurs|fri|satur)day', 'i');
// is the same as
new RandExp(new RegExp('(sun|mon|tue|wednes|thurs|fri|satur)day', 'i'));If you're only going to use gen() once with a regexp and want slightly shorter syntax for it
var randexp = require('randexp').randexp;
randexp(/[1-6]/); // 4
randexp('great|good( job)?|excellent'); // greatIf you miss the old syntax
require('randexp').sugar();
/yes|no|maybe|i don't know/.gen(); // maybeMotivation#
Regular expressions are used in every language, every programmer is familiar with them. Regex can be used to easily express complex strings. What better way to generate a random string than with a language you can use to express the string you want?
Thanks to String-Random for giving me the idea to make this in the first place and randexp for the sweet .gen() syntax.
Default Range#
The default generated character range includes printable ASCII. In order to add or remove characters,
a defaultRange attribute is exposed. you can subtract(from, to) and add(from, to)
var randexp = new RandExp(/random stuff: .+/);
randexp.defaultRange.subtract(32, 126);
randexp.defaultRange.add(0, 65535);
randexp.gen();
// => random stuff: 湐箻ໜ䫴㳸長���邓蕲뤀쑡篷皇硬剈궦佔칗븛뀃匫鴔事좍ﯣ⭼ꝏ䭍詳蒂䥂뽭Custom PRNG#
The default randomness is provided by Math.random(). If you need to use a seedable or cryptographic PRNG, you
can override RandExp.prototype.randInt or randexp.randInt (where randexp is an instance of RandExp). randInt(from, to) accepts an inclusive range and returns a randomly selected
number within that range.
Infinite Repetitionals#
Repetitional tokens such as *, +, and {3,} have an infinite max range. In this case, randexp looks at its min and adds 100 to it to get a useable max value. If you want to use another int other than 100 you can change the max property in RandExp.prototype or the RandExp instance.
var randexp = new RandExp(/no{1,}/);
randexp.max = 1000000;With RandExp.sugar()
var regexp = /(hi)*/;
regexp.max = 1000000;Bad Regular Expressions#
There are some regular expressions which can never match any string.
-
Ones with badly placed positionals such as
/a^/and/$c/m. Randexp will ignore positional tokens. -
Back references to non-existing groups like
/(a)\1\2/. Randexp will ignore those references, returning an empty string for them. If the group exists only after the reference is used such as in/\1 (hey)/, it will too be ignored. -
Custom negated character sets with two sets inside that cancel each other out. Example:
/[^\w\W]/. If you give this to randexp, it will return an empty string for this set since it can't match anything.
Projects based on randexp.js#
JSON-Schema Faker#
Use generators to populate JSON Schema samples. See: jsf on github and jsf demo page.
Install#
Node.js#
npm install randexp
Browser#
Download the minified version from the latest release.
Tests#
Tests are written with mocha
npm testLicense#
Load module from string in Node.
Install#
$ npm install --save require-from-string
Usage#
var requireFromString = require('require-from-string');
requireFromString('module.exports = 1');
//=> 1API#
requireFromString(code, [filename], [options])#
code#
Required
Type: string
Module code.
filename#
Type: string
Default: ''
Optional filename.
options#
Type: object
appendPaths#
Type: Array
List of paths, that will be appended to module paths. Useful, when you want
to be able require modules from these paths.
prependPaths#
Type: Array
Same as appendPaths, but paths will be prepended.
License#
MIT © Vsevolod Strukchinsky # Regular Expression Tokenizer
Tokenizes strings that represent a regular expressions.
Usage#
var ret = require('ret');
var tokens = ret(/foo|bar/.source);tokens will contain the following object
{
"type": ret.types.ROOT
"options": [
[ { "type": ret.types.CHAR, "value", 102 },
{ "type": ret.types.CHAR, "value", 111 },
{ "type": ret.types.CHAR, "value", 111 } ],
[ { "type": ret.types.CHAR, "value", 98 },
{ "type": ret.types.CHAR, "value", 97 },
{ "type": ret.types.CHAR, "value", 114 } ]
]
}Token Types#
ret.types is a collection of the various token types exported by ret.
ROOT#
Only used in the root of the regexp. This is needed due to the posibility of the root containing a pipe | character. In that case, the token will have an options key that will be an array of arrays of tokens. If not, it will contain a stack key that is an array of tokens.
{
"type": ret.types.ROOT,
"stack": [token1, token2...],
}{
"type": ret.types.ROOT,
"options" [
[token1, token2...],
[othertoken1, othertoken2...]
...
],
}GROUP#
Groups contain tokens that are inside of a parenthesis. If the group begins with ? followed by another character, it's a special type of group. A ':' tells the group not to be remembered when exec is used. '=' means the previous token matches only if followed by this group, and '!' means the previous token matches only if NOT followed.
Like root, it can contain an options key instead of stack if there is a pipe.
{
"type": ret.types.GROUP,
"remember" true,
"followedBy": false,
"notFollowedBy": false,
"stack": [token1, token2...],
}{
"type": ret.types.GROUP,
"remember" true,
"followedBy": false,
"notFollowedBy": false,
"options" [
[token1, token2...],
[othertoken1, othertoken2...]
...
],
}POSITION#
\b, \B, ^, and $ specify positions in the regexp.
{
"type": ret.types.POSITION,
"value": "^",
}SET#
Contains a key set specifying what tokens are allowed and a key not specifying if the set should be negated. A set can contain other sets, ranges, and characters.
{
"type": ret.types.SET,
"set": [token1, token2...],
"not": false,
}RANGE#
Used in set tokens to specify a character range. from and to are character codes.
{
"type": ret.types.RANGE,
"from": 97,
"to": 122,
}REPETITION#
{
"type": ret.types.REPETITION,
"min": 0,
"max": Infinity,
"value": token,
}REFERENCE#
References a group token. value is 1-9.
{
"type": ret.types.REFERENCE,
"value": 1,
}CHAR#
Represents a single character token. value is the character code. This might seem a bit cluttering instead of concatenating characters together. But since repetition tokens only repeat the last token and not the last clause like the pipe, it's simpler to do it this way.
{
"type": ret.types.CHAR,
"value": 123,
}Errors#
ret.js will throw errors if given a string with an invalid regular expression. All possible errors are
- Invalid group. When a group with an immediate
?character is followed by an invalid character. It can only be followed by!,=, or:. Example:/(?_abc)/ - Nothing to repeat. Thrown when a repetitional token is used as the first token in the current clause, as in right in the beginning of the regexp or group, or right after a pipe. Example:
/foo|?bar/,/{1,3}foo|bar/,/foo(+bar)/ - Unmatched ). A group was not opened, but was closed. Example:
/hello)2u/ - Unterminated group. A group was not closed. Example:
/(1(23)4/ - Unterminated character class. A custom character set was not closed. Example:
/[abc/
Install#
npm install ret
Tests#
Tests are written with vows
npm testLicense#
MIT Schemes#
A javascript object map of official iana.org Uniform Resource Identifier (URI) Schemes and crowd sourced unofficial schemes.
This can be used to look up the rfc's for the corresponding schemes or check a schemes validity based on of it exists in the list of not.
Usage#
var schemes = require('schemes');
schemes.permanent[0]; // {
// "scheme": "aaa",
// "description": "Diameter Protocol",
// "reference": [
// {
// "type": "rfc",
// "href": "http://www.iana.org/go/rfc6733"
// }
// ]
// }
schemes.provisional[0]; // {
// "scheme": "acr",
// "description": "acr",
// "reference": [],
// "template": "http://www.iana.org/assignments/uri-schemes/prov/acr"
// }
schemes.historical[0]; // {
// "scheme": "fax",
// "description": "fax",
// "reference": [
// {
// "type": "rfc",
// "href": "http://www.iana.org/go/rfc2806"
// },
// {
// "type": "rfc",
// "href": "http://www.iana.org/go/rfc3966"
// }
// ]
// }
schemes.unofficial[0]; // {
// "scheme": "android-app"
// }
schemes.allByName; // {
// 'aaa': { ... } // scheme object
// 'aaas': { ... } // scheme object
// 'about': { ... } // scheme object
// 'acap': { ... } // scheme object
// 'acct': { ... } // scheme object
// 'cap': { ... } // scheme object
// 'cid': { ... } // scheme object
// 'coap': { ... } // scheme object
// 'coaps': { ... } // scheme object
// 'crid': { ... } // scheme object
// ...
// }Contributing#
Part of this module is auto generated from iana official lists, but the unofficial ones are not. If you find that a specific scheme is missing from these lists, please submit a pull request that adds it to the unofficial schemes list.
License#
(The MIT License)
Copyright (c) 2015 Peter Müller munter@fumle.dk
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. # smtp-address-parser
Parse an SMTP (RFC-5321) address.
Some notes#
** Changes in version 1.1.0: **
** Domains are now checked beyond RFC-5321 syntax only **
Domain names must be fully qualified; that is with at least two labels. The top-level domain must have at least two octets.
** Length limitations are now checked **
Total length limit of an address is 986 octets; based on a 1,000 octet SMTP line length.
See https://tools.ietf.org/html/rfc1035 section 2.3.4. Size limits:
Domain names are limited to 255 octets, when encoded with a length byte before each label, and including the top-level zero length label. So, the effctive limit with interstitial dots is 253 octets.
Labels within a domain name are limited to 63 octets.
The above are limits of the DNS protocol, not any particular implementation.
RFC-5321 section 4.5.3.1. “Size Limits and Minimums” still says:
“To the maximum extent possible, implementation techniques that impose no limits on the length of these objects should be used.”



