diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..31dae4e --- /dev/null +++ b/.eslintignore @@ -0,0 +1,2 @@ +/coverage +/lib diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..b56bd5b --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,18 @@ +module.exports = { + extends: [ + 'standard', + 'prettier', + 'prettier/standard' + ], + env: { + es6: true, + node: true + }, + plugins: ['prettier'], + rules: { + 'prettier/prettier': ['error', { + singleQuote: true, + semi: false + }] + } +} diff --git a/package.json b/package.json index 96e656d..6429a06 100644 --- a/package.json +++ b/package.json @@ -30,8 +30,9 @@ "clean": "npm run clean:lib", "clean:lib": "rm -rf lib", "deploy": "./scripts/deploy.sh", - "lint": "standard --verbose | snazzy", - "lint:fix": "standard --verbose --fix", + "format": "npm run lint:fix", + "lint": "eslint .", + "lint:fix": "eslint --fix .", "postinstall": "postinstall-build lib --script build:lib", "prepublish": "npm run clean:lib && npm run build:lib", "preversion": "npm run update-schema && npm run build:docs && git add schema.json docs", @@ -100,15 +101,22 @@ "coveralls": "^3.0.0", "cross-env": "^5.1.1", "doctoc": "^1.3.0", + "eslint": "^4.10.0", + "eslint-config-prettier": "^2.7.0", + "eslint-config-standard": "^10.2.1", + "eslint-plugin-import": "^2.8.0", "eslint-plugin-markdown": "^1.0.0-beta.6", + "eslint-plugin-node": "^5.2.1", + "eslint-plugin-prettier": "^2.3.1", + "eslint-plugin-promise": "^3.6.0", + "eslint-plugin-standard": "^3.0.1", "graphql-markdown": "^3.2.0", "nodemon": "^1.11.0", "nyc": "^11.1.0", + "prettier": "^1.8.0", "rimraf": "^2.6.1", "sepia": "^2.0.2", - "sinon": "^4.0.2", - "snazzy": "^7.0.0", - "standard": "^10.0.3" + "sinon": "^4.0.2" }, "standard": { "parser": "babel-eslint" diff --git a/scripts/build-extension-docs.js b/scripts/build-extension-docs.js index fab237d..e95d462 100644 --- a/scripts/build-extension-docs.js +++ b/scripts/build-extension-docs.js @@ -10,40 +10,43 @@ const extensionModules = [ 'the-audio-db' ] -function getSchemaJSON (schema) { +function getSchemaJSON(schema) { return graphql(schema, introspectionQuery).then(result => result.data) } -Promise.all(extensionModules.map(extensionModule => { - const extension = require(`../src/extensions/${extensionModule}`).default - console.log(`Generating docs for “${extension.name}” extension...`) - const schema = createSchema(baseSchema, { extensions: [extension] }) - return Promise.all([ - getSchemaJSON(baseSchema), - getSchemaJSON(schema) - ]).then(([baseSchemaJSON, schemaJSON]) => { - const outputSchema = diffSchema(baseSchemaJSON, schemaJSON, { - processTypeDiff (type) { - if (type.description === undefined) { - type.description = - ':small_blue_diamond: *This type has been extended. See the ' + - '[base schema](../types.md)\nfor a description and additional ' + - 'fields.*' - } - return type +Promise.all( + extensionModules.map(extensionModule => { + const extension = require(`../src/extensions/${extensionModule}`).default + console.log(`Generating docs for “${extension.name}” extension...`) + const schema = createSchema(baseSchema, { extensions: [extension] }) + return Promise.all([getSchemaJSON(baseSchema), getSchemaJSON(schema)]).then( + ([baseSchemaJSON, schemaJSON]) => { + const outputSchema = diffSchema(baseSchemaJSON, schemaJSON, { + processTypeDiff(type) { + if (type.description === undefined) { + type.description = + ':small_blue_diamond: *This type has been extended. See the ' + + '[base schema](../types.md)\nfor a description and additional ' + + 'fields.*' + } + return type + } + }) + const outputPath = path.resolve( + __dirname, + `../docs/extensions/${extensionModule}.md` + ) + return updateSchema(outputPath, outputSchema, { + unknownTypeURL: '../types.md', + headingLevel: 2 + }) } - }) - const outputPath = path.resolve( - __dirname, - `../docs/extensions/${extensionModule}.md` ) - return updateSchema(outputPath, outputSchema, { - unknownTypeURL: '../types.md', - headingLevel: 2 - }) }) -})).then((extensions) => { - console.log(`Built docs for ${extensions.length} extension(s).`) -}).catch(err => { - console.log('Error:', err) -}) +) + .then(extensions => { + console.log(`Built docs for ${extensions.length} extension(s).`) + }) + .catch(err => { + console.log('Error:', err) + }) diff --git a/scripts/print-schema.js b/scripts/print-schema.js index e98d22c..8e0331a 100644 --- a/scripts/print-schema.js +++ b/scripts/print-schema.js @@ -2,11 +2,13 @@ import { graphql, introspectionQuery, printSchema } from 'graphql' import schema from '../src/schema' if (process.argv[2] === '--json') { - graphql(schema, introspectionQuery).then(result => { - console.log(JSON.stringify(result, null, 2)) - }).catch(err => { - console.error(err) - }) + graphql(schema, introspectionQuery) + .then(result => { + console.log(JSON.stringify(result, null, 2)) + }) + .catch(err => { + console.error(err) + }) } else { console.log(printSchema(schema)) } diff --git a/src/api/client.js b/src/api/client.js index 87c4ea3..8df8bdf 100644 --- a/src/api/client.js +++ b/src/api/client.js @@ -21,33 +21,35 @@ const RETRY_CODES = { } export class ClientError extends ExtendableError { - constructor (message, statusCode) { + constructor(message, statusCode) { super(message) this.statusCode = statusCode } } export default class Client { - constructor ({ - baseURL, - userAgent = `${pkg.name}/${pkg.version} ` + - `( ${pkg.homepage || pkg.author.url || pkg.author.email} )`, - extraHeaders = {}, - errorClass = ClientError, - timeout = 60000, - limit = 1, - period = 1000, - concurrency = 10, - retries = 10, - // It's OK for `retryDelayMin` to be less than one second, even 0, because - // `RateLimit` will already make sure we don't exceed the API rate limit. - // We're not doing exponential backoff because it will help with being - // rate limited, but rather to be chill in case MusicBrainz is returning - // some other error or our network is failing. - retryDelayMin = 100, - retryDelayMax = 60000, - randomizeRetry = true - } = {}) { + constructor( + { + baseURL, + userAgent = `${pkg.name}/${pkg.version} ` + + `( ${pkg.homepage || pkg.author.url || pkg.author.email} )`, + extraHeaders = {}, + errorClass = ClientError, + timeout = 60000, + limit = 1, + period = 1000, + concurrency = 10, + retries = 10, + // It's OK for `retryDelayMin` to be less than one second, even 0, because + // `RateLimit` will already make sure we don't exceed the API rate limit. + // We're not doing exponential backoff because it will help with being + // rate limited, but rather to be chill in case MusicBrainz is returning + // some other error or our network is failing. + retryDelayMin = 100, + retryDelayMax = 60000, + randomizeRetry = true + } = {} + ) { this.baseURL = baseURL this.userAgent = userAgent this.extraHeaders = extraHeaders @@ -67,14 +69,14 @@ export default class Client { * Retry any 5XX response from MusicBrainz, as well as any error in * `RETRY_CODES`. */ - shouldRetry (err) { + shouldRetry(err) { if (err instanceof this.errorClass) { return err.statusCode >= 500 && err.statusCode < 600 } return RETRY_CODES[err.code] || false } - parseErrorMessage (response, body) { + parseErrorMessage(response, body) { return typeof body === 'string' && body ? body : `${response.statusCode}` } @@ -82,7 +84,7 @@ export default class Client { * Send a request without any retrying or rate limiting. * Use `get` instead. */ - _get (path, options = {}, info = {}) { + _get(path, options = {}, info = {}) { return new Promise((resolve, reject) => { options = { baseUrl: this.baseURL, @@ -122,7 +124,7 @@ export default class Client { /** * Send a request with retrying and rate limiting. */ - get (path, options = {}) { + get(path, options = {}) { return new Promise((resolve, reject) => { const fn = this._get.bind(this) const operation = retry.operation(this.retryOptions) @@ -130,7 +132,8 @@ export default class Client { // This will increase the priority in our `RateLimit` queue for each // retry, so that newer requests don't delay this one further. const priority = currentAttempt - this.limiter.enqueue(fn, [path, options, { currentAttempt }], priority) + this.limiter + .enqueue(fn, [path, options, { currentAttempt }], priority) .then(resolve) .catch(err => { if (!this.shouldRetry(err) || !operation.retry(err)) { diff --git a/src/api/index.js b/src/api/index.js index 1b39214..5808195 100644 --- a/src/api/index.js +++ b/src/api/index.js @@ -1,7 +1,3 @@ import MusicBrainz, { MusicBrainzError } from './musicbrainz' -export { - MusicBrainz as default, - MusicBrainz, - MusicBrainzError -} +export { MusicBrainz as default, MusicBrainz, MusicBrainzError } diff --git a/src/api/musicbrainz.js b/src/api/musicbrainz.js index 6d42e54..9daaaf4 100644 --- a/src/api/musicbrainz.js +++ b/src/api/musicbrainz.js @@ -4,30 +4,33 @@ import Client, { ClientError } from './client' export class MusicBrainzError extends ClientError {} export default class MusicBrainz extends Client { - constructor ({ - baseURL = process.env.MUSICBRAINZ_BASE_URL || 'http://musicbrainz.org/ws/2/', - errorClass = MusicBrainzError, - // MusicBrainz API requests are limited to an *average* of 1 req/sec. - // That means if, for example, we only need to make a few API requests to - // fulfill a query, we might as well make them all at once - as long as - // we then wait a few seconds before making more. In practice this can - // seemingly be set to about 5 requests every 5 seconds before we're - // considered to exceed the rate limit. - limit = 5, - period = 5500, - ...options - } = {}) { + constructor( + { + baseURL = process.env.MUSICBRAINZ_BASE_URL || + 'http://musicbrainz.org/ws/2/', + errorClass = MusicBrainzError, + // MusicBrainz API requests are limited to an *average* of 1 req/sec. + // That means if, for example, we only need to make a few API requests to + // fulfill a query, we might as well make them all at once - as long as + // we then wait a few seconds before making more. In practice this can + // seemingly be set to about 5 requests every 5 seconds before we're + // considered to exceed the rate limit. + limit = 5, + period = 5500, + ...options + } = {} + ) { super({ baseURL, errorClass, limit, period, ...options }) } - parseErrorMessage (response, body) { + parseErrorMessage(response, body) { if (body && body.error) { return body.error } return super.parseErrorMessage(response, body) } - stringifyParams (params) { + stringifyParams(params) { if (Array.isArray(params.inc)) { params = { ...params, @@ -48,41 +51,41 @@ export default class MusicBrainz extends Client { } return qs.stringify(params, { skipNulls: true, - filter: (key, value) => value === '' ? undefined : value + filter: (key, value) => (value === '' ? undefined : value) }) } - getURL (path, params) { + getURL(path, params) { const query = params ? this.stringifyParams(params) : '' return query ? `${path}?${query}` : path } - getLookupURL (entity, id, params) { + getLookupURL(entity, id, params) { if (id == null) { return this.getBrowseURL(entity, params) } return this.getURL(`${entity}/${id}`, params) } - lookup (entity, id, params = {}) { + lookup(entity, id, params = {}) { const url = this.getLookupURL(entity, id, params) return this.get(url, { json: true, qs: { fmt: 'json' } }) } - getBrowseURL (entity, params) { + getBrowseURL(entity, params) { return this.getURL(entity, params) } - browse (entity, params = {}) { + browse(entity, params = {}) { const url = this.getBrowseURL(entity, params) return this.get(url, { json: true, qs: { fmt: 'json' } }) } - getSearchURL (entity, query, params) { + getSearchURL(entity, query, params) { return this.getURL(entity, { ...params, query }) } - search (entity, query, params = {}) { + search(entity, query, params = {}) { const url = this.getSearchURL(entity, query, params) return this.get(url, { json: true, qs: { fmt: 'json' } }) } diff --git a/src/context.js b/src/context.js index f6c3504..506fda6 100644 --- a/src/context.js +++ b/src/context.js @@ -2,22 +2,26 @@ import createLoaders from './loaders' const debug = require('debug')('graphbrainz:context') -export function extendContext (extension, context, options) { +export function extendContext(extension, context, options) { if (extension.extendContext) { if (typeof extension.extendContext === 'function') { - debug(`Extending context via a function from the “${extension.name}” extension.`) + debug( + `Extending context via a function from the “${ + extension.name + }” extension.` + ) context = extension.extendContext(context, options) } else { throw new Error( `Extension “${extension.name}” contains an invalid \`extendContext\` ` + - `value: ${extension.extendContext}` + `value: ${extension.extendContext}` ) } } return context } -export function createContext (options = {}) { +export function createContext(options = {}) { const { client } = options const loaders = createLoaders(client) const context = { client, loaders } diff --git a/src/extensions/cover-art-archive/client.js b/src/extensions/cover-art-archive/client.js index 539ebf1..edd419f 100644 --- a/src/extensions/cover-art-archive/client.js +++ b/src/extensions/cover-art-archive/client.js @@ -1,19 +1,22 @@ import Client from '../../api/client' export default class CoverArtArchiveClient extends Client { - constructor ({ - baseURL = process.env.COVER_ART_ARCHIVE_BASE_URL || 'http://coverartarchive.org/', - limit = 10, - period = 1000, - ...options - } = {}) { + constructor( + { + baseURL = process.env.COVER_ART_ARCHIVE_BASE_URL || + 'http://coverartarchive.org/', + limit = 10, + period = 1000, + ...options + } = {} + ) { super({ baseURL, limit, period, ...options }) } /** * Sinfully attempt to parse HTML responses for the error message. */ - parseErrorMessage (response, body) { + parseErrorMessage(response, body) { if (typeof body === 'string' && body.startsWith('([^<]+)<\/h1>/i.exec(body) const message = /

([^<]+)<\/p>/i.exec(body) @@ -22,16 +25,17 @@ export default class CoverArtArchiveClient extends Client { return super.parseErrorMessage(response, body) } - images (entityType, mbid) { + images(entityType, mbid) { return this.get(`${entityType}/${mbid}`, { json: true }) } - imageURL (entityType, mbid, typeOrID = 'front', size) { + imageURL(entityType, mbid, typeOrID = 'front', size) { let url = `${entityType}/${mbid}/${typeOrID}` if (size != null) { url += `-${size}` } - return this.get(url, { method: 'HEAD', followRedirect: false }) - .then(headers => headers.location) + return this.get(url, { method: 'HEAD', followRedirect: false }).then( + headers => headers.location + ) } } diff --git a/src/extensions/cover-art-archive/index.js b/src/extensions/cover-art-archive/index.js index 4523c36..6019555 100644 --- a/src/extensions/cover-art-archive/index.js +++ b/src/extensions/cover-art-archive/index.js @@ -8,14 +8,18 @@ export default { name: 'Cover Art Archive', description: `Retrieve cover art images for releases from the [Cover Art Archive](https://coverartarchive.org/).`, - extendContext (context, { coverArtClient, coverArtArchive = {} } = {}) { + extendContext(context, { coverArtClient, coverArtArchive = {} } = {}) { const client = coverArtClient || new CoverArtArchiveClient(coverArtArchive) const cacheSize = parseInt( - process.env.COVER_ART_ARCHIVE_CACHE_SIZE || process.env.GRAPHBRAINZ_CACHE_SIZE || 8192, + process.env.COVER_ART_ARCHIVE_CACHE_SIZE || + process.env.GRAPHBRAINZ_CACHE_SIZE || + 8192, 10 ) const cacheTTL = parseInt( - process.env.COVER_ART_ARCHIVE_CACHE_TTL || process.env.GRAPHBRAINZ_CACHE_TTL || ONE_DAY, + process.env.COVER_ART_ARCHIVE_CACHE_TTL || + process.env.GRAPHBRAINZ_CACHE_TTL || + ONE_DAY, 10 ) return { diff --git a/src/extensions/cover-art-archive/loaders.js b/src/extensions/cover-art-archive/loaders.js index b6dde6d..ec26ba3 100644 --- a/src/extensions/cover-art-archive/loaders.js +++ b/src/extensions/cover-art-archive/loaders.js @@ -3,12 +3,12 @@ import LRUCache from 'lru-cache' const debug = require('debug')('graphbrainz:extensions/cover-art-archive') -export default function createLoaders (options) { +export default function createLoaders(options) { const { client } = options const cache = LRUCache({ max: options.cacheSize, maxAge: options.cacheTTL, - dispose (key) { + dispose(key) { debug(`Removed from cache. key=${key}`) } }) @@ -17,37 +17,50 @@ export default function createLoaders (options) { cache.clear = cache.reset return { - coverArtArchive: new DataLoader(keys => { - return Promise.all(keys.map(key => { - const [ entityType, id ] = key - return client.images(entityType, id) - .catch(err => { - if (err.statusCode === 404) { - return { images: [] } - } - throw err - }).then(coverArt => ({ - ...coverArt, - _entityType: entityType, - _id: id, - _releaseID: coverArt.release && coverArt.release.split('/').pop() - })) - })) - }, { - cacheKeyFn: ([ entityType, id ]) => `${entityType}/${id}`, - cacheMap: cache - }), - coverArtArchiveURL: new DataLoader(keys => { - return Promise.all(keys.map(key => { - const [ entityType, id, type, size ] = key - return client.imageURL(entityType, id, type, size) - })) - }, { - cacheKeyFn: ([ entityType, id, type, size ]) => { - const key = `${entityType}/${id}/${type}` - return size ? `${key}-${size}` : key + coverArtArchive: new DataLoader( + keys => { + return Promise.all( + keys.map(key => { + const [entityType, id] = key + return client + .images(entityType, id) + .catch(err => { + if (err.statusCode === 404) { + return { images: [] } + } + throw err + }) + .then(coverArt => ({ + ...coverArt, + _entityType: entityType, + _id: id, + _releaseID: + coverArt.release && coverArt.release.split('/').pop() + })) + }) + ) }, - cacheMap: cache - }) + { + cacheKeyFn: ([entityType, id]) => `${entityType}/${id}`, + cacheMap: cache + } + ), + coverArtArchiveURL: new DataLoader( + keys => { + return Promise.all( + keys.map(key => { + const [entityType, id, type, size] = key + return client.imageURL(entityType, id, type, size) + }) + ) + }, + { + cacheKeyFn: ([entityType, id, type, size]) => { + const key = `${entityType}/${id}/${type}` + return size ? `${key}-${size}` : key + }, + cacheMap: cache + } + ) } } diff --git a/src/extensions/cover-art-archive/resolvers.js b/src/extensions/cover-art-archive/resolvers.js index faa89c5..f0f8136 100644 --- a/src/extensions/cover-art-archive/resolvers.js +++ b/src/extensions/cover-art-archive/resolvers.js @@ -9,7 +9,7 @@ const SIZES = new Map([ ['LARGE', 500] ]) -function resolveImage (coverArt, args, { loaders }, info) { +function resolveImage(coverArt, args, { loaders }, info) { // Since migrating the schema to an extension, we lost custom enum values // for the time being. Translate any incoming `size` arg to the old enum // values. diff --git a/src/extensions/fanart-tv/client.js b/src/extensions/fanart-tv/client.js index e27e1c9..b4b8a6b 100644 --- a/src/extensions/fanart-tv/client.js +++ b/src/extensions/fanart-tv/client.js @@ -1,23 +1,26 @@ import Client from '../../api/client' export default class FanArtClient extends Client { - constructor ({ - apiKey = process.env.FANART_API_KEY, - baseURL = process.env.FANART_BASE_URL || 'http://webservice.fanart.tv/v3/', - limit = 10, - period = 1000, - ...options - } = {}) { + constructor( + { + apiKey = process.env.FANART_API_KEY, + baseURL = process.env.FANART_BASE_URL || + 'http://webservice.fanart.tv/v3/', + limit = 10, + period = 1000, + ...options + } = {} + ) { super({ baseURL, limit, period, ...options }) this.apiKey = apiKey } - get (path, options = {}) { + get(path, options = {}) { const ClientError = this.errorClass if (!this.apiKey) { - return Promise.reject(new ClientError( - 'No API key was configured for the fanart.tv client.' - )) + return Promise.reject( + new ClientError('No API key was configured for the fanart.tv client.') + ) } options = { json: true, @@ -30,7 +33,7 @@ export default class FanArtClient extends Client { return super.get(path, options) } - musicEntity (entityType, mbid) { + musicEntity(entityType, mbid) { const ClientError = this.errorClass switch (entityType) { case 'artist': @@ -40,21 +43,21 @@ export default class FanArtClient extends Client { case 'release-group': return this.musicAlbum(mbid) default: - return Promise.reject(new ClientError( - `Entity type unsupported: ${entityType}` - )) + return Promise.reject( + new ClientError(`Entity type unsupported: ${entityType}`) + ) } } - musicArtist (mbid) { + musicArtist(mbid) { return this.get(`music/${mbid}`) } - musicAlbum (mbid) { + musicAlbum(mbid) { return this.get(`music/albums/${mbid}`) } - musicLabel (mbid) { + musicLabel(mbid) { return this.get(`music/${mbid}`) } } diff --git a/src/extensions/fanart-tv/index.js b/src/extensions/fanart-tv/index.js index bfeecb4..557aa1b 100644 --- a/src/extensions/fanart-tv/index.js +++ b/src/extensions/fanart-tv/index.js @@ -8,14 +8,18 @@ export default { name: 'fanart.tv', description: `Retrieve high quality artwork for artists, releases, and labels from [fanart.tv](https://fanart.tv/).`, - extendContext (context, { fanArt = {} } = {}) { + extendContext(context, { fanArt = {} } = {}) { const client = new FanArtClient(fanArt) const cacheSize = parseInt( - process.env.FANART_CACHE_SIZE || process.env.GRAPHBRAINZ_CACHE_SIZE || 8192, + process.env.FANART_CACHE_SIZE || + process.env.GRAPHBRAINZ_CACHE_SIZE || + 8192, 10 ) const cacheTTL = parseInt( - process.env.FANART_CACHE_TTL || process.env.GRAPHBRAINZ_CACHE_TTL || ONE_DAY, + process.env.FANART_CACHE_TTL || + process.env.GRAPHBRAINZ_CACHE_TTL || + ONE_DAY, 10 ) return { diff --git a/src/extensions/fanart-tv/loader.js b/src/extensions/fanart-tv/loader.js index ce04486..ad967dc 100644 --- a/src/extensions/fanart-tv/loader.js +++ b/src/extensions/fanart-tv/loader.js @@ -3,12 +3,12 @@ import LRUCache from 'lru-cache' const debug = require('debug')('graphbrainz:extensions/fanart-tv') -export default function createLoader (options) { +export default function createLoader(options) { const { client } = options const cache = LRUCache({ max: options.cacheSize, maxAge: options.cacheTTL, - dispose (key) { + dispose(key) { debug(`Removed from cache. key=${key}`) } }) @@ -16,37 +16,48 @@ export default function createLoader (options) { cache.delete = cache.del cache.clear = cache.reset - const loader = new DataLoader(keys => { - return Promise.all(keys.map(key => { - const [ entityType, id ] = key - return client.musicEntity(entityType, id) - .catch(err => { - if (err.statusCode === 404) { - // 404s are OK, just return empty data. - return { - artistbackground: [], - artistthumb: [], - musiclogo: [], - hdmusiclogo: [], - musicbanner: [], - musiclabel: [], - albums: {} - } - } - throw err - }).then(body => { - if (entityType === 'artist') { - const releaseGroupIDs = Object.keys(body.albums) - debug(`Priming album cache with ${releaseGroupIDs.length} album(s).`) - releaseGroupIDs.forEach(key => loader.prime(['release-group', key], body)) - } - return body + const loader = new DataLoader( + keys => { + return Promise.all( + keys.map(key => { + const [entityType, id] = key + return client + .musicEntity(entityType, id) + .catch(err => { + if (err.statusCode === 404) { + // 404s are OK, just return empty data. + return { + artistbackground: [], + artistthumb: [], + musiclogo: [], + hdmusiclogo: [], + musicbanner: [], + musiclabel: [], + albums: {} + } + } + throw err + }) + .then(body => { + if (entityType === 'artist') { + const releaseGroupIDs = Object.keys(body.albums) + debug( + `Priming album cache with ${releaseGroupIDs.length} album(s).` + ) + releaseGroupIDs.forEach(key => + loader.prime(['release-group', key], body) + ) + } + return body + }) }) - })) - }, { - cacheKeyFn: ([ entityType, id ]) => `${entityType}/${id}`, - cacheMap: cache - }) + ) + }, + { + cacheKeyFn: ([entityType, id]) => `${entityType}/${id}`, + cacheMap: cache + } + ) return loader } diff --git a/src/extensions/fanart-tv/resolvers.js b/src/extensions/fanart-tv/resolvers.js index 37d606c..be653cd 100644 --- a/src/extensions/fanart-tv/resolvers.js +++ b/src/extensions/fanart-tv/resolvers.js @@ -56,7 +56,8 @@ export default { }, ReleaseGroup: { fanArt: (releaseGroup, args, context) => { - return context.loaders.fanArt.load(['release-group', releaseGroup.id]) + return context.loaders.fanArt + .load(['release-group', releaseGroup.id]) .then(artist => artist.albums[releaseGroup.id]) } } diff --git a/src/extensions/mediawiki/client.js b/src/extensions/mediawiki/client.js index 9249e1a..5265bc4 100644 --- a/src/extensions/mediawiki/client.js +++ b/src/extensions/mediawiki/client.js @@ -2,22 +2,20 @@ import URL from 'url' import Client from '../../api/client' export default class MediaWikiClient extends Client { - constructor ({ - limit = 10, - period = 1000, - ...options - } = {}) { + constructor({ limit = 10, period = 1000, ...options } = {}) { super({ limit, period, ...options }) } - imageInfo (page) { + imageInfo(page) { const pageURL = URL.parse(page, true) const ClientError = this.errorClass if (!pageURL.pathname.startsWith('/wiki/')) { - return Promise.reject(new ClientError( - `MediaWiki page URL does not have the expected /wiki/ prefix: ${page}` - )) + return Promise.reject( + new ClientError( + `MediaWiki page URL does not have the expected /wiki/ prefix: ${page}` + ) + ) } const apiURL = URL.format({ @@ -34,21 +32,20 @@ export default class MediaWikiClient extends Client { } }) - return this.get(apiURL, { json: true }) - .then(body => { - const pageIDs = Object.keys(body.query.pages) - if (pageIDs.length !== 1) { - throw new ClientError( - `Query returned multiple pages: [${pageIDs.join(', ')}]` - ) - } - const imageInfo = body.query.pages[pageIDs[0]].imageinfo - if (imageInfo.length !== 1) { - throw new ClientError( - `Query returned info for ${imageInfo.length} images, expected 1.` - ) - } - return imageInfo[0] - }) + return this.get(apiURL, { json: true }).then(body => { + const pageIDs = Object.keys(body.query.pages) + if (pageIDs.length !== 1) { + throw new ClientError( + `Query returned multiple pages: [${pageIDs.join(', ')}]` + ) + } + const imageInfo = body.query.pages[pageIDs[0]].imageinfo + if (imageInfo.length !== 1) { + throw new ClientError( + `Query returned info for ${imageInfo.length} images, expected 1.` + ) + } + return imageInfo[0] + }) } } diff --git a/src/extensions/mediawiki/index.js b/src/extensions/mediawiki/index.js index bc58d40..c1bdaaa 100644 --- a/src/extensions/mediawiki/index.js +++ b/src/extensions/mediawiki/index.js @@ -8,14 +8,18 @@ export default { name: 'MediaWiki', description: `Retrieve information from MediaWiki image pages, like the actual image file URL and EXIF metadata.`, - extendContext (context, { mediaWiki = {} } = {}) { + extendContext(context, { mediaWiki = {} } = {}) { const client = new MediaWikiClient(mediaWiki) const cacheSize = parseInt( - process.env.MEDIAWIKI_CACHE_SIZE || process.env.GRAPHBRAINZ_CACHE_SIZE || 8192, + process.env.MEDIAWIKI_CACHE_SIZE || + process.env.GRAPHBRAINZ_CACHE_SIZE || + 8192, 10 ) const cacheTTL = parseInt( - process.env.MEDIAWIKI_CACHE_TTL || process.env.GRAPHBRAINZ_CACHE_TTL || ONE_DAY, + process.env.MEDIAWIKI_CACHE_TTL || + process.env.GRAPHBRAINZ_CACHE_TTL || + ONE_DAY, 10 ) return { diff --git a/src/extensions/mediawiki/loader.js b/src/extensions/mediawiki/loader.js index ca58d98..309d1a4 100644 --- a/src/extensions/mediawiki/loader.js +++ b/src/extensions/mediawiki/loader.js @@ -3,12 +3,12 @@ import LRUCache from 'lru-cache' const debug = require('debug')('graphbrainz:extensions/mediawiki') -export default function createLoader (options) { +export default function createLoader(options) { const { client } = options const cache = LRUCache({ max: options.cacheSize, maxAge: options.cacheTTL, - dispose (key) { + dispose(key) { debug(`Removed from cache. key=${key}`) } }) @@ -16,7 +16,10 @@ export default function createLoader (options) { cache.delete = cache.del cache.clear = cache.reset - return new DataLoader(keys => { - return Promise.all(keys.map(key => client.imageInfo(key))) - }, { cacheMap: cache }) + return new DataLoader( + keys => { + return Promise.all(keys.map(key => client.imageInfo(key))) + }, + { cacheMap: cache } + ) } diff --git a/src/extensions/mediawiki/resolvers.js b/src/extensions/mediawiki/resolvers.js index 84c1c6f..7764db4 100644 --- a/src/extensions/mediawiki/resolvers.js +++ b/src/extensions/mediawiki/resolvers.js @@ -1,22 +1,25 @@ import URL from 'url' -function resolveMediaWikiImages (source, args, { loaders }) { - const isURL = (relation) => relation['target-type'] === 'url' +function resolveMediaWikiImages(source, args, { loaders }) { + const isURL = relation => relation['target-type'] === 'url' let rels = source.relations ? source.relations.filter(isURL) : [] if (!rels.length) { - rels = loaders.lookup.load([source._type, source.id, { inc: 'url-rels' }]) + rels = loaders.lookup + .load([source._type, source.id, { inc: 'url-rels' }]) .then(source => source.relations.filter(isURL)) } return Promise.resolve(rels).then(rels => { - const pages = rels.filter(rel => { - if (rel.type === args.type) { - const url = URL.parse(rel.url.resource) - if (url.pathname.match(/^\/wiki\/(File|Image):/)) { - return true + const pages = rels + .filter(rel => { + if (rel.type === args.type) { + const url = URL.parse(rel.url.resource) + if (url.pathname.match(/^\/wiki\/(File|Image):/)) { + return true + } } - } - return false - }).map(rel => rel.url.resource) + return false + }) + .map(rel => rel.url.resource) return loaders.mediaWiki.loadMany(pages) }) } @@ -57,13 +60,14 @@ export default { const data = imageInfo.extmetadata.LicenseUrl return data ? data.value : null }, - metadata: imageInfo => Object.keys(imageInfo.extmetadata).map(key => { - const data = imageInfo.extmetadata[key] - return { ...data, name: key } - }) + metadata: imageInfo => + Object.keys(imageInfo.extmetadata).map(key => { + const data = imageInfo.extmetadata[key] + return { ...data, name: key } + }) }, MediaWikiImageMetadata: { - value: obj => obj.value == null ? obj.value : `${obj.value}` + value: obj => (obj.value == null ? obj.value : `${obj.value}`) }, Artist: { mediaWikiImages: resolveMediaWikiImages diff --git a/src/extensions/the-audio-db/client.js b/src/extensions/the-audio-db/client.js index 977038d..5b28bcf 100644 --- a/src/extensions/the-audio-db/client.js +++ b/src/extensions/the-audio-db/client.js @@ -1,28 +1,31 @@ import Client from '../../api/client' export default class TheAudioDBClient extends Client { - constructor ({ - apiKey = process.env.THEAUDIODB_API_KEY, - baseURL = process.env.THEAUDIODB_BASE_URL || 'http://www.theaudiodb.com/api/v1/json/', - limit = 10, - period = 1000, - ...options - } = {}) { + constructor( + { + apiKey = process.env.THEAUDIODB_API_KEY, + baseURL = process.env.THEAUDIODB_BASE_URL || + 'http://www.theaudiodb.com/api/v1/json/', + limit = 10, + period = 1000, + ...options + } = {} + ) { super({ baseURL, limit, period, ...options }) this.apiKey = apiKey } - get (path, options = {}) { + get(path, options = {}) { const ClientError = this.errorClass if (!this.apiKey) { - return Promise.reject(new ClientError( - 'No API key was configured for TheAudioDB client.' - )) + return Promise.reject( + new ClientError('No API key was configured for TheAudioDB client.') + ) } return super.get(`${this.apiKey}/${path}`, { json: true, ...options }) } - entity (entityType, mbid) { + entity(entityType, mbid) { const ClientError = this.errorClass switch (entityType) { case 'artist': @@ -32,39 +35,36 @@ export default class TheAudioDBClient extends Client { case 'recording': return this.track(mbid) default: - return Promise.reject(new ClientError( - `Entity type unsupported: ${entityType}` - )) + return Promise.reject( + new ClientError(`Entity type unsupported: ${entityType}`) + ) } } - artist (mbid) { - return this.get('artist-mb.php', { qs: { i: mbid } }) - .then(body => { - if (body.artists && body.artists.length === 1) { - return body.artists[0] - } - return null - }) + artist(mbid) { + return this.get('artist-mb.php', { qs: { i: mbid } }).then(body => { + if (body.artists && body.artists.length === 1) { + return body.artists[0] + } + return null + }) } - album (mbid) { - return this.get('album-mb.php', { qs: { i: mbid } }) - .then(body => { - if (body.album && body.album.length === 1) { - return body.album[0] - } - return null - }) + album(mbid) { + return this.get('album-mb.php', { qs: { i: mbid } }).then(body => { + if (body.album && body.album.length === 1) { + return body.album[0] + } + return null + }) } - track (mbid) { - return this.get('track-mb.php', { qs: { i: mbid } }) - .then(body => { - if (body.track && body.track.length === 1) { - return body.track[0] - } - return null - }) + track(mbid) { + return this.get('track-mb.php', { qs: { i: mbid } }).then(body => { + if (body.track && body.track.length === 1) { + return body.track[0] + } + return null + }) } } diff --git a/src/extensions/the-audio-db/index.js b/src/extensions/the-audio-db/index.js index a6fb611..2014870 100644 --- a/src/extensions/the-audio-db/index.js +++ b/src/extensions/the-audio-db/index.js @@ -8,14 +8,18 @@ export default { name: 'TheAudioDB', description: `Retrieve images and information about artists, releases, and recordings from [TheAudioDB.com](http://www.theaudiodb.com/).`, - extendContext (context, { theAudioDB = {} } = {}) { + extendContext(context, { theAudioDB = {} } = {}) { const client = new TheAudioDBClient(theAudioDB) const cacheSize = parseInt( - process.env.THEAUDIODB_CACHE_SIZE || process.env.GRAPHBRAINZ_CACHE_SIZE || 8192, + process.env.THEAUDIODB_CACHE_SIZE || + process.env.GRAPHBRAINZ_CACHE_SIZE || + 8192, 10 ) const cacheTTL = parseInt( - process.env.THEAUDIODB_CACHE_TTL || process.env.GRAPHBRAINZ_CACHE_TTL || ONE_DAY, + process.env.THEAUDIODB_CACHE_TTL || + process.env.GRAPHBRAINZ_CACHE_TTL || + ONE_DAY, 10 ) return { diff --git a/src/extensions/the-audio-db/loader.js b/src/extensions/the-audio-db/loader.js index 51e4868..e408971 100644 --- a/src/extensions/the-audio-db/loader.js +++ b/src/extensions/the-audio-db/loader.js @@ -3,12 +3,12 @@ import LRUCache from 'lru-cache' const debug = require('debug')('graphbrainz:extensions/the-audio-db') -export default function createLoader (options) { +export default function createLoader(options) { const { client } = options const cache = LRUCache({ max: options.cacheSize, maxAge: options.cacheTTL, - dispose (key) { + dispose(key) { debug(`Removed from cache. key=${key}`) } }) @@ -16,13 +16,18 @@ export default function createLoader (options) { cache.delete = cache.del cache.clear = cache.reset - return new DataLoader(keys => { - return Promise.all(keys.map(key => { - const [ entityType, id ] = key - return client.entity(entityType, id) - })) - }, { - cacheKeyFn: ([ entityType, id ]) => `${entityType}/${id}`, - cacheMap: cache - }) + return new DataLoader( + keys => { + return Promise.all( + keys.map(key => { + const [entityType, id] = key + return client.entity(entityType, id) + }) + ) + }, + { + cacheKeyFn: ([entityType, id]) => `${entityType}/${id}`, + cacheMap: cache + } + ) } diff --git a/src/extensions/the-audio-db/resolvers.js b/src/extensions/the-audio-db/resolvers.js index 95064cd..3e1ad84 100644 --- a/src/extensions/the-audio-db/resolvers.js +++ b/src/extensions/the-audio-db/resolvers.js @@ -1,6 +1,6 @@ -function handleImageSize (resolver) { +function handleImageSize(resolver) { return (source, args, context, info) => { - const getURL = (url) => args.size === 'PREVIEW' ? `${url}/preview` : url + const getURL = url => (args.size === 'PREVIEW' ? `${url}/preview` : url) const url = resolver(source, args, context, info) if (!url) { return null diff --git a/src/index.js b/src/index.js index bf0ce6b..f879176 100644 --- a/src/index.js +++ b/src/index.js @@ -8,24 +8,26 @@ import { createContext } from './context' const debug = require('debug')('graphbrainz') -const formatError = (err) => ({ +const formatError = err => ({ message: err.message, locations: err.locations, stack: err.stack }) -const middleware = ({ - client = new MusicBrainz(), - extensions = process.env.GRAPHBRAINZ_EXTENSIONS - ? JSON.parse(process.env.GRAPHBRAINZ_EXTENSIONS) - : [ - './extensions/cover-art-archive', - './extensions/fanart-tv', - './extensions/mediawiki', - './extensions/the-audio-db' - ], - ...middlewareOptions -} = {}) => { +const middleware = ( + { + client = new MusicBrainz(), + extensions = process.env.GRAPHBRAINZ_EXTENSIONS + ? JSON.parse(process.env.GRAPHBRAINZ_EXTENSIONS) + : [ + './extensions/cover-art-archive', + './extensions/fanart-tv', + './extensions/mediawiki', + './extensions/the-audio-db' + ], + ...middlewareOptions + } = {} +) => { debug(`Loading ${extensions.length} extension(s).`) const options = { client, @@ -52,7 +54,7 @@ const middleware = ({ export default middleware -export function start (options) { +export function start(options) { require('dotenv').config({ silent: true }) const app = express() const port = process.env.PORT || 3000 diff --git a/src/loaders.js b/src/loaders.js index 98b4dfe..dbed51d 100644 --- a/src/loaders.js +++ b/src/loaders.js @@ -5,13 +5,13 @@ import { ONE_DAY } from './util' const debug = require('debug')('graphbrainz:loaders') -export default function createLoaders (client) { +export default function createLoaders(client) { // All loaders share a single LRU cache that will remember 8192 responses, // each cached for 1 day. const cache = LRUCache({ max: parseInt(process.env.GRAPHBRAINZ_CACHE_SIZE || 8192, 10), maxAge: parseInt(process.env.GRAPHBRAINZ_CACHE_TTL || ONE_DAY, 10), - dispose (key) { + dispose(key) { debug(`Removed from cache. key=${key}`) } }) @@ -19,56 +19,71 @@ export default function createLoaders (client) { cache.delete = cache.del cache.clear = cache.reset - const lookup = new DataLoader(keys => { - return Promise.all(keys.map(key => { - const [ entityType, id, params = {} ] = key - return client.lookup(entityType, id, params).then(entity => { - if (entity) { - // Store the entity type so we can determine what type of object this - // is elsewhere in the code. - entity._type = entityType - } - return entity - }) - })) - }, { - cacheKeyFn: (key) => client.getLookupURL(...key), - cacheMap: cache - }) - - const browse = new DataLoader(keys => { - return Promise.all(keys.map(key => { - const [ entityType, params = {} ] = key - return client.browse(entityType, params).then(list => { - list[toPlural(entityType)].forEach(entity => { - // Store the entity type so we can determine what type of object this - // is elsewhere in the code. - entity._type = entityType + const lookup = new DataLoader( + keys => { + return Promise.all( + keys.map(key => { + const [entityType, id, params = {}] = key + return client.lookup(entityType, id, params).then(entity => { + if (entity) { + // Store the entity type so we can determine what type of object this + // is elsewhere in the code. + entity._type = entityType + } + return entity + }) }) - return list - }) - })) - }, { - cacheKeyFn: (key) => client.getBrowseURL(...key), - cacheMap: cache - }) + ) + }, + { + cacheKeyFn: key => client.getLookupURL(...key), + cacheMap: cache + } + ) - const search = new DataLoader(keys => { - return Promise.all(keys.map(key => { - const [ entityType, query, params = {} ] = key - return client.search(entityType, query, params).then(list => { - list[toPlural(entityType)].forEach(entity => { - // Store the entity type so we can determine what type of object this - // is elsewhere in the code. - entity._type = entityType + const browse = new DataLoader( + keys => { + return Promise.all( + keys.map(key => { + const [entityType, params = {}] = key + return client.browse(entityType, params).then(list => { + list[toPlural(entityType)].forEach(entity => { + // Store the entity type so we can determine what type of object this + // is elsewhere in the code. + entity._type = entityType + }) + return list + }) }) - return list - }) - })) - }, { - cacheKeyFn: key => client.getSearchURL(...key), - cacheMap: cache - }) + ) + }, + { + cacheKeyFn: key => client.getBrowseURL(...key), + cacheMap: cache + } + ) + + const search = new DataLoader( + keys => { + return Promise.all( + keys.map(key => { + const [entityType, query, params = {}] = key + return client.search(entityType, query, params).then(list => { + list[toPlural(entityType)].forEach(entity => { + // Store the entity type so we can determine what type of object this + // is elsewhere in the code. + entity._type = entityType + }) + return list + }) + }) + ) + }, + { + cacheKeyFn: key => client.getSearchURL(...key), + cacheMap: cache + } + ) return { lookup, browse, search } } diff --git a/src/queries/browse.js b/src/queries/browse.js index 26686a5..c3ec6ed 100644 --- a/src/queries/browse.js +++ b/src/queries/browse.js @@ -60,7 +60,7 @@ const work = { description: 'The MBID of a work to which the entity is linked.' } -function createBrowseField (connectionType, args) { +function createBrowseField(connectionType, args) { const typeName = toWords(connectionType.name.slice(0, -10)) return { type: connectionType, @@ -173,7 +173,8 @@ release, but is not included in the credits for the release itself.` export const browse = { type: BrowseQuery, - description: 'Browse all MusicBrainz entities directly linked to another entity.', + description: + 'Browse all MusicBrainz entities directly linked to another entity.', // We only have work to do once we know what entity types are being requested, // so this can just resolve to an empty object. resolve: () => ({}) diff --git a/src/queries/lookup.js b/src/queries/lookup.js index 50277bf..9f6c9ac 100644 --- a/src/queries/lookup.js +++ b/src/queries/lookup.js @@ -21,7 +21,7 @@ import { Work } from '../types' -function createLookupField (entity, args) { +function createLookupField(entity, args) { const typeName = toWords(entity.name) return { type: entity, diff --git a/src/queries/search.js b/src/queries/search.js index 4d9f7c7..b9cf6bb 100644 --- a/src/queries/search.js +++ b/src/queries/search.js @@ -16,7 +16,7 @@ import { } from '../types' import { toWords } from '../types/helpers' -function createSearchField (connectionType) { +function createSearchField(connectionType) { const typeName = toWords(connectionType.name.slice(0, -10)) return { type: connectionType, diff --git a/src/rate-limit.js b/src/rate-limit.js index 9f07e41..e1fc4f7 100644 --- a/src/rate-limit.js +++ b/src/rate-limit.js @@ -1,12 +1,14 @@ const debug = require('debug')('graphbrainz:rate-limit') export default class RateLimit { - constructor ({ - limit = 1, - period = 1000, - concurrency = limit || 1, - defaultPriority = 1 - } = {}) { + constructor( + { + limit = 1, + period = 1000, + concurrency = limit || 1, + defaultPriority = 1 + } = {} + ) { this.limit = limit this.period = period this.defaultPriority = defaultPriority @@ -20,16 +22,16 @@ export default class RateLimit { this.prevTaskID = null } - nextTaskID (prevTaskID = this.prevTaskID) { + nextTaskID(prevTaskID = this.prevTaskID) { const id = (prevTaskID || 0) + 1 this.prevTaskID = id return id } - enqueue (fn, args, priority = this.defaultPriority) { + enqueue(fn, args, priority = this.defaultPriority) { priority = Math.max(0, priority) return new Promise((resolve, reject) => { - const queue = this.queues[priority] = this.queues[priority] || [] + const queue = (this.queues[priority] = this.queues[priority] || []) const id = this.nextTaskID() debug(`Enqueuing task. id=${id} priority=${priority}`) queue.push({ fn, args, resolve, reject, id }) @@ -43,7 +45,7 @@ export default class RateLimit { }) } - dequeue () { + dequeue() { let task for (let i = this.queues.length - 1; i >= 0; i--) { const queue = this.queues[i] @@ -60,7 +62,7 @@ export default class RateLimit { return task } - flush () { + flush() { if (this.numPending < this.concurrency && this.periodCapacity > 0) { const task = this.dequeue() if (task) { @@ -83,12 +85,12 @@ export default class RateLimit { } this.numPending += 1 this.periodCapacity -= 1 - const onResolve = (value) => { + const onResolve = value => { this.numPending -= 1 resolve(value) this.flush() } - const onReject = (err) => { + const onReject = err => { this.numPending -= 1 reject(err) this.flush() diff --git a/src/resolvers.js b/src/resolvers.js index 9a5c55a..cecc7c8 100644 --- a/src/resolvers.js +++ b/src/resolvers.js @@ -6,7 +6,7 @@ import { } from 'graphql-relay' import { getFields, extendIncludes } from './util' -export function includeRelationships (params, info, fragments = info.fragments) { +export function includeRelationships(params, info, fragments = info.fragments) { let fields = getFields(info, fragments) if (info.fieldName !== 'relationships') { if (fields.relationships) { @@ -36,7 +36,7 @@ export function includeRelationships (params, info, fragments = info.fragments) return params } -export function includeSubqueries (params, info, fragments = info.fragments) { +export function includeSubqueries(params, info, fragments = info.fragments) { const subqueryIncludes = { aliases: ['aliases'], artistCredit: ['artist-credits'], @@ -67,7 +67,7 @@ export function includeSubqueries (params, info, fragments = info.fragments) { return params } -export function resolveLookup (root, { mbid, ...params }, { loaders }, info) { +export function resolveLookup(root, { mbid, ...params }, { loaders }, info) { if (!mbid && !params.resource) { throw new Error('Lookups by a field other than MBID must provide: resource') } @@ -77,16 +77,12 @@ export function resolveLookup (root, { mbid, ...params }, { loaders }, info) { return loaders.lookup.load([entityType, mbid, params]) } -export function resolveBrowse (root, { - first, - after, - type = [], - status = [], - discID, - isrc, - iswc, - ...args -}, { loaders }, info) { +export function resolveBrowse( + root, + { first, after, type = [], status = [], discID, isrc, iswc, ...args }, + { loaders }, + info +) { const pluralName = toDashed(info.fieldName) const singularName = toSingular(pluralName) let params = { @@ -127,7 +123,11 @@ export function resolveBrowse (root, { [`${singularName}-count`]: arrayLength = arraySlice.length } = list const meta = { sliceStart, arrayLength } - const connection = connectionFromArraySlice(arraySlice, { first, after }, meta) + const connection = connectionFromArraySlice( + arraySlice, + { first, after }, + meta + ) return { nodes: connection.edges.map(edge => edge.node), totalCount: arrayLength, @@ -136,12 +136,12 @@ export function resolveBrowse (root, { }) } -export function resolveSearch (root, { - after, - first, - query, - ...args -}, { loaders }, info) { +export function resolveSearch( + root, + { after, first, query, ...args }, + { loaders }, + info +) { const pluralName = toDashed(info.fieldName) const singularName = toSingular(pluralName) let params = { @@ -157,10 +157,17 @@ export function resolveSearch (root, { count: arrayLength } = list const meta = { sliceStart, arrayLength } - const connection = connectionFromArraySlice(arraySlice, { first, after }, meta) + const connection = connectionFromArraySlice( + arraySlice, + { first, after }, + meta + ) // Move the `score` field up to the edge object and make sure it's a // number (MusicBrainz returns a string). - const edges = connection.edges.map(edge => ({ ...edge, score: +edge.node.score })) + const edges = connection.edges.map(edge => ({ + ...edge, + score: +edge.node.score + })) const connectionWithExtras = { nodes: edges.map(edge => edge.node), totalCount: arrayLength, @@ -171,7 +178,7 @@ export function resolveSearch (root, { }) } -export function resolveRelationship (rels, args, context, info) { +export function resolveRelationship(rels, args, context, info) { const targetType = toDashed(toSingular(info.fieldName)).replace('-', '_') let matches = rels.filter(rel => rel['target-type'] === targetType) // There's no way to filter these at the API level, so do it here. @@ -192,7 +199,7 @@ export function resolveRelationship (rels, args, context, info) { } } -export function resolveLinked (entity, args, context, info) { +export function resolveLinked(entity, args, context, info) { const parentEntity = toDashed(info.parentType.name) args = { ...args, [parentEntity]: entity.id } return resolveBrowse(entity, args, context, info) @@ -203,7 +210,10 @@ export function resolveLinked (entity, args, context, info) { * for a particular field that's being requested, make another request to grab * it (after making sure it isn't already available). */ -export function createSubqueryResolver ({ inc, key } = {}, handler = value => value) { +export function createSubqueryResolver( + { inc, key } = {}, + handler = value => value +) { return (entity, args, { loaders }, info) => { key = key || toDashed(info.fieldName) let promise @@ -218,7 +228,7 @@ export function createSubqueryResolver ({ inc, key } = {}, handler = value => va } } -export function resolveDiscReleases (disc, args, context, info) { +export function resolveDiscReleases(disc, args, context, info) { const { releases } = disc if (releases != null) { const connection = connectionFromArray(releases, args) diff --git a/src/schema.js b/src/schema.js index d4edcc0..5925bc2 100644 --- a/src/schema.js +++ b/src/schema.js @@ -5,11 +5,13 @@ import { nodeField } from './types/node' const debug = require('debug')('graphbrainz:schema') -export function applyExtension (extension, schema, options = {}) { +export function applyExtension(extension, schema, options = {}) { let outputSchema = schema if (extension.extendSchema) { if (typeof extension.extendSchema === 'object') { - debug(`Extending schema via an object from the “${extension.name}” extension.`) + debug( + `Extending schema via an object from the “${extension.name}” extension.` + ) const { schemas = [], resolvers } = extension.extendSchema outputSchema = schemas.reduce((updatedSchema, extensionSchema) => { if (typeof extensionSchema === 'string') { @@ -21,12 +23,16 @@ export function applyExtension (extension, schema, options = {}) { addResolveFunctionsToSchema(outputSchema, resolvers) } } else if (typeof extension.extendSchema === 'function') { - debug(`Extending schema via a function from the “${extension.name}” extension.`) + debug( + `Extending schema via a function from the “${ + extension.name + }” extension.` + ) outputSchema = extension.extendSchema(schema, options) } else { throw new Error( `The “${extension.name}” extension contains an invalid ` + - `\`extendSchema\` value: ${extension.extendSchema}` + `\`extendSchema\` value: ${extension.extendSchema}` ) } } @@ -38,7 +44,7 @@ export function applyExtension (extension, schema, options = {}) { return outputSchema } -export function createSchema (schema, options = {}) { +export function createSchema(schema, options = {}) { const extensions = options.extensions || [] return extensions.reduce((updatedSchema, extension) => { return applyExtension(extension, updatedSchema, options) diff --git a/src/types/alias.js b/src/types/alias.js index 61ade82..2fd605c 100644 --- a/src/types/alias.js +++ b/src/types/alias.js @@ -1,7 +1,4 @@ -import { - GraphQLObjectType, - GraphQLBoolean -} from 'graphql/type' +import { GraphQLObjectType, GraphQLBoolean } from 'graphql/type' import { Locale } from './scalars' import { name, sortName, fieldWithID } from './helpers' diff --git a/src/types/artist-credit.js b/src/types/artist-credit.js index 0d6f59b..65ea446 100644 --- a/src/types/artist-credit.js +++ b/src/types/artist-credit.js @@ -13,7 +13,7 @@ track, etc., and join phrases between them.`, type: Artist, description: `The entity representing the artist referenced in the credits.`, - resolve: (source) => { + resolve: source => { const { artist } = source if (artist) { artist._type = 'artist' diff --git a/src/types/collection.js b/src/types/collection.js index c234ff0..9388761 100644 --- a/src/types/collection.js +++ b/src/types/collection.js @@ -1,8 +1,4 @@ -import { - GraphQLObjectType, - GraphQLNonNull, - GraphQLString -} from 'graphql/type' +import { GraphQLObjectType, GraphQLNonNull, GraphQLString } from 'graphql/type' import Node from './node' import Entity from './entity' import { diff --git a/src/types/entity.js b/src/types/entity.js index f1f29d7..e871bc6 100644 --- a/src/types/entity.js +++ b/src/types/entity.js @@ -4,7 +4,7 @@ import { mbid, connectionWithExtras } from './helpers' const Entity = new GraphQLInterfaceType({ name: 'Entity', description: 'An entity in the MusicBrainz schema.', - resolveType (value) { + resolveType(value) { if (value._type && require.resolve(`./${value._type}`)) { return require(`./${value._type}`).default } diff --git a/src/types/enums.js b/src/types/enums.js index 263b2f4..c87f438 100644 --- a/src/types/enums.js +++ b/src/types/enums.js @@ -18,7 +18,8 @@ distinctive name.`, }, ORCHESTRA: { name: 'Orchestra', - description: 'This indicates an orchestra (a large instrumental ensemble).', + description: + 'This indicates an orchestra (a large instrumental ensemble).', value: 'Orchestra' }, CHOIR: { diff --git a/src/types/event.js b/src/types/event.js index d4b603d..4342062 100644 --- a/src/types/event.js +++ b/src/types/event.js @@ -45,7 +45,8 @@ artists and works. See the [setlist documentation](https://musicbrainz.org/doc/E for syntax and examples.` }, ...fieldWithID('type', { - description: 'What kind of event the event is, e.g. concert, festival, etc.' + description: + 'What kind of event the event is, e.g. concert, festival, etc.' }), relationships, collections, diff --git a/src/types/helpers.js b/src/types/helpers.js index e666cdb..ee0f781 100644 --- a/src/types/helpers.js +++ b/src/types/helpers.js @@ -44,15 +44,15 @@ import { export const toPascal = pascalCase export const toDashed = dashify -export function toPlural (name) { +export function toPlural(name) { return name.endsWith('s') ? name : name + 's' } -export function toSingular (name) { +export function toSingular(name) { return name.endsWith('s') && !/series/i.test(name) ? name.slice(0, -1) : name } -export function toWords (name) { +export function toWords(name) { return toPascal(name).replace(/([^A-Z])?([A-Z]+)/g, (match, tail, head) => { tail = tail ? tail + ' ' : '' head = head.length > 1 ? head : head.toLowerCase() @@ -60,13 +60,13 @@ export function toWords (name) { }) } -export function resolveHyphenated (obj, args, context, info) { +export function resolveHyphenated(obj, args, context, info) { const name = toDashed(info.fieldName) return obj[name] } -export function resolveWithFallback (keys) { - return (obj) => { +export function resolveWithFallback(keys) { + return obj => { for (let i = 0; i < keys.length; i++) { const key = keys[i] if (key in obj) { @@ -76,7 +76,7 @@ export function resolveWithFallback (keys) { } } -export function fieldWithID (name, config = {}) { +export function fieldWithID(name, config = {}) { config = { type: GraphQLString, resolve: resolveHyphenated, @@ -95,7 +95,8 @@ field.`, if (fieldName in entity) { return entity[fieldName] } - return loaders.lookup.load([entity._type, entity.id]) + return loaders.lookup + .load([entity._type, entity.id]) .then(data => data[fieldName]) } } @@ -105,7 +106,7 @@ field.`, } } -export function createCollectionField (config) { +export function createCollectionField(config) { const typeName = toPlural(toWords(config.type.name.slice(0, -10))) return { ...config, @@ -145,7 +146,7 @@ meaning depends on the type of entity.`, resolve: resolveHyphenated } -function linkedQuery (connectionType, { args, ...config } = {}) { +function linkedQuery(connectionType, { args, ...config } = {}) { const typeName = toPlural(toWords(connectionType.name.slice(0, -10))) return { type: connectionType, @@ -293,7 +294,7 @@ export const score = { these results were found through a search.` } -export function connectionWithExtras (nodeType) { +export function connectionWithExtras(nodeType) { return connectionDefinitions({ nodeType, connectionFields: () => ({ diff --git a/src/types/index.js b/src/types/index.js index b054640..0651012 100644 --- a/src/types/index.js +++ b/src/types/index.js @@ -12,7 +12,10 @@ export { default as Label, LabelConnection } from './label' export { default as Place, PlaceConnection } from './place' export { default as Recording, RecordingConnection } from './recording' export { default as Release, ReleaseConnection } from './release' -export { default as ReleaseGroup, ReleaseGroupConnection } from './release-group' +export { + default as ReleaseGroup, + ReleaseGroupConnection +} from './release-group' export { default as Series, SeriesConnection } from './series' export { default as Tag, TagConnection } from './tag' export { default as URL, URLConnection } from './url' diff --git a/src/types/media.js b/src/types/media.js index 60162c6..22ea296 100644 --- a/src/types/media.js +++ b/src/types/media.js @@ -35,7 +35,8 @@ multi-disc release).` }, discs: { type: new GraphQLList(Disc), - description: 'A list of physical discs and their disc IDs for this medium.' + description: + 'A list of physical discs and their disc IDs for this medium.' } }) }) diff --git a/src/types/node.js b/src/types/node.js index 427d004..8adab4a 100644 --- a/src/types/node.js +++ b/src/types/node.js @@ -13,7 +13,7 @@ const { nodeInterface, nodeField } = nodeDefinitions( const entityType = toDashed(type) return loaders.lookup.load([entityType, id]) }, - (obj) => { + obj => { const type = TYPE_MODULES[obj._type] || obj._type try { return require(`./${type}`).default diff --git a/src/types/recording.js b/src/types/recording.js index cf950ca..db6e0c3 100644 --- a/src/types/recording.js +++ b/src/types/recording.js @@ -1,8 +1,4 @@ -import { - GraphQLObjectType, - GraphQLList, - GraphQLBoolean -} from 'graphql/type' +import { GraphQLObjectType, GraphQLList, GraphQLBoolean } from 'graphql/type' import Node from './node' import Entity from './entity' import { Duration, ISRC } from './scalars' diff --git a/src/types/relationship.js b/src/types/relationship.js index 750cc37..0a08f90 100644 --- a/src/types/relationship.js +++ b/src/types/relationship.js @@ -7,11 +7,7 @@ import { } from 'graphql/type' import { DateType } from './scalars' import Entity from './entity' -import { - resolveHyphenated, - fieldWithID, - connectionWithExtras -} from './helpers' +import { resolveHyphenated, fieldWithID, connectionWithExtras } from './helpers' const Relationship = new GraphQLObjectType({ name: 'Relationship', @@ -35,7 +31,8 @@ other and to URLs outside MusicBrainz.`, }, targetType: { type: new GraphQLNonNull(GraphQLString), - description: 'The type of entity on the receiving end of the relationship.', + description: + 'The type of entity on the receiving end of the relationship.', resolve: resolveHyphenated }, sourceCredit: { @@ -56,7 +53,8 @@ from its main (performance) name.`, }, end: { type: DateType, - description: 'The date on which the relationship became no longer applicable.' + description: + 'The date on which the relationship became no longer applicable.' }, ended: { type: GraphQLBoolean, diff --git a/src/types/release.js b/src/types/release.js index 68b00ab..80f8abc 100644 --- a/src/types/release.js +++ b/src/types/release.js @@ -1,8 +1,4 @@ -import { - GraphQLObjectType, - GraphQLString, - GraphQLList -} from 'graphql/type' +import { GraphQLObjectType, GraphQLString, GraphQLList } from 'graphql/type' import Node from './node' import Entity from './entity' import { ASIN, DateType } from './scalars' diff --git a/src/types/scalars.js b/src/types/scalars.js index fc9febe..32a56b8 100644 --- a/src/types/scalars.js +++ b/src/types/scalars.js @@ -1,11 +1,11 @@ import { Kind } from 'graphql/language' import { GraphQLScalarType } from 'graphql/type' -function createScalar (config) { +function createScalar(config) { return new GraphQLScalarType({ serialize: value => value, parseValue: value => value, - parseLiteral (ast) { + parseLiteral(ast) { if (ast.kind === Kind.STRING) { return ast.value } @@ -20,28 +20,28 @@ const locale = /^([a-z]{2})(_[A-Z]{2})?(\.[a-zA-Z0-9-]+)?$/ // Be extremely lenient; just prevent major input errors. const url = /^\w+:\/\/[\w-]+\.\w+/ -function validateMBID (value) { +function validateMBID(value) { if (typeof value === 'string' && uuid.test(value)) { return value } throw new TypeError(`Malformed MBID: ${value}`) } -function validatePositive (value) { +function validatePositive(value) { if (value >= 0) { return value } throw new TypeError(`Expected positive value: ${value}`) } -function validateLocale (value) { +function validateLocale(value) { if (typeof value === 'string' && locale.test(value)) { return value } throw new TypeError(`Malformed locale: ${value}`) } -function validateURL (value) { +function validateURL(value) { if (typeof value === 'string' && url.test(value)) { return value } @@ -57,7 +57,8 @@ and its partners for product identification within the Amazon organization.` export const DateType = createScalar({ name: 'Date', - description: 'Year, month (optional), and day (optional) in YYYY-MM-DD format.' + description: + 'Year, month (optional), and day (optional) in YYYY-MM-DD format.' }) export const Degrees = createScalar({ @@ -87,7 +88,7 @@ export const Duration = createScalar({ description: 'A length of time, in milliseconds.', serialize: validatePositive, parseValue: validatePositive, - parseLiteral (ast) { + parseLiteral(ast) { if (ast.kind === Kind.INT) { return validatePositive(parseInt(ast.value, 10)) } @@ -135,7 +136,7 @@ export const Locale = createScalar({ description: 'Language code, optionally with country and encoding.', serialize: validateLocale, parseValue: validateLocale, - parseLiteral (ast) { + parseLiteral(ast) { if (ast.kind === Kind.STRING) { return validateLocale(ast.value) } @@ -149,7 +150,7 @@ export const MBID = createScalar({ 36-character UUIDs.`, serialize: validateMBID, parseValue: validateMBID, - parseLiteral (ast) { + parseLiteral(ast) { if (ast.kind === Kind.STRING) { return validateMBID(ast.value) } @@ -167,7 +168,7 @@ export const URLString = createScalar({ description: 'A web address.', serialize: validateURL, parseValue: validateURL, - parseLiteral (ast) { + parseLiteral(ast) { if (ast.kind === Kind.STRING) { return validateURL(ast.value) } diff --git a/src/util.js b/src/util.js index 808b244..0ddd908 100644 --- a/src/util.js +++ b/src/util.js @@ -2,7 +2,7 @@ import util from 'util' export const ONE_DAY = 24 * 60 * 60 * 1000 -export function getFields (info, fragments = info.fragments) { +export function getFields(info, fragments = info.fragments) { if (info.kind !== 'Field') { info = info.fieldNodes[0] } @@ -25,17 +25,18 @@ export function getFields (info, fragments = info.fragments) { return selections.reduce(reducer, {}) } -export function prettyPrint (obj, { depth = 5, - colors = true, - breakLength = 120 } = {}) { +export function prettyPrint( + obj, + { depth = 5, colors = true, breakLength = 120 } = {} +) { console.log(util.inspect(obj, { depth, colors, breakLength })) } -export function toFilteredArray (obj) { +export function toFilteredArray(obj) { return (Array.isArray(obj) ? obj : [obj]).filter(x => x) } -export function extendIncludes (includes, moreIncludes) { +export function extendIncludes(includes, moreIncludes) { includes = toFilteredArray(includes) moreIncludes = toFilteredArray(moreIncludes) const seen = {} diff --git a/test/api/client.js b/test/api/client.js index ecde9bf..74fd5e8 100644 --- a/test/api/client.js +++ b/test/api/client.js @@ -3,7 +3,10 @@ import Client from '../../src/api/client' test('parseErrorMessage() returns the body or status code', t => { const client = new Client() - t.is(client.parseErrorMessage({ statusCode: 500 }, 'something went wrong'), 'something went wrong') + t.is( + client.parseErrorMessage({ statusCode: 500 }, 'something went wrong'), + 'something went wrong' + ) t.is(client.parseErrorMessage({ statusCode: 500 }, ''), '500') t.is(client.parseErrorMessage({ statusCode: 404 }, {}), '404') }) diff --git a/test/api/musicbrainz.js b/test/api/musicbrainz.js index d30b5b3..4b5d9fd 100644 --- a/test/api/musicbrainz.js +++ b/test/api/musicbrainz.js @@ -3,28 +3,39 @@ import MusicBrainz, { MusicBrainzError } from '../../src/api' import client from '../helpers/client/musicbrainz' test('getLookupURL() generates a lookup URL', t => { - t.is(client.getLookupURL('artist', 'c8da2e40-bd28-4d4e-813a-bd2f51958ba8', { - inc: ['recordings', 'release-groups'] - }), 'artist/c8da2e40-bd28-4d4e-813a-bd2f51958ba8?inc=recordings%2Brelease-groups') + t.is( + client.getLookupURL('artist', 'c8da2e40-bd28-4d4e-813a-bd2f51958ba8', { + inc: ['recordings', 'release-groups'] + }), + 'artist/c8da2e40-bd28-4d4e-813a-bd2f51958ba8?inc=recordings%2Brelease-groups' + ) }) test('getBrowseURL() generates a browse URL', t => { - t.is(client.getBrowseURL('recording', { - artist: 'c8da2e40-bd28-4d4e-813a-bd2f51958ba8', - limit: null, - offset: 0 - }), 'recording?artist=c8da2e40-bd28-4d4e-813a-bd2f51958ba8&offset=0') + t.is( + client.getBrowseURL('recording', { + artist: 'c8da2e40-bd28-4d4e-813a-bd2f51958ba8', + limit: null, + offset: 0 + }), + 'recording?artist=c8da2e40-bd28-4d4e-813a-bd2f51958ba8&offset=0' + ) }) test('getSearchURL() generates a search URL', t => { - t.is(client.getSearchURL('artist', 'Lures', { inc: null }), 'artist?query=Lures') + t.is( + client.getSearchURL('artist', 'Lures', { inc: null }), + 'artist?query=Lures' + ) }) test('lookup() sends a lookup query', t => { - return client.lookup('artist', 'c8da2e40-bd28-4d4e-813a-bd2f51958ba8').then(response => { - t.is(response.id, 'c8da2e40-bd28-4d4e-813a-bd2f51958ba8') - t.is(response.type, 'Group') - }) + return client + .lookup('artist', 'c8da2e40-bd28-4d4e-813a-bd2f51958ba8') + .then(response => { + t.is(response.id, 'c8da2e40-bd28-4d4e-813a-bd2f51958ba8') + t.is(response.type, 'Group') + }) }) test('rejects the promise when the API returns an error', t => { @@ -60,7 +71,10 @@ test('shouldRetry() retries only transient local connection issues', t => { test('rejects non-MusicBrainz errors', t => { const client = new MusicBrainz({ baseURL: '$!@#$' }) - return t.throws(client.get('artist/5b11f4ce-a62d-471e-81fc-a69a8278c7da'), Error) + return t.throws( + client.get('artist/5b11f4ce-a62d-471e-81fc-a69a8278c7da'), + Error + ) }) test('uses the default error impementation if there is no JSON error', t => { diff --git a/test/extensions/cover-art-archive/client.js b/test/extensions/cover-art-archive/client.js index d9fd005..b913203 100644 --- a/test/extensions/cover-art-archive/client.js +++ b/test/extensions/cover-art-archive/client.js @@ -2,23 +2,35 @@ import test from 'ava' import client from '../../helpers/client/cover-art-archive' test('can retrieve a front image URL', t => { - return client.imageURL('release', '76df3287-6cda-33eb-8e9a-044b5e15ffdd', 'front') + return client + .imageURL('release', '76df3287-6cda-33eb-8e9a-044b5e15ffdd', 'front') .then(url => { - t.is(url, 'http://archive.org/download/mbid-76df3287-6cda-33eb-8e9a-044b5e15ffdd/mbid-76df3287-6cda-33eb-8e9a-044b5e15ffdd-829521842.jpg') + t.is( + url, + 'http://archive.org/download/mbid-76df3287-6cda-33eb-8e9a-044b5e15ffdd/mbid-76df3287-6cda-33eb-8e9a-044b5e15ffdd-829521842.jpg' + ) }) }) test('can retrieve a back image URL', t => { - return client.imageURL('release', '76df3287-6cda-33eb-8e9a-044b5e15ffdd', 'back') + return client + .imageURL('release', '76df3287-6cda-33eb-8e9a-044b5e15ffdd', 'back') .then(url => { - t.is(url, 'http://archive.org/download/mbid-76df3287-6cda-33eb-8e9a-044b5e15ffdd/mbid-76df3287-6cda-33eb-8e9a-044b5e15ffdd-5769317885.jpg') + t.is( + url, + 'http://archive.org/download/mbid-76df3287-6cda-33eb-8e9a-044b5e15ffdd/mbid-76df3287-6cda-33eb-8e9a-044b5e15ffdd-5769317885.jpg' + ) }) }) test('can retrieve a list of release images', t => { - return client.images('release', '76df3287-6cda-33eb-8e9a-044b5e15ffdd') + return client + .images('release', '76df3287-6cda-33eb-8e9a-044b5e15ffdd') .then(data => { - t.is(data.release, 'http://musicbrainz.org/release/76df3287-6cda-33eb-8e9a-044b5e15ffdd') + t.is( + data.release, + 'http://musicbrainz.org/release/76df3287-6cda-33eb-8e9a-044b5e15ffdd' + ) t.true(data.images.length >= 3) data.images.forEach(image => { t.true(image.approved) diff --git a/test/extensions/cover-art-archive/schema.js b/test/extensions/cover-art-archive/schema.js index 59ffa0d..9a456a7 100644 --- a/test/extensions/cover-art-archive/schema.js +++ b/test/extensions/cover-art-archive/schema.js @@ -7,7 +7,7 @@ import baseContext from '../../helpers/context' const schema = applyExtension(extension, baseSchema) const context = extension.extendContext(baseContext) -function testData (t, query, handler) { +function testData(t, query, handler) { return graphql(schema, query, null, context).then(result => { if (result.errors !== undefined) { console.log(result.errors) @@ -17,7 +17,10 @@ function testData (t, query, handler) { }) } -test('releases have a cover art summary', testData, ` +test( + 'releases have a cover art summary', + testData, + ` { lookup { release(mbid: "b84ee12a-09ef-421b-82de-0441a926375b") { @@ -28,13 +31,18 @@ test('releases have a cover art summary', testData, ` } } } -`, (t, data) => { - const { coverArtArchive } = data.lookup.release - t.true(coverArtArchive.artwork) - t.true(coverArtArchive.count >= 10) -}) +`, + (t, data) => { + const { coverArtArchive } = data.lookup.release + t.true(coverArtArchive.artwork) + t.true(coverArtArchive.count >= 10) + } +) -test('releases have a set of cover art images', testData, ` +test( + 'releases have a set of cover art images', + testData, + ` { lookup { release(mbid: "b84ee12a-09ef-421b-82de-0441a926375b") { @@ -59,28 +67,55 @@ test('releases have a set of cover art images', testData, ` } } } -`, (t, data) => { - const { coverArtArchive } = data.lookup.release - t.is(coverArtArchive.front, 'http://coverartarchive.org/release/b84ee12a-09ef-421b-82de-0441a926375b/1611507818.jpg') - t.is(coverArtArchive.back, 'http://coverartarchive.org/release/b84ee12a-09ef-421b-82de-0441a926375b/13536418798.jpg') - t.true(coverArtArchive.images.length >= 10) - t.true(coverArtArchive.images.some(image => image.front === true)) - t.true(coverArtArchive.images.some(image => image.back === true)) - t.true(coverArtArchive.images.some(image => image.types.indexOf('Front') >= 0)) - t.true(coverArtArchive.images.some(image => image.types.indexOf('Back') >= 0)) - t.true(coverArtArchive.images.some(image => image.types.indexOf('Liner') >= 0)) - t.true(coverArtArchive.images.some(image => image.types.indexOf('Poster') >= 0)) - t.true(coverArtArchive.images.some(image => image.types.indexOf('Medium') >= 0)) - t.true(coverArtArchive.images.some(image => image.edit === 18544122)) - t.true(coverArtArchive.images.some(image => image.comment === '')) - t.true(coverArtArchive.images.some(image => image.fileID === '1611507818')) - t.true(coverArtArchive.images.some(image => image.image === 'http://coverartarchive.org/release/b84ee12a-09ef-421b-82de-0441a926375b/13536422691.jpg')) - t.true(coverArtArchive.images.every(image => image.approved === true)) - t.true(coverArtArchive.images.every(image => image.thumbnails.small)) - t.true(coverArtArchive.images.every(image => image.thumbnails.large)) -}) +`, + (t, data) => { + const { coverArtArchive } = data.lookup.release + t.is( + coverArtArchive.front, + 'http://coverartarchive.org/release/b84ee12a-09ef-421b-82de-0441a926375b/1611507818.jpg' + ) + t.is( + coverArtArchive.back, + 'http://coverartarchive.org/release/b84ee12a-09ef-421b-82de-0441a926375b/13536418798.jpg' + ) + t.true(coverArtArchive.images.length >= 10) + t.true(coverArtArchive.images.some(image => image.front === true)) + t.true(coverArtArchive.images.some(image => image.back === true)) + t.true( + coverArtArchive.images.some(image => image.types.indexOf('Front') >= 0) + ) + t.true( + coverArtArchive.images.some(image => image.types.indexOf('Back') >= 0) + ) + t.true( + coverArtArchive.images.some(image => image.types.indexOf('Liner') >= 0) + ) + t.true( + coverArtArchive.images.some(image => image.types.indexOf('Poster') >= 0) + ) + t.true( + coverArtArchive.images.some(image => image.types.indexOf('Medium') >= 0) + ) + t.true(coverArtArchive.images.some(image => image.edit === 18544122)) + t.true(coverArtArchive.images.some(image => image.comment === '')) + t.true(coverArtArchive.images.some(image => image.fileID === '1611507818')) + t.true( + coverArtArchive.images.some( + image => + image.image === + 'http://coverartarchive.org/release/b84ee12a-09ef-421b-82de-0441a926375b/13536422691.jpg' + ) + ) + t.true(coverArtArchive.images.every(image => image.approved === true)) + t.true(coverArtArchive.images.every(image => image.thumbnails.small)) + t.true(coverArtArchive.images.every(image => image.thumbnails.large)) + } +) -test('can request a size for front and back cover art', testData, ` +test( + 'can request a size for front and back cover art', + testData, + ` { lookup { release(mbid: "b84ee12a-09ef-421b-82de-0441a926375b") { @@ -92,14 +127,28 @@ test('can request a size for front and back cover art', testData, ` } } } -`, (t, data) => { - const { coverArtArchive } = data.lookup.release - t.is(coverArtArchive.front, 'http://coverartarchive.org/release/b84ee12a-09ef-421b-82de-0441a926375b/1611507818-500.jpg') - t.is(coverArtArchive.back, 'http://coverartarchive.org/release/b84ee12a-09ef-421b-82de-0441a926375b/13536418798-250.jpg') - t.is(coverArtArchive.fullFront, 'http://coverartarchive.org/release/b84ee12a-09ef-421b-82de-0441a926375b/1611507818.jpg') -}) +`, + (t, data) => { + const { coverArtArchive } = data.lookup.release + t.is( + coverArtArchive.front, + 'http://coverartarchive.org/release/b84ee12a-09ef-421b-82de-0441a926375b/1611507818-500.jpg' + ) + t.is( + coverArtArchive.back, + 'http://coverartarchive.org/release/b84ee12a-09ef-421b-82de-0441a926375b/13536418798-250.jpg' + ) + t.is( + coverArtArchive.fullFront, + 'http://coverartarchive.org/release/b84ee12a-09ef-421b-82de-0441a926375b/1611507818.jpg' + ) + } +) -test('release groups have a front cover art image', testData, ` +test( + 'release groups have a front cover art image', + testData, + ` { lookup { releaseGroup(mbid: "f5093c06-23e3-404f-aeaa-40f72885ee3a") { @@ -118,17 +167,25 @@ test('release groups have a front cover art image', testData, ` } } } -`, (t, data) => { - const { coverArtArchive } = data.lookup.releaseGroup - t.true(coverArtArchive.artwork) - t.is(coverArtArchive.front, 'http://coverartarchive.org/release/25fbfbb4-b1ee-4448-aadf-ae3bc2e2dd27/1675312275.jpg') - t.is(coverArtArchive.release.mbid, '25fbfbb4-b1ee-4448-aadf-ae3bc2e2dd27') - t.is(coverArtArchive.release.title, 'The Dark Side of the Moon') - t.is(coverArtArchive.images.length, 1) - t.true(coverArtArchive.images[0].front) -}) +`, + (t, data) => { + const { coverArtArchive } = data.lookup.releaseGroup + t.true(coverArtArchive.artwork) + t.is( + coverArtArchive.front, + 'http://coverartarchive.org/release/25fbfbb4-b1ee-4448-aadf-ae3bc2e2dd27/1675312275.jpg' + ) + t.is(coverArtArchive.release.mbid, '25fbfbb4-b1ee-4448-aadf-ae3bc2e2dd27') + t.is(coverArtArchive.release.title, 'The Dark Side of the Moon') + t.is(coverArtArchive.images.length, 1) + t.true(coverArtArchive.images[0].front) + } +) -test('release groups have different cover art sizes available', testData, ` +test( + 'release groups have different cover art sizes available', + testData, + ` { lookup { releaseGroup(mbid: "f5093c06-23e3-404f-aeaa-40f72885ee3a") { @@ -139,13 +196,24 @@ test('release groups have different cover art sizes available', testData, ` } } } -`, (t, data) => { - const { coverArtArchive } = data.lookup.releaseGroup - t.is(coverArtArchive.small, 'http://coverartarchive.org/release/25fbfbb4-b1ee-4448-aadf-ae3bc2e2dd27/1675312275-250.jpg') - t.is(coverArtArchive.large, 'http://coverartarchive.org/release/25fbfbb4-b1ee-4448-aadf-ae3bc2e2dd27/1675312275-500.jpg') -}) +`, + (t, data) => { + const { coverArtArchive } = data.lookup.releaseGroup + t.is( + coverArtArchive.small, + 'http://coverartarchive.org/release/25fbfbb4-b1ee-4448-aadf-ae3bc2e2dd27/1675312275-250.jpg' + ) + t.is( + coverArtArchive.large, + 'http://coverartarchive.org/release/25fbfbb4-b1ee-4448-aadf-ae3bc2e2dd27/1675312275-500.jpg' + ) + } +) -test('can retrieve cover art in searches', testData, ` +test( + 'can retrieve cover art in searches', + testData, + ` { search { releases(query: "You Want It Darker") { @@ -164,11 +232,13 @@ test('can retrieve cover art in searches', testData, ` } } } -`, (t, data) => { - const releases = data.search.releases.edges.map(edge => edge.node) - t.is(releases.length, 25) - t.true(releases.some(release => release.coverArtArchive.artwork === true)) - t.true(releases.some(release => release.coverArtArchive.images.length > 0)) - t.true(releases.some(release => release.coverArtArchive.front === null)) - t.true(releases.some(release => release.coverArtArchive.back === null)) -}) +`, + (t, data) => { + const releases = data.search.releases.edges.map(edge => edge.node) + t.is(releases.length, 25) + t.true(releases.some(release => release.coverArtArchive.artwork === true)) + t.true(releases.some(release => release.coverArtArchive.images.length > 0)) + t.true(releases.some(release => release.coverArtArchive.front === null)) + t.true(releases.some(release => release.coverArtArchive.back === null)) + } +) diff --git a/test/extensions/fanart-tv/schema.js b/test/extensions/fanart-tv/schema.js index 4ddc201..ed5f466 100644 --- a/test/extensions/fanart-tv/schema.js +++ b/test/extensions/fanart-tv/schema.js @@ -7,7 +7,7 @@ import baseContext from '../../helpers/context' const schema = applyExtension(extension, baseSchema) const context = extension.extendContext(baseContext) -function testData (t, query, handler) { +function testData(t, query, handler) { return graphql(schema, query, null, context).then(result => { if (result.errors !== undefined) { console.log(result.errors) @@ -17,7 +17,10 @@ function testData (t, query, handler) { }) } -test('artists have a fanArt field and preview images', testData, ` +test( + 'artists have a fanArt field and preview images', + testData, + ` { lookup { artist(mbid: "5b11f4ce-a62d-471e-81fc-a69a8278c7da") { @@ -56,21 +59,26 @@ test('artists have a fanArt field and preview images', testData, ` } } } -`, (t, data) => { - t.snapshot(data) - const { fanArt } = data.lookup.artist - const allImages = [] - .concat(fanArt.backgrounds) - .concat(fanArt.banners) - .concat(fanArt.logos) - .concat(fanArt.logosHD) - .concat(fanArt.thumbnails) - allImages.forEach(image => { - t.not(image.url, image.fullSizeURL) - }) -}) +`, + (t, data) => { + t.snapshot(data) + const { fanArt } = data.lookup.artist + const allImages = [] + .concat(fanArt.backgrounds) + .concat(fanArt.banners) + .concat(fanArt.logos) + .concat(fanArt.logosHD) + .concat(fanArt.thumbnails) + allImages.forEach(image => { + t.not(image.url, image.fullSizeURL) + }) + } +) -test('release groups have a fanArt field and preview images', testData, ` +test( + 'release groups have a fanArt field and preview images', + testData, + ` { lookup { releaseGroup(mbid: "f5093c06-23e3-404f-aeaa-40f72885ee3a") { @@ -92,18 +100,21 @@ test('release groups have a fanArt field and preview images', testData, ` } } } -`, (t, data) => { - t.snapshot(data) - const { fanArt } = data.lookup.releaseGroup - const allImages = [] - .concat(fanArt.albumCovers) - .concat(fanArt.discImages) - allImages.forEach(image => { - t.not(image.url, image.fullSizeURL) - }) -}) +`, + (t, data) => { + t.snapshot(data) + const { fanArt } = data.lookup.releaseGroup + const allImages = [].concat(fanArt.albumCovers).concat(fanArt.discImages) + allImages.forEach(image => { + t.not(image.url, image.fullSizeURL) + }) + } +) -test('labels have a fanArt field and preview images', testData, ` +test( + 'labels have a fanArt field and preview images', + testData, + ` { lookup { label(mbid: "0cf56645-50ec-4411-aeb6-c9f4ce0f8edb") { @@ -119,10 +130,12 @@ test('labels have a fanArt field and preview images', testData, ` } } } -`, (t, data) => { - t.snapshot(data) - const { fanArt } = data.lookup.label - fanArt.logos.forEach(image => { - t.not(image.url, image.fullSizeURL) - }) -}) +`, + (t, data) => { + t.snapshot(data) + const { fanArt } = data.lookup.label + fanArt.logos.forEach(image => { + t.not(image.url, image.fullSizeURL) + }) + } +) diff --git a/test/extensions/mediawiki/schema.js b/test/extensions/mediawiki/schema.js index 8633a67..bf3c4e4 100644 --- a/test/extensions/mediawiki/schema.js +++ b/test/extensions/mediawiki/schema.js @@ -7,7 +7,7 @@ import baseContext from '../../helpers/context' const schema = applyExtension(extension, baseSchema) const context = extension.extendContext(baseContext) -function testData (t, query, handler) { +function testData(t, query, handler) { return graphql(schema, query, null, context).then(result => { if (result.errors !== undefined) { console.log(result.errors) @@ -40,7 +40,10 @@ const fragment = ` } ` -test('artists have a mediaWikiImages field', testData, ` +test( + 'artists have a mediaWikiImages field', + testData, + ` { lookup { artist(mbid: "5b11f4ce-a62d-471e-81fc-a69a8278c7da") { @@ -50,11 +53,16 @@ test('artists have a mediaWikiImages field', testData, ` } } } -`, (t, data) => { - t.snapshot(data) -}) +`, + (t, data) => { + t.snapshot(data) + } +) -test('instruments have a mediaWikiImages field', testData, ` +test( + 'instruments have a mediaWikiImages field', + testData, + ` { search { instruments(query: "guitar", first: 20) { @@ -66,11 +74,16 @@ test('instruments have a mediaWikiImages field', testData, ` } } } -`, (t, data) => { - t.snapshot(data) -}) +`, + (t, data) => { + t.snapshot(data) + } +) -test('labels have a mediaWikiImages field', testData, ` +test( + 'labels have a mediaWikiImages field', + testData, + ` { search { labels(query: "Sony", first: 50) { @@ -82,11 +95,16 @@ test('labels have a mediaWikiImages field', testData, ` } } } -`, (t, data) => { - t.snapshot(data) -}) +`, + (t, data) => { + t.snapshot(data) + } +) -test('places have a mediaWikiImages field', testData, ` +test( + 'places have a mediaWikiImages field', + testData, + ` { lookup { place(mbid: "b5297256-8482-4cba-968a-25db61563faf") { @@ -96,6 +114,8 @@ test('places have a mediaWikiImages field', testData, ` } } } -`, (t, data) => { - t.snapshot(data) -}) +`, + (t, data) => { + t.snapshot(data) + } +) diff --git a/test/extensions/the-audio-db/schema.js b/test/extensions/the-audio-db/schema.js index 5b4fb04..91834e0 100644 --- a/test/extensions/the-audio-db/schema.js +++ b/test/extensions/the-audio-db/schema.js @@ -7,7 +7,7 @@ import baseContext from '../../helpers/context' const schema = applyExtension(extension, baseSchema) const context = extension.extendContext(baseContext) -function testData (t, query, handler) { +function testData(t, query, handler) { return graphql(schema, query, null, context).then(result => { if (result.errors !== undefined) { console.log(result.errors) @@ -17,7 +17,10 @@ function testData (t, query, handler) { }) } -test('artists have a theAudioDB field', testData, ` +test( + 'artists have a theAudioDB field', + testData, + ` { lookup { artist(mbid: "5b11f4ce-a62d-471e-81fc-a69a8278c7da") { @@ -41,11 +44,16 @@ test('artists have a theAudioDB field', testData, ` } } } -`, (t, data) => { - t.snapshot(data) -}) +`, + (t, data) => { + t.snapshot(data) + } +) -test('release groups have a theAudioDB field', testData, ` +test( + 'release groups have a theAudioDB field', + testData, + ` { lookup { releaseGroup(mbid: "aa997ea0-2936-40bd-884d-3af8a0e064dc") { @@ -75,11 +83,16 @@ test('release groups have a theAudioDB field', testData, ` } } } -`, (t, data) => { - t.snapshot(data) -}) +`, + (t, data) => { + t.snapshot(data) + } +) -test('recordings have a theAudioDB field', testData, ` +test( + 'recordings have a theAudioDB field', + testData, + ` { lookup { recording(mbid: "1109d8da-ce4a-4739-9414-242dc3e9b81c") { @@ -113,6 +126,8 @@ test('recordings have a theAudioDB field', testData, ` } } } -`, (t, data) => { - t.snapshot(data) -}) +`, + (t, data) => { + t.snapshot(data) + } +) diff --git a/test/helpers/client/cover-art-archive.js b/test/helpers/client/cover-art-archive.js index af978a8..0e5e5d5 100644 --- a/test/helpers/client/cover-art-archive.js +++ b/test/helpers/client/cover-art-archive.js @@ -4,8 +4,7 @@ import CoverArtArchiveClient from '../../../src/extensions/cover-art-archive/cli sepia.fixtureDir(path.join(__dirname, '..', '..', 'fixtures')) -const options = process.env.VCR_MODE === 'playback' - ? { limit: Infinity, period: 0 } - : {} +const options = + process.env.VCR_MODE === 'playback' ? { limit: Infinity, period: 0 } : {} export default new CoverArtArchiveClient(options) diff --git a/test/helpers/client/musicbrainz.js b/test/helpers/client/musicbrainz.js index 6ce707d..c84107b 100644 --- a/test/helpers/client/musicbrainz.js +++ b/test/helpers/client/musicbrainz.js @@ -4,8 +4,7 @@ import MusicBrainz from '../../../src/api' sepia.fixtureDir(path.join(__dirname, '..', '..', 'fixtures')) -const options = process.env.VCR_MODE === 'playback' - ? { limit: Infinity, period: 0 } - : {} +const options = + process.env.VCR_MODE === 'playback' ? { limit: Infinity, period: 0 } : {} export default new MusicBrainz(options) diff --git a/test/schema.js b/test/schema.js index fa56082..5ae0d43 100644 --- a/test/schema.js +++ b/test/schema.js @@ -3,7 +3,7 @@ import { graphql } from 'graphql' import schema from '../src/schema' import context from './helpers/context' -function testData (t, query, handler) { +function testData(t, query, handler) { return graphql(schema, query, null, context).then(result => { if (result.errors !== undefined) { console.log(result.errors) @@ -13,7 +13,7 @@ function testData (t, query, handler) { }) } -function testError (t, query, handler) { +function testError(t, query, handler) { return graphql(schema, query, null, context).then(result => { t.truthy(result.errors) t.true(result.errors.length > 0) @@ -21,12 +21,15 @@ function testError (t, query, handler) { }) } -function testThrows (t, query, handler) { +function testThrows(t, query, handler) { const error = t.throws(graphql(schema, query, null, context)) return handler(t, error) } -test('schema has a node field', testData, ` +test( + 'schema has a node field', + testData, + ` { node(id: "UmVsZWFzZUdyb3VwOmUzN2QyNzQwLTQ1MDMtNGUzZi1hYjZkLWU2MjJhMjVlOTY0ZA==") { __typename @@ -35,16 +38,21 @@ test('schema has a node field', testData, ` } } } -`, (t, data) => { - t.deepEqual(data, { - node: { - __typename: 'ReleaseGroup', - mbid: 'e37d2740-4503-4e3f-ab6d-e622a25e964d' - } - }) -}) +`, + (t, data) => { + t.deepEqual(data, { + node: { + __typename: 'ReleaseGroup', + mbid: 'e37d2740-4503-4e3f-ab6d-e622a25e964d' + } + }) + } +) -test('schema has a lookup query', testData, ` +test( + 'schema has a lookup query', + testData, + ` { lookup { artist (mbid: "c8da2e40-bd28-4d4e-813a-bd2f51958ba8") { @@ -54,19 +62,24 @@ test('schema has a lookup query', testData, ` } } } -`, (t, data) => { - t.deepEqual(data, { - lookup: { - artist: { - mbid: 'c8da2e40-bd28-4d4e-813a-bd2f51958ba8', - name: 'Lures', - type: 'Group' +`, + (t, data) => { + t.deepEqual(data, { + lookup: { + artist: { + mbid: 'c8da2e40-bd28-4d4e-813a-bd2f51958ba8', + name: 'Lures', + type: 'Group' + } } - } - }) -}) + }) + } +) -test('schema has a search query', testData, ` +test( + 'schema has a search query', + testData, + ` { search { recordings (query: "Burn the Witch") { @@ -81,14 +94,19 @@ test('schema has a search query', testData, ` } } } -`, (t, data) => { - const { recordings } = data.search - t.true(recordings.totalCount > 0) - t.true(recordings.edges.length === 25) - recordings.edges.forEach(edge => t.true(edge.score > 0)) -}) +`, + (t, data) => { + const { recordings } = data.search + t.true(recordings.totalCount > 0) + t.true(recordings.edges.length === 25) + recordings.edges.forEach(edge => t.true(edge.score > 0)) + } +) -test('schema has a browse query', testData, ` +test( + 'schema has a browse query', + testData, + ` { browse { releaseGroups(artist: "c8da2e40-bd28-4d4e-813a-bd2f51958ba8") { @@ -109,14 +127,19 @@ test('schema has a browse query', testData, ` } } } -`, (t, data) => { - const { releaseGroups } = data.browse - t.true(releaseGroups.totalCount > 0) - t.true(releaseGroups.edges.length > 0) - releaseGroups.edges.forEach(edge => t.truthy(edge.node.title)) -}) +`, + (t, data) => { + const { releaseGroups } = data.browse + t.true(releaseGroups.totalCount > 0) + t.true(releaseGroups.edges.length > 0) + releaseGroups.edges.forEach(edge => t.truthy(edge.node.title)) + } +) -test('supports deeply nested queries', testData, ` +test( + 'supports deeply nested queries', + testData, + ` query AppleRecordsMarriages { search { labels(query: "Apple Records", first: 1) { @@ -184,13 +207,18 @@ test('supports deeply nested queries', testData, ` } } } -`, (t, data) => { - const { labels } = data.search - t.true(labels.edges.length > 0) - t.is(labels.edges[0].node.releases.edges.length, 1) -}) +`, + (t, data) => { + const { labels } = data.search + t.true(labels.edges.length > 0) + t.is(labels.edges[0].node.releases.edges.length, 1) + } +) -test('connections have a nodes shortcut field', testData, ` +test( + 'connections have a nodes shortcut field', + testData, + ` query AppleRecordsMarriages { search { labels(query: "Apple Records", first: 1) { @@ -248,14 +276,19 @@ test('connections have a nodes shortcut field', testData, ` } } } -`, (t, data) => { - const { labels } = data.search - t.true(labels.nodes.length > 0) - t.is(labels.nodes[0].releases.nodes.length, 1) -}) +`, + (t, data) => { + const { labels } = data.search + t.true(labels.nodes.length > 0) + t.is(labels.nodes[0].releases.nodes.length, 1) + } +) // FIXME: https://github.com/graphql/graphql-js/issues/910 -test('throws an error if given a malformed MBID', testThrows, ` +test( + 'throws an error if given a malformed MBID', + testThrows, + ` { lookup { artist(mbid: "ABC123") { @@ -263,13 +296,18 @@ test('throws an error if given a malformed MBID', testThrows, ` } } } -`, async (t, promise) => { - const err = await promise - t.true(err instanceof TypeError) - t.is(err.message, 'Malformed MBID: ABC123') -}) +`, + async (t, promise) => { + const err = await promise + t.true(err instanceof TypeError) + t.is(err.message, 'Malformed MBID: ABC123') + } +) -test('artist areas access begin_area/end_area for lookup queries', testData, ` +test( + 'artist areas access begin_area/end_area for lookup queries', + testData, + ` { lookup { artist(mbid: "65314b12-0e08-43fa-ba33-baaa7b874c15") { @@ -282,13 +320,18 @@ test('artist areas access begin_area/end_area for lookup queries', testData, ` } } } -`, (t, data) => { - const { artist } = data.lookup - t.is(artist.beginArea.name, 'Westmount') - t.is(artist.endArea.name, 'Los Angeles') -}) +`, + (t, data) => { + const { artist } = data.lookup + t.is(artist.beginArea.name, 'Westmount') + t.is(artist.endArea.name, 'Los Angeles') + } +) -test('artist areas access begin_area/end_area for browse queries', testData, ` +test( + 'artist areas access begin_area/end_area for browse queries', + testData, + ` { browse { artists(area: "3f504d54-c40c-487d-bc16-c1990eac887f") { @@ -305,14 +348,19 @@ test('artist areas access begin_area/end_area for browse queries', testData, ` } } } -`, (t, data) => { - const artists = data.browse.artists.edges.map(edge => edge.node) - t.true(artists.length > 1) - t.true(artists.some(artist => artist.beginArea)) - t.true(artists.some(artist => artist.endArea)) -}) +`, + (t, data) => { + const artists = data.browse.artists.edges.map(edge => edge.node) + t.true(artists.length > 1) + t.true(artists.some(artist => artist.beginArea)) + t.true(artists.some(artist => artist.endArea)) + } +) -test('artist areas access begin-area/end-area for search queries', testData, ` +test( + 'artist areas access begin-area/end-area for search queries', + testData, + ` { search { artists(query: "Leonard Cohen", first: 1) { @@ -329,14 +377,19 @@ test('artist areas access begin-area/end-area for search queries', testData, ` } } } -`, (t, data) => { - const artists = data.search.artists.edges.map(edge => edge.node) - t.true(artists.length === 1) - t.is(artists[0].beginArea.name, 'Westmount') - t.is(artists[0].endArea.name, 'Los Angeles') -}) +`, + (t, data) => { + const artists = data.search.artists.edges.map(edge => edge.node) + t.true(artists.length === 1) + t.is(artists[0].beginArea.name, 'Westmount') + t.is(artists[0].endArea.name, 'Los Angeles') + } +) -test('relationships are grouped by target type', testData, ` +test( + 'relationships are grouped by target type', + testData, + ` { lookup { artist(mbid: "65314b12-0e08-43fa-ba33-baaa7b874c15") { @@ -375,26 +428,31 @@ test('relationships are grouped by target type', testData, ` } } } -`, (t, data) => { - const { relationships } = data.lookup.artist - t.is(relationships.artists.edges.length, 5) - relationships.artists.edges.forEach(edge => { - t.is(edge.node.targetType, 'artist') - t.is(edge.node.target.__typename, 'Artist') - }) - t.is(relationships.recordings.edges.length, 5) - relationships.recordings.edges.forEach(edge => { - t.is(edge.node.targetType, 'recording') - t.is(edge.node.target.__typename, 'Recording') - }) - t.is(relationships.releases.edges.length, 5) - relationships.releases.edges.forEach(edge => { - t.is(edge.node.targetType, 'release') - t.is(edge.node.target.__typename, 'Release') - }) -}) +`, + (t, data) => { + const { relationships } = data.lookup.artist + t.is(relationships.artists.edges.length, 5) + relationships.artists.edges.forEach(edge => { + t.is(edge.node.targetType, 'artist') + t.is(edge.node.target.__typename, 'Artist') + }) + t.is(relationships.recordings.edges.length, 5) + relationships.recordings.edges.forEach(edge => { + t.is(edge.node.targetType, 'recording') + t.is(edge.node.target.__typename, 'Recording') + }) + t.is(relationships.releases.edges.length, 5) + relationships.releases.edges.forEach(edge => { + t.is(edge.node.targetType, 'release') + t.is(edge.node.target.__typename, 'Release') + }) + } +) -test('relationships can be filtered by type', testData, ` +test( + 'relationships can be filtered by type', + testData, + ` { lookup { artist(mbid: "65314b12-0e08-43fa-ba33-baaa7b874c15") { @@ -411,17 +469,22 @@ test('relationships can be filtered by type', testData, ` } } } -`, (t, data) => { - const { artist } = data.lookup - const rels = artist.relationships.artists.edges.map(edge => edge.node) - t.is(rels.length, 2) - rels.forEach(rel => { - t.is(rel.targetType, 'artist') - t.is(rel.type, 'parent') - }) -}) +`, + (t, data) => { + const { artist } = data.lookup + const rels = artist.relationships.artists.edges.map(edge => edge.node) + t.is(rels.length, 2) + rels.forEach(rel => { + t.is(rel.targetType, 'artist') + t.is(rel.type, 'parent') + }) + } +) -test('relationships can be filtered by type ID', testData, ` +test( + 'relationships can be filtered by type ID', + testData, + ` { lookup { artist(mbid: "65314b12-0e08-43fa-ba33-baaa7b874c15") { @@ -438,17 +501,22 @@ test('relationships can be filtered by type ID', testData, ` } } } -`, (t, data) => { - const { artist } = data.lookup - const rels = artist.relationships.artists.edges.map(edge => edge.node) - t.is(rels.length, 1) - rels.forEach(rel => { - t.is(rel.targetType, 'artist') - t.is(rel.type, 'involved with') - }) -}) +`, + (t, data) => { + const { artist } = data.lookup + const rels = artist.relationships.artists.edges.map(edge => edge.node) + t.is(rels.length, 1) + rels.forEach(rel => { + t.is(rel.targetType, 'artist') + t.is(rel.type, 'involved with') + }) + } +) -test('relationships can be filtered by direction', testData, ` +test( + 'relationships can be filtered by direction', + testData, + ` { lookup { area(mbid: "10cb2ebd-1bc7-4c11-b10d-54f60c421d20") { @@ -473,23 +541,28 @@ test('relationships can be filtered by direction', testData, ` } } } -`, (t, data) => { - const { area } = data.lookup - const isPartOf = area.relationships.isPartOf.edges.map(edge => edge.node) - const hasParts = area.relationships.hasParts.edges.map(edge => edge.node) - t.true(isPartOf.length > 0) - t.true(hasParts.length > 0) - isPartOf.forEach(rel => { - t.is(rel.type, 'part of') - t.is(rel.direction, 'backward') - }) - hasParts.forEach(rel => { - t.is(rel.type, 'part of') - t.is(rel.direction, 'forward') - }) -}) +`, + (t, data) => { + const { area } = data.lookup + const isPartOf = area.relationships.isPartOf.edges.map(edge => edge.node) + const hasParts = area.relationships.hasParts.edges.map(edge => edge.node) + t.true(isPartOf.length > 0) + t.true(hasParts.length > 0) + isPartOf.forEach(rel => { + t.is(rel.type, 'part of') + t.is(rel.direction, 'backward') + }) + hasParts.forEach(rel => { + t.is(rel.type, 'part of') + t.is(rel.direction, 'forward') + }) + } +) -test('area maps iso-3166-1-codes to isoCodes', testData, ` +test( + 'area maps iso-3166-1-codes to isoCodes', + testData, + ` { lookup { area(mbid: "489ce91b-6658-3307-9877-795b68554c98") { @@ -498,11 +571,16 @@ test('area maps iso-3166-1-codes to isoCodes', testData, ` } } } -`, (t, data) => { - t.deepEqual(data.lookup.area.isoCodes, ['US']) -}) +`, + (t, data) => { + t.deepEqual(data.lookup.area.isoCodes, ['US']) + } +) -test('areas have a type and typeID', testData, ` +test( + 'areas have a type and typeID', + testData, + ` { search { areas(query: "Germany", first: 5) { @@ -514,11 +592,16 @@ test('areas have a type and typeID', testData, ` } } } -`, (t, data) => { - t.snapshot(data) -}) +`, + (t, data) => { + t.snapshot(data) + } +) -test('alias locales use the locale scalar', testData, ` +test( + 'alias locales use the locale scalar', + testData, + ` { lookup { artist(mbid: "f99b7d67-4e63-4678-aa66-4c6ac0f7d24a") { @@ -529,13 +612,18 @@ test('alias locales use the locale scalar', testData, ` } } } -`, (t, data) => { - const { aliases } = data.lookup.artist - t.is(aliases.find(alias => alias.locale === 'en').name, 'PSY') - t.is(aliases.find(alias => alias.locale === 'ko').name, '싸이') -}) +`, + (t, data) => { + const { aliases } = data.lookup.artist + t.is(aliases.find(alias => alias.locale === 'en').name, 'PSY') + t.is(aliases.find(alias => alias.locale === 'ko').name, '싸이') + } +) -test('work ISWCs use the ISWC scalar', testData, ` +test( + 'work ISWCs use the ISWC scalar', + testData, + ` { lookup { work(mbid: "ef7d0814-da6a-32f5-a600-ff81cffd1aed") { @@ -544,13 +632,18 @@ test('work ISWCs use the ISWC scalar', testData, ` } } } -`, (t, data) => { - const { work } = data.lookup - t.is(work.title, 'Song of the French Partisan') - t.deepEqual(work.iswcs, ['T-900.755.682-3']) -}) +`, + (t, data) => { + const { work } = data.lookup + t.is(work.title, 'Song of the French Partisan') + t.deepEqual(work.iswcs, ['T-900.755.682-3']) + } +) -test('URLs may be looked up by resource', testData, ` +test( + 'URLs may be looked up by resource', + testData, + ` { lookup { url(resource: "http://www.nirvana.com/") { @@ -559,14 +652,19 @@ test('URLs may be looked up by resource', testData, ` } } } -`, (t, data) => { - const { url } = data.lookup - t.is(url.mbid, '4347ffe2-82ec-4059-9520-6a1a3f73a304') - t.is(url.resource, 'http://www.nirvana.com/') -}) +`, + (t, data) => { + const { url } = data.lookup + t.is(url.mbid, '4347ffe2-82ec-4059-9520-6a1a3f73a304') + t.is(url.resource, 'http://www.nirvana.com/') + } +) // FIXME: https://github.com/graphql/graphql-js/issues/910 -test('throws an error if given a malformed resource URL', testThrows, ` +test( + 'throws an error if given a malformed resource URL', + testThrows, + ` { lookup { url(resource: "http:foo") { @@ -575,13 +673,18 @@ test('throws an error if given a malformed resource URL', testThrows, ` } } } -`, async (t, promise) => { - const err = await promise - t.true(err instanceof TypeError) - t.is(err.message, 'Malformed URL: http:foo') -}) +`, + async (t, promise) => { + const err = await promise + t.true(err instanceof TypeError) + t.is(err.message, 'Malformed URL: http:foo') + } +) -test('release groups can be browsed by type', testData, ` +test( + 'release groups can be browsed by type', + testData, + ` { browse { releaseGroups(artist: "5b11f4ce-a62d-471e-81fc-a69a8278c7da", type: EP) { @@ -593,13 +696,18 @@ test('release groups can be browsed by type', testData, ` } } } -`, (t, data) => { - const releaseGroups = data.browse.releaseGroups.edges.map(edge => edge.node) - t.is(releaseGroups.length, 8) - releaseGroups.forEach(releaseGroup => t.is(releaseGroup.primaryType, 'EP')) -}) +`, + (t, data) => { + const releaseGroups = data.browse.releaseGroups.edges.map(edge => edge.node) + t.is(releaseGroups.length, 8) + releaseGroups.forEach(releaseGroup => t.is(releaseGroup.primaryType, 'EP')) + } +) -test('releases can be browsed by type and status', testData, ` +test( + 'releases can be browsed by type and status', + testData, + ` { browse { releases(artist: "5b11f4ce-a62d-471e-81fc-a69a8278c7da", type: EP, status: BOOTLEG) { @@ -611,13 +719,18 @@ test('releases can be browsed by type and status', testData, ` } } } -`, (t, data) => { - const releases = data.browse.releases.edges.map(edge => edge.node) - t.is(releases.length, 6) - releases.forEach(release => t.is(release.status, 'BOOTLEG')) -}) +`, + (t, data) => { + const releases = data.browse.releases.edges.map(edge => edge.node) + t.is(releases.length, 6) + releases.forEach(release => t.is(release.status, 'BOOTLEG')) + } +) -test('releases have an ASIN field', testData, ` +test( + 'releases have an ASIN field', + testData, + ` { lookup { release(mbid: "d5cdb7fd-c7e9-460a-9549-8a369655cc52") { @@ -625,12 +738,17 @@ test('releases have an ASIN field', testData, ` } } } -`, (t, data) => { - const { release } = data.lookup - t.is(release.asin, 'B01KN6XDS6') -}) +`, + (t, data) => { + const { release } = data.lookup + t.is(release.asin, 'B01KN6XDS6') + } +) -test('artists have a list of ISNIs and IPIs', testData, ` +test( + 'artists have a list of ISNIs and IPIs', + testData, + ` { lookup { artist(mbid: "65314b12-0e08-43fa-ba33-baaa7b874c15") { @@ -639,13 +757,18 @@ test('artists have a list of ISNIs and IPIs', testData, ` } } } -`, (t, data) => { - const { artist } = data.lookup - t.deepEqual(artist.ipis, ['00006457004']) - t.deepEqual(artist.isnis, ['0000000110273481']) -}) +`, + (t, data) => { + const { artist } = data.lookup + t.deepEqual(artist.ipis, ['00006457004']) + t.deepEqual(artist.isnis, ['0000000110273481']) + } +) -test('artistCredits is an alias for artistCredit', testData, ` +test( + 'artistCredits is an alias for artistCredit', + testData, + ` { lookup { recording(mbid: "07649758-09c8-4d70-bc6f-5c37ab36334d") { @@ -680,27 +803,32 @@ test('artistCredits is an alias for artistCredit', testData, ` } } } -`, (t, data) => { - const { recording, release, releaseGroup } = data.lookup - t.deepEqual(recording.artistCredit, [ - { name: 'Holly Golightly', joinPhrase: ' & ' }, - { name: 'The Brokeoffs', joinPhrase: '' } - ]) - t.deepEqual(recording.artistCredits, recording.artistCredit) +`, + (t, data) => { + const { recording, release, releaseGroup } = data.lookup + t.deepEqual(recording.artistCredit, [ + { name: 'Holly Golightly', joinPhrase: ' & ' }, + { name: 'The Brokeoffs', joinPhrase: '' } + ]) + t.deepEqual(recording.artistCredits, recording.artistCredit) - t.deepEqual(release.artistCredit, [ - { name: 'Leonard Cohen', joinPhrase: '' } - ]) - t.deepEqual(release.artistCredits, release.artistCredit) + t.deepEqual(release.artistCredit, [ + { name: 'Leonard Cohen', joinPhrase: '' } + ]) + t.deepEqual(release.artistCredits, release.artistCredit) - t.deepEqual(releaseGroup.artistCredit, [ - { name: 'DJ Muggs', joinPhrase: ' vs. ' }, - { name: 'Ill Bill', joinPhrase: '' } - ]) - t.deepEqual(releaseGroup.artistCredits, releaseGroup.artistCredit) -}) + t.deepEqual(releaseGroup.artistCredit, [ + { name: 'DJ Muggs', joinPhrase: ' vs. ' }, + { name: 'Ill Bill', joinPhrase: '' } + ]) + t.deepEqual(releaseGroup.artistCredits, releaseGroup.artistCredit) + } +) -test('recordings can be browsed by ISRC', testData, ` +test( + 'recordings can be browsed by ISRC', + testData, + ` { browse { recordings(isrc: "USSUB0200002") { @@ -714,15 +842,20 @@ test('recordings can be browsed by ISRC', testData, ` } } } -`, (t, data) => { - const recordings = data.browse.recordings.edges.map(edge => edge.node) - t.is(data.browse.recordings.totalCount, 1) - t.deepEqual(recordings, [ - { title: 'About a Girl', isrcs: ['USSUB0200002', 'USUG10200084'] } - ]) -}) +`, + (t, data) => { + const recordings = data.browse.recordings.edges.map(edge => edge.node) + t.is(data.browse.recordings.totalCount, 1) + t.deepEqual(recordings, [ + { title: 'About a Girl', isrcs: ['USSUB0200002', 'USUG10200084'] } + ]) + } +) -test('releases can be browsed by Disc ID', testData, ` +test( + 'releases can be browsed by Disc ID', + testData, + ` { browse { releases(discID: "XzPS7vW.HPHsYemQh0HBUGr8vuU-") { @@ -736,14 +869,27 @@ test('releases can be browsed by Disc ID', testData, ` } } } -`, (t, data) => { - const releases = data.browse.releases.edges.map(edge => edge.node) - t.true(data.browse.releases.totalCount >= 2) - t.true(releases.some(release => release.mbid === '5a6e5ad7-c2bd-3484-a20e-121bf981c883')) - t.true(releases.some(release => release.mbid === '96f6f90e-d831-4f37-bf72-ce2982e459fb')) -}) +`, + (t, data) => { + const releases = data.browse.releases.edges.map(edge => edge.node) + t.true(data.browse.releases.totalCount >= 2) + t.true( + releases.some( + release => release.mbid === '5a6e5ad7-c2bd-3484-a20e-121bf981c883' + ) + ) + t.true( + releases.some( + release => release.mbid === '96f6f90e-d831-4f37-bf72-ce2982e459fb' + ) + ) + } +) -test('works can be browsed by ISWC', testData, ` +test( + 'works can be browsed by ISWC', + testData, + ` { browse { works(iswc: "T-900.755.682-3") { @@ -757,15 +903,20 @@ test('works can be browsed by ISWC', testData, ` } } } -`, (t, data) => { - const works = data.browse.works.edges.map(edge => edge.node) - t.is(data.browse.works.totalCount, 1) - t.deepEqual(works, [ - { title: 'Song of the French Partisan', iswcs: ['T-900.755.682-3'] } - ]) -}) +`, + (t, data) => { + const works = data.browse.works.edges.map(edge => edge.node) + t.is(data.browse.works.totalCount, 1) + t.deepEqual(works, [ + { title: 'Song of the French Partisan', iswcs: ['T-900.755.682-3'] } + ]) + } +) -test('recordings have a length in milliseconds', testData, ` +test( + 'recordings have a length in milliseconds', + testData, + ` { lookup { recording(mbid: "9f9cf187-d6f9-437f-9d98-d59cdbd52757") { @@ -773,12 +924,17 @@ test('recordings have a length in milliseconds', testData, ` } } } -`, (t, data) => { - const { recording } = data.lookup - t.is(recording.length, 383493) -}) +`, + (t, data) => { + const { recording } = data.lookup + t.is(recording.length, 383493) + } +) -test('collections can be browsed by the entities they contain', testData, ` +test( + 'collections can be browsed by the entities they contain', + testData, + ` { browse { collections(artist: "24f1766e-9635-4d58-a4d4-9413f9f98a4c") { @@ -803,20 +959,27 @@ test('collections can be browsed by the entities they contain', testData, ` } } } -`, (t, data) => { - const collections = data.browse.collections.edges.map(edge => edge.node) - t.true(collections.length >= 2) - t.true(collections.some(collection => collection.editor === 'arist.on')) - t.true(collections.some(collection => collection.editor === 'ListMyCDs.com')) - collections.forEach(collection => { - t.is(collection.entityType, 'artist') - t.is(collection.type, 'Artist') - t.true(collection.artists.totalCount > 0) - t.true(collection.artists.edges.length > 0) - }) -}) +`, + (t, data) => { + const collections = data.browse.collections.edges.map(edge => edge.node) + t.true(collections.length >= 2) + t.true(collections.some(collection => collection.editor === 'arist.on')) + t.true( + collections.some(collection => collection.editor === 'ListMyCDs.com') + ) + collections.forEach(collection => { + t.is(collection.entityType, 'artist') + t.is(collection.type, 'Artist') + t.true(collection.artists.totalCount > 0) + t.true(collection.artists.edges.length > 0) + }) + } +) -test('collections can be looked up by MBID', testData, ` +test( + 'collections can be looked up by MBID', + testData, + ` { lookup { collection(mbid: "85da782d-2ec0-41ec-a97f-9be464bba309") { @@ -831,13 +994,18 @@ test('collections can be looked up by MBID', testData, ` } } } -`, (t, data) => { - const { collection } = data.lookup - t.is(collection.name, 'Beets Music Collection') - t.is(collection.releases.edges.length, 25) -}) +`, + (t, data) => { + const { collection } = data.lookup + t.is(collection.name, 'Beets Music Collection') + t.is(collection.releases.edges.length, 25) + } +) -test('entities have a collections field', testData, ` +test( + 'entities have a collections field', + testData, + ` { lookup { release(mbid: "0702057c-cb90-43d3-b7b4-6d0cc37e8644") { @@ -864,14 +1032,19 @@ test('entities have a collections field', testData, ` } } } -`, (t, data) => { - const { release, artist } = data.lookup - t.true(release.collections.totalCount > 0) - t.true(release.collections.edges.length > 0) - t.true(artist.collections.edges.length > 0) -}) +`, + (t, data) => { + const { release, artist } = data.lookup + t.true(release.collections.totalCount > 0) + t.true(release.collections.edges.length > 0) + t.true(artist.collections.edges.length > 0) + } +) -test('releases support a list of media', testData, ` +test( + 'releases support a list of media', + testData, + ` { lookup { release(mbid: "a4864e94-6d75-4ade-bc93-0dabf3521453") { @@ -885,27 +1058,32 @@ test('releases support a list of media', testData, ` } } } -`, (t, data) => { - const { release } = data.lookup - t.deepEqual(release.media, [ - { - title: 'Left', - format: 'CD', - formatID: '9712d52a-4509-3d4b-a1a2-67c88c643e31', - position: 1, - trackCount: 12 - }, - { - title: 'Right', - format: 'CD', - formatID: '9712d52a-4509-3d4b-a1a2-67c88c643e31', - position: 2, - trackCount: 11 - } - ]) -}) +`, + (t, data) => { + const { release } = data.lookup + t.deepEqual(release.media, [ + { + title: 'Left', + format: 'CD', + formatID: '9712d52a-4509-3d4b-a1a2-67c88c643e31', + position: 1, + trackCount: 12 + }, + { + title: 'Right', + format: 'CD', + formatID: '9712d52a-4509-3d4b-a1a2-67c88c643e31', + position: 2, + trackCount: 11 + } + ]) + } +) -test('throws an error if looking up a URL without an argument', testError, ` +test( + 'throws an error if looking up a URL without an argument', + testError, + ` { lookup { url { @@ -913,11 +1091,19 @@ test('throws an error if looking up a URL without an argument', testError, ` } } } -`, (t, errors) => { - t.is(errors[0].message, 'Lookups by a field other than MBID must provide: resource') -}) +`, + (t, errors) => { + t.is( + errors[0].message, + 'Lookups by a field other than MBID must provide: resource' + ) + } +) -test('some entities support ratings', testData, ` +test( + 'some entities support ratings', + testData, + ` { lookup { event(mbid: "eec75a81-8864-4cea-b8b4-e99cd08b29f1") { @@ -978,27 +1164,34 @@ test('some entities support ratings', testData, ` } } } -`, (t, data) => { - const { event, work } = data.lookup - const artists = data.browse.artists.edges.map(edge => edge.node) - const recordings = data.browse.recordings.edges.map(edge => edge.node) - const labels = data.search.labels.edges.map(edge => edge.node) - const releaseGroups = data.search.releaseGroups.edges.map(edge => edge.node) - t.is(event.rating.voteCount, 0) - t.is(event.rating.value, null) - t.true(work.rating.voteCount > 0) - t.true(work.rating.value >= 4) - t.true(artists.some(artist => artist.rating.voteCount > 0)) - t.true(artists.some(artist => artist.rating.value > 3)) - t.true(recordings.some(recording => recording.rating.voteCount > 0)) - t.true(recordings.some(recording => recording.rating.value > 3)) - t.true(labels.some(label => label.rating.voteCount > 0)) - t.true(labels.some(label => label.rating.value > 3)) - t.true(releaseGroups.some(releaseGroup => releaseGroup.rating.voteCount > 0)) - t.true(releaseGroups.some(releaseGroup => releaseGroup.rating.value > 3)) -}) +`, + (t, data) => { + const { event, work } = data.lookup + const artists = data.browse.artists.edges.map(edge => edge.node) + const recordings = data.browse.recordings.edges.map(edge => edge.node) + const labels = data.search.labels.edges.map(edge => edge.node) + const releaseGroups = data.search.releaseGroups.edges.map(edge => edge.node) + t.is(event.rating.voteCount, 0) + t.is(event.rating.value, null) + t.true(work.rating.voteCount > 0) + t.true(work.rating.value >= 4) + t.true(artists.some(artist => artist.rating.voteCount > 0)) + t.true(artists.some(artist => artist.rating.value > 3)) + t.true(recordings.some(recording => recording.rating.voteCount > 0)) + t.true(recordings.some(recording => recording.rating.value > 3)) + t.true(labels.some(label => label.rating.voteCount > 0)) + t.true(labels.some(label => label.rating.value > 3)) + t.true( + releaseGroups.some(releaseGroup => releaseGroup.rating.voteCount > 0) + ) + t.true(releaseGroups.some(releaseGroup => releaseGroup.rating.value > 3)) + } +) -test('discs can be looked up by disc ID', testData, ` +test( + 'discs can be looked up by disc ID', + testData, + ` { lookup { disc(discID: "TMXdzZkTcc9Jq24PD0w5J9_AXms-") { @@ -1018,20 +1211,36 @@ test('discs can be looked up by disc ID', testData, ` } } } -`, (t, data) => { - const { disc } = data.lookup - t.is(disc.discID, 'TMXdzZkTcc9Jq24PD0w5J9_AXms-') - t.is(disc.offsetCount, 9) - t.is(disc.sectors, 193443) - t.deepEqual(disc.offsets, [ - 150, 18190, 34163, 66150, 87453, 116853, 151413, 166833, 184123 - ]) - t.is(disc.releases.totalCount, 1) - t.is(disc.releases.edges.length, 1) - t.is(disc.releases.edges[0].node.mbid, '7f6d3088-837d-495e-905f-be5c70ac2d82') -}) +`, + (t, data) => { + const { disc } = data.lookup + t.is(disc.discID, 'TMXdzZkTcc9Jq24PD0w5J9_AXms-') + t.is(disc.offsetCount, 9) + t.is(disc.sectors, 193443) + t.deepEqual(disc.offsets, [ + 150, + 18190, + 34163, + 66150, + 87453, + 116853, + 151413, + 166833, + 184123 + ]) + t.is(disc.releases.totalCount, 1) + t.is(disc.releases.edges.length, 1) + t.is( + disc.releases.edges[0].node.mbid, + '7f6d3088-837d-495e-905f-be5c70ac2d82' + ) + } +) -test('release media has a list of discs', testData, ` +test( + 'release media has a list of discs', + testData, + ` { lookup { release(mbid: "7f6d3088-837d-495e-905f-be5c70ac2d82") { @@ -1051,13 +1260,18 @@ test('release media has a list of discs', testData, ` } } } -`, (t, data) => { - const { release } = data.lookup - t.is(release.media.length, 1) - t.is(release.media[0].discs.length, 2) -}) +`, + (t, data) => { + const { release } = data.lookup + t.is(release.media.length, 1) + t.is(release.media[0].discs.length, 2) + } +) -test('disc queries can be deeply nested', testData, ` +test( + 'disc queries can be deeply nested', + testData, + ` { lookup { disc(discID: "TMXdzZkTcc9Jq24PD0w5J9_AXms-") { @@ -1102,27 +1316,32 @@ test('disc queries can be deeply nested', testData, ` } } } -`, (t, data) => { - const { disc } = data.lookup - t.true(disc.releases.edges.length > 0) - disc.releases.edges.forEach(release => { - t.true(release.node.media.length > 0) - release.node.media.forEach(medium => { - t.true(medium.discs.length > 0) - medium.discs.forEach(disc => { - t.true(disc.releases.edges.length > 0) - disc.releases.edges.forEach(release => { - t.true(release.node.media.length > 0) - release.node.media.forEach(medium => { - t.true(medium.discs.length > 0) +`, + (t, data) => { + const { disc } = data.lookup + t.true(disc.releases.edges.length > 0) + disc.releases.edges.forEach(release => { + t.true(release.node.media.length > 0) + release.node.media.forEach(medium => { + t.true(medium.discs.length > 0) + medium.discs.forEach(disc => { + t.true(disc.releases.edges.length > 0) + disc.releases.edges.forEach(release => { + t.true(release.node.media.length > 0) + release.node.media.forEach(medium => { + t.true(medium.discs.length > 0) + }) }) }) }) }) - }) -}) + } +) -test('entities support tags', testData, ` +test( + 'entities support tags', + testData, + ` { lookup { label(mbid: "38dc88de-7720-4100-9d5b-3cdc41b0c474") { @@ -1153,11 +1372,13 @@ test('entities support tags', testData, ` } } } -`, (t, data) => { - const { label } = data.lookup - const artists = data.search.artists.edges.map(edge => edge.node) - t.true(label.tags.edges.some(edge => edge.node.name === 'indie folk')) - t.true(label.tags.edges.some(edge => edge.node.count > 0)) - t.true(artists[0].tags.edges.some(edge => edge.node.name === 'blues rock')) - t.true(artists[0].tags.edges.some(edge => edge.node.count > 0)) -}) +`, + (t, data) => { + const { label } = data.lookup + const artists = data.search.artists.edges.map(edge => edge.node) + t.true(label.tags.edges.some(edge => edge.node.name === 'indie folk')) + t.true(label.tags.edges.some(edge => edge.node.count > 0)) + t.true(artists[0].tags.edges.some(edge => edge.node.name === 'blues rock')) + t.true(artists[0].tags.edges.some(edge => edge.node.count > 0)) + } +) diff --git a/test/types/scalars.js b/test/types/scalars.js index a609341..84c5a1e 100644 --- a/test/types/scalars.js +++ b/test/types/scalars.js @@ -1,6 +1,12 @@ import test from 'ava' import { Kind } from 'graphql/language' -import { Duration, Locale, MBID, ISWC, URLString } from '../../src/types/scalars' +import { + Duration, + Locale, + MBID, + ISWC, + URLString +} from '../../src/types/scalars' test('Locale scalar allows language code', t => { t.is(Locale.parseLiteral({ kind: Kind.STRING, value: 'en' }), 'en') @@ -15,9 +21,18 @@ test('Locale scalar allows language and country code', t => { }) test('Locale scalar allows language, country, and encoding', t => { - t.is(Locale.parseLiteral({ kind: Kind.STRING, value: 'en_US.UTF-8' }), 'en_US.UTF-8') - t.is(Locale.parseLiteral({ kind: Kind.STRING, value: 'de_CH.utf8' }), 'de_CH.utf8') - t.is(Locale.parseLiteral({ kind: Kind.STRING, value: 'zh_TW.Big5' }), 'zh_TW.Big5') + t.is( + Locale.parseLiteral({ kind: Kind.STRING, value: 'en_US.UTF-8' }), + 'en_US.UTF-8' + ) + t.is( + Locale.parseLiteral({ kind: Kind.STRING, value: 'de_CH.utf8' }), + 'de_CH.utf8' + ) + t.is( + Locale.parseLiteral({ kind: Kind.STRING, value: 'zh_TW.Big5' }), + 'zh_TW.Big5' + ) }) test('Locale scalar only accepts strings', t => { @@ -26,16 +41,46 @@ test('Locale scalar only accepts strings', t => { }) test('Locale scalar rejects malformed locales', t => { - t.throws(() => Locale.parseLiteral({ kind: Kind.STRING, value: 'en_' }), TypeError) - t.throws(() => Locale.parseLiteral({ kind: Kind.STRING, value: 'en_USA' }), TypeError) - t.throws(() => Locale.parseLiteral({ kind: Kind.STRING, value: 'EN' }), TypeError) - t.throws(() => Locale.parseLiteral({ kind: Kind.STRING, value: 'en_us' }), TypeError) - t.throws(() => Locale.parseLiteral({ kind: Kind.STRING, value: 'en-US' }), TypeError) - t.throws(() => Locale.parseLiteral({ kind: Kind.STRING, value: 'en_US_foo' }), TypeError) - t.throws(() => Locale.parseLiteral({ kind: Kind.STRING, value: 'en_US-utf8' }), TypeError) - t.throws(() => Locale.parseLiteral({ kind: Kind.STRING, value: '12_US' }), TypeError) - t.throws(() => Locale.parseLiteral({ kind: Kind.STRING, value: 'en_US.' }), TypeError) - t.throws(() => Locale.parseLiteral({ kind: Kind.STRING, value: 'en_US.utf!' }), TypeError) + t.throws( + () => Locale.parseLiteral({ kind: Kind.STRING, value: 'en_' }), + TypeError + ) + t.throws( + () => Locale.parseLiteral({ kind: Kind.STRING, value: 'en_USA' }), + TypeError + ) + t.throws( + () => Locale.parseLiteral({ kind: Kind.STRING, value: 'EN' }), + TypeError + ) + t.throws( + () => Locale.parseLiteral({ kind: Kind.STRING, value: 'en_us' }), + TypeError + ) + t.throws( + () => Locale.parseLiteral({ kind: Kind.STRING, value: 'en-US' }), + TypeError + ) + t.throws( + () => Locale.parseLiteral({ kind: Kind.STRING, value: 'en_US_foo' }), + TypeError + ) + t.throws( + () => Locale.parseLiteral({ kind: Kind.STRING, value: 'en_US-utf8' }), + TypeError + ) + t.throws( + () => Locale.parseLiteral({ kind: Kind.STRING, value: '12_US' }), + TypeError + ) + t.throws( + () => Locale.parseLiteral({ kind: Kind.STRING, value: 'en_US.' }), + TypeError + ) + t.throws( + () => Locale.parseLiteral({ kind: Kind.STRING, value: 'en_US.utf!' }), + TypeError + ) }) test('Duration scalar must be a positive integer', t => { @@ -43,8 +88,14 @@ test('Duration scalar must be a positive integer', t => { t.is(Duration.parseLiteral({ kind: Kind.INT, value: 1 }), 1) t.is(Duration.parseLiteral({ kind: Kind.INT, value: 3000 }), 3000) t.is(Duration.parseLiteral({ kind: Kind.STRING, value: '1000' }), null) - t.throws(() => Duration.parseLiteral({ kind: Kind.INT, value: -1 }), TypeError) - t.throws(() => Duration.parseLiteral({ kind: Kind.INT, value: -1000 }), TypeError) + t.throws( + () => Duration.parseLiteral({ kind: Kind.INT, value: -1 }), + TypeError + ) + t.throws( + () => Duration.parseLiteral({ kind: Kind.INT, value: -1000 }), + TypeError + ) t.is(Duration.parseValue(0), 0) t.is(Duration.parseValue(1), 1) t.is(Duration.parseValue(3000), 3000) @@ -54,11 +105,29 @@ test('Duration scalar must be a positive integer', t => { test('URLString scalar must be a valid URL', t => { t.is(URLString.parseLiteral({ kind: Kind.INT, value: 1000 }), null) - t.is(URLString.parseLiteral({ kind: Kind.STRING, value: 'http://www.google.com' }), 'http://www.google.com') - t.throws(() => URLString.parseLiteral({ kind: Kind.STRING, value: 'foo:bar' }), TypeError) - t.throws(() => URLString.parseLiteral({ kind: Kind.STRING, value: 'foo:/bar' }), TypeError) - t.throws(() => URLString.parseLiteral({ kind: Kind.STRING, value: 'foo://bar' }), TypeError) - t.throws(() => URLString.parseLiteral({ kind: Kind.STRING, value: 'foo://bar.' }), TypeError) + t.is( + URLString.parseLiteral({ + kind: Kind.STRING, + value: 'http://www.google.com' + }), + 'http://www.google.com' + ) + t.throws( + () => URLString.parseLiteral({ kind: Kind.STRING, value: 'foo:bar' }), + TypeError + ) + t.throws( + () => URLString.parseLiteral({ kind: Kind.STRING, value: 'foo:/bar' }), + TypeError + ) + t.throws( + () => URLString.parseLiteral({ kind: Kind.STRING, value: 'foo://bar' }), + TypeError + ) + t.throws( + () => URLString.parseLiteral({ kind: Kind.STRING, value: 'foo://bar.' }), + TypeError + ) }) test('ISWC scalar only accepts strings', t => { @@ -79,6 +148,19 @@ test('MBID scalar only accepts strings', t => { }) test('MBID scalar must be a valid UUID', t => { - t.is(MBID.parseLiteral({ kind: Kind.STRING, value: 'c8da2e40-bd28-4d4e-813a-bd2f51958ba8' }), 'c8da2e40-bd28-4d4e-813a-bd2f51958ba8') - t.throws(() => MBID.parseLiteral({ kind: Kind.STRING, value: 'c8da2e40-bd28-4d4e-813a-bd2f51958bag' }), TypeError) + t.is( + MBID.parseLiteral({ + kind: Kind.STRING, + value: 'c8da2e40-bd28-4d4e-813a-bd2f51958ba8' + }), + 'c8da2e40-bd28-4d4e-813a-bd2f51958ba8' + ) + t.throws( + () => + MBID.parseLiteral({ + kind: Kind.STRING, + value: 'c8da2e40-bd28-4d4e-813a-bd2f51958bag' + }), + TypeError + ) }) diff --git a/test/util.js b/test/util.js index 0a95e69..ad47f69 100644 --- a/test/util.js +++ b/test/util.js @@ -2,8 +2,12 @@ import test from 'ava' import sinon from 'sinon' import { prettyPrint } from '../src/util' -test.beforeEach(t => { sinon.stub(console, 'log') }) -test.afterEach(t => { console.log.restore() }) +test.beforeEach(t => { + sinon.stub(console, 'log') +}) +test.afterEach(t => { + console.log.restore() +}) test('prettyPrint writes to stdout', t => { prettyPrint('foo') diff --git a/yarn.lock b/yarn.lock index 5c30dd7..73e1aec 100644 --- a/yarn.lock +++ b/yarn.lock @@ -72,20 +72,13 @@ acorn@^3.0.4: version "3.3.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" -acorn@^5.0.1: - version "5.0.3" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.0.3.tgz#c460df08491463f028ccb82eab3730bf01087b3d" +acorn@^5.1.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.2.1.tgz#317ac7821826c22c702d66189ab8359675f135d7" -ajv-keywords@^1.0.0: - version "1.5.1" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" - -ajv@^4.7.0: - version "4.11.8" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" - dependencies: - co "^4.6.0" - json-stable-stringify "^1.0.1" +ajv-keywords@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762" ajv@^5.1.0: version "5.2.3" @@ -96,6 +89,15 @@ ajv@^5.1.0: json-schema-traverse "^0.3.0" json-stable-stringify "^1.0.1" +ajv@^5.2.0, ajv@^5.2.3: + version "5.3.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.3.0.tgz#4414ff74a50879c208ee5fdc826e32c303549eda" + dependencies: + co "^4.6.0" + fast-deep-equal "^1.0.0" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.3.0" + align-text@^0.1.1, align-text@^0.1.3: version "0.1.4" resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" @@ -120,14 +122,14 @@ ansi-align@^2.0.0: dependencies: string-width "^2.0.0" -ansi-escapes@^1.1.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" - ansi-escapes@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-2.0.0.tgz#5bae52be424878dd9783e8910e3fc2922e83c81b" +ansi-escapes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.0.0.tgz#ec3e8b4e9f8064fc02c3ac9b65f1c275bda8ef92" + ansi-regex@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" @@ -228,13 +230,6 @@ array-unique@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" -array.prototype.find@^2.0.1: - version "2.0.4" - resolved "https://registry.yarnpkg.com/array.prototype.find/-/array.prototype.find-2.0.4.tgz#556a5c5362c08648323ddaeb9de9d14bc1864c90" - dependencies: - define-properties "^1.1.2" - es-abstract "^1.7.0" - arrify@^1.0.0, arrify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" @@ -395,7 +390,7 @@ babel-code-frame@7.0.0-beta.0: esutils "^2.0.2" js-tokens "^3.0.0" -babel-code-frame@^6.16.0, babel-code-frame@^6.22.0: +babel-code-frame@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4" dependencies: @@ -1340,6 +1335,14 @@ chalk@^2.0.0, chalk@^2.0.1: escape-string-regexp "^1.0.5" supports-color "^4.0.0" +chalk@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.0.tgz#b5ea48efc9c1793dccc9b4767c93914d3f2d52ba" + dependencies: + ansi-styles "^3.1.0" + escape-string-regexp "^1.0.5" + supports-color "^4.0.0" + character-entities-html4@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/character-entities-html4/-/character-entities-html4-1.1.0.tgz#1ab08551d3ce1fa1df08d00fb9ca1defb147a06c" @@ -1376,8 +1379,8 @@ ci-info@^1.0.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.0.0.tgz#dc5285f2b4e251821683681c381c3388f46ec534" circular-json@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.1.tgz#be8b36aefccde8b3ca7aa2d6afc07a37242c0d2d" + version "0.3.3" + resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" clean-stack@^1.1.1: version "1.3.0" @@ -1391,12 +1394,6 @@ cli-boxes@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143" -cli-cursor@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" - dependencies: - restore-cursor "^1.0.1" - cli-cursor@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" @@ -1415,8 +1412,8 @@ cli-truncate@^1.0.0: string-width "^2.0.0" cli-width@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a" + version "2.2.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" cliui@^2.1.0: version "2.1.0" @@ -1512,7 +1509,7 @@ concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" -concat-stream@^1.5.0, concat-stream@^1.5.2: +concat-stream@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" dependencies: @@ -1670,12 +1667,6 @@ currently-unhandled@^0.4.1: dependencies: array-find-index "^1.0.1" -d@1: - version "1.0.0" - resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" - dependencies: - es5-ext "^0.10.9" - dashdash@^1.12.0: version "1.14.1" resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" @@ -1700,16 +1691,10 @@ date-time@^2.1.0: dependencies: time-zone "^1.0.0" -debug-log@^1.0.0, debug-log@^1.0.1: +debug-log@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/debug-log/-/debug-log-1.0.1.tgz#2307632d4c04382b8df8a32f70b895046d52745f" -debug@2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" - dependencies: - ms "0.7.1" - debug@2.6.9, debug@^2.6.8: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -1754,24 +1739,6 @@ default-require-extensions@^1.0.0: dependencies: strip-bom "^2.0.0" -define-properties@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" - dependencies: - foreach "^2.0.5" - object-keys "^1.0.8" - -deglob@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/deglob/-/deglob-2.1.0.tgz#4d44abe16ef32c779b4972bd141a80325029a14a" - dependencies: - find-root "^1.0.0" - glob "^7.0.5" - ignore "^3.0.9" - pkg-config "^1.1.0" - run-parallel "^1.1.2" - uniq "^1.0.1" - del@^2.0.2: version "2.2.2" resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" @@ -1829,7 +1796,7 @@ doctoc@^1.3.0: underscore "~1.8.3" update-section "^0.3.0" -doctrine@1.5.0, doctrine@^1.2.2: +doctrine@1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" dependencies: @@ -1934,83 +1901,14 @@ error-ex@^1.2.0: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.7.0.tgz#dfade774e01bfcd97f96180298c449c8623fb94c" - dependencies: - es-to-primitive "^1.1.1" - function-bind "^1.1.0" - is-callable "^1.1.3" - is-regex "^1.0.3" - -es-to-primitive@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.1.1.tgz#45355248a88979034b6792e19bb81f2b7975dd0d" - dependencies: - is-callable "^1.1.1" - is-date-object "^1.0.1" - is-symbol "^1.0.1" - -es5-ext@^0.10.14, es5-ext@^0.10.9, es5-ext@~0.10.14: - version "0.10.21" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.21.tgz#19a725f9e51d0300bbc1e8e821109fd9daf55925" - dependencies: - es6-iterator "2" - es6-symbol "~3.1" - es6-error@^4.0.1, es6-error@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.0.2.tgz#eec5c726eacef51b7f6b73c20db6e1b13b069c98" -es6-iterator@2, es6-iterator@^2.0.1, es6-iterator@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.1.tgz#8e319c9f0453bf575d374940a655920e59ca5512" - dependencies: - d "1" - es5-ext "^0.10.14" - es6-symbol "^3.1" - -es6-map@^0.1.3: - version "0.1.5" - resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0" - dependencies: - d "1" - es5-ext "~0.10.14" - es6-iterator "~2.0.1" - es6-set "~0.1.5" - es6-symbol "~3.1.1" - event-emitter "~0.3.5" - es6-promise@^3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.3.1.tgz#a08cdde84ccdbf34d027a1451bc91d4bcd28a613" -es6-set@~0.1.5: - version "0.1.5" - resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" - dependencies: - d "1" - es5-ext "~0.10.14" - es6-iterator "~2.0.1" - es6-symbol "3.1.1" - event-emitter "~0.3.5" - -es6-symbol@3.1.1, es6-symbol@^3.1, es6-symbol@^3.1.1, es6-symbol@~3.1, es6-symbol@~3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" - dependencies: - d "1" - es5-ext "~0.10.14" - -es6-weak-map@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.2.tgz#5e3ab32251ffd1538a1f8e5ffa1357772f92d96f" - dependencies: - d "1" - es5-ext "^0.10.14" - es6-iterator "^2.0.1" - es6-symbol "^3.1.1" - escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" @@ -2019,52 +1917,44 @@ escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.4, escape-string-regexp@^ version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" -escope@^3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" +eslint-config-prettier@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-2.7.0.tgz#7bbfef66ad783277836f4ea556e68b9bcc9da4d0" dependencies: - es6-map "^0.1.3" - es6-weak-map "^2.0.1" - esrecurse "^4.1.0" - estraverse "^4.1.1" + get-stdin "^5.0.1" -eslint-config-standard-jsx@4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/eslint-config-standard-jsx/-/eslint-config-standard-jsx-4.0.2.tgz#009e53c4ddb1e9ee70b4650ffe63a7f39f8836e1" - -eslint-config-standard@10.2.1: +eslint-config-standard@^10.2.1: version "10.2.1" resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-10.2.1.tgz#c061e4d066f379dc17cd562c64e819b4dd454591" -eslint-import-resolver-node@^0.2.0: - version "0.2.3" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.2.3.tgz#5add8106e8c928db2cba232bcd9efa846e3da16c" +eslint-import-resolver-node@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.1.tgz#4422574cde66a9a7b099938ee4d508a199e0e3cc" dependencies: - debug "^2.2.0" - object-assign "^4.0.1" - resolve "^1.1.6" + debug "^2.6.8" + resolve "^1.2.0" -eslint-module-utils@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.0.0.tgz#a6f8c21d901358759cdc35dbac1982ae1ee58bce" +eslint-module-utils@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.1.1.tgz#abaec824177613b8a95b299639e1b6facf473449" dependencies: - debug "2.2.0" + debug "^2.6.8" pkg-dir "^1.0.0" -eslint-plugin-import@~2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.2.0.tgz#72ba306fad305d67c4816348a4699a4229ac8b4e" +eslint-plugin-import@^2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.8.0.tgz#fa1b6ef31fcb3c501c09859c1b86f1fc5b986894" dependencies: builtin-modules "^1.1.1" contains-path "^0.1.0" - debug "^2.2.0" + debug "^2.6.8" doctrine "1.5.0" - eslint-import-resolver-node "^0.2.0" - eslint-module-utils "^2.0.0" + eslint-import-resolver-node "^0.3.1" + eslint-module-utils "^2.1.1" has "^1.0.1" lodash.cond "^4.3.0" minimatch "^3.0.3" - pkg-up "^1.0.0" + read-pkg-up "^2.0.0" eslint-plugin-markdown@^1.0.0-beta.6: version "1.0.0-beta.6" @@ -2074,73 +1964,78 @@ eslint-plugin-markdown@^1.0.0-beta.6: remark-parse "^3.0.0" unified "^6.1.2" -eslint-plugin-node@~4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-4.2.2.tgz#82959ca9aed79fcbd28bb1b188d05cac04fb3363" +eslint-plugin-node@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-5.2.1.tgz#80df3253c4d7901045ec87fa660a284e32bdca29" dependencies: - ignore "^3.0.11" - minimatch "^3.0.2" - object-assign "^4.0.1" - resolve "^1.1.7" + ignore "^3.3.6" + minimatch "^3.0.4" + resolve "^1.3.3" semver "5.3.0" -eslint-plugin-promise@~3.5.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-3.5.0.tgz#78fbb6ffe047201627569e85a6c5373af2a68fca" - -eslint-plugin-react@~6.10.0: - version "6.10.3" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-6.10.3.tgz#c5435beb06774e12c7db2f6abaddcbf900cd3f78" +eslint-plugin-prettier@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-2.3.1.tgz#e7a746c67e716f335274b88295a9ead9f544e44d" dependencies: - array.prototype.find "^2.0.1" - doctrine "^1.2.2" - has "^1.0.1" - jsx-ast-utils "^1.3.4" - object.assign "^4.0.4" + fast-diff "^1.1.1" + jest-docblock "^21.0.0" -eslint-plugin-standard@~3.0.1: +eslint-plugin-promise@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-3.6.0.tgz#54b7658c8f454813dc2a870aff8152ec4969ba75" + +eslint-plugin-standard@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-3.0.1.tgz#34d0c915b45edc6f010393c7eef3823b08565cf2" -eslint@~3.19.0: - version "3.19.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-3.19.0.tgz#c8fc6201c7f40dd08941b87c085767386a679acc" +eslint-scope@^3.7.1: + version "3.7.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8" dependencies: - babel-code-frame "^6.16.0" - chalk "^1.1.3" - concat-stream "^1.5.2" - debug "^2.1.1" + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint@^4.10.0: + version "4.10.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.10.0.tgz#f25d0d7955c81968c2309aa5c9a229e045176bb7" + dependencies: + 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" - escope "^3.6.0" - espree "^3.4.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" - glob "^7.0.3" - globals "^9.14.0" - ignore "^3.2.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 "^0.12.0" - is-my-json-valid "^2.10.0" + inquirer "^3.0.6" is-resolvable "^1.0.0" - js-yaml "^3.5.1" - json-stable-stringify "^1.0.0" + js-yaml "^3.9.1" + json-stable-stringify "^1.0.1" levn "^0.3.0" - lodash "^4.0.0" - mkdirp "^0.5.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.1" - pluralize "^1.2.1" - progress "^1.1.8" - require-uncached "^1.0.2" - shelljs "^0.7.5" - strip-bom "^3.0.0" + 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 "^3.7.8" + table "^4.0.1" text-table "~0.2.0" - user-home "^2.0.0" espower-location-detector@^1.0.0: version "1.0.0" @@ -2151,11 +2046,11 @@ espower-location-detector@^1.0.0: source-map "^0.5.0" xtend "^4.0.0" -espree@^3.4.0: - version "3.4.3" - resolved "https://registry.yarnpkg.com/espree/-/espree-3.4.3.tgz#2910b5ccd49ce893c2ffffaab4fd8b3a31b82374" +espree@^3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.1.tgz#0c988b8ab46db53100a1954ae4ba995ddd27d87e" dependencies: - acorn "^5.0.1" + acorn "^5.1.1" acorn-jsx "^3.0.0" esprima@^3.1.1: @@ -2179,20 +2074,16 @@ esquery@^1.0.0: estraverse "^4.0.0" esrecurse@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.1.0.tgz#4713b6536adf7f2ac4f327d559e7756bff648220" + version "4.2.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.0.tgz#fa9568d98d3823f9a41d91e902dcab9ea6e5b163" dependencies: - estraverse "~4.1.0" + estraverse "^4.1.0" object-assign "^4.0.1" -estraverse@^4.0.0, estraverse@^4.1.1, estraverse@^4.2.0: +estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" -estraverse@~4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.1.1.tgz#f6caca728933a850ef90661d0e17982ba47111a2" - esutils@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" @@ -2201,13 +2092,6 @@ etag@~1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" -event-emitter@~0.3.5: - version "0.3.5" - resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" - dependencies: - d "1" - es5-ext "~0.10.14" - event-stream@~3.3.0: version "3.3.4" resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571" @@ -2255,10 +2139,6 @@ execa@^0.7.0: signal-exit "^3.0.0" strip-eof "^1.0.0" -exit-hook@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" - expand-brackets@^0.1.4: version "0.1.5" resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" @@ -2319,6 +2199,14 @@ extend@^3.0.0, extend@~3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" +external-editor@^2.0.4: + version "2.0.5" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.0.5.tgz#52c249a3981b9ba187c7cacf5beb50bf1d91a6bc" + dependencies: + iconv-lite "^0.4.17" + jschardet "^1.4.2" + tmp "^0.0.33" + extglob@^0.3.1: version "0.3.2" resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" @@ -2337,17 +2225,14 @@ fast-diff@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.1.1.tgz#0aea0e4e605b6a2189f0e936d4b7fbaf1b7cfd9b" +fast-json-stable-stringify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + fast-levenshtein@~2.0.4: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" -figures@^1.3.5: - version "1.7.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" - dependencies: - escape-string-regexp "^1.0.5" - object-assign "^4.1.0" - figures@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" @@ -2403,10 +2288,6 @@ find-cache-dir@^1.0.0: make-dir "^1.0.0" pkg-dir "^2.0.0" -find-root@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.0.0.tgz#962ff211aab25c6520feeeb8d6287f8f6e95807a" - find-up@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" @@ -2421,8 +2302,8 @@ find-up@^2.0.0, find-up@^2.1.0: locate-path "^2.0.0" flat-cache@^1.2.1: - version "1.2.2" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.2.2.tgz#fa86714e72c21db88601761ecf2f555d1abc6b96" + version "1.3.0" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.3.0.tgz#d3030b32b38154f4e3b7e9c709f490f7ef97c481" dependencies: circular-json "^0.3.1" del "^2.0.2" @@ -2443,10 +2324,6 @@ for-own@^0.1.4: dependencies: for-in "^1.0.1" -foreach@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" - foreground-child@^1.5.3, foreground-child@^1.5.6: version "1.5.6" resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-1.5.6.tgz#4fd71ad2dfde96789b980a5c0a295937cb2f5ce9" @@ -2516,7 +2393,7 @@ fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2: mkdirp ">=0.5 0" rimraf "2" -function-bind@^1.0.2, function-bind@^1.1.0: +function-bind@^1.0.2: version "1.1.0" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.0.tgz#16176714c801798e4e8f2cf7f7529467bb4a5771" @@ -2524,6 +2401,10 @@ function-name-support@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/function-name-support/-/function-name-support-0.2.0.tgz#55d3bfaa6eafd505a50f9bc81fdf57564a0bb071" +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + gauge@~2.7.3: version "2.7.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" @@ -2537,16 +2418,6 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" -generate-function@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" - -generate-object-property@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" - dependencies: - is-property "^1.0.0" - get-caller-file@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" @@ -2593,7 +2464,7 @@ glob-parent@^2.0.0: dependencies: is-glob "^2.0.0" -glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.2: +glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.2: version "7.1.2" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" dependencies: @@ -2614,11 +2485,11 @@ globals@^10.0.0: version "10.1.0" resolved "https://registry.yarnpkg.com/globals/-/globals-10.1.0.tgz#4425a1881be0d336b4a823a82a7be725d5dd987c" -globals@^9.0.0, globals@^9.14.0: +globals@^9.0.0: version "9.17.0" resolved "https://registry.yarnpkg.com/globals/-/globals-9.17.0.tgz#0c0ca696d9b9bb694d2e5470bd37777caad50286" -globals@^9.18.0: +globals@^9.17.0, globals@^9.18.0: version "9.18.0" resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" @@ -2828,7 +2699,7 @@ iconv-lite@0.4.15, iconv-lite@~0.4.13: version "0.4.15" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" -iconv-lite@0.4.19: +iconv-lite@0.4.19, iconv-lite@^0.4.17: version "0.4.19" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" @@ -2836,9 +2707,9 @@ ignore-by-default@^1.0.0, ignore-by-default@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" -ignore@^3.0.11, ignore@^3.0.9, ignore@^3.2.0: - version "3.3.3" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.3.tgz#432352e57accd87ab3110e82d3fea0e47812156d" +ignore@^3.3.3, ignore@^3.3.6: + version "3.3.7" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.7.tgz#612289bfb3c220e186a58118618d5be8c1bab021" import-lazy@^2.1.0: version "2.1.0" @@ -2872,7 +2743,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1: +inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" @@ -2880,28 +2751,25 @@ ini@^1.3.4, ini@~1.3.0: version "1.3.4" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" -inquirer@^0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" +inquirer@^3.0.6: + version "3.3.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" dependencies: - ansi-escapes "^1.1.0" - ansi-regex "^2.0.0" - chalk "^1.0.0" - cli-cursor "^1.0.1" + ansi-escapes "^3.0.0" + chalk "^2.0.0" + cli-cursor "^2.1.0" cli-width "^2.0.0" - figures "^1.3.5" + external-editor "^2.0.4" + figures "^2.0.0" lodash "^4.3.0" - readline2 "^1.0.1" - run-async "^0.1.0" - rx-lite "^3.1.2" - string-width "^1.0.1" - strip-ansi "^3.0.0" + mute-stream "0.0.7" + 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" -interpret@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.3.tgz#cbc35c62eeee73f19ab7b10a801511401afc0f90" - invariant@^2.2.0, invariant@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" @@ -2951,20 +2819,12 @@ is-builtin-module@^1.0.0: dependencies: builtin-modules "^1.0.0" -is-callable@^1.1.1, is-callable@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.3.tgz#86eb75392805ddc33af71c92a0eedf74ee7604b2" - is-ci@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.0.10.tgz#f739336b2632365061a9d48270cd56ae3369318e" dependencies: ci-info "^1.0.0" -is-date-object@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" - is-decimal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-1.0.0.tgz#940579b6ea63c628080a69e62bda88c8470b4fe0" @@ -3028,15 +2888,6 @@ is-installed-globally@^0.1.0: global-dirs "^0.1.0" is-path-inside "^1.0.0" -is-my-json-valid@^2.10.0: - version "2.16.0" - resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz#f079dd9bfdae65ee2038aae8acbc86ab109e3693" - dependencies: - generate-function "^2.0.0" - generate-object-property "^1.1.0" - jsonpointer "^4.0.0" - xtend "^4.0.0" - is-npm@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4" @@ -3089,20 +2940,10 @@ is-promise@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" -is-property@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" - is-redirect@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" -is-regex@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" - dependencies: - has "^1.0.1" - is-resolvable@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62" @@ -3117,10 +2958,6 @@ is-stream@^1.0.0, is-stream@^1.0.1, is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" -is-symbol@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572" - is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" @@ -3218,6 +3055,10 @@ iterall@1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.1.3.tgz#1cbbff96204056dde6656e2ed2e2226d0e6d72c9" +jest-docblock@^21.0.0: + version "21.2.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-21.2.0.tgz#51529c3b30d5fd159da60c27ceedc195faf8d414" + jodid25519@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967" @@ -3236,24 +3077,28 @@ js-tokens@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" -js-yaml@^3.5.1, js-yaml@^3.8.2: - version "3.8.4" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.8.4.tgz#520b4564f86573ba96662af85a8cafa7b4b5a6f6" - dependencies: - argparse "^1.0.7" - esprima "^3.1.1" - -js-yaml@^3.6.1: +js-yaml@^3.6.1, js-yaml@^3.9.1: version "3.10.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.10.0.tgz#2e78441646bd4682e963f22b6e92823c309c62dc" dependencies: argparse "^1.0.7" esprima "^4.0.0" +js-yaml@^3.8.2: + version "3.8.4" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.8.4.tgz#520b4564f86573ba96662af85a8cafa7b4b5a6f6" + dependencies: + argparse "^1.0.7" + esprima "^3.1.1" + jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" +jschardet@^1.4.2: + version "1.6.0" + resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-1.6.0.tgz#c7d1a71edcff2839db2f9ec30fc5d5ebd3c1a678" + jsesc@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" @@ -3270,7 +3115,7 @@ json-schema@0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" -json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: +json-stable-stringify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" dependencies: @@ -3288,10 +3133,6 @@ jsonify@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" -jsonpointer@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" - jsprim@^1.2.2: version "1.4.0" resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.0.tgz#a3b87e40298d8c380552d8cc7628a0bb95a22918" @@ -3301,10 +3142,6 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.3.6" -jsx-ast-utils@^1.3.4: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz#3867213e8dd79bf1e8f2300c0cfc1efb182c0df1" - just-extend@^1.1.26: version "1.1.27" resolved "https://registry.yarnpkg.com/just-extend/-/just-extend-1.1.27.tgz#ec6e79410ff914e472652abfa0e603c03d60e905" @@ -3484,7 +3321,7 @@ lodash.restparam@^3.0.0: version "3.6.1" resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" -lodash@^4.0.0, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.3.0: +lodash@^4.17.4, lodash@^4.2.0, lodash@^4.3.0: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" @@ -3691,7 +3528,7 @@ minimist@0.0.8, minimist@~0.0.1: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" -minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@~1.2.0: +minimist@^1.1.3, minimist@^1.2.0, minimist@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" @@ -3701,10 +3538,6 @@ minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@~1. dependencies: minimist "0.0.8" -ms@0.7.1: - version "0.7.1" - resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" - ms@2.0.0, ms@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -3718,9 +3551,9 @@ multimatch@^2.1.0: arrify "^1.0.0" minimatch "^3.0.0" -mute-stream@0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" +mute-stream@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" nan@^2.3.0: version "2.6.2" @@ -3873,18 +3706,6 @@ object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" -object-keys@^1.0.10, object-keys@^1.0.8: - version "1.0.11" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d" - -object.assign@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.0.4.tgz#b1c9cc044ef1b9fe63606fc141abbb32e14730cc" - dependencies: - define-properties "^1.1.2" - function-bind "^1.1.0" - object-keys "^1.0.10" - object.omit@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" @@ -3915,10 +3736,6 @@ once@^1.3.0, once@^1.3.3: dependencies: wrappy "1" -onetime@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" - onetime@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" @@ -3959,7 +3776,7 @@ os-locale@^2.0.0: lcid "^1.0.0" mem "^1.1.0" -os-tmpdir@^1.0.0, os-tmpdir@^1.0.1: +os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" @@ -4073,7 +3890,7 @@ path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" -path-is-inside@^1.0.1: +path-is-inside@^1.0.1, path-is-inside@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" @@ -4154,14 +3971,6 @@ pkg-conf@^2.0.0: find-up "^2.0.0" load-json-file "^2.0.0" -pkg-config@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/pkg-config/-/pkg-config-1.1.1.tgz#557ef22d73da3c8837107766c52eadabde298fe4" - dependencies: - debug-log "^1.0.0" - find-root "^1.0.0" - xtend "^4.0.1" - pkg-dir@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4" @@ -4174,21 +3983,15 @@ pkg-dir@^2.0.0: dependencies: find-up "^2.1.0" -pkg-up@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-1.0.0.tgz#3e08fb461525c4421624a33b9f7e6d0af5b05a26" - dependencies: - find-up "^1.0.0" - plur@^2.0.0, plur@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/plur/-/plur-2.1.2.tgz#7482452c1a0f508e3e344eaec312c91c29dc655a" dependencies: irregular-plurals "^1.0.0" -pluralize@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" +pluralize@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" postinstall-build@^5.0.1: version "5.0.1" @@ -4206,6 +4009,10 @@ preserve@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" +prettier@^1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.8.0.tgz#d9dc68277cf1ded816c8e8863ab47889c29ce9a6" + pretty-ms@^0.2.1: version "0.2.2" resolved "https://registry.yarnpkg.com/pretty-ms/-/pretty-ms-0.2.2.tgz#da879a682ff33a37011046f13d627f67c73b84f6" @@ -4227,9 +4034,9 @@ process-nextick-args@~1.0.6: version "1.0.7" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" -progress@^1.1.8: - version "1.1.8" - resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" +progress@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f" proxy-addr@~2.0.2: version "2.0.2" @@ -4323,7 +4130,7 @@ read-pkg@^2.0.0: normalize-package-data "^2.3.2" path-type "^2.0.0" -readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.1.5, readable-stream@^2.2.2: +readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.1.5: version "2.2.9" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.9.tgz#cf78ec6f4a6d1eb43d26488cac97f042e74b7fc8" dependencies: @@ -4335,6 +4142,18 @@ readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.4, readable string_decoder "~1.0.0" util-deprecate "~1.0.1" +readable-stream@^2.2.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" + dependencies: + 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" + readdirp@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" @@ -4344,20 +4163,6 @@ readdirp@^2.0.0: readable-stream "^2.0.2" set-immediate-shim "^1.0.1" -readline2@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - mute-stream "0.0.5" - -rechoir@^0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" - dependencies: - resolve "^1.1.6" - redent@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" @@ -4546,7 +4351,7 @@ require-precompiled@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/require-precompiled/-/require-precompiled-0.1.0.tgz#5a1b52eb70ebed43eb982e974c85ab59571e56fa" -require-uncached@^1.0.2: +require-uncached@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" dependencies: @@ -4575,19 +4380,12 @@ resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" -resolve@^1.1.6, resolve@^1.1.7: - version "1.3.3" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.3.3.tgz#655907c3469a8680dc2de3a275a8fdd69691f0e5" +resolve@^1.2.0, resolve@^1.3.3: + version "1.5.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36" dependencies: path-parse "^1.0.5" -restore-cursor@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" - dependencies: - exit-hook "^1.0.0" - onetime "^1.0.0" - restore-cursor@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" @@ -4605,33 +4403,35 @@ right-align@^0.1.1: dependencies: align-text "^0.1.1" -rimraf@2, rimraf@^2.2.8, rimraf@^2.3.3, rimraf@^2.5.1, rimraf@^2.5.4: +rimraf@2, rimraf@^2.3.3, rimraf@^2.5.1, rimraf@^2.5.4: version "2.6.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d" dependencies: glob "^7.0.5" -rimraf@^2.6.1: +rimraf@^2.2.8, rimraf@^2.6.1: version "2.6.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" dependencies: glob "^7.0.5" -run-async@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" +run-async@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" dependencies: - once "^1.3.0" + is-promise "^2.1.0" -run-parallel@^1.1.2: - version "1.1.6" - resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.6.tgz#29003c9a2163e01e2d2dfc90575f2c6c1d61a039" +rx-lite-aggregates@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" + dependencies: + rx-lite "*" -rx-lite@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" +rx-lite@*, rx-lite@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" -safe-buffer@5.1.1, safe-buffer@^5.1.1: +safe-buffer@5.1.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" @@ -4712,14 +4512,6 @@ shebang-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" -shelljs@^0.7.5: - version "0.7.7" - resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.7.tgz#b2f5c77ef97148f4b4f6e22682e10bba8667cff1" - dependencies: - glob "^7.0.0" - interpret "^1.0.0" - rechoir "^0.6.2" - signal-exit@^3.0.0, signal-exit@^3.0.1, signal-exit@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" @@ -4744,21 +4536,16 @@ slice-ansi@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" +slice-ansi@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-1.0.0.tgz#044f1a49d8842ff307aad6b505ed178bd950134d" + dependencies: + is-fullwidth-code-point "^2.0.0" + slide@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" -snazzy@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/snazzy/-/snazzy-7.0.0.tgz#95edaccc4a8d6f80f4ac5cc7b520e8f8f9ac2325" - dependencies: - chalk "^1.1.0" - inherits "^2.0.1" - minimist "^1.1.1" - readable-stream "^2.0.6" - standard-json "^1.0.0" - text-table "^0.2.0" - sntp@2.x.x: version "2.0.2" resolved "https://registry.yarnpkg.com/sntp/-/sntp-2.0.2.tgz#5064110f0af85f7cfdb7d6b67a40028ce52b4b2b" @@ -4847,35 +4634,6 @@ stack-utils@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.1.tgz#d4f33ab54e8e38778b0ca5cfd3b3afb12db68620" -standard-engine@~7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/standard-engine/-/standard-engine-7.0.0.tgz#ebb77b9c8fc2c8165ffa353bd91ba0dff41af690" - dependencies: - deglob "^2.1.0" - get-stdin "^5.0.1" - minimist "^1.1.0" - pkg-conf "^2.0.0" - -standard-json@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/standard-json/-/standard-json-1.0.2.tgz#82dea4a14c78cd9e35d38cde4b88ac6b62596a23" - dependencies: - concat-stream "^1.5.0" - -standard@^10.0.3: - version "10.0.3" - resolved "https://registry.yarnpkg.com/standard/-/standard-10.0.3.tgz#7869bcbf422bdeeaab689a1ffb1fea9677dd50ea" - dependencies: - eslint "~3.19.0" - eslint-config-standard "10.2.1" - eslint-config-standard-jsx "4.0.2" - eslint-plugin-import "~2.2.0" - eslint-plugin-node "~4.2.2" - eslint-plugin-promise "~3.5.0" - eslint-plugin-react "~6.10.0" - eslint-plugin-standard "~3.0.1" - standard-engine "~7.0.0" - state-toggle@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/state-toggle/-/state-toggle-1.0.0.tgz#d20f9a616bb4f0c3b98b91922d25b640aa2bc425" @@ -4905,12 +4663,25 @@ string-width@^2.0.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^3.0.0" +string-width@^2.1.0, string-width@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + string_decoder@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.1.tgz#62e200f039955a6810d8df0a33ffc0f013662d98" dependencies: safe-buffer "^5.0.1" +string_decoder@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" + dependencies: + safe-buffer "~5.1.0" + stringify-entities@^1.0.1: version "1.3.0" resolved "https://registry.yarnpkg.com/stringify-entities/-/stringify-entities-1.3.0.tgz#2244a516c4f1e8e01b73dad01023016776abd917" @@ -5007,16 +4778,16 @@ symbol-observable@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.4.tgz#29bf615d4aa7121bdd898b22d4b3f9bc4e2aa03d" -table@^3.7.8: - version "3.8.3" - resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f" +table@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/table/-/table-4.0.2.tgz#a33447375391e766ad34d3486e6e2aedc84d2e36" dependencies: - ajv "^4.7.0" - ajv-keywords "^1.0.0" - chalk "^1.1.1" - lodash "^4.0.0" - slice-ansi "0.0.4" - string-width "^2.0.0" + 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" tar-pack@^3.4.0: version "3.4.0" @@ -5097,6 +4868,12 @@ timed-out@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + dependencies: + os-tmpdir "~1.0.2" + to-fast-properties@^1.0.1, to-fast-properties@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" @@ -5239,10 +5016,6 @@ unified@^6.1.2: x-is-function "^1.0.4" x-is-string "^0.1.0" -uniq@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" - unique-string@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a" @@ -5320,12 +5093,6 @@ user-home@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" -user-home@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" - dependencies: - os-homedir "^1.0.0" - util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"