diff --git a/documentation.md b/documentation.md index 01a2e94..07ee11a 100644 --- a/documentation.md +++ b/documentation.md @@ -272,9 +272,10 @@ gtt report --output=markdown gtt report --output=csv gtt report --output=pdf --file=filename.pdf gtt report --output=xlsx --file=filename.xlsx +gtt report --output=sqlite --file=filename.sqlite ``` -Defaults to `table`. `csv` and `markdown` can be printed to stdout, `pdf` and `xlsx` need the file parameter. +Defaults to `table`. `csv` and `markdown` can be printed to stdout, `pdf`, `xlsx` and `sqlite` need the file parameter. #### Print the output to a file @@ -589,7 +590,7 @@ timeFormat: timezone: "Europe/Berlin" # Output type -# Available: csv, table, markdown, pdf, xlsx +# Available: csv, table, markdown, pdf, xlsx, sqlite # defaults to table output: markdown diff --git a/package.json b/package.json index 8dc55e8..6c44901 100755 --- a/package.json +++ b/package.json @@ -56,6 +56,7 @@ "request": "^2.87.0", "request-promise-native": "^1.0.4", "shelljs": "^0.8.3", + "sqlite3": "^4.0.6", "tempfile": "^2.0.0", "underscore": "^1.9.1", "xdg-basedir": "^3.0.0", diff --git a/src/gtt-report.js b/src/gtt-report.js index fac46da..b84192e 100755 --- a/src/gtt-report.js +++ b/src/gtt-report.js @@ -15,7 +15,8 @@ const Output = { pdf: require('./output/pdf'), markdown: require('./output/markdown'), dump: require('./output/dump'), - xlsx: require('./output/xlsx') + xlsx: require('./output/xlsx'), + sqlite: require('./output/sqlite') }; // this collects options @@ -181,6 +182,10 @@ if (config.get('output') === 'xlsx' && !config.get('file')) { Cli.error(`Cannot output an xlsx to stdout. You probably forgot to use the --file parameter`); } +if (config.get('output') === 'sqlite' && !config.get('file')) { + Cli.error(`Cannot output an sqlite to stdout. You probably forgot to use the --file parameter`); +} + // file prompt new Promise(resolve => { if (config.get('file') && fs.existsSync(config.get('file'))) { diff --git a/src/output/sqlite.js b/src/output/sqlite.js new file mode 100755 index 0000000..d4303d1 --- /dev/null +++ b/src/output/sqlite.js @@ -0,0 +1,429 @@ +const _ = require('underscore'); +const fs = require('fs'); +const path = require('path'); +const sqlite3 = require('sqlite3').verbose(); + +const Base = require('./base'); +const Cli = require('./../include/cli'); + + +/* + * Constants + */ +const TABLE_ISSUES = 'issues'; +const TABLE_MERGE_REQUESTS = 'merge_requests'; +const TABLE_TIMES = 'times'; +const TABLE_LABELS = 'labels'; +const TABLE_LABEL_GROUP = 'label_groups'; +const TABLE_MILESTONES = 'milestones'; + +const COLUMNS = { + [TABLE_ISSUES]: 'issueColumns', + [TABLE_MERGE_REQUESTS]: 'mergeRequestColumns', + [TABLE_TIMES]: 'recordColumns' +}; + + +/** + * Returns the SQLite type for a specific column name. + * Note that this is a general mapper, i.e. there is no distinction between table differences. + * + * @param columnName + * @returns {string} + */ +function getGeneralColumnType(columnName) { + if(['id'].includes(columnName)) { + return 'INTEGER PRIMARY KEY'; + } + + if(['iid', 'project_id', 'gid'].includes(columnName)) { + return 'INTEGER NOT NULL'; + } + + if(['spent', 'total_spent', 'total_estimate', 'time'].includes(columnName)) { + return 'REAL'; + } + + if(['date', 'updated_at', 'created_at', 'due_date'].includes(columnName)) { + return 'DATE'; + } + + if(columnName === 'label_group') { + return `REFERENCES ${TABLE_LABEL_GROUP}(gid)`; + } + + if(columnName === 'label_id') { + return `REFERENCES ${TABLE_LABELS}(id)`; + } + + if(columnName === 'milestone') { + return `REFERENCES ${TABLE_MILESTONES}(id)`; + } + + // default: + return 'TEXT'; +} + + +/** + * Data required to create a SQLite table and fill with records. + */ +class Table { + + /** + * + * @param name of the Table + * @param columns Array of column names + * @param records Array of records to insert + */ + constructor(name, columns, records) { + this.name = name; + this.columns = columns; + this.records = records; + } +} + +/** + * Promise-based abstraction of the SQLite database driver + */ +class SqliteDatabaseAbstraction { + + constructor(file) { + this.file = file; + } + + /** + * Opens the SQLite database in write mode + * + * @returns {Promise} + */ + open() { + return new Promise((resolve, reject) => { + this.database = new sqlite3.Database(this.file, err => err? reject(err) : resolve()); + }); + } + + /** + * Closes the SQLite database before shutdown + * + * @returns {Promise} + */ + close() { + return new Promise((resolve, reject) => { + this.database.close(err => err? reject(err) : resolve()); + }); + } + + /** + * Creates a table and inserts the records. + * + * @param table + * @returns {Promise} + */ + async buildTable(table) { + const cols = table.columns.map(name => [name, getGeneralColumnType(name)]); + await this.createTable(table.name, cols); + + await this.insertRecords(table); + } + + /** + * Inserts multiple records according to a column list into a table. + * + * @param table + * @returns {Promise} + */ + insertRecords(table) { + return new Promise((resolve, reject) => { + const query = `INSERT INTO ${table.name} VALUES (${table.columns.map(() => '?').join(', ')})`; + const stmt = this.database.prepare(query); + for (const record of table.records) { + stmt.run(...record) + } + + stmt.finalize((err) => { + if(err) { + reject(err); + } else { + resolve(); + } + }); + }); + } + + /** + * Creates a new table in the SQLite Database + * + * @param name + * @param columnNameTypes + * @returns {Promise} + */ + async createTable(name, columnNameTypes) { + await new Promise((resolve, reject) => { + this.database.run(`DROP TABLE IF EXISTS ${name}`, (err) => err? reject(err): resolve()); + }); + + await new Promise((resolve, reject) => { + const columns = columnNameTypes.map(col => `${col[0]} ${col[1]}`).join(', '); + this.database.run(`CREATE TABLE ${name} (${columns})`, (err) => err? reject(err): resolve()); + }); + } + + /** + * Creates a new view in the SQLite Database + * @returns {Promise} + */ + async createView(view) { + await new Promise((resolve, reject) => { + this.database.run(`DROP VIEW IF EXISTS ${view[0]}`, (err) => err? reject(err): resolve()); + }); + + await new Promise((resolve, reject) => { + this.database.run(`CREATE VIEW ${view[0]} AS ${view[1]}`, (err) => err? reject(err): resolve()); + }); + } +} + +/** + * sqlite output + */ +class Sqlite extends Base { + + constructor(config, report) { + super(config, report); + this.tables = new Map(); + this.stats = new Map(); + + this.initSpecialTables(); + } + + /** + * Initializes special tables like labels or milestones, which are extracted from the output tables. + */ + initSpecialTables() { + const issueColumns = this.config.get(COLUMNS[TABLE_ISSUES]); + const mergeRequestColumns = this.config.get(COLUMNS[TABLE_MERGE_REQUESTS]); + if(issueColumns.includes('labels') || mergeRequestColumns.includes('labels')) { + /** + * @type {Map} Maps Labels to label group ids. + */ + this.labels = new Map(); + this.labelGroupSerial = 0; + this.labelsSerial = 0; + + this.tables.set(TABLE_LABELS, new Table( + TABLE_LABELS, + ['id', 'name'], + [] + )); + this.tables.set(TABLE_LABEL_GROUP, new Table( + TABLE_LABEL_GROUP, + ['gid', 'label_id'], + [] + )); + } + + if(issueColumns.includes('milestone') || mergeRequestColumns.includes('milestone')) { + /** + * @type {Map} Maps Milestones to ids + */ + this.milestones = new Map(); + this.milestonesSerial = 0; + + this.tables.set(TABLE_MILESTONES, new Table( + TABLE_MILESTONES, + ['id', 'name'], + [] + )); + } + } + + makeStats() { + this.stats.set('view_time_per_user', 'SELECT user, SUM(time) FROM times GROUP BY user'); + + // General Time Tracking summaries for some columns over multiple tables + const queries = []; + const fieldTables = [TABLE_ISSUES, TABLE_TIMES]; + const columns = ['total_estimate', 'total_spent', 'spent']; + + for(const column of columns) { + const subTableQueries = fieldTables + .filter(table => this.config.get(COLUMNS[table]).includes(column)) + .map(table => `SELECT ${column} FROM ${table}`) + .join(' UNION ALL '); + + if(subTableQueries.length > 0) { + queries.push(`SELECT '${column}', SUM(${column}) FROM (${subTableQueries})`); + } + } + + if(queries.length > 0) { + this.stats.set('view_time_stats', queries.join(' UNION ALL ')); + } + } + + makeIssues() { + const table = this.makeTable(TABLE_ISSUES, this.report.issues); + const columns = this.config.get(COLUMNS[TABLE_ISSUES]); + + if(columns.includes('milestone')) { + table.records.forEach(record => { + const columnIndex = columns.indexOf('milestone'); + record[columnIndex] = this.parseMilestone(record[columnIndex]); + }); + } + + if(columns.includes('labels')) { + columns.push('label_group'); + + table.records.forEach(record => { + record[columns.indexOf('label_group')] = this.parseLabelList(record[columns.indexOf('labels')]); + }); + } + } + + makeMergeRequests() { + const table = this.makeTable(TABLE_MERGE_REQUESTS, this.report.mergeRequests); + const columns = this.config.get(COLUMNS[TABLE_MERGE_REQUESTS]); + + if(columns.includes('labels')) { + columns.push('label_group'); + + table.records.forEach(record => { + record[columns.indexOf('label_group')] = this.parseLabelList(record[columns.indexOf('labels')]); + }); + } + } + + makeRecords() { + this.makeTable(TABLE_TIMES, this.times); + } + + makeTable(name, data) { + const columns = this.config.get(COLUMNS[name]); + const preparedData = data.map(record => this.prepare(record, columns)); + + const table = new Table(name, columns, preparedData); + this.tables.set(name,table); + return table; + } + + /** + * Creates a normalized table for milestones. + * + * @param milestone {string | number} Name of the milestone (or 0 if empty) + * @returns {number | null} ID of the milestone record. + */ + parseMilestone(milestone) { + if(milestone === 0) { + return null; + } + + return this.getOrCreateMilestoneId(milestone); + } + + + /** + * Creates a normalized labels structure from a labels comma list. + * + * @param labels {Array} + * @returns {number | null} id of the new label group + */ + parseLabelList(labels) { + const serial = this.labelGroupSerial++; + + if(!labels) { + return null; + } + + const records = labels + .map(label => this.getOrCreateLabelId(label)) + .map(labelId => [serial, labelId]); + this.tables.get(TABLE_LABEL_GROUP).records.push(...records); + + return serial; + } + + /** + * Gets the id of a label (and create it, if it not yet exists) + * + * @param name + * @returns {number} id of the label + */ + getOrCreateLabelId(name) { + if(this.labels.has(name)) { + return this.labels.get(name); + } + + const serial = this.labelsSerial++; + this.tables.get('labels').records.push([serial, name]); + this.labels.set(name, serial); + return serial; + } + + + /** + * Creates a Milestone (or fetches the existing one) and returns the ID. + * + * @param milestone {string} + * @returns {number} + */ + getOrCreateMilestoneId(milestone) { + if(this.milestones.has(milestone)) { + return this.milestones.get(milestone); + } + + const serial = this.milestonesSerial++; + this.tables.get('milestones').records.push([serial, milestone]); + this.milestones.set(milestone, serial); + return serial; + } + + + toFile(file, resolve) { + this.db = new SqliteDatabaseAbstraction(file); + this.provisionDatabase() + .then(() => resolve()) + .catch((err) => Cli.error("SQLITE: Error while building the database", err)); + } + + async provisionDatabase() { + await this.db.open(); + + for(const table of this.tables.values()) { + await this.db.buildTable(table); + } + + if (this.config.get('report').includes('stats')) { + for(const view of this.stats) { + await this.db.createView(view); + } + } + + await this.db.close(); + } + + toStdOut() { + Cli.error(`Can't output sqlite to std out`); + } + + + + /** + * prepare the given object by converting numeric + * columns/properties as numbers instead of strings + * on top of what the parent method already does + * + * suboptimally done here to avoid impacts on other outputs + * + * @param obj + * @param columns + * @returns {Array} + */ + prepare(obj = {}, columns = []) { + let formattedObj = super.prepare(obj, columns); + return formattedObj.map(field => isNaN(field) ? field : Number(field)); + } +} + +module.exports = Sqlite; diff --git a/yarn.lock b/yarn.lock index 2da1b0d..b5a312d 100755 --- a/yarn.lock +++ b/yarn.lock @@ -72,6 +72,10 @@ ansi-regex@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" @@ -86,6 +90,17 @@ app-module-path@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/app-module-path/-/app-module-path-2.2.0.tgz#641aa55dfb7d6a6f0a8141c4b9c0aa50b6c24dd5" +aproba@^1.0.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + +are-we-there-yet@~1.1.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" @@ -374,6 +389,10 @@ check-error@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" +chownr@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494" + class-utils@^0.3.5: version "0.3.6" resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" @@ -407,6 +426,10 @@ co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + codepage@~1.14.0: version "1.14.0" resolved "https://registry.yarnpkg.com/codepage/-/codepage-1.14.0.tgz#8cbe25481323559d7d307571b0fff91e7a1d2f99" @@ -496,6 +519,10 @@ concat-stream@^1.4.7: readable-stream "^2.2.2" typedarray "^0.0.6" +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + copy-descriptor@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" @@ -555,7 +582,7 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" -debug@2.6.9, debug@^2.2.0, debug@^2.3.3: +debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" dependencies: @@ -585,6 +612,10 @@ deep-equal@~0.2.1: version "0.2.2" resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-0.2.2.tgz#84b745896f34c684e98f2ce0e42abaf43bba017d" +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" @@ -612,6 +643,14 @@ delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + +detect-libc@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + diff@3.5.0, diff@^3.1.0: version "3.5.0" resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" @@ -889,10 +928,29 @@ fs-extra@~6.0.1: jsonfile "^4.0.0" universalify "^0.1.0" +fs-minipass@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" + dependencies: + minipass "^2.2.1" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + 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" @@ -949,7 +1007,7 @@ glob@^5.0.15: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.0.0, glob@^7.1.2: +glob@^7.0.0, glob@^7.1.2, glob@^7.1.3: version "7.1.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" dependencies: @@ -1035,6 +1093,10 @@ has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + has-value@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" @@ -1131,6 +1193,18 @@ i@0.3.x: version "0.3.6" resolved "https://registry.yarnpkg.com/i/-/i-0.3.6.tgz#d96c92732076f072711b6b10fd7d4f65ad8ee23d" +iconv-lite@^0.4.4: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ignore-walk@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" + dependencies: + minimatch "^3.0.4" + ignore@^3.3.5: version "3.3.10" resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" @@ -1150,10 +1224,13 @@ inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" +ini@~1.3.0: + version "1.3.5" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + interpret@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296" - integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw== into-stream@4.0.0: version "4.0.0" @@ -1220,6 +1297,16 @@ is-extglob@^2.1.0, is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + is-glob@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" @@ -1554,7 +1641,7 @@ minimist@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" -minimist@1.2.0, minimist@~1.2.0: +minimist@1.2.0, minimist@^1.2.0, minimist@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" @@ -1562,6 +1649,19 @@ minimist@~0.0.1: version "0.0.10" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" +minipass@^2.2.1, minipass@^2.3.4: + version "2.3.5" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848" + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + +minizlib@^1.1.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614" + dependencies: + minipass "^2.2.1" + mixin-deep@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" @@ -1634,6 +1734,10 @@ mute-stream@~0.0.4: version "0.0.7" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" +nan@~2.10.0: + version "2.10.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" + nanomatch@^1.2.9: version "1.2.13" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" @@ -1658,6 +1762,14 @@ ncp@1.0.x: version "1.0.1" resolved "https://registry.yarnpkg.com/ncp/-/ncp-1.0.1.tgz#d15367e5cb87432ba117d2bf80fdf45aecfb4246" +needle@^2.2.1: + version "2.2.4" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.4.tgz#51931bff82533b1928b7d1d69e01f1b00ffd2a4e" + dependencies: + debug "^2.1.2" + iconv-lite "^0.4.4" + sax "^1.2.4" + nise@^1.0.1: version "1.3.3" resolved "https://registry.yarnpkg.com/nise/-/nise-1.3.3.tgz#c17a850066a8a1dfeb37f921da02441afc4a82ba" @@ -1668,6 +1780,21 @@ nise@^1.0.1: path-to-regexp "^1.7.0" text-encoding "^0.6.4" +node-pre-gyp@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz#db1f33215272f692cd38f03238e3e9b47c5dd054" + dependencies: + detect-libc "^1.0.2" + mkdirp "^0.5.1" + needle "^2.2.1" + nopt "^4.0.1" + npm-packlist "^1.1.6" + npmlog "^4.0.2" + rc "^1.2.7" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^4" + node-spinner@^0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/node-spinner/-/node-spinner-0.0.4.tgz#4c5dad762f953bdcae74ec000f6cea054ef20c8e" @@ -1680,6 +1807,37 @@ nopt@3.x: dependencies: abbrev "1" +nopt@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + dependencies: + abbrev "1" + osenv "^0.1.4" + +npm-bundled@^1.0.1: + version "1.0.6" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.6.tgz#e7ba9aadcef962bb61248f91721cd932b3fe6bdd" + +npm-packlist@^1.1.6: + version "1.4.1" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.1.tgz#19064cdf988da80ea3cee45533879d90192bbfbc" + dependencies: + ignore-walk "^3.0.1" + npm-bundled "^1.0.1" + +npmlog@^4.0.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + oauth-sign@~0.8.1, oauth-sign@~0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" @@ -1688,6 +1846,10 @@ oauth-sign@~0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" +object-assign@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + object-copy@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" @@ -1742,10 +1904,21 @@ optionator@^0.8.1: type-check "~0.3.2" wordwrap "~1.0.0" -os-tmpdir@^1.0.1, os-tmpdir@~1.0.2: +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + +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" +osenv@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + p-is-promise@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.0.0.tgz#7554e3d572109a87e1f3f53f6a7d85d1b194f4c5" @@ -1928,6 +2101,15 @@ qs@~6.5.1, qs@~6.5.2: version "6.5.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" +rc@^1.2.7: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + read-yaml@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/read-yaml/-/read-yaml-1.1.0.tgz#0d273ac0c95be92230dc0d4c4c4f5b8960a336d6" @@ -1941,7 +2123,7 @@ read@1.0.x: dependencies: mute-stream "~0.0.4" -readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@^2.1.4, readable-stream@^2.1.5, readable-stream@^2.2.2: +readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.1.5, readable-stream@^2.2.2: version "2.3.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" dependencies: @@ -1956,7 +2138,6 @@ readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@^2.1.4, readable rechoir@^0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" - integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q= dependencies: resolve "^1.1.6" @@ -2131,7 +2312,6 @@ resolve@1.6.0: resolve@^1.1.6: version "1.10.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.10.0.tgz#3bdaaeaf45cc07f375656dfd2e54ed0810b101ba" - integrity sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg== dependencies: path-parse "^1.0.6" @@ -2162,6 +2342,12 @@ rimraf@2.x.x: dependencies: glob "^7.0.5" +rimraf@^2.6.1: + version "2.6.3" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" + dependencies: + glob "^7.1.3" + safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" @@ -2172,7 +2358,7 @@ safe-regex@^1.1.0: dependencies: ret "~0.1.10" -safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: +"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" @@ -2180,7 +2366,11 @@ samsam@1.3.0, samsam@1.x, samsam@^1.1.3: version "1.3.0" resolved "https://registry.yarnpkg.com/samsam/-/samsam-1.3.0.tgz#8d1d9350e25622da30de3e44ba692b5221ab7c50" -semver@~5.6.0: +sax@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + +semver@^5.3.0, semver@~5.6.0: version "5.6.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" @@ -2188,6 +2378,10 @@ series-stream@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/series-stream/-/series-stream-1.0.1.tgz#311a09c5c1d5a091440832e1a480a47400f1005d" +set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + set-value@^0.4.3: version "0.4.3" resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" @@ -2209,13 +2403,12 @@ set-value@^2.0.0: shelljs@^0.8.3: version "0.8.3" resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.3.tgz#a7f3319520ebf09ee81275b2368adb286659b097" - integrity sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A== dependencies: glob "^7.0.0" interpret "^1.0.0" rechoir "^0.6.2" -signal-exit@^3.0.2: +signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" @@ -2322,6 +2515,14 @@ sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" +sqlite3@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/sqlite3/-/sqlite3-4.0.6.tgz#e587b583b5acc6cb38d4437dedb2572359c080ad" + dependencies: + nan "~2.10.0" + node-pre-gyp "^0.11.0" + request "^2.87.0" + ssf@~0.10.2: version "0.10.2" resolved "https://registry.yarnpkg.com/ssf/-/ssf-0.10.2.tgz#65b2b4fcdfd967bc8e8383a41349009893115976" @@ -2372,6 +2573,21 @@ stream-meter@1.0.4: dependencies: readable-stream "^2.1.4" +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +"string-width@^1.0.2 || 2": + 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.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" @@ -2386,12 +2602,22 @@ stringstream@~0.0.5: version "0.0.6" resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.6.tgz#7880225b0d4ad10e30927d167a1d6f2fd3b33a72" -strip-ansi@^3.0.0: +strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" dependencies: ansi-regex "^2.0.0" +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + dependencies: + ansi-regex "^3.0.0" + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + supports-color@5.4.0: version "5.4.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" @@ -2414,6 +2640,18 @@ supports-color@^5.3.0: dependencies: has-flag "^3.0.0" +tar@^4: + version "4.4.8" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.8.tgz#b19eec3fde2a96e64666df9fdb40c5ca1bc3747d" + dependencies: + chownr "^1.1.1" + fs-minipass "^1.2.5" + minipass "^2.3.4" + minizlib "^1.1.1" + mkdirp "^0.5.0" + safe-buffer "^5.1.2" + yallist "^3.0.2" + temp-dir@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-1.0.0.tgz#0a7c0ea26d3a39afa7e0ebea9c1fc0bc4daa011d" @@ -2643,6 +2881,12 @@ which@^1.1.1, which@^1.2.10: dependencies: isexe "^2.0.0" +wide-align@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + dependencies: + string-width "^1.0.2 || 2" + window-size@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" @@ -2710,6 +2954,10 @@ xtend@^4.0.0, xtend@~4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" +yallist@^3.0.0, yallist@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9" + yargs@~3.10.0: version "3.10.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1"