diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000..cb614553 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,3 @@ +/node_modules/ +/build/airtable.browser.js +/test/test_files/airtable.browser.js diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 00000000..f5a5d513 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,115 @@ +{ + "env": { + "browser": true, + "node": true + }, + "globals": { + "Promise": true + }, + "extends": [ + "eslint:recommended" + ], + "rules": { + "no-case-declarations": "warn", + "no-debugger": "warn", + "no-empty": "warn", + "no-extra-boolean-cast": "warn", + "no-extra-semi": "warn", + "no-redeclare": "warn", + "no-regex-spaces": "warn", + "no-self-assign": "warn", + "no-sparse-arrays": "warn", + "no-unreachable": "warn", + "no-console": "off", + "require-yield": "off", + "array-bracket-spacing": "warn", + "array-callback-return": "error", + "arrow-spacing": "warn", + "block-scoped-var": "error", + "block-spacing": "warn", + "comma-spacing": "warn", + "comma-style": "warn", + "computed-property-spacing": "warn", + "consistent-return": "error", + "consistent-this": ["warn", "that"], + "curly": "warn", + "default-case": "warn", + "dot-notation": ["warn", {"allowPattern": "[$_0-9]"}], + "eqeqeq": "error", + "func-call-spacing": "error", + "guard-for-in": "error", + "handle-callback-err": "error", + "key-spacing": "warn", + "keyword-spacing": "warn", + "linebreak-style": "warn", + "indent": ["warn", 4], + "new-parens": "warn", + "no-array-constructor": "error", + "no-caller": "error", + "no-catch-shadow": "error", + "no-confusing-arrow": "warn", + "no-constant-condition": "warn", + "no-div-regex": "warn", + "no-eq-null": "error", + "no-eval": "error", + "no-extend-native": "error", + "no-extra-bind": "warn", + "no-extra-label": "error", + "no-floating-decimal": "warn", + "no-global-assign": "warn", + "no-implicit-globals": "warn", + "no-implied-eval": "error", + "no-iterator": "error", + "no-labels": "error", + "no-label-var": "error", + "no-loop-func": "error", + "no-lone-blocks": "error", + "no-native-reassign": "error", + "no-mixed-operators": ["warn", {"groups": [["&&", "||"]]}], + "no-mixed-requires": "error", + "no-multi-spaces": "warn", + "no-multi-str": "warn", + "no-new-object": "warn", + "no-new-require": "error", + "no-new-wrappers": "warn", + "no-octal-escape": "error", + "no-path-concat": "error", + "no-proto": "error", + "no-script-url": "error", + "no-sequences": "error", + "no-self-compare": "error", + "no-shadow": "error", + "no-shadow-restricted-names": "error", + "no-spaced-func": "warn", + "no-template-curly-in-string": "error", + "no-throw-literal": "warn", + "no-undef": "error", + "no-undef-init": "warn", + "no-unneeded-ternary": "warn", + "no-unsafe-negation": "warn", + "no-unused-expressions": "error", + "no-unused-vars": "warn", + "no-useless-call": "warn", + "no-useless-computed-key": "warn", + "no-useless-concat": "warn", + "no-useless-constructor": "warn", + "no-undefined": "error", + "no-whitespace-before-property": "warn", + "no-with": "error", + "object-curly-spacing": "warn", + "one-var-declaration-per-line": "warn", + "quotes": ["warn", "single", "avoid-escape"], + "radix": "error", + "semi": "warn", + "semi-spacing": "warn", + "space-before-blocks": "warn", + "space-before-function-paren": [ + "warn", + {"anonymous": "never", "named": "never", "asyncArrow": "always"} + ], + "space-in-parens": "warn", + "space-unary-ops": "warn", + "spaced-comment": "warn", + "yoda": "warn" + } +} diff --git a/gruntfile.js b/gruntfile.js index 52bafe25..75e821db 100644 --- a/gruntfile.js +++ b/gruntfile.js @@ -6,32 +6,6 @@ module.exports = function(grunt) { // Project configuration. grunt.initConfig({ pkg: pkg, - jshint: { - // define the files to lint - files: ['gruntfile.js', 'lib/**/!(class.js)*.js', 'test/*.test.js'], - // configure JSHint (documented at http://www.jshint.com/docs/) - options: { - // more options here if you want to override JSHint defaults - strict: true, - globalstrict: true, - globals: { - console: true, - module: true, - require: true, - process: true, - setTimeout: true, - jest: true, - describe: true, - beforeEach: true, - beforeAll: true, - afterAll: true, - it: true, - expect: true, - Promise: true, - __dirname: true - } - } - }, browserify: { client: { src: './lib/airtable.js', @@ -44,18 +18,12 @@ module.exports = function(grunt) { }] ], preBundleCB: function(b) { - b.require('./lib/airtable.js', { expose: 'airtable' }); + b.require('./lib/airtable.js', {expose: 'airtable'}); } } } }, }); - // Load the plugin that provides the "uglify" task. - grunt.loadNpmTasks('grunt-contrib-jshint'); - - // Default task(s). - grunt.registerTask('default', ['jshint']); - grunt.loadNpmTasks('grunt-browserify'); }; diff --git a/lib/airtable.js b/lib/airtable.js index 57286653..f48353ad 100644 --- a/lib/airtable.js +++ b/lib/airtable.js @@ -47,7 +47,7 @@ var Airtable = Class.extend({ } }); -Airtable.default_config = function () { +Airtable.default_config = function() { return { endpointUrl: process.env.AIRTABLE_ENDPOINT_URL || 'https://api.airtable.com', apiVersion: '0.1.0', diff --git a/lib/airtable_error.js b/lib/airtable_error.js index 4def3c87..8a2e1521 100644 --- a/lib/airtable_error.js +++ b/lib/airtable_error.js @@ -12,7 +12,7 @@ var AirtableError = Class.extend({ return [ this.message, '(', this.error, ')', - this.statusCode ? '[Http code ' + this.statusCode + ']' : '' + this.statusCode ? '[Http code ' + this.statusCode + ']' : '' ].join(''); } }); diff --git a/lib/base.js b/lib/base.js index 00861b75..bdc86197 100644 --- a/lib/base.js +++ b/lib/base.js @@ -27,26 +27,26 @@ var Base = Class.extend({ } else if (statusCode === 403) { return new AirtableError('NOT_AUTHORIZED', 'You are not authorized to perform this operation', statusCode); } else if (statusCode === 404) { - return (function(){ + return (function() { var message = (body && body.error && body.error.message) ? body.error.message : 'Could not find what you are looking for'; return new AirtableError('NOT_FOUND', message, statusCode); })(); } else if (statusCode === 413) { return new AirtableError('REQUEST_TOO_LARGE', 'Request body is too large', statusCode); } else if (statusCode === 422) { - return (function(){ + return (function() { var type = (body && body.error && body.error.type) ? body.error.type : 'UNPROCESSABLE_ENTITY'; var message = (body && body.error && body.error.message) ? body.error.message : 'The operation cannot be processed'; return new AirtableError(type, message, statusCode); })(); } else if (statusCode === 429) { return new AirtableError('TOO_MANY_REQUESTS', 'You have made too many requests in a short period of time. Please retry your request later', statusCode); - }else if (statusCode === 500) { + } else if (statusCode === 500) { return new AirtableError('SERVER_ERROR', 'Try again. If the problem persists, contact support.', statusCode); } else if (statusCode === 503) { return new AirtableError('SERVICE_UNAVAILABLE', 'The service is temporarily unavailable. Please retry shortly.', statusCode); } else if (statusCode >= 400) { - return (function(){ + return (function() { var type = (body && body.error && body.error.type) ? body.error.type : 'UNEXPECTED_ERROR'; var message = (body && body.error && body.error.message) ? body.error.message : 'An unexpected error occurred'; return new AirtableError(type, message, statusCode); diff --git a/lib/callback_to_promise.js b/lib/callback_to_promise.js index 1b037db9..5c7b7f47 100644 --- a/lib/callback_to_promise.js +++ b/lib/callback_to_promise.js @@ -17,7 +17,7 @@ function callbackToPromise(fn, context, callbackArgIndex) { var callbackArg = arguments[thisCallbackArgIndex]; if (typeof callbackArg === 'function') { fn.apply(context, arguments); - return; + return void 0; } else { var args = []; // If an explicit callbackArgIndex is set, but the function is called diff --git a/lib/class.js b/lib/class.js index 90350f7d..0bbfecaa 100644 --- a/lib/class.js +++ b/lib/class.js @@ -1,4 +1,4 @@ -// jshint ignore: start +/* eslint-disable */ /* Simple JavaScript Inheritance * By John Resig http://ejohn.org/ diff --git a/lib/table.js b/lib/table.js index 5fd6c6fc..ec5b0a1e 100644 --- a/lib/table.js +++ b/lib/table.js @@ -75,7 +75,7 @@ var Table = Class.extend({ throw new Error('Airtable: the parameter for `select` should be a plain object or undefined.'); } }, - _urlEncodedNameOrId: function(){ + _urlEncodedNameOrId: function() { return this.id || encodeURIComponent(this.name); }, _createRecords: function(recordsData, optionalParameters, done) { @@ -98,7 +98,7 @@ var Table = Class.extend({ var result; if (isCreatingMultipleRecords) { - result = body.records.map(function (record) { + result = body.records.map(function(record) { return new Record(that, record.id, record); }); } else { @@ -121,7 +121,7 @@ var Table = Class.extend({ this._base.runAction(method, '/' + this._urlEncodedNameOrId() + '/', {}, requestData, function(err, resp, body) { if (err) { done(err); return; } - var result = body.records.map(function (record) { + var result = body.records.map(function(record) { return new Record(that, record.id, record); }); done(null, result); @@ -144,7 +144,7 @@ var Table = Class.extend({ if (isArray(recordIdsOrId)) { var that = this; var queryParams = {records: recordIdsOrId}; - this._base.runAction('delete', '/' + this._urlEncodedNameOrId(), queryParams, null, function (err, response, results) { + this._base.runAction('delete', '/' + this._urlEncodedNameOrId(), queryParams, null, function(err, response, results) { if (err) { done(err); return; @@ -171,7 +171,7 @@ var Table = Class.extend({ limit: limit, offset: offset }, opts); - this._base.runAction('get', '/' + this._urlEncodedNameOrId() + '/', listRecordsParameters, null, function (err, response, results) { + this._base.runAction('get', '/' + this._urlEncodedNameOrId() + '/', listRecordsParameters, null, function(err, response, results) { if (err) { done(err); return; diff --git a/package-lock.json b/package-lock.json index 014f647a..c56be75c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -565,6 +565,12 @@ "acorn-walk": "^6.0.1" } }, + "acorn-jsx": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.1.tgz", + "integrity": "sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg==", + "dev": true + }, "acorn-node": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.6.2.tgz", @@ -1358,6 +1364,12 @@ "supports-color": "^5.3.0" } }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, "chokidar": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.5.tgz", @@ -1425,32 +1437,21 @@ } } }, - "cli": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz", - "integrity": "sha1-IoF1NPJL+klQw01TLUjsvGIbjBQ=", + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", "dev": true, "requires": { - "exit": "0.1.2", - "glob": "^7.1.1" - }, - "dependencies": { - "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "dev": true, - "requires": { - "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" - } - } + "restore-cursor": "^2.0.0" } }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "dev": true + }, "cliui": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", @@ -1940,22 +1941,13 @@ "randombytes": "^2.0.0" } }, - "dom-serializer": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", - "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, "requires": { - "domelementtype": "^1.3.0", - "entities": "^1.1.1" - }, - "dependencies": { - "entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", - "dev": true - } + "esutils": "^2.0.2" } }, "dom-walk": { @@ -1969,12 +1961,6 @@ "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", "dev": true }, - "domelementtype": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", - "dev": true - }, "domexception": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", @@ -1984,25 +1970,6 @@ "webidl-conversions": "^4.0.2" } }, - "domhandler": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz", - "integrity": "sha1-LeWaCCLVAn+r/28DLCsloqir5zg=", - "dev": true, - "requires": { - "domelementtype": "1" - } - }, - "domutils": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", - "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", - "dev": true, - "requires": { - "dom-serializer": "0", - "domelementtype": "1" - } - }, "duplexer2": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", @@ -2043,6 +2010,12 @@ "minimalistic-crypto-utils": "^1.0.0" } }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -2058,12 +2031,6 @@ "once": "^1.4.0" } }, - "entities": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", - "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=", - "dev": true - }, "envify": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/envify/-/envify-4.1.0.tgz", @@ -2148,12 +2115,163 @@ } } }, + "eslint": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.0.1.tgz", + "integrity": "sha512-DyQRaMmORQ+JsWShYsSg4OPTjY56u1nCjAmICrE8vLWqyLKxhFXOthwMj1SA8xwfrv0CofLNVnqbfyhwCkaO0w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^4.0.3", + "eslint-utils": "^1.3.1", + "eslint-visitor-keys": "^1.0.0", + "espree": "^6.0.0", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^3.1.0", + "globals": "^11.7.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^6.2.2", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.11", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^5.5.1", + "strip-ansi": "^4.0.0", + "strip-json-comments": "^2.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0" + }, + "dependencies": { + "ajv": { + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.1.tgz", + "integrity": "sha512-w1YQaVGNC6t2UCPjEawK/vo/dG8OOrVtUmhBT1uJJYxbl5kU2Tj3v6LGqBcsysN1yhuCStJCCA3GqdvKY8sqXQ==", + "dev": true, + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "eslint-scope": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.3.1.tgz", + "integrity": "sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q==", + "dev": true + }, + "eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", + "dev": true + }, + "espree": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.0.0.tgz", + "integrity": "sha512-lJvCS6YbCn3ImT3yKkPe0+tJ+mH6ljhGNjHQH9mRtiO6gjhVAOhVXW1yjnwqGwTkK3bGbye+hb00nFNmu0l/1Q==", + "dev": true, + "requires": { + "acorn": "^6.0.7", + "acorn-jsx": "^5.0.0", + "eslint-visitor-keys": "^1.0.0" + } + }, "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, + "esquery": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", + "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", + "dev": true, + "requires": { + "estraverse": "^4.0.0" + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "^4.1.0" + } + }, "estraverse": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", @@ -2342,6 +2460,17 @@ } } }, + "external-editor": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz", + "integrity": "sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, "extglob": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", @@ -2437,6 +2566,24 @@ "bser": "^2.0.0" } }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, "fill-range": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", @@ -2509,6 +2656,23 @@ } } }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "flatted": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", + "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==", + "dev": true + }, "for-each": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.2.tgz", @@ -3129,6 +3293,12 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, "get-assigned-identifiers": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz", @@ -3332,17 +3502,6 @@ } } }, - "grunt-contrib-jshint": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/grunt-contrib-jshint/-/grunt-contrib-jshint-2.1.0.tgz", - "integrity": "sha512-65S2/C/6RfjY/umTxfwXXn+wVvaYmykHkHSsW6Q6rhkbv3oudTEgqnFFZvWzWCoHUb+3GMZLbP3oSrNyvshmIQ==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "hooker": "^0.2.3", - "jshint": "~2.10.2" - } - }, "grunt-known-options": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-1.1.1.tgz", @@ -3531,45 +3690,6 @@ "integrity": "sha1-OgPtwiFLyjtmQko+eVk0lQnLA1E=", "dev": true }, - "htmlparser2": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", - "integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=", - "dev": true, - "requires": { - "domelementtype": "1", - "domhandler": "2.3", - "domutils": "1.5", - "entities": "1.0", - "readable-stream": "1.1" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - } - } - }, "http-errors": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", @@ -3614,6 +3734,30 @@ "integrity": "sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA==", "dev": true }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "import-fresh": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.1.0.tgz", + "integrity": "sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + } + } + }, "import-local": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", @@ -3664,6 +3808,27 @@ "source-map": "~0.5.3" } }, + "inquirer": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.4.1.tgz", + "integrity": "sha512-/Jw+qPZx4EDYsaT6uz7F4GJRNFMRdKNeUZw3ZnKV8lyuUgz/YWRCSUAJMZSVhSq4Ec0R2oYnyi6b3d4JXcL5Nw==", + "dev": true, + "requires": { + "ansi-escapes": "^3.2.0", + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^2.0.0", + "lodash": "^4.17.11", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rxjs": "^6.4.0", + "string-width": "^2.1.0", + "strip-ansi": "^5.1.0", + "through": "^2.3.6" + } + }, "insert-module-globals": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/insert-module-globals/-/insert-module-globals-7.2.0.tgz", @@ -3888,6 +4053,12 @@ "isobject": "^3.0.1" } }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true + }, "is-regex": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", @@ -4594,22 +4765,6 @@ "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true }, - "jshint": { - "version": "2.10.2", - "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.10.2.tgz", - "integrity": "sha512-e7KZgCSXMJxznE/4WULzybCMNXNAd/bf5TSrvVEq78Q/K8ZwFpmBqQeDtNiHc3l49nV4E/+YeHU/JZjSUIrLAA==", - "dev": true, - "requires": { - "cli": "~1.0.0", - "console-browserify": "1.1.x", - "exit": "0.1.x", - "htmlparser2": "3.8.x", - "lodash": "~4.17.11", - "minimatch": "~3.0.2", - "shelljs": "0.3.x", - "strip-json-comments": "1.0.x" - } - }, "json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", @@ -4635,6 +4790,12 @@ "jsonify": "~0.0.0" } }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -5083,6 +5244,12 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "dev": true + }, "nan": { "version": "2.13.2", "resolved": "https://registry.npmjs.org/nan/-/nan-2.13.2.tgz", @@ -5303,6 +5470,23 @@ "wrappy": "1" } }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + }, + "dependencies": { + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true + } + } + }, "optimist": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", @@ -5315,7 +5499,7 @@ "dependencies": { "minimist": { "version": "0.0.10", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", "dev": true } @@ -5360,6 +5544,12 @@ "mem": "^4.0.0" } }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, "outpipe": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/outpipe/-/outpipe-1.1.1.tgz", @@ -5432,6 +5622,15 @@ "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==", "dev": true }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, "parents": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz", @@ -5662,6 +5861,12 @@ "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", "dev": true }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, "prompts": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.1.0.tgz", @@ -5872,6 +6077,12 @@ "safe-regex": "^1.1.0" } }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true + }, "remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", @@ -5999,6 +6210,16 @@ "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", "dev": true }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + } + }, "ret": { "version": "0.1.15", "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", @@ -6046,6 +6267,24 @@ "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", "dev": true }, + "run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "dev": true, + "requires": { + "is-promise": "^2.1.0" + } + }, + "rxjs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.2.tgz", + "integrity": "sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -6217,12 +6456,6 @@ "jsonify": "~0.0.0" } }, - "shelljs": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", - "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=", - "dev": true - }, "shellwords": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", @@ -6253,6 +6486,17 @@ "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", "dev": true }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + } + }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -6645,9 +6889,9 @@ } }, "strip-json-comments": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", - "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true }, "subarg": { @@ -6683,6 +6927,55 @@ "acorn-node": "^1.2.0" } }, + "table": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.1.tgz", + "integrity": "sha512-E6CK1/pZe2N75rGZQotFOdmzWQ1AILtgYbMAbAjvms0S1l5IDB47zG3nCnFGB/w+7nB3vKofbLXCH7HPBo864w==", + "dev": true, + "requires": { + "ajv": "^6.9.1", + "lodash": "^4.17.11", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "dependencies": { + "ajv": { + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.1.tgz", + "integrity": "sha512-w1YQaVGNC6t2UCPjEawK/vo/dG8OOrVtUmhBT1uJJYxbl5kU2Tj3v6LGqBcsysN1yhuCStJCCA3GqdvKY8sqXQ==", + "dev": true, + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + } + } + }, "test-exclude": { "version": "5.2.3", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz", @@ -6784,6 +7077,12 @@ } } }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, "throat": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz", @@ -6823,6 +7122,15 @@ } } }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, "tmpl": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", @@ -6941,6 +7249,12 @@ "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", "dev": true }, + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", + "dev": true + }, "tty-browserify": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", @@ -7145,6 +7459,23 @@ "integrity": "sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==", "dev": true }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + }, + "dependencies": { + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + } + } + }, "urix": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", @@ -7331,7 +7662,7 @@ }, "wrap-ansi": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "dev": true, "requires": { @@ -7367,7 +7698,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { @@ -7382,6 +7713,15 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, "write-file-atomic": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.1.tgz", diff --git a/package.json b/package.json index 1d173a6b..199d2c5c 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "private": false, "scripts": { "pretest": "npm run lint", - "lint": "grunt jshint", + "lint": "eslint .", "test": "jest --env node" }, "dependencies": { @@ -22,11 +22,11 @@ "devDependencies": { "body-parser": "^1.19.0", "envify": "^4.1.0", + "eslint": "^6.0.1", "express": "^4.17.1", "get-port": "^5.0.0", "grunt": "^1.0.4", "grunt-browserify": "^5.3.0", - "grunt-contrib-jshint": "^2.1.0", "jest": "^24.8.0" }, "keywords": [ diff --git a/test/.eslintrc.json b/test/.eslintrc.json new file mode 100644 index 00000000..e121608c --- /dev/null +++ b/test/.eslintrc.json @@ -0,0 +1,9 @@ +{ + "env": { + "jest": true, + "es6": true + }, + "rules": { + "no-undefined": "off" + } +} diff --git a/test/airtable.test.js b/test/airtable.test.js index c0cd131e..c622be7b 100644 --- a/test/airtable.test.js +++ b/test/airtable.test.js @@ -2,12 +2,12 @@ var Airtable = require('../lib/airtable'); -describe('Airtable', function () { - it("doesn't include the API key as an enumerable property", function () { - var fakeAirtable = new Airtable({apiKey: 'keyXyz'}); +describe('Airtable', function() { + it("doesn't include the API key as an enumerable property", function() { + var fakeAirtable = new Airtable({apiKey: 'keyXyz'}); - Object.values(fakeAirtable).forEach(function (value) { - expect(value).not.toEqual('keyXyz'); + Object.values(fakeAirtable).forEach(function(value) { + expect(value).not.toEqual('keyXyz'); + }); }); - }); }); diff --git a/test/base.test.js b/test/base.test.js index 6bd046f6..ebd99505 100644 --- a/test/base.test.js +++ b/test/base.test.js @@ -6,35 +6,35 @@ var Airtable = require('../lib/airtable'); jest.mock('request'); -describe('Base', function () { - describe('#runAction', function () { - it('makes requests with the right options', function () { - var fakeAirtable = new Airtable({ - apiKey: 'keyXyz', - requestTimeout: 1234 - }); - var fakeBase = fakeAirtable.base('app123'); +describe('Base', function() { + describe('#runAction', function() { + it('makes requests with the right options', function() { + var fakeAirtable = new Airtable({ + apiKey: 'keyXyz', + requestTimeout: 1234 + }); + var fakeBase = fakeAirtable.base('app123'); - fakeBase.runAction('get', '/my_table/rec456', {}, null, function () {}); + fakeBase.runAction('get', '/my_table/rec456', {}, null, function() {}); - expect(request).toHaveBeenCalledTimes(1); - expect(request).toHaveBeenCalledWith({ - method: 'GET', - url: 'https://api.airtable.com/v0/app123/my_table/rec456?', - json: true, - timeout: 1234, - headers: { - authorization: 'Bearer keyXyz', - 'x-api-version': '0.1.0', - 'x-airtable-application-id': 'app123', - 'User-Agent': 'Airtable.js/' + version - }, - agentOptions: { - rejectUnauthorized: false - } - }, expect.any(Function)); + expect(request).toHaveBeenCalledTimes(1); + expect(request).toHaveBeenCalledWith({ + method: 'GET', + url: 'https://api.airtable.com/v0/app123/my_table/rec456?', + json: true, + timeout: 1234, + headers: { + authorization: 'Bearer keyXyz', + 'x-api-version': '0.1.0', + 'x-airtable-application-id': 'app123', + 'User-Agent': 'Airtable.js/' + version + }, + agentOptions: { + rejectUnauthorized: false + } + }, expect.any(Function)); - expect(version).toEqual(expect.stringMatching(/^\d+\.\d+\.\d+$/)); + expect(version).toEqual(expect.stringMatching(/^\d+\.\d+\.\d+$/)); + }); }); - }); }); \ No newline at end of file diff --git a/test/browser_build.test.js b/test/browser_build.test.js index d729e226..8af65438 100644 --- a/test/browser_build.test.js +++ b/test/browser_build.test.js @@ -5,26 +5,26 @@ var path = require('path'); var BUILD_PATH = path.join(__dirname, '..', 'build', 'airtable.browser.js'); -describe('browser build', function () { - it("doesn't contain any environment variables", function (done) { - fs.readFile(BUILD_PATH, 'utf8', function (err, builtJs) { - if (err) { - done(err); - return; - } +describe('browser build', function() { + it("doesn't contain any environment variables", function(done) { + fs.readFile(BUILD_PATH, 'utf8', function(err, builtJs) { + if (err) { + done(err); + return; + } - var exceptions = [ - /process\.env\.NODE_DEBUG/, - /process\.env = {}/ - ]; + var exceptions = [ + /process\.env\.NODE_DEBUG/, + /process\.env = {}/ + ]; - var builtWithoutExceptions = exceptions.reduce(function (result, exception) { - return result.replace(exception, ''); - }, builtJs); + var builtWithoutExceptions = exceptions.reduce(function(result, exception) { + return result.replace(exception, ''); + }, builtJs); - expect(builtWithoutExceptions).not.toContain('process.env'); + expect(builtWithoutExceptions).not.toContain('process.env'); - done(); + done(); + }); }); - }); }); \ No newline at end of file diff --git a/test/callback_to_promise.test.js b/test/callback_to_promise.test.js index 4a5d2d6e..c6aed821 100644 --- a/test/callback_to_promise.test.js +++ b/test/callback_to_promise.test.js @@ -2,9 +2,9 @@ var callbackToPromise = require('../lib/callback_to_promise'); -describe('callbackToPromise', function () { +describe('callbackToPromise', function() { function returnThisPlusValue(value, callback) { - callback(null, this + value); // jshint ignore:line + callback(null, this + value); } function sum() { @@ -16,30 +16,30 @@ describe('callbackToPromise', function () { callback(null, result); } - it('lets a function return a promise', function () { + it('lets a function return a promise', function() { var wrapped = callbackToPromise(returnThisPlusValue, 1); expect(wrapped(2)).resolves.toBe(3); }); - it('maintains the ability to call a function with a callback', function (done) { + it('maintains the ability to call a function with a callback', function(done) { var wrapped = callbackToPromise(returnThisPlusValue, 1); - wrapped(2, function (err, result) { + wrapped(2, function(err, result) { expect(err).toBeNull(); expect(result).toBe(3); done(); }); }); - it('is resilient to changes in the number of arguments', function (done) { + it('is resilient to changes in the number of arguments', function(done) { var wrapped = callbackToPromise(sum, null); - wrapped(1, 2, function (err1, result1) { + wrapped(1, 2, function(err1, result1) { expect(err1).toBeNull(); expect(result1).toBe(3); - wrapped(3, 4, 5, function (err2, result2) { + wrapped(3, 4, 5, function(err2, result2) { expect(err2).toBeNull(); expect(result2).toBe(12); - wrapped(6, function (err3, result3) { + wrapped(6, function(err3, result3) { expect(err3).toBeNull(); expect(result3).toBe(6); done(); diff --git a/test/create.test.js b/test/create.test.js index fd71921e..ed35ff83 100644 --- a/test/create.test.js +++ b/test/create.test.js @@ -2,129 +2,129 @@ var testHelpers = require('./test_helpers'); -describe('record creation', function () { - var airtable; - var teardownAsync; +describe('record creation', function() { + var airtable; + var teardownAsync; - beforeAll(function () { - return testHelpers.getMockEnvironmentAsync().then(function (env) { - airtable = env.airtable; - teardownAsync = env.teardownAsync; + beforeAll(function() { + return testHelpers.getMockEnvironmentAsync().then(function(env) { + airtable = env.airtable; + teardownAsync = env.teardownAsync; + }); }); - }); - afterAll(function () { - return teardownAsync(); - }); + afterAll(function() { + return teardownAsync(); + }); - it('can create one record', function () { - return airtable - .base('app123') - .table('Table') - .create({ - foo: 'boo', - bar: 'yar', - }) - .then(function (createdRecord) { - expect(createdRecord.id).toBe('rec0'); - expect(createdRecord.get('foo')).toBe('boo'); - expect(createdRecord.get('bar')).toBe('yar'); - }); - }); + it('can create one record', function() { + return airtable + .base('app123') + .table('Table') + .create({ + foo: 'boo', + bar: 'yar', + }) + .then(function(createdRecord) { + expect(createdRecord.id).toBe('rec0'); + expect(createdRecord.get('foo')).toBe('boo'); + expect(createdRecord.get('bar')).toBe('yar'); + }); + }); - it('can create one record and call a callback', function (done) { - airtable - .base('app123') - .table('Table') - .create({ - foo: 'boo', - bar: 'yar', - }, function (err, createdRecord) { - expect(err).toBeNull(); - expect(createdRecord.id).toBe('rec0'); - expect(createdRecord.get('foo')).toBe('boo'); - expect(createdRecord.get('bar')).toBe('yar'); - done(); - }); - }); + it('can create one record and call a callback', function(done) { + airtable + .base('app123') + .table('Table') + .create({ + foo: 'boo', + bar: 'yar', + }, function(err, createdRecord) { + expect(err).toBeNull(); + expect(createdRecord.id).toBe('rec0'); + expect(createdRecord.get('foo')).toBe('boo'); + expect(createdRecord.get('bar')).toBe('yar'); + done(); + }); + }); - it('can add the "typecast" parameter when creating one record', function () { - return airtable - .base('app123') - .table('Table') - .create({ - foo: 'boo', - bar: 'yar', - }, {typecast: true}) - .then(function (createdRecord) { - expect(createdRecord.id).toBe('rec0'); - expect(createdRecord.get('typecasted')).toBe(true); - }); - }); + it('can add the "typecast" parameter when creating one record', function() { + return airtable + .base('app123') + .table('Table') + .create({ + foo: 'boo', + bar: 'yar', + }, {typecast: true}) + .then(function(createdRecord) { + expect(createdRecord.id).toBe('rec0'); + expect(createdRecord.get('typecasted')).toBe(true); + }); + }); - it('can create one record with an array', function () { - return airtable - .base('app123') - .table('Table') - .create([{ - fields: {foo: 'boo'} - }]) - .then(function (createdRecords) { - expect(createdRecords).toHaveLength(1); - expect(createdRecords[0].id).toBe('rec0'); - expect(createdRecords[0].get('foo')).toBe('boo'); - }); - }); + it('can create one record with an array', function() { + return airtable + .base('app123') + .table('Table') + .create([{ + fields: {foo: 'boo'} + }]) + .then(function(createdRecords) { + expect(createdRecords).toHaveLength(1); + expect(createdRecords[0].id).toBe('rec0'); + expect(createdRecords[0].get('foo')).toBe('boo'); + }); + }); - it('can create two records', function () { - return airtable - .base('app123') - .table('Table') - .create([ - {fields: {foo: 'boo'}}, - {fields: {bar: 'yar'}}, - ]) - .then(function (createdRecords) { - expect(createdRecords).toHaveLength(2); - expect(createdRecords[0].id).toBe('rec0'); - expect(createdRecords[0].get('foo')).toBe('boo'); - expect(createdRecords[1].id).toBe('rec1'); - expect(createdRecords[1].get('bar')).toBe('yar'); - }); - }); + it('can create two records', function() { + return airtable + .base('app123') + .table('Table') + .create([ + {fields: {foo: 'boo'}}, + {fields: {bar: 'yar'}}, + ]) + .then(function(createdRecords) { + expect(createdRecords).toHaveLength(2); + expect(createdRecords[0].id).toBe('rec0'); + expect(createdRecords[0].get('foo')).toBe('boo'); + expect(createdRecords[1].id).toBe('rec1'); + expect(createdRecords[1].get('bar')).toBe('yar'); + }); + }); - it('can create two records and call a callback', function (done) { - airtable - .base('app123') - .table('Table') - .create([ - {fields: {foo: 'boo'}}, - {fields: {bar: 'yar'}}, - ], function (err, createdRecords) { - expect(err).toBeNull(); - expect(createdRecords).toHaveLength(2); - expect(createdRecords[0].id).toBe('rec0'); - expect(createdRecords[0].get('foo')).toBe('boo'); - expect(createdRecords[1].id).toBe('rec1'); - expect(createdRecords[1].get('bar')).toBe('yar'); - done(); - }); - }); + it('can create two records and call a callback', function(done) { + airtable + .base('app123') + .table('Table') + .create([ + {fields: {foo: 'boo'}}, + {fields: {bar: 'yar'}}, + ], function(err, createdRecords) { + expect(err).toBeNull(); + expect(createdRecords).toHaveLength(2); + expect(createdRecords[0].id).toBe('rec0'); + expect(createdRecords[0].get('foo')).toBe('boo'); + expect(createdRecords[1].id).toBe('rec1'); + expect(createdRecords[1].get('bar')).toBe('yar'); + done(); + }); + }); - it('can create two records with the "typecast" parameter', function () { - return airtable - .base('app123') - .table('Table') - .create([ - {fields: {foo: 'boo'}}, - {fields: {bar: 'yar'}}, - ], {typecast: true}) - .then(function (createdRecords) { - expect(createdRecords).toHaveLength(2); - expect(createdRecords[0].id).toBe('rec0'); - expect(createdRecords[0].get('typecasted')).toBe(true); - expect(createdRecords[1].id).toBe('rec1'); - expect(createdRecords[1].get('typecasted')).toBe(true); - }); - }); + it('can create two records with the "typecast" parameter', function() { + return airtable + .base('app123') + .table('Table') + .create([ + {fields: {foo: 'boo'}}, + {fields: {bar: 'yar'}}, + ], {typecast: true}) + .then(function(createdRecords) { + expect(createdRecords).toHaveLength(2); + expect(createdRecords[0].id).toBe('rec0'); + expect(createdRecords[0].get('typecasted')).toBe(true); + expect(createdRecords[1].id).toBe('rec1'); + expect(createdRecords[1].get('typecasted')).toBe(true); + }); + }); }); diff --git a/test/delete.test.js b/test/delete.test.js index 01ca35b2..517679a0 100644 --- a/test/delete.test.js +++ b/test/delete.test.js @@ -2,65 +2,65 @@ var testHelpers = require('./test_helpers'); -describe('record deletion', function () { - var airtable; - var teardownAsync; +describe('record deletion', function() { + var airtable; + var teardownAsync; - beforeAll(function () { - return testHelpers.getMockEnvironmentAsync().then(function (env) { - airtable = env.airtable; - teardownAsync = env.teardownAsync; + beforeAll(function() { + return testHelpers.getMockEnvironmentAsync().then(function(env) { + airtable = env.airtable; + teardownAsync = env.teardownAsync; + }); }); - }); - afterAll(function () { - return teardownAsync(); - }); + afterAll(function() { + return teardownAsync(); + }); - it('can delete one record', function () { - return airtable - .base('app123') - .table('Table') - .destroy('rec123') - .then(function (deletedRecord) { - expect(deletedRecord.id).toBe('rec123'); - }); - }); + it('can delete one record', function() { + return airtable + .base('app123') + .table('Table') + .destroy('rec123') + .then(function(deletedRecord) { + expect(deletedRecord.id).toBe('rec123'); + }); + }); - it('can delete one record and call a callback', function (done) { - airtable - .base('app123') - .table('Table') - .destroy('rec123', function (err, deletedRecord) { - expect(err).toBeNull(); - expect(deletedRecord.id).toBe('rec123'); - done(); - }); - }); + it('can delete one record and call a callback', function(done) { + airtable + .base('app123') + .table('Table') + .destroy('rec123', function(err, deletedRecord) { + expect(err).toBeNull(); + expect(deletedRecord.id).toBe('rec123'); + done(); + }); + }); - it('can delete multiple records', function () { - return airtable - .base('app123') - .table('Table') - .destroy(['rec123', 'rec456']) - .then(function (deletedRecords) { - expect(deletedRecords).toHaveLength(2); - expect(deletedRecords[0].id).toBe('rec123'); - expect(deletedRecords[1].id).toBe('rec456'); - }); - }); + it('can delete multiple records', function() { + return airtable + .base('app123') + .table('Table') + .destroy(['rec123', 'rec456']) + .then(function(deletedRecords) { + expect(deletedRecords).toHaveLength(2); + expect(deletedRecords[0].id).toBe('rec123'); + expect(deletedRecords[1].id).toBe('rec456'); + }); + }); - it('can delete multiple records and call a callback', function (done) { - airtable - .base('app123') - .table('Table') - .destroy(['rec123', 'rec456'], function (err, deletedRecords) { - expect(err).toBeNull(); - expect(deletedRecords).toHaveLength(2); - expect(deletedRecords).toHaveLength(2); - expect(deletedRecords[0].id).toBe('rec123'); - expect(deletedRecords[1].id).toBe('rec456'); - done(); - }); - }); + it('can delete multiple records and call a callback', function(done) { + airtable + .base('app123') + .table('Table') + .destroy(['rec123', 'rec456'], function(err, deletedRecords) { + expect(err).toBeNull(); + expect(deletedRecords).toHaveLength(2); + expect(deletedRecords).toHaveLength(2); + expect(deletedRecords[0].id).toBe('rec123'); + expect(deletedRecords[1].id).toBe('rec456'); + done(); + }); + }); }); diff --git a/test/has.test.js b/test/has.test.js index cb54e4c5..1dda1516 100644 --- a/test/has.test.js +++ b/test/has.test.js @@ -13,6 +13,6 @@ describe('has', function() { }); it('works even if the object has a property called "hasOwnProperty"', function() { - expect(has({hasOwnProperty: 123}, 'hasOwnProperty')).toBe(true); // jshint ignore:line + expect(has({hasOwnProperty: 123}, 'hasOwnProperty')).toBe(true); }); }); diff --git a/test/object_to_query_param_string.test.js b/test/object_to_query_param_string.test.js index 2082a721..2e52ee90 100644 --- a/test/object_to_query_param_string.test.js +++ b/test/object_to_query_param_string.test.js @@ -3,12 +3,12 @@ var querystring = require('querystring'); var objectToQueryParamString = require('../lib/object_to_query_param_string'); -describe('objectToQueryParamString', function () { - it('returns the empty string for an empty object', function () { +describe('objectToQueryParamString', function() { + it('returns the empty string for an empty object', function() { expect(objectToQueryParamString({})).toBe(''); }); - it('serializes strings', function () { + it('serializes strings', function() { expect(objectToQueryParamString({foo: 'boo'})).toBe('foo=boo'); expect(objectToQueryParamString({foo: 'bar baz'})).toBe('foo=bar+baz'); @@ -19,7 +19,7 @@ describe('objectToQueryParamString', function () { expect(objectToQueryParamString({foo: '🌴'})).toBe('foo=%F0%9F%8C%B4'); }); - it('serializes numbers', function () { + it('serializes numbers', function() { expect(objectToQueryParamString({n: 0})).toBe('n=0'); expect(objectToQueryParamString({n: 1})).toBe('n=1'); expect(objectToQueryParamString({n: 1.23})).toBe('n=1.23'); @@ -31,17 +31,17 @@ describe('objectToQueryParamString', function () { expect(objectToQueryParamString({n: NaN})).toBe('n=NaN'); }); - it('serializes booleans', function () { + it('serializes booleans', function() { expect(objectToQueryParamString({b: true})).toBe('b=true'); expect(objectToQueryParamString({b: false})).toBe('b=false'); }); - it('serializes null and undefined', function () { + it('serializes null and undefined', function() { expect(objectToQueryParamString({x: null})).toBe(''); expect(objectToQueryParamString({x: undefined})).toBe('x='); }); - it('serializes arrays', function () { + it('serializes arrays', function() { expect(objectToQueryParamString({arr: [1]})).toBe(encodeURIComponent('arr[]') + '=1'); expect(objectToQueryParamString({arr: [1, 2]})).toBe([ encodeURIComponent('arr[]'), '=', '1', @@ -65,7 +65,7 @@ describe('objectToQueryParamString', function () { expect(actual).toEqual(expected); }); - it('serializes objects', function () { + it('serializes objects', function() { expect(objectToQueryParamString({obj: {foo: 'boo'}})).toBe(encodeURIComponent('obj[foo]') + '=boo'); expect(objectToQueryParamString({ diff --git a/test/record.test.js b/test/record.test.js index 7edec7e0..2943798b 100644 --- a/test/record.test.js +++ b/test/record.test.js @@ -2,27 +2,27 @@ var Record = require('../lib/record'); -describe('Record', function () { +describe('Record', function() { var table; - beforeEach(function () { + beforeEach(function() { table = { _base: { runAction: jest.fn(), }, - _urlEncodedNameOrId: function () { + _urlEncodedNameOrId: function() { return 'My%20Table'; }, }; }); - it('can be initialized with a record ID and no data', function () { + it('can be initialized with a record ID and no data', function() { var record = new Record(table, 'rec123'); expect(record.id).toBe('rec123'); expect(record.fields).toEqual({}); }); - it('can be initialized with data, which contains the ID', function () { + it('can be initialized with data, which contains the ID', function() { var record = new Record(table, null, { id: 'rec123', fields: {foo: 'bar'}, @@ -32,7 +32,7 @@ describe('Record', function () { expect(record.get('foo')).toBe('bar'); }); - it('can be initialized with data and an ID (the explicit ID wins)', function () { + it('can be initialized with data and an ID (the explicit ID wins)', function() { var record = new Record(table, 'rec123', { id: 'recIGNORED', fields: {foo: 'bar'}, @@ -41,40 +41,40 @@ describe('Record', function () { expect(record.fields).toEqual({foo: 'bar'}); }); - describe('getId', function () { - it('returns the record ID', function () { + describe('getId', function() { + it('returns the record ID', function() { expect(new Record(table, 'rec123').getId()).toBe('rec123'); }); }); - describe('get', function () { + describe('get', function() { var record; - beforeEach(function () { + beforeEach(function() { record = new Record(table, null, { id: 'rec123', fields: {foo: 'bar'}, }); }); - it("returns a field's value if set", function () { + it("returns a field's value if set", function() { expect(record.get('foo')).toBe('bar'); }); - it("returns undefined if requesting a cell value that doesn't exist", function () { + it("returns undefined if requesting a cell value that doesn't exist", function() { expect(record.get('missing')).toBeUndefined(); }); }); - describe('patchUpdate', function () { + describe('patchUpdate', function() { var record; - beforeEach(function () { + beforeEach(function() { record = new Record(table, null, { id: 'rec123', fields: {foo: 'bar'}, }); - table._base.runAction.mockImplementationOnce(function (method, path, queryParams, bodyData, callback) { + table._base.runAction.mockImplementationOnce(function(method, path, queryParams, bodyData, callback) { callback(null, null, { id: bodyData.id, createdTime: '2020-04-20T16:20:00.000Z', @@ -83,8 +83,8 @@ describe('Record', function () { }); }); - it('patch-updates the record and calls a callback', function (done) { - record.patchUpdate({baz: 'qux'}, function (err, updatedRecord) { + it('patch-updates the record and calls a callback', function(done) { + record.patchUpdate({baz: 'qux'}, function(err, updatedRecord) { expect(err).toBeNull(); expect(updatedRecord).toBe(record); @@ -99,30 +99,30 @@ describe('Record', function () { }); }); - it('returns a promise when no callback is passed', function () { + it('returns a promise when no callback is passed', function() { return record.patchUpdate({baz: 'qux'}) - .then(function (updatedRecord) { + .then(function(updatedRecord) { expect(updatedRecord).toBe(record); expect(record.get('foo')).toEqual('bar'); expect(record.get('baz')).toEqual('qux'); }); }); - it('aliases "updateFields"', function () { + it('aliases "updateFields"', function() { expect(record.updateFields).toBe(record.patchUpdate); }); }); - describe('putUpdate', function () { + describe('putUpdate', function() { var record; - beforeEach(function () { + beforeEach(function() { record = new Record(table, null, { id: 'rec123', fields: {foo: 'bar'}, }); - table._base.runAction.mockImplementationOnce(function (method, path, queryParams, bodyData, callback) { + table._base.runAction.mockImplementationOnce(function(method, path, queryParams, bodyData, callback) { callback(null, null, { id: bodyData.id, createdTime: '2020-04-20T16:20:00.000Z', @@ -131,8 +131,8 @@ describe('Record', function () { }); }); - it('patch-updates the record and calls a callback', function (done) { - record.putUpdate({baz: 'qux'}, function (err, updatedRecord) { + it('patch-updates the record and calls a callback', function(done) { + record.putUpdate({baz: 'qux'}, function(err, updatedRecord) { expect(err).toBeNull(); expect(updatedRecord).toBe(record); @@ -147,23 +147,23 @@ describe('Record', function () { }); }); - it('returns a promise when no callback is passed', function () { + it('returns a promise when no callback is passed', function() { return record.patchUpdate({baz: 'qux'}) - .then(function (updatedRecord) { + .then(function(updatedRecord) { expect(updatedRecord).toBe(record); expect(record.get('foo')).toBeUndefined(); expect(record.get('baz')).toEqual('qux'); }); }); - it('aliases "replaceFields"', function () { + it('aliases "replaceFields"', function() { expect(record.replaceFields).toBe(record.putUpdate); }); }); - describe('fetch', function () { - beforeEach(function () { - table._base.runAction.mockImplementationOnce(function (method, path, queryParams, bodyData, callback) { + describe('fetch', function() { + beforeEach(function() { + table._base.runAction.mockImplementationOnce(function(method, path, queryParams, bodyData, callback) { callback(null, null, { id: 'rec123', createdTime: '2020-04-20T16:20:00.000Z', @@ -172,10 +172,10 @@ describe('Record', function () { }); }); - it('fetches a record and calls a callback', function (done) { + it('fetches a record and calls a callback', function(done) { var record = new Record(table, 'rec123'); - record.fetch(function (err, fetchedRecord) { + record.fetch(function(err, fetchedRecord) { expect(err).toBeNull(); expect(fetchedRecord).toBe(record); @@ -188,10 +188,10 @@ describe('Record', function () { }); }); - it('returns a promise when no callback is passed', function () { + it('returns a promise when no callback is passed', function() { var record = new Record(table, 'rec123'); - return record.fetch().then(function (fetchedRecord) { + return record.fetch().then(function(fetchedRecord) { expect(fetchedRecord).toBe(record); expect(record.get('foo')).toBe('bar'); expect(record.get('baz')).toBeUndefined(); diff --git a/test/test_helpers.js b/test/test_helpers.js index 2cbe4302..e381b4c4 100644 --- a/test/test_helpers.js +++ b/test/test_helpers.js @@ -9,122 +9,122 @@ var util = require('util'); var FAKE_CREATED_TIME = '2020-04-20T16:20:00.000Z'; function getMockEnvironmentAsync() { - var app = express(); + var app = express(); - app.use(bodyParser.json()); + app.use(bodyParser.json()); - app.post('/v0/:baseId/:tableIdOrName', _checkParamsMiddleware, function (req, res) { - var isCreatingJustOneRecord = !!req.body.fields; - var recordsInBody = isCreatingJustOneRecord ? [req.body] : req.body.records; + app.post('/v0/:baseId/:tableIdOrName', _checkParamsMiddleware, function(req, res) { + var isCreatingJustOneRecord = !!req.body.fields; + var recordsInBody = isCreatingJustOneRecord ? [req.body] : req.body.records; - var records = recordsInBody.map(function (record, index) { - var fields = req.body.typecast ? {typecasted: true} : record.fields; - return { - id: 'rec' + index, - createdTime: FAKE_CREATED_TIME, - fields: fields, - }; + var records = recordsInBody.map(function(record, index) { + var fields = req.body.typecast ? {typecasted: true} : record.fields; + return { + id: 'rec' + index, + createdTime: FAKE_CREATED_TIME, + fields: fields, + }; + }); + + var responseBody = isCreatingJustOneRecord ? records[0] : {records: records}; + res.json(responseBody); }); - var responseBody = isCreatingJustOneRecord ? records[0] : {records: records}; - res.json(responseBody); - }); - - const singleRecordUpdate = [ - _checkParamsMiddleware, - function(req, res) { - var fields = req.body.typecast ? {typecasted: true} : req.body.fields; - - res.json({ - id: req.params.recordId, - createdTime: FAKE_CREATED_TIME, - fields: fields, - }); - }, - ]; - const batchRecordUpdate = [ - _checkParamsMiddleware, - function(req, res) { - res.json({ - records: req.body.records.map(function (record) { - var fields = req.body.typecast ? {typecasted: true} : record.fields; - return { - id: record.id, - createdTime: FAKE_CREATED_TIME, - fields: fields - }; - }), - }); - }, - ]; - - app.patch('/v0/:baseId/:tableIdOrName/:recordId', singleRecordUpdate); - app.put('/v0/:baseId/:tableIdOrName/:recordId', singleRecordUpdate); - - app.patch('/v0/:baseId/:tableIdOrName', batchRecordUpdate); - app.put('/v0/:baseId/:tableIdOrName', batchRecordUpdate); - - app.delete('/v0/:baseId/:tableIdOrName/:recordId', _checkParamsMiddleware, function (req, res) { - res.json({ - id: req.params.recordId, - deleted: true + const singleRecordUpdate = [ + _checkParamsMiddleware, + function(req, res) { + var fields = req.body.typecast ? {typecasted: true} : req.body.fields; + + res.json({ + id: req.params.recordId, + createdTime: FAKE_CREATED_TIME, + fields: fields, + }); + }, + ]; + const batchRecordUpdate = [ + _checkParamsMiddleware, + function(req, res) { + res.json({ + records: req.body.records.map(function(record) { + var fields = req.body.typecast ? {typecasted: true} : record.fields; + return { + id: record.id, + createdTime: FAKE_CREATED_TIME, + fields: fields + }; + }), + }); + }, + ]; + + app.patch('/v0/:baseId/:tableIdOrName/:recordId', singleRecordUpdate); + app.put('/v0/:baseId/:tableIdOrName/:recordId', singleRecordUpdate); + + app.patch('/v0/:baseId/:tableIdOrName', batchRecordUpdate); + app.put('/v0/:baseId/:tableIdOrName', batchRecordUpdate); + + app.delete('/v0/:baseId/:tableIdOrName/:recordId', _checkParamsMiddleware, function(req, res) { + res.json({ + id: req.params.recordId, + deleted: true + }); }); - }); - - app.delete('/v0/:baseId/:tableIdOrName', _checkParamsMiddleware, function (req, res) { - res.json({ - records: req.query.records.map(function (recordId) { - return { - id: recordId, - deleted: true - }; - }) + + app.delete('/v0/:baseId/:tableIdOrName', _checkParamsMiddleware, function(req, res) { + res.json({ + records: req.query.records.map(function(recordId) { + return { + id: recordId, + deleted: true + }; + }) + }); }); - }); - - app.use(function (err, req, res, next) { - console.error(err); - res.status(500); - res.json({ - error: { - type: 'TEST_ERROR', - message: err.message, - } + + app.use(function(err, req, res, next) { // eslint-disable-line no-unused-vars + console.error(err); + res.status(500); + res.json({ + error: { + type: 'TEST_ERROR', + message: err.message, + } + }); }); - }); - - return getPort().then(function (testServerPort) { - return new Promise(function (resolve, reject) { - var testServer = app.listen(testServerPort, function (err) { - if (err) { - reject(err); - } else { - resolve({ - airtable: new Airtable({ - apiKey: 'key123', - endpointUrl: 'http://localhost:' + testServerPort, - }), - teardownAsync: util.promisify(testServer.close.bind(testServer)), - }); - } - }); + + return getPort().then(function(testServerPort) { + return new Promise(function(resolve, reject) { + var testServer = app.listen(testServerPort, function(err) { + if (err) { + reject(err); + } else { + resolve({ + airtable: new Airtable({ + apiKey: 'key123', + endpointUrl: 'http://localhost:' + testServerPort, + }), + teardownAsync: util.promisify(testServer.close.bind(testServer)), + }); + } + }); + }); }); - }); } function _checkParamsMiddleware(req, res, next) { - var areParamsValid = ( - (req.get('authorization') === 'Bearer key123') && + var areParamsValid = ( + (req.get('authorization') === 'Bearer key123') && (req.params.baseId === 'app123') && (req.params.tableIdOrName === 'Table') - ); - if (areParamsValid) { - next(); - } else { - next(new Error('Bad parameters')); - } + ); + if (areParamsValid) { + next(); + } else { + next(new Error('Bad parameters')); + } } module.exports = { - getMockEnvironmentAsync: getMockEnvironmentAsync, + getMockEnvironmentAsync: getMockEnvironmentAsync, }; diff --git a/test/update.test.js b/test/update.test.js index 2d03fe23..5226e647 100644 --- a/test/update.test.js +++ b/test/update.test.js @@ -2,242 +2,242 @@ var testHelpers = require('./test_helpers'); -describe('record updates', function () { - var airtable; - var teardownAsync; - - beforeAll(function () { - return testHelpers.getMockEnvironmentAsync().then(function (env) { - airtable = env.airtable; - teardownAsync = env.teardownAsync; - }); - }); - - afterAll(function () { - return teardownAsync(); - }); - - describe('non-destructive updates', function () { - it('can update one record', function () { - return airtable - .base('app123') - .table('Table') - .update('rec123', { - foo: 'boo', - bar: 'yar', - }) - .then(function (updatedRecord) { - expect(updatedRecord.id).toBe('rec123'); - expect(updatedRecord.get('foo')).toBe('boo'); - expect(updatedRecord.get('bar')).toBe('yar'); +describe('record updates', function() { + var airtable; + var teardownAsync; + + beforeAll(function() { + return testHelpers.getMockEnvironmentAsync().then(function(env) { + airtable = env.airtable; + teardownAsync = env.teardownAsync; }); }); - it('can update one record and call a callback', function (done) { - airtable - .base('app123') - .table('Table') - .update('rec123', { - foo: 'boo', - bar: 'yar', - }, function (err, updatedRecord) { - expect(err).toBeNull(); - expect(updatedRecord.id).toBe('rec123'); - expect(updatedRecord.get('foo')).toBe('boo'); - expect(updatedRecord.get('bar')).toBe('yar'); - done(); - }); + afterAll(function() { + return teardownAsync(); }); - it('can add the "typecast" parameter when updating one record', function () { - return airtable - .base('app123') - .table('Table') - .update('rec123', { - foo: 'boo', - bar: 'yar', - }, {typecast: true}) - .then(function (updatedRecord) { - expect(updatedRecord.id).toBe('rec123'); - expect(updatedRecord.get('typecasted')).toBe(true); + describe('non-destructive updates', function() { + it('can update one record', function() { + return airtable + .base('app123') + .table('Table') + .update('rec123', { + foo: 'boo', + bar: 'yar', + }) + .then(function(updatedRecord) { + expect(updatedRecord.id).toBe('rec123'); + expect(updatedRecord.get('foo')).toBe('boo'); + expect(updatedRecord.get('bar')).toBe('yar'); + }); }); - }); - it('can update one record with an array', function () { - return airtable - .base('app123') - .table('Table') - .update([{ - id: 'rec123', - fields: {foo: 'boo'}, - }]) - .then(function (updatedRecords) { - expect(updatedRecords).toHaveLength(1); - expect(updatedRecords[0].id).toBe('rec123'); - expect(updatedRecords[0].get('foo')).toBe('boo'); + it('can update one record and call a callback', function(done) { + airtable + .base('app123') + .table('Table') + .update('rec123', { + foo: 'boo', + bar: 'yar', + }, function(err, updatedRecord) { + expect(err).toBeNull(); + expect(updatedRecord.id).toBe('rec123'); + expect(updatedRecord.get('foo')).toBe('boo'); + expect(updatedRecord.get('bar')).toBe('yar'); + done(); + }); }); - }); - it('can update two records', function () { - return airtable - .base('app123') - .table('Table') - .update([ - { - id: 'rec123', - fields: {foo: 'boo'}, - }, - { - id: 'rec456', - fields: {bar: 'yar'}, - }, - ]) - .then(function (updatedRecords) { - expect(updatedRecords).toHaveLength(2); - expect(updatedRecords[0].id).toBe('rec123'); - expect(updatedRecords[0].get('foo')).toBe('boo'); - expect(updatedRecords[1].id).toBe('rec456'); - expect(updatedRecords[1].get('bar')).toBe('yar'); + it('can add the "typecast" parameter when updating one record', function() { + return airtable + .base('app123') + .table('Table') + .update('rec123', { + foo: 'boo', + bar: 'yar', + }, {typecast: true}) + .then(function(updatedRecord) { + expect(updatedRecord.id).toBe('rec123'); + expect(updatedRecord.get('typecasted')).toBe(true); + }); }); - }); - it('can update two records and call a callback', function (done) { - airtable - .base('app123') - .table('Table') - .update([ - { - id: 'rec123', - fields: {foo: 'boo'}, - }, - { - id: 'rec456', - fields: {bar: 'yar'}, - }, - ], function (err, updatedRecords) { - expect(err).toBeNull(); - expect(updatedRecords).toHaveLength(2); - expect(updatedRecords[0].id).toBe('rec123'); - expect(updatedRecords[0].get('foo')).toBe('boo'); - expect(updatedRecords[1].id).toBe('rec456'); - expect(updatedRecords[1].get('bar')).toBe('yar'); - done(); + it('can update one record with an array', function() { + return airtable + .base('app123') + .table('Table') + .update([{ + id: 'rec123', + fields: {foo: 'boo'}, + }]) + .then(function(updatedRecords) { + expect(updatedRecords).toHaveLength(1); + expect(updatedRecords[0].id).toBe('rec123'); + expect(updatedRecords[0].get('foo')).toBe('boo'); + }); }); - }); - it('can update two records with the "typecast" parameter', function () { - return airtable - .base('app123') - .table('Table') - .update([ - { - id: 'rec123', - fields: {foo: 'boo'}, - }, - { - id: 'rec456', - fields: {bar: 'yar'}, - }, - ], {typecast: true}) - .then(function (updatedRecords) { - expect(updatedRecords).toHaveLength(2); - expect(updatedRecords[0].id).toBe('rec123'); - expect(updatedRecords[0].get('typecasted')).toBe(true); - expect(updatedRecords[1].id).toBe('rec456'); - expect(updatedRecords[1].get('typecasted')).toBe(true); + it('can update two records', function() { + return airtable + .base('app123') + .table('Table') + .update([ + { + id: 'rec123', + fields: {foo: 'boo'}, + }, + { + id: 'rec456', + fields: {bar: 'yar'}, + }, + ]) + .then(function(updatedRecords) { + expect(updatedRecords).toHaveLength(2); + expect(updatedRecords[0].id).toBe('rec123'); + expect(updatedRecords[0].get('foo')).toBe('boo'); + expect(updatedRecords[1].id).toBe('rec456'); + expect(updatedRecords[1].get('bar')).toBe('yar'); + }); }); - }); - }); - - describe('destructive updates', function () { - it('can update one record', function () { - return airtable - .base('app123') - .table('Table') - .replace('rec123', { - foo: 'boo', - bar: 'yar', - }) - .then(function (updatedRecord) { - expect(updatedRecord.id).toBe('rec123'); - expect(updatedRecord.get('foo')).toBe('boo'); - expect(updatedRecord.get('bar')).toBe('yar'); + + it('can update two records and call a callback', function(done) { + airtable + .base('app123') + .table('Table') + .update([ + { + id: 'rec123', + fields: {foo: 'boo'}, + }, + { + id: 'rec456', + fields: {bar: 'yar'}, + }, + ], function(err, updatedRecords) { + expect(err).toBeNull(); + expect(updatedRecords).toHaveLength(2); + expect(updatedRecords[0].id).toBe('rec123'); + expect(updatedRecords[0].get('foo')).toBe('boo'); + expect(updatedRecords[1].id).toBe('rec456'); + expect(updatedRecords[1].get('bar')).toBe('yar'); + done(); + }); }); - }); - it('can add the "typecast" parameter when updating one record', function () { - return airtable - .base('app123') - .table('Table') - .replace('rec123', { - foo: 'boo', - bar: 'yar', - }, {typecast: true}) - .then(function (updatedRecord) { - expect(updatedRecord.id).toBe('rec123'); - expect(updatedRecord.get('typecasted')).toBe(true); + it('can update two records with the "typecast" parameter', function() { + return airtable + .base('app123') + .table('Table') + .update([ + { + id: 'rec123', + fields: {foo: 'boo'}, + }, + { + id: 'rec456', + fields: {bar: 'yar'}, + }, + ], {typecast: true}) + .then(function(updatedRecords) { + expect(updatedRecords).toHaveLength(2); + expect(updatedRecords[0].id).toBe('rec123'); + expect(updatedRecords[0].get('typecasted')).toBe(true); + expect(updatedRecords[1].id).toBe('rec456'); + expect(updatedRecords[1].get('typecasted')).toBe(true); + }); }); }); - it('can update one record with an array', function () { - return airtable - .base('app123') - .table('Table') - .replace([{ - id: 'rec123', - fields: {foo: 'boo'}, - }]) - .then(function (updatedRecords) { - expect(updatedRecords).toHaveLength(1); - expect(updatedRecords[0].id).toBe('rec123'); - expect(updatedRecords[0].get('foo')).toBe('boo'); + describe('destructive updates', function() { + it('can update one record', function() { + return airtable + .base('app123') + .table('Table') + .replace('rec123', { + foo: 'boo', + bar: 'yar', + }) + .then(function(updatedRecord) { + expect(updatedRecord.id).toBe('rec123'); + expect(updatedRecord.get('foo')).toBe('boo'); + expect(updatedRecord.get('bar')).toBe('yar'); + }); }); - }); - it('can update two records', function () { - return airtable - .base('app123') - .table('Table') - .replace([ - { - id: 'rec123', - fields: {foo: 'boo'}, - }, - { - id: 'rec456', - fields: {bar: 'yar'}, - }, - ]) - .then(function (updatedRecords) { - expect(updatedRecords).toHaveLength(2); - expect(updatedRecords[0].id).toBe('rec123'); - expect(updatedRecords[0].get('foo')).toBe('boo'); - expect(updatedRecords[1].id).toBe('rec456'); - expect(updatedRecords[1].get('bar')).toBe('yar'); + it('can add the "typecast" parameter when updating one record', function() { + return airtable + .base('app123') + .table('Table') + .replace('rec123', { + foo: 'boo', + bar: 'yar', + }, {typecast: true}) + .then(function(updatedRecord) { + expect(updatedRecord.id).toBe('rec123'); + expect(updatedRecord.get('typecasted')).toBe(true); + }); + }); + + it('can update one record with an array', function() { + return airtable + .base('app123') + .table('Table') + .replace([{ + id: 'rec123', + fields: {foo: 'boo'}, + }]) + .then(function(updatedRecords) { + expect(updatedRecords).toHaveLength(1); + expect(updatedRecords[0].id).toBe('rec123'); + expect(updatedRecords[0].get('foo')).toBe('boo'); + }); + }); + + it('can update two records', function() { + return airtable + .base('app123') + .table('Table') + .replace([ + { + id: 'rec123', + fields: {foo: 'boo'}, + }, + { + id: 'rec456', + fields: {bar: 'yar'}, + }, + ]) + .then(function(updatedRecords) { + expect(updatedRecords).toHaveLength(2); + expect(updatedRecords[0].id).toBe('rec123'); + expect(updatedRecords[0].get('foo')).toBe('boo'); + expect(updatedRecords[1].id).toBe('rec456'); + expect(updatedRecords[1].get('bar')).toBe('yar'); + }); }); - }); - it('can update two records with the "typecast" parameter', function () { - return airtable - .base('app123') - .table('Table') - .replace([ - { - id: 'rec123', - fields: {foo: 'boo'}, - }, - { - id: 'rec456', - fields: {bar: 'yar'}, - }, - ], {typecast: true}) - .then(function (updatedRecords) { - expect(updatedRecords).toHaveLength(2); - expect(updatedRecords[0].id).toBe('rec123'); - expect(updatedRecords[0].get('typecasted')).toBe(true); - expect(updatedRecords[1].id).toBe('rec456'); - expect(updatedRecords[1].get('typecasted')).toBe(true); + it('can update two records with the "typecast" parameter', function() { + return airtable + .base('app123') + .table('Table') + .replace([ + { + id: 'rec123', + fields: {foo: 'boo'}, + }, + { + id: 'rec456', + fields: {bar: 'yar'}, + }, + ], {typecast: true}) + .then(function(updatedRecords) { + expect(updatedRecords).toHaveLength(2); + expect(updatedRecords[0].id).toBe('rec123'); + expect(updatedRecords[0].get('typecasted')).toBe(true); + expect(updatedRecords[1].id).toBe('rec456'); + expect(updatedRecords[1].get('typecasted')).toBe(true); + }); }); }); - }); });