diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..378eac2 --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +build diff --git a/.gitignore b/.gitignore index 3c3629e..dd87e2d 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ node_modules +build diff --git a/.travis.yml b/.travis.yml index 21d7f7c..6535747 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,4 +3,5 @@ node_js: - '6' - '8' script: +- npm build - npm test diff --git a/README.md b/README.md index 447579f..1c60a30 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ Config is described with a combination of a functions: var parser = root(section({ system: section({ parallelLimit: option({ + defaultValue: 0, parseEnv: Number, parseCli: Number, validate: function() {...} diff --git a/config.ts b/config.ts new file mode 100644 index 0000000..a6fe677 --- /dev/null +++ b/config.ts @@ -0,0 +1,104 @@ +import { root, map, section, option } from './lib'; +import { buildLazyObject } from './lib/lazy'; + +// const map1 = map(section({ +// r: option({ +// defaultValue: '1', +// map: (v) => +v +// }), +// t: option({ +// defaultValue: 0, +// map: (v) => v.toString() +// }) +// }), +// {'': { +// r: 's', +// t: 0 +// }} +// ); + +// const config = root(, {envPrefix: '', cliPrefix: ''})({ +// options: {}, +// env: process.env, +// argv: process.argv +// }); + +// console.log(config); + +const rootOption = option({ + defaultValue: 'root', + map: (v: string): string[] => [].concat(v) +}); +const tralalaOption = option({ + defaultValue: 1234 +}) +const mainSection = section({ + r: rootOption, + t: tralalaOption +}); +const fileMap = map(mainSection, { + 'tralala': { + r: [''], + t: 0 + } +}); +const configParser = root(fileMap, { + envPrefix: '', + cliPrefix: '' +}); +const config2 = configParser({ + options: {}, + env: process.env, + argv: process.argv +}); + +type A = { + system: { + parallelLimit: number; + }; + browsers: { + [x: string]: { + calibrate: boolean; + windowSize: number; + }; + }; +}; + +const parser = root(section({ + system: section({ + parallelLimit: option({ + defaultValue: 123, + parseEnv: Number, + parseCli: Number, + map: (value, config, node) => { + return value * 2; + } + }) + }), + browsers: map(section({ + calibrate: option({ + defaultValue: true + }), + windowSize: option({ + defaultValue: 1024 + }) + }), {'': {}}) +}), { + envPrefix: '', + cliPrefix: '' +}); + +const parsedConfig = parser({ + options: { + browsers: { + '': {calibrate: false, } + }, + system: {parallelLimit: 1} + }, + env: process.env, + argv: process.argv +}); + +const a = root(section({ + id: option({defaultValue: 1}) +}), { envPrefix: '', cliPrefix: '' })({ options: { id: 1 }, env: process.env, argv: process.argv }); diff --git a/lib/core.js b/lib/core.js deleted file mode 100644 index 2335a55..0000000 --- a/lib/core.js +++ /dev/null @@ -1,100 +0,0 @@ -const _ = require('lodash'); -const {buildLazyObject, forceParsing} = require('./lazy'); -const {MissingOptionError, UnknownKeysError} = require('./errors'); -const initLocator = require('./locator'); - -/** - * Single option - */ -function option({ - defaultValue, - parseCli = _.identity, - parseEnv = _.identity, - validate = _.noop, - map: mapFunc = _.identity -}) { - return (locator, parsed) => { - const config = parsed.root; - const currNode = locator.parent ? _.get(config, locator.parent) : config; - - let value; - if (locator.cliOption !== undefined) { - value = parseCli(locator.cliOption); - } else if (locator.envVar !== undefined) { - value = parseEnv(locator.envVar); - } else if (locator.option !== undefined) { - value = locator.option; - } else if (defaultValue !== undefined) { - value = _.isFunction(defaultValue) - ? defaultValue(config, currNode) - : defaultValue; - } else { - throw new MissingOptionError(locator.name); - } - validate(value, config, currNode); - - return mapFunc(value, config, currNode); - }; -} - -/** - * Object with fixed properties. - * Any unknown property will be reported as error. - */ -function section(properties) { - const expectedKeys = _.keys(properties); - return (locator, config) => { - const unknownKeys = _.difference( - _.keys(locator.option), - expectedKeys - ); - if (unknownKeys.length > 0) { - throw new UnknownKeysError( - unknownKeys.map((key) => `${locator.name}.${key}`) - ); - } - - const lazyResult = buildLazyObject(expectedKeys, (key) => { - const parser = properties[key]; - return () => parser(locator.nested(key), config); - }); - - _.set(config, locator.name, lazyResult); - - return lazyResult; - }; -} - -/** - * Object with user-specified keys and values, - * parsed by valueParser. - */ -function map(valueParser, defaultValue) { - return (locator, config) => { - if (locator.option === undefined) { - if (!defaultValue) { - return {}; - } - locator = locator.resetOption(defaultValue); - } - - const optionsToParse = Object.keys(locator.option); - const lazyResult = buildLazyObject(optionsToParse, (key) => { - return () => valueParser(locator.nested(key), config); - }); - _.set(config, locator.name, lazyResult); - - return lazyResult; - }; -} - -function root(rootParser, {envPrefix, cliPrefix}) { - return ({options, env, argv}) => { - const rootLocator = initLocator({options, env, argv, envPrefix, cliPrefix}); - const parsed = {}; - rootParser(rootLocator, parsed); - return forceParsing(parsed.root); - }; -} - -module.exports = {option, section, map, root}; diff --git a/lib/core.ts b/lib/core.ts new file mode 100644 index 0000000..74ae76a --- /dev/null +++ b/lib/core.ts @@ -0,0 +1,119 @@ +import _ from 'lodash'; + +import { MissingOptionError, UnknownKeysError } from './errors'; +import { buildLazyObject, forceParsing } from './lazy'; +import initLocator from './locator'; + +import type { LazyObject } from './types/lazy'; +import type { RootParsedConfig } from './types/common'; +import type { MapParser } from './types/map'; +import type { OptionParser, OptionParserConfig } from './types/option'; +import type { RootParser, RootPrefixes, ConfigParser } from './types/root'; +import type { SectionParser, SectionProperties } from './types/section'; +import type { DeepPartial } from './types/utils'; +import type { Locator } from './types/locator'; + +type Parser = OptionParser | SectionParser | MapParser; + +/** + * Single option + */ +export function option({ + defaultValue, + parseCli = _.identity, + parseEnv = _.identity, + validate = _.noop, + map: mapFunc = _.identity +}: OptionParserConfig): OptionParser { + const validateFunc: typeof validate = validate; + + return (locator, parsed) => { + const config = parsed.root; + const currNode = locator.parent ? _.get(parsed, locator.parent) : config; + + let value: unknown; + if (locator.cliOption !== undefined) { + value = parseCli(locator.cliOption); + } else if (locator.envVar !== undefined) { + value = parseEnv(locator.envVar); + } else if (locator.option !== undefined) { + value = locator.option; + } else if (defaultValue !== undefined) { + value = _.isFunction(defaultValue) + ? defaultValue(config, currNode) + : defaultValue; + } else { + throw new MissingOptionError(locator.name); + } + + validateFunc(value, config, currNode); + + return mapFunc(value, config, currNode); + }; +} + +/** + * Object with fixed properties. + * Any unknown property will be reported as error. + */ +export function section(properties: SectionProperties): SectionParser { + const expectedKeys = _.keys(properties) as Array; + + return (locator, config) => { + const unknownKeys = _.difference( + _.keys(locator.option), + expectedKeys as Array + ); + + if (unknownKeys.length > 0) { + throw new UnknownKeysError( + unknownKeys.map((key) => `${locator.name}.${key}`) + ); + } + + const lazyResult = buildLazyObject(expectedKeys, (key) => { + const parser = properties[key]; + + return () => parser(locator.nested(key) as Locator>, config); + }); + + _.set(config, locator.name, lazyResult); + + return lazyResult; + }; +} + +/** + * Object with user-specified keys and values, + * parsed by valueParser. + */ +export function map, V extends T[string] = T[string], R = any>( + valueParser: Parser, + defaultValue: DeepPartial> +): MapParser, R> { + return (locator, config) => { + if (locator.option === undefined) { + if (!defaultValue) { + return {} as LazyObject; + } + locator = locator.resetOption(defaultValue); + } + + const optionsToParse = Object.keys(locator.option as Record); + const lazyResult = buildLazyObject>(optionsToParse, (key) => { + return () => valueParser(locator.nested(key) as Locator>, config); + }); + _.set(config, locator.name, lazyResult); + + return lazyResult; + }; +} + +export function root(rootParser: RootParser, {envPrefix, cliPrefix}: RootPrefixes): ConfigParser { + return ({options, env, argv}) => { + const rootLocator = initLocator({options, env, argv, envPrefix, cliPrefix}); + const parsed = rootParser(rootLocator, {} as RootParsedConfig); + + return forceParsing(parsed); + }; +} diff --git a/lib/errors.js b/lib/errors.ts similarity index 68% rename from lib/errors.js rename to lib/errors.ts index 69d1daf..dc40062 100644 --- a/lib/errors.js +++ b/lib/errors.ts @@ -1,5 +1,7 @@ -class MissingOptionError extends Error { - constructor(optionName) { +export class MissingOptionError extends Error { + public optionName: string; + + constructor(optionName: string) { const message = `${optionName} is required`; super(message); this.name = 'MissingOptionError'; @@ -10,8 +12,10 @@ class MissingOptionError extends Error { } } -class UnknownKeysError extends Error { - constructor(keys) { +export class UnknownKeysError extends Error { + public keys: Array; + + constructor(keys: Array) { const message = `Unknown options: ${keys.join(', ')}`; super(message); this.name = 'UnknownKeysError'; @@ -21,5 +25,3 @@ class UnknownKeysError extends Error { Error.captureStackTrace(this, UnknownKeysError); } } - -module.exports = {MissingOptionError, UnknownKeysError}; diff --git a/lib/index.js b/lib/index.js deleted file mode 100644 index 76fbcbc..0000000 --- a/lib/index.js +++ /dev/null @@ -1,7 +0,0 @@ -const {root, section, map, option} = require('./core'); -const {MissingOptionError, UnknownKeysError} = require('./errors'); - -module.exports = { - root, section, map, option, - MissingOptionError, UnknownKeysError -}; diff --git a/lib/index.ts b/lib/index.ts new file mode 100644 index 0000000..7ec9749 --- /dev/null +++ b/lib/index.ts @@ -0,0 +1,2 @@ +export { root, section, map, option } from './core'; +export { MissingOptionError, UnknownKeysError } from './errors'; diff --git a/lib/lazy.js b/lib/lazy.js deleted file mode 100644 index 1af3c3b..0000000 --- a/lib/lazy.js +++ /dev/null @@ -1,38 +0,0 @@ -const _ = require('lodash'); - -const isLazy = Symbol('isLazy'); - -function buildLazyObject(keys, getKeyGetter) { - const target = { - [isLazy]: true - }; - for (const key of keys) { - defineLazy(target, key, getKeyGetter(key)); - } - return target; -} - -function forceParsing(lazyObject) { - return _.cloneDeep(lazyObject); -} - -function defineLazy(object, key, getter) { - let defined = false; - let value; - - Object.defineProperty(object, key, { - get() { - if (!defined) { - defined = true; - value = getter(); - if (_.isObject(value) && value[isLazy]) { - value = forceParsing(value); - } - } - return value; - }, - enumerable: true - }); -} - -module.exports = {forceParsing, buildLazyObject}; diff --git a/lib/lazy.ts b/lib/lazy.ts new file mode 100644 index 0000000..e381773 --- /dev/null +++ b/lib/lazy.ts @@ -0,0 +1,52 @@ +import _ from 'lodash'; + +import type { LazyObject } from './types/lazy'; + +export const isLazy = Symbol('isLazy'); + +export function buildLazyObject(keys: Array, getKeyGetter: (key: keyof T) => () => (T[keyof T] | LazyObject)): LazyObject { + const target = { + [isLazy]: true + } as LazyObject; + + for (const key of keys) { + defineLazy(target, key, getKeyGetter(key)); + } + + return target; +} + +export function forceParsing(lazyObject: LazyObject): T { + return _.cloneDeep(lazyObject); +} + +function defineLazy(object: LazyObject, key: keyof T, getter: () => T[keyof T] | LazyObject): void { + let defined = false; + let value: T[keyof T]; + + Object.defineProperty(object, key, { + get(): T[keyof T] { + if (!defined) { + defined = true; + const val = getter(); + + if (isLazyObject(val)) { + value = forceParsing(val); + } else { + value = val; + } + } + + return value; + }, + enumerable: true + }); +} + +function isLazyObject(value: T): value is LazyObject { + return _.isObject(value) && hasOwnProperty(value, isLazy) && value[isLazy] === true; +} + +function hasOwnProperty(obj: T, prop: PropertyKey): obj is T & Record { + return obj.hasOwnProperty(prop); +} diff --git a/lib/locator.js b/lib/locator.ts similarity index 62% rename from lib/locator.js rename to lib/locator.ts index 63f8207..a990e13 100644 --- a/lib/locator.js +++ b/lib/locator.ts @@ -1,6 +1,8 @@ -const _ = require('lodash'); +import _ from 'lodash'; -function parseArgv(argv, cliPrefix) { +import type { LocatorArg, Locator, Node, Prefixes } from './types/locator'; + +function parseArgv(argv: Array, cliPrefix: string): Array { return argv.reduce(function(argv, arg) { if (!arg.startsWith(cliPrefix) || !_.includes(arg, '=')) { return argv.concat(arg); @@ -11,20 +13,20 @@ function parseArgv(argv, cliPrefix) { const value = parts.slice(1).join('='); return argv.concat(option, value); - }, []); + }, [] as Array); } -module.exports = function({options, env, argv, envPrefix = '', cliPrefix = '--'}) { +export default function({options, env, argv, envPrefix = '', cliPrefix = '--'}: LocatorArg): Locator { const parsedArgv = parseArgv(argv, cliPrefix); - function getNested(option, {namePrefix, envPrefix, cliPrefix}) { + function getNested(option: T | undefined, {namePrefix, envPrefix, cliPrefix}: Prefixes): (key: keyof T) => Locator { return (subKey) => { - const envName = envPrefix + _.snakeCase(subKey); - const cliFlag = cliPrefix + _.kebabCase(subKey); + const envName = envPrefix + _.snakeCase(subKey.toString()); + const cliFlag = cliPrefix + _.kebabCase(subKey.toString()); const argIndex = parsedArgv.lastIndexOf(cliFlag); const subOption = _.get(option, subKey); - const newName = namePrefix ? `${namePrefix}.${subKey}` : subKey; + const newName = namePrefix ? `${namePrefix}.${subKey}` : subKey.toString(); return mkLocator( { @@ -43,14 +45,11 @@ module.exports = function({options, env, argv, envPrefix = '', cliPrefix = '--'} }; } - function mkLocator(base, prefixes) { + function mkLocator(base: Node, prefixes: Prefixes): Locator { return _.extend(base, { nested: getNested(base.option, prefixes), - resetOption: function(newOptions) { - return _.extend({}, base, { - option: newOptions, - nested: getNested(newOptions, prefixes) - }); + resetOption: function(newOptions: T): Locator { + return mkLocator({ ...base, option: newOptions }, prefixes); } }); } @@ -64,7 +63,7 @@ module.exports = function({options, env, argv, envPrefix = '', cliPrefix = '--'} cliOption: undefined }, { - namePrefix: '', + namePrefix: 'root', envPrefix, cliPrefix } diff --git a/lib/types/common.ts b/lib/types/common.ts new file mode 100644 index 0000000..80666bd --- /dev/null +++ b/lib/types/common.ts @@ -0,0 +1,10 @@ +import type { LazyObject } from './lazy'; +import type { MapParser } from './map'; +import type { OptionParser } from './option'; +import type { SectionParser } from './section'; + +export type ParsedConfig = {[K in keyof T]: LazyObject}; + +export type RootParsedConfig = ParsedConfig<{root: LazyObject}>; + +export type Parser = OptionParser | SectionParser | MapParser; diff --git a/lib/types/lazy.ts b/lib/types/lazy.ts new file mode 100644 index 0000000..f538f4d --- /dev/null +++ b/lib/types/lazy.ts @@ -0,0 +1,5 @@ +import type { isLazy } from "../lazy"; + +export type LazyObject = T & { + [isLazy]: true; +}; diff --git a/lib/types/locator.ts b/lib/types/locator.ts new file mode 100644 index 0000000..f7c232b --- /dev/null +++ b/lib/types/locator.ts @@ -0,0 +1,20 @@ +import type { RootPrefixes, ConfigParserArg } from './root'; + +export type LocatorArg = RootPrefixes & ConfigParserArg; + +export type Prefixes = Required & { + namePrefix: string; +}; + +export type Node = { + name: string; + parent: string; + option?: T; + envVar?: string; + cliOption?: string; +}; + +export interface Locator extends Node { + nested: (key: keyof T) => Locator; + resetOption: (newOption: T) => Locator; +} diff --git a/lib/types/map.ts b/lib/types/map.ts new file mode 100644 index 0000000..c813203 --- /dev/null +++ b/lib/types/map.ts @@ -0,0 +1,6 @@ +import type { RootParsedConfig } from "./common"; +import type { LazyObject } from "./lazy"; +import type { Locator } from "./locator"; +import type { DeepPartial } from "./utils"; + +export type MapParser = (locator: Locator>, config: RootParsedConfig) => LazyObject; diff --git a/lib/types/option.ts b/lib/types/option.ts new file mode 100644 index 0000000..e1877dd --- /dev/null +++ b/lib/types/option.ts @@ -0,0 +1,14 @@ +import type { RootParsedConfig } from './common'; +import type { LazyObject } from './lazy'; +import type { Locator } from './locator'; +import type { DeepPartial } from './utils'; + +export type OptionParserConfig = { + defaultValue?: T | ((config: LazyObject, currNode: LazyObject | LazyObject

) => T); + parseCli?: (input: string) => T; + parseEnv?: (input: string) => T; + validate?: (value: unknown, config: LazyObject, currNode: LazyObject | LazyObject

) => asserts value is T; + map?(value: T, config: LazyObject, currNode: LazyObject | LazyObject

): S; +}; + +export type OptionParser = (locator: Locator>, config: RootParsedConfig) => T; diff --git a/lib/types/root.ts b/lib/types/root.ts new file mode 100644 index 0000000..e39d6a8 --- /dev/null +++ b/lib/types/root.ts @@ -0,0 +1,18 @@ +import type { MapParser } from './map'; +import type { SectionParser } from './section'; +import type { DeepPartial } from './utils'; + +export type ConfigParserArg = { + options?: T; + env: NodeJS.ProcessEnv; + argv: NodeJS.Process["argv"]; +}; + +export type ConfigParser = (arg: ConfigParserArg>) => T; + +export type RootPrefixes = { + envPrefix?: string; + cliPrefix?: string; +}; + +export type RootParser = SectionParser | MapParser; diff --git a/lib/types/section.ts b/lib/types/section.ts new file mode 100644 index 0000000..fdd4300 --- /dev/null +++ b/lib/types/section.ts @@ -0,0 +1,7 @@ +import type { Parser, RootParsedConfig } from './common'; +import type { LazyObject } from './lazy'; +import type { Locator } from './locator'; +import type { DeepPartial } from './utils'; + +export type SectionProperties = {[K in keyof T]: Parser}; +export type SectionParser = (locator: Locator>, config: RootParsedConfig) => LazyObject; diff --git a/lib/types/utils.ts b/lib/types/utils.ts new file mode 100644 index 0000000..75376ea --- /dev/null +++ b/lib/types/utils.ts @@ -0,0 +1,3 @@ +export type DeepPartial = { + [K in keyof T]?: T[K] extends {} ? DeepPartial : T[K]; +} diff --git a/package-lock.json b/package-lock.json index 39844c7..78b0044 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,24 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@tsconfig/recommended": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@tsconfig/recommended/-/recommended-1.0.1.tgz", + "integrity": "sha512-2xN+iGTbPBEzGSnVp/Hd64vKJCJWxsi9gfs88x4PPMyEjHJoA3o5BY9r5OLPHIZU2pAQxkSAsJFqn6itClP8mQ==", + "dev": true + }, + "@types/lodash": { + "version": "4.14.176", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.176.tgz", + "integrity": "sha512-xZmuPTa3rlZoIbtDUyJKZQimJV3bxCmzMIO2c9Pz9afyDro6kr7R79GwcB6mRhuoPmV2p1Vb66WOJH7F886WKQ==", + "dev": true + }, + "@types/node": { + "version": "16.11.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.6.tgz", + "integrity": "sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w==", + "dev": true + }, "acorn": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.1.2.tgz", @@ -16,7 +34,7 @@ "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", "dev": true, "requires": { - "acorn": "3.3.0" + "acorn": "^3.0.4" }, "dependencies": { "acorn": { @@ -33,10 +51,10 @@ "integrity": "sha1-wG9Zh3jETGsWGrr+NGa4GtGBTtI=", "dev": true, "requires": { - "co": "4.6.0", - "fast-deep-equal": "1.0.0", - "json-schema-traverse": "0.3.1", - "json-stable-stringify": "1.0.1" + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "json-schema-traverse": "^0.3.0", + "json-stable-stringify": "^1.0.1" } }, "ajv-keywords": { @@ -69,7 +87,7 @@ "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", "dev": true, "requires": { - "sprintf-js": "1.0.3" + "sprintf-js": "~1.0.2" } }, "array-union": { @@ -78,7 +96,7 @@ "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", "dev": true, "requires": { - "array-uniq": "1.0.3" + "array-uniq": "^1.0.1" } }, "array-uniq": { @@ -105,9 +123,9 @@ "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", "dev": true, "requires": { - "chalk": "1.1.3", - "esutils": "2.0.2", - "js-tokens": "3.0.2" + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" }, "dependencies": { "chalk": { @@ -116,11 +134,11 @@ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" } }, "strip-ansi": { @@ -129,7 +147,7 @@ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } } } @@ -146,7 +164,7 @@ "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", "dev": true, "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, @@ -162,7 +180,7 @@ "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", "dev": true, "requires": { - "callsites": "0.2.0" + "callsites": "^0.2.0" } }, "callsites": { @@ -177,12 +195,12 @@ "integrity": "sha1-D2RYS6ZC8PKs4oBiefTwbKI61zw=", "dev": true, "requires": { - "assertion-error": "1.0.2", - "check-error": "1.0.2", - "deep-eql": "3.0.1", - "get-func-name": "2.0.0", - "pathval": "1.1.0", - "type-detect": "4.0.3" + "assertion-error": "^1.0.1", + "check-error": "^1.0.1", + "deep-eql": "^3.0.0", + "get-func-name": "^2.0.0", + "pathval": "^1.0.0", + "type-detect": "^4.0.0" } }, "chalk": { @@ -191,9 +209,9 @@ "integrity": "sha512-0BMM/2hG3ZaoPfR6F+h/oWpZtsh3b/s62TjSM6MGCJWEbJDN1acqCXvyhhZsDSVFklpebUoQ5O1kKC7lOzrn9g==", "dev": true, "requires": { - "ansi-styles": "3.2.0", - "escape-string-regexp": "1.0.5", - "supports-color": "4.5.0" + "ansi-styles": "^3.1.0", + "escape-string-regexp": "^1.0.5", + "supports-color": "^4.0.0" }, "dependencies": { "ansi-styles": { @@ -202,7 +220,7 @@ "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", "dev": true, "requires": { - "color-convert": "1.9.0" + "color-convert": "^1.9.0" } }, "supports-color": { @@ -211,7 +229,7 @@ "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", "dev": true, "requires": { - "has-flag": "2.0.0" + "has-flag": "^2.0.0" } } } @@ -234,7 +252,7 @@ "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", "dev": true, "requires": { - "restore-cursor": "2.0.0" + "restore-cursor": "^2.0.0" } }, "cli-width": { @@ -255,7 +273,7 @@ "integrity": "sha1-Gsz5fdc5uYO/mU1W/sj5WFNkG3o=", "dev": true, "requires": { - "color-name": "1.1.3" + "color-name": "^1.1.1" } }, "color-name": { @@ -282,9 +300,9 @@ "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", "dev": true, "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.3", - "typedarray": "0.0.6" + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" } }, "core-util-is": { @@ -299,9 +317,9 @@ "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "dev": true, "requires": { - "lru-cache": "4.1.1", - "shebang-command": "1.2.0", - "which": "1.3.0" + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" } }, "debug": { @@ -319,7 +337,7 @@ "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", "dev": true, "requires": { - "type-detect": "4.0.3" + "type-detect": "^4.0.0" } }, "deep-is": { @@ -334,13 +352,13 @@ "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", "dev": true, "requires": { - "globby": "5.0.0", - "is-path-cwd": "1.0.0", - "is-path-in-cwd": "1.0.0", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1", - "rimraf": "2.6.2" + "globby": "^5.0.0", + "is-path-cwd": "^1.0.0", + "is-path-in-cwd": "^1.0.0", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "rimraf": "^2.2.8" } }, "diff": { @@ -355,8 +373,8 @@ "integrity": "sha1-xz2NKQnSIpHhoAejlYBNqLZl/mM=", "dev": true, "requires": { - "esutils": "2.0.2", - "isarray": "1.0.0" + "esutils": "^2.0.2", + "isarray": "^1.0.0" } }, "escape-string-regexp": { @@ -371,43 +389,43 @@ "integrity": "sha1-doedJ0BoJhsZH+Dy9Wx0wvQgjos=", "dev": true, "requires": { - "ajv": "5.2.3", - "babel-code-frame": "6.26.0", - "chalk": "2.2.0", - "concat-stream": "1.6.0", - "cross-spawn": "5.1.0", - "debug": "3.1.0", - "doctrine": "2.0.0", - "eslint-scope": "3.7.1", - "espree": "3.5.1", - "esquery": "1.0.0", - "estraverse": "4.2.0", - "esutils": "2.0.2", - "file-entry-cache": "2.0.0", - "functional-red-black-tree": "1.0.1", - "glob": "7.1.2", - "globals": "9.18.0", - "ignore": "3.3.5", - "imurmurhash": "0.1.4", - "inquirer": "3.3.0", - "is-resolvable": "1.0.0", - "js-yaml": "3.10.0", - "json-stable-stringify": "1.0.1", - "levn": "0.3.0", - "lodash": "4.17.4", - "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "natural-compare": "1.4.0", - "optionator": "0.8.2", - "path-is-inside": "1.0.2", - "pluralize": "7.0.0", - "progress": "2.0.0", - "require-uncached": "1.0.3", - "semver": "5.4.1", - "strip-ansi": "4.0.0", - "strip-json-comments": "2.0.1", - "table": "4.0.2", - "text-table": "0.2.0" + "ajv": "^5.2.0", + "babel-code-frame": "^6.22.0", + "chalk": "^2.1.0", + "concat-stream": "^1.6.0", + "cross-spawn": "^5.1.0", + "debug": "^3.0.1", + "doctrine": "^2.0.0", + "eslint-scope": "^3.7.1", + "espree": "^3.5.1", + "esquery": "^1.0.0", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "file-entry-cache": "^2.0.0", + "functional-red-black-tree": "^1.0.1", + "glob": "^7.1.2", + "globals": "^9.17.0", + "ignore": "^3.3.3", + "imurmurhash": "^0.1.4", + "inquirer": "^3.0.6", + "is-resolvable": "^1.0.0", + "js-yaml": "^3.9.1", + "json-stable-stringify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.4", + "minimatch": "^3.0.2", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.2", + "pluralize": "^7.0.0", + "progress": "^2.0.0", + "require-uncached": "^1.0.3", + "semver": "^5.3.0", + "strip-ansi": "^4.0.0", + "strip-json-comments": "~2.0.1", + "table": "^4.0.1", + "text-table": "~0.2.0" } }, "eslint-config-gemini-testing": { @@ -422,8 +440,8 @@ "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=", "dev": true, "requires": { - "esrecurse": "4.2.0", - "estraverse": "4.2.0" + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" } }, "espree": { @@ -432,8 +450,8 @@ "integrity": "sha1-DJiLirRttTEAoZVK5LqZXd0n2H4=", "dev": true, "requires": { - "acorn": "5.1.2", - "acorn-jsx": "3.0.1" + "acorn": "^5.1.1", + "acorn-jsx": "^3.0.0" } }, "esprima": { @@ -448,7 +466,7 @@ "integrity": "sha1-z7qLV9f7qT8XKYqKAGoEzaE9gPo=", "dev": true, "requires": { - "estraverse": "4.2.0" + "estraverse": "^4.0.0" } }, "esrecurse": { @@ -457,8 +475,8 @@ "integrity": "sha1-+pVo2Y04I/mkHZHpAtyrnqblsWM=", "dev": true, "requires": { - "estraverse": "4.2.0", - "object-assign": "4.1.1" + "estraverse": "^4.1.0", + "object-assign": "^4.0.1" } }, "estraverse": { @@ -479,9 +497,9 @@ "integrity": "sha512-Msjo64WT5W+NhOpQXh0nOHm+n0RfU1QUwDnKYvJ8dEJ8zlwLrqXNTv5mSUTJpepf41PDJGyhueTw2vNZW+Fr/w==", "dev": true, "requires": { - "iconv-lite": "0.4.19", - "jschardet": "1.5.1", - "tmp": "0.0.33" + "iconv-lite": "^0.4.17", + "jschardet": "^1.4.2", + "tmp": "^0.0.33" } }, "fast-deep-equal": { @@ -502,7 +520,7 @@ "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", "dev": true, "requires": { - "escape-string-regexp": "1.0.5" + "escape-string-regexp": "^1.0.5" } }, "file-entry-cache": { @@ -511,8 +529,8 @@ "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", "dev": true, "requires": { - "flat-cache": "1.3.0", - "object-assign": "4.1.1" + "flat-cache": "^1.2.1", + "object-assign": "^4.0.1" } }, "flat-cache": { @@ -521,10 +539,10 @@ "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", "dev": true, "requires": { - "circular-json": "0.3.3", - "del": "2.2.2", - "graceful-fs": "4.1.11", - "write": "0.2.1" + "circular-json": "^0.3.1", + "del": "^2.0.2", + "graceful-fs": "^4.1.2", + "write": "^0.2.1" } }, "formatio": { @@ -533,7 +551,7 @@ "integrity": "sha1-87IWfZBoxGmKjVH092CjmlTYGOs=", "dev": true, "requires": { - "samsam": "1.3.0" + "samsam": "1.x" } }, "fs.realpath": { @@ -560,12 +578,12 @@ "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, "globals": { @@ -580,12 +598,12 @@ "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", "dev": true, "requires": { - "array-union": "1.0.2", - "arrify": "1.0.1", - "glob": "7.1.2", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" + "array-union": "^1.0.1", + "arrify": "^1.0.0", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" } }, "graceful-fs": { @@ -606,7 +624,7 @@ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "has-flag": { @@ -645,8 +663,8 @@ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" + "once": "^1.3.0", + "wrappy": "1" } }, "inherits": { @@ -661,20 +679,20 @@ "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", "dev": true, "requires": { - "ansi-escapes": "3.0.0", - "chalk": "2.2.0", - "cli-cursor": "2.1.0", - "cli-width": "2.2.0", - "external-editor": "2.0.5", - "figures": "2.0.0", - "lodash": "4.17.4", + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.0", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^2.0.4", + "figures": "^2.0.0", + "lodash": "^4.3.0", "mute-stream": "0.0.7", - "run-async": "2.3.0", - "rx-lite": "4.0.8", - "rx-lite-aggregates": "4.0.8", - "string-width": "2.1.1", - "strip-ansi": "4.0.0", - "through": "2.3.8" + "run-async": "^2.2.0", + "rx-lite": "^4.0.8", + "rx-lite-aggregates": "^4.0.8", + "string-width": "^2.1.0", + "strip-ansi": "^4.0.0", + "through": "^2.3.6" } }, "is-fullwidth-code-point": { @@ -695,7 +713,7 @@ "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=", "dev": true, "requires": { - "is-path-inside": "1.0.0" + "is-path-inside": "^1.0.0" } }, "is-path-inside": { @@ -704,7 +722,7 @@ "integrity": "sha1-/AbloWg/vaE95mev9xe7wQpI838=", "dev": true, "requires": { - "path-is-inside": "1.0.2" + "path-is-inside": "^1.0.1" } }, "is-promise": { @@ -719,7 +737,7 @@ "integrity": "sha1-jfV8YeouPFAUCNEA+wE8+NbgzGI=", "dev": true, "requires": { - "tryit": "1.0.3" + "tryit": "^1.0.1" } }, "isarray": { @@ -746,8 +764,8 @@ "integrity": "sha512-O2v52ffjLa9VeM43J4XocZE//WT9N0IiwDa3KSHH7Tu8CtH+1qM8SIZvnsTh6v+4yFy5KUY3BHUVwjpfAWsjIA==", "dev": true, "requires": { - "argparse": "1.0.9", - "esprima": "4.0.0" + "argparse": "^1.0.7", + "esprima": "^4.0.0" } }, "jschardet": { @@ -768,7 +786,7 @@ "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", "dev": true, "requires": { - "jsonify": "0.0.0" + "jsonify": "~0.0.0" } }, "jsonify": { @@ -789,8 +807,8 @@ "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", "dev": true, "requires": { - "prelude-ls": "1.1.2", - "type-check": "0.3.2" + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" } }, "lodash": { @@ -816,8 +834,8 @@ "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", "dev": true, "requires": { - "pseudomap": "1.0.2", - "yallist": "2.1.2" + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" } }, "mimic-fn": { @@ -832,7 +850,7 @@ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "1.1.8" + "brace-expansion": "^1.1.7" } }, "minimist": { @@ -874,7 +892,7 @@ "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", "dev": true, "requires": { - "has-flag": "2.0.0" + "has-flag": "^2.0.0" } } } @@ -909,11 +927,11 @@ "integrity": "sha512-f5DMJB0MqBaSuP2NAwPx7HyVKPdaozds0KsNe9XIP3npKWt/QUg73l5TTLRTSwfG/Y3AB0ktacuxX4QNcg6vVw==", "dev": true, "requires": { - "formatio": "1.2.0", - "just-extend": "1.1.22", - "lolex": "1.6.0", - "path-to-regexp": "1.7.0", - "text-encoding": "0.6.4" + "formatio": "^1.2.0", + "just-extend": "^1.1.22", + "lolex": "^1.6.0", + "path-to-regexp": "^1.7.0", + "text-encoding": "^0.6.4" }, "dependencies": { "lolex": { @@ -936,7 +954,7 @@ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, "onetime": { @@ -945,7 +963,7 @@ "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", "dev": true, "requires": { - "mimic-fn": "1.1.0" + "mimic-fn": "^1.0.0" } }, "optionator": { @@ -954,12 +972,12 @@ "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", "dev": true, "requires": { - "deep-is": "0.1.3", - "fast-levenshtein": "2.0.6", - "levn": "0.3.0", - "prelude-ls": "1.1.2", - "type-check": "0.3.2", - "wordwrap": "1.0.0" + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" } }, "os-tmpdir": { @@ -1021,7 +1039,7 @@ "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", "dev": true, "requires": { - "pinkie": "2.0.4" + "pinkie": "^2.0.0" } }, "pluralize": { @@ -1060,13 +1078,13 @@ "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "safe-buffer": "5.1.1", - "string_decoder": "1.0.3", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.0.3", + "util-deprecate": "~1.0.1" } }, "require-uncached": { @@ -1075,8 +1093,8 @@ "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", "dev": true, "requires": { - "caller-path": "0.1.0", - "resolve-from": "1.0.1" + "caller-path": "^0.1.0", + "resolve-from": "^1.0.0" } }, "resolve-from": { @@ -1091,8 +1109,8 @@ "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", "dev": true, "requires": { - "onetime": "2.0.1", - "signal-exit": "3.0.2" + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" } }, "rimraf": { @@ -1101,7 +1119,7 @@ "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "dev": true, "requires": { - "glob": "7.1.2" + "glob": "^7.0.5" } }, "run-async": { @@ -1110,7 +1128,7 @@ "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", "dev": true, "requires": { - "is-promise": "2.1.0" + "is-promise": "^2.1.0" } }, "rx-lite": { @@ -1125,7 +1143,7 @@ "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", "dev": true, "requires": { - "rx-lite": "4.0.8" + "rx-lite": "*" } }, "safe-buffer": { @@ -1152,7 +1170,7 @@ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { - "shebang-regex": "1.0.0" + "shebang-regex": "^1.0.0" } }, "shebang-regex": { @@ -1173,16 +1191,16 @@ "integrity": "sha512-4qIY0pCWCvGCJpV/1JkFu9kbsNEZ9O34cG1oru/c7OCDtrEs50Gq/VjkA2ID5ZwLyoNx1i1ws118oh/p6fVeDg==", "dev": true, "requires": { - "diff": "3.3.1", + "diff": "^3.1.0", "formatio": "1.2.0", - "lodash.get": "4.4.2", - "lolex": "2.1.3", - "native-promise-only": "0.8.1", - "nise": "1.1.1", - "path-to-regexp": "1.7.0", - "samsam": "1.3.0", + "lodash.get": "^4.4.2", + "lolex": "^2.1.3", + "native-promise-only": "^0.8.1", + "nise": "^1.1.1", + "path-to-regexp": "^1.7.0", + "samsam": "^1.1.3", "text-encoding": "0.6.4", - "type-detect": "4.0.3" + "type-detect": "^4.0.0" } }, "slice-ansi": { @@ -1191,7 +1209,7 @@ "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", "dev": true, "requires": { - "is-fullwidth-code-point": "2.0.0" + "is-fullwidth-code-point": "^2.0.0" } }, "sprintf-js": { @@ -1200,23 +1218,23 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, - "string_decoder": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", - "dev": true, - "requires": { - "safe-buffer": "5.1.1" - } - }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" } }, "strip-ansi": { @@ -1225,7 +1243,7 @@ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { - "ansi-regex": "3.0.0" + "ansi-regex": "^3.0.0" }, "dependencies": { "ansi-regex": { @@ -1254,12 +1272,12 @@ "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", "dev": true, "requires": { - "ajv": "5.2.3", - "ajv-keywords": "2.1.0", - "chalk": "2.2.0", - "lodash": "4.17.4", + "ajv": "^5.2.3", + "ajv-keywords": "^2.1.0", + "chalk": "^2.1.0", + "lodash": "^4.17.4", "slice-ansi": "1.0.0", - "string-width": "2.1.1" + "string-width": "^2.1.1" } }, "text-encoding": { @@ -1286,7 +1304,7 @@ "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", "dev": true, "requires": { - "os-tmpdir": "1.0.2" + "os-tmpdir": "~1.0.2" } }, "tryit": { @@ -1301,7 +1319,7 @@ "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", "dev": true, "requires": { - "prelude-ls": "1.1.2" + "prelude-ls": "~1.1.2" } }, "type-detect": { @@ -1316,6 +1334,12 @@ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "dev": true }, + "typescript": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz", + "integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==", + "dev": true + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -1328,7 +1352,7 @@ "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", "dev": true, "requires": { - "isexe": "2.0.0" + "isexe": "^2.0.0" } }, "wordwrap": { @@ -1349,7 +1373,7 @@ "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", "dev": true, "requires": { - "mkdirp": "0.5.1" + "mkdirp": "^0.5.1" } }, "yallist": { diff --git a/package.json b/package.json index d766183..7207019 100644 --- a/package.json +++ b/package.json @@ -2,21 +2,26 @@ "name": "gemini-configparser", "version": "1.1.1", "description": "Config parser module for gemini", - "main": "lib/index.js", - "types": "./typings/index.d.ts", + "main": "build/index.js", "author": "Sergey Tatarintsev (https://github.com/SevInf)", "license": "MIT", + "typings": "./build/index.d.ts", "devDependencies": { + "@tsconfig/recommended": "^1.0.1", + "@types/lodash": "^4.14.176", + "@types/node": "^16.11.6", "chai": "^4.1.2", "eslint": "^4.9.0", "eslint-config-gemini-testing": "^2.0.0", "mocha": "^4.0.1", - "sinon": "^4.0.1" + "sinon": "^4.0.1", + "typescript": "^4.4.4" }, "dependencies": { "lodash": "^4.17.4" }, "scripts": { + "build": "tsc", "test": "npm run lint && npm run test-unit", "lint": "eslint .", "test-unit": "mocha test" diff --git a/test/lazy.js b/test/lazy.js index 51f6378..69576e9 100644 --- a/test/lazy.js +++ b/test/lazy.js @@ -1,4 +1,4 @@ -const {buildLazyObject, forceParsing} = require('../lib/lazy'); +const {buildLazyObject, forceParsing} = require('../build/lazy'); describe('build lazy object', () => { it('should build an object with given keys', () => { diff --git a/test/locator.js b/test/locator.js index 8cd49d5..15a619a 100644 --- a/test/locator.js +++ b/test/locator.js @@ -1,4 +1,4 @@ -const locator = require('../lib/locator'); +const locator = require('../build/locator').default; function locatorWithOptions(options) { return locator({options, env: {}, argv: []}); @@ -37,20 +37,20 @@ describe('locator', () => { it('should return nested name after nest call', () => { const pointer = locatorWithOptions({}); const childPointer = pointer.nested('key'); - assert.propertyVal(childPointer, 'name', 'key'); + assert.propertyVal(childPointer, 'name', 'root.key'); }); - it('should return empty parent for root children', () => { + it('should return parent for root children', () => { const pointer = locatorWithOptions({someKey: 'someVal'}); const childPointer = pointer.nested('key'); - assert.propertyVal(childPointer, 'parent', ''); + assert.propertyVal(childPointer, 'parent', 'root'); }); it('should return parent name for not root children', () => { const pointer = locatorWithOptions({someKey: 'someVal'}); const childPointer = pointer.nested('child'); const subChildPointer = childPointer.nested('subChild'); - assert.propertyVal(subChildPointer, 'parent', 'child'); + assert.propertyVal(subChildPointer, 'parent', 'root.child'); }); it('should return env var value after nested call', () => { diff --git a/test/map.js b/test/map.js index bc1ff75..7d3dd8c 100644 --- a/test/map.js +++ b/test/map.js @@ -1,5 +1,5 @@ -const {map} = require('../lib/core'); -const {forceParsing} = require('../lib/lazy'); +const {map} = require('../build/core'); +const {forceParsing} = require('../build/lazy'); const _ = require('lodash'); describe('map', () => { diff --git a/test/option.js b/test/option.js index 2336773..adc825a 100644 --- a/test/option.js +++ b/test/option.js @@ -1,5 +1,5 @@ -const {option} = require('../lib/core'); -const {MissingOptionError} = require('../lib/errors'); +const {option} = require('../build/core'); +const {MissingOptionError} = require('../build/errors'); describe('option', () => { const LAZY_CONFIG = { @@ -130,7 +130,7 @@ describe('option', () => { } }; - parser({parent: 'topLevel'}, config); + parser({parent: 'root.topLevel'}, config); assert.calledWith(defaultValStub, config.root, {subLevel: 'subLevelVal'}); }); @@ -178,7 +178,7 @@ describe('option', () => { } }; - parser({option: 'value', parent: 'topLevel'}, config); + parser({option: 'value', parent: 'root.topLevel'}, config); assert.calledWith(callback, 'value', config.root, {subLevel: 'subLevelVal'}); }); diff --git a/test/section.js b/test/section.js index e20691a..4854307 100644 --- a/test/section.js +++ b/test/section.js @@ -1,5 +1,5 @@ -const {section} = require('../lib/core'); -const {forceParsing} = require('../lib/lazy'); +const {section} = require('../build/core'); +const {forceParsing} = require('../build/lazy'); function stubLocator(locatorKeys) { return Object.assign({ diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..f80152b --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "@tsconfig/recommended/tsconfig.json", + "include": ["lib/**/*"], + "exclude": ["build", "test", "types"], + "compilerOptions": { + "outDir": "build", + "types": ["node"], + "allowJs": true, + "noImplicitReturns": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "declaration": true + } +} diff --git a/typings/index.d.ts b/typings/index.d.ts deleted file mode 100644 index c8aa6da..0000000 --- a/typings/index.d.ts +++ /dev/null @@ -1,41 +0,0 @@ -declare module "gemini-configparser" { - type PartialConfig = never; - type Locator = never; - type UnsanitizedRootConfig = any; - type UnsanitizedConfigNode = any; - - type Parser = (locator: Locator, config: PartialConfig) => T; - - type RootPrefixes = { - envPrefix: string; - cliPrefix: string; - }; - - type OptionParserConfig = { - defaultValue: T | ((config: UnsanitizedRootConfig, currNode: UnsanitizedConfigNode) => T); - parseCli?(input: string): T; - parseEnv?(input: string): T; - validate?(value: T, config: UnsanitizedRootConfig, currNode: UnsanitizedConfigNode): void; - }; - - type MappedOptionParserConfig = OptionParserConfig & { - map(value: S, config: UnsanitizedRootConfig, currNode: UnsanitizedConfigNode): T; - }; - - type SectionProperties = { [name in keyof T]: Parser }; - - export function option(description: OptionParserConfig): Parser; - export function option(description: MappedOptionParserConfig): Parser; - export function section(properties: SectionProperties): Parser; - - type RootParserArg = { - options: UnsanitizedRootConfig; - env: NodeJS.ProcessEnv; - argv: Array; - }; - type RootParser = (arg: RootParserArg) => T; - export function root(rootParser: Parser, prefixes: RootPrefixes): RootParser; - - export class MissingOptionError extends Error {} - export class UnknownKeysError extends Error {} -}