diff --git a/args-parser.js b/args-parser.js new file mode 100644 index 0000000..1125024 --- /dev/null +++ b/args-parser.js @@ -0,0 +1,81 @@ +const data = require('caniuse-db/data.json'); +const path = require('path'); +const osHomedir = require('os-homedir'); +const yargs = require('yargs'); + +module.exports = yargs + .option('short', { + alias: 's', + type: 'boolean', + default: undefined, + describe: "Short output: show browsers on one line and don't display notes or description (default when displaying multiple results)" + }).option('long', { + alias: 'l', + type: 'boolean', + default: undefined, + describe: "Long output: show more information (default when displaying a single result)" + }).option('oneline', { + alias: '1', + type: 'boolean', + default: false, + describe: "One-line output: just global percentages, no per-browser info" + }).option('oneline-browser', { + alias: '2', + type: 'boolean', + default: false, + describe: "One-line output with browser info, implies --abbrev and --current" + }).option('abbrev', { + alias: 'a', + type: 'boolean', + default: false, + describe: "Abbreviate browser names" + }).option('percentages', { + alias: 'p', + type: 'boolean', + default: false, + describe: "Include browser version usage percentages" + }).option('future', { + alias: 'f', + type: 'boolean', + default: false, + describe: "Include future browser versions" + }).option('current', { + alias: 'c', + type: 'boolean', + default: false, + describe: "Don't include old browser versions, equivalent to --era e0" + }).option('era', { + alias: 'e', + type: 'string', + describe: `How many versions back to go, e0 to ${Object.keys(data.eras)[0]}` + }).option('mobile', { + alias: 'm', + type: 'boolean', + default: false, + describe: "Include mobile browsers" + }).option('desktop', { + alias: 'd', + type: 'boolean', + default: true, + describe: "Include desktop browsers" + }).option('browser', { + alias: 'b', + type: 'string', + describe: `Show results for these browsers, comma-separated (${Object.keys(data.agents)})` + }).option('ascii', { + alias: 'A', + type: 'boolean', + default: false, + describe: "UTF-8 symbols replacement with ASCII description" + }).option('web', { + alias: 'w', + type: 'boolean', + default: false, + describe: "Go to the search page on caniuse.com" + }).option('config', { + alias: 'C', + type: 'string', + default: path.join(osHomedir(), '.caniuse.json'), + describe: "Specify a config file with default options" + }).config('config') + .help('help'); diff --git a/bin.js b/bin.js index 0f7c912..34bb6ee 100755 --- a/bin.js +++ b/bin.js @@ -1,3 +1,2 @@ #!/usr/bin/env node -require('coffee-script/register'); -require('./caniuse.coffee'); \ No newline at end of file +require('./caniuse-cli.js'); \ No newline at end of file diff --git a/caniuse-cli.js b/caniuse-cli.js new file mode 100644 index 0000000..ac7f496 --- /dev/null +++ b/caniuse-cli.js @@ -0,0 +1,12 @@ +const argsParser = require('./args-parser'); +const { toStreams } = require('./caniuse.decaffeinate'); + +const { + argv +} = argsParser; + +if (argv.web) { + return open(`http://caniuse.com/#search=${encodeURIComponent(argv._.join(' '))}`); +} + +toStreams(argv); diff --git a/caniuse.coffee b/caniuse.coffee deleted file mode 100644 index d37a97f..0000000 --- a/caniuse.coffee +++ /dev/null @@ -1,252 +0,0 @@ -data = require 'caniuse-db/data.json' -colors = require 'colors' -linewrap = require 'linewrap' -open = require 'open' -path = require 'path' -osHomedir = require 'os-homedir' -os = require 'os' - -argv = require 'yargs' - .option 'short', - alias: 's' - type: 'boolean' - default: undefined - describe: "Short output: show browsers on one line and don't display notes or description (default when displaying multiple results)" - .option 'long', - alias: 'l' - type: 'boolean' - default: undefined - describe: "Long output: show more information (default when displaying a single result)" - .option 'oneline', - alias: '1' - type: 'boolean' - default: false - describe: "One-line output: just global percentages, no per-browser info" - .option 'oneline-browser', - alias: '2' - type: 'boolean' - default: false - describe: "One-line output with browser info, implies --abbrev and --current" - .option 'abbrev', - alias: 'a' - type: 'boolean' - default: false - describe: "Abbreviate browser names" - .option 'percentages', - alias: 'p' - type: 'boolean' - default: false - describe: "Include browser version usage percentages" - .option 'future', - alias: 'f' - type: 'boolean' - default: false - describe: "Include future browser versions" - .option 'current', - alias: 'c' - type: 'boolean' - default: false - describe: "Don't include old browser versions, equivalent to --era e0" - .option 'era', - alias: 'e' - type: 'string' - describe: "How many versions back to go, e0 to #{Object.keys(data.eras)[0]}" - .option 'mobile', - alias: 'm' - type: 'boolean' - default: false - describe: "Include mobile browsers" - .option 'desktop', - alias: 'd' - type: 'boolean' - default: true - describe: "Include desktop browsers" - .option 'browser', - alias: 'b' - type: 'string' - describe: "Show results for these browsers, comma-separated (#{Object.keys(data.agents)})" - .option 'ascii', - alias: 'A' - type: 'boolean' - default: false - describe: "UTF-8 symbols replacement with ASCII description" - .option 'web', - alias: 'w' - type: 'boolean' - default: false - describe: "Go to the search page on caniuse.com" - .option 'config', - alias: 'C' - type: 'string' - default: path.join(osHomedir(), '.caniuse.json') - describe: "Specify a config file with default options" - .config 'config' - .help 'help' - .argv - -resultmap = y: "✔", n: "✘", a: "◒", u: "‽", i: "ⓘ", w: "⚠" -supernums = "⁰¹²³⁴⁵⁶⁷⁸⁹" - -if (os.platform() == 'win32') - resultmap = y: "\u221A", n: "\u00D7", a: "\u0398", u: "\u203D", i: "\u24D8", w: "\u26A0" - -if argv["ascii"] - resultmap = y: "[Yes]", n: "[No]", a: "[Partly]", u: "[?!]", i: "[Info]", w: "[Warning]" - -if (Date.now()/1000 - data.updated) > 30*60*60*24 - console.warn """ - #{resultmap.w} Caniuse data is more than 30 days out of date! - Consider updating: npm install -g caniuse-cmd - - """.yellow - -if argv.web - return open "http://caniuse.com/#search=#{encodeURIComponent argv._.join ' '}" - -searchkey = argv._.join('').toLowerCase().replace(/\W*/g, '') -agents = data.agents - -xwrap = linewrap (process.stdout.columns or 80), - skipScheme: 'ansi-color' - whitespace: 'line' - tabWidth: 2 - wrapLineIndent: 0 - wrapLineIndentBase: /\S/ - -# Replace our scary braille spaces with real spaces -wrap = (str) -> xwrap(str).replace(/\u2800/g, ' ') - -if argv["oneline-browser"] - argv.abbrev = true - argv.short = true - argv.current = true - - -types = [] -types.push 'desktop' if argv.desktop -types.push 'mobile' if argv.mobile - -eras = Object.keys(data.eras) -currentVersion = eras.indexOf("e0") -versionrange = [0, currentVersion] -versionrange[1] = Infinity if argv.future -versionrange[0] = currentVersion if argv.current -versionrange[0] = eras.indexOf(argv.era) if argv.era - -# Generate the text for a single version result -# FIXME: gross output parameter -makeResult = (result, nums={}) -> - support = result.support[0] - out = '' - # \u2800 is a braille space - the only kind of space I could find that - # doesn't get split by the word wrapper - out += (resultmap[support] || support) + "\u2800" - out += result.version if result.version - out += "ᵖ" if "x" in result.support - if note = result.support.match(/#(\d+)/)?[1] - nums[note] = true - out += supernums[note] - - if argv.percentages and result.usage - out += " " unless out.slice(-1) is "\u2800" - out += "(#{Math.round(result.usage*1)/1}%)" - out += ' ' - switch support - when "y" then out.green - when "n" then out.red - when "a" then out.yellow - else out - -# Generate an array of version results for a browser -makeResults = (browser, stats) -> - results = [] - current = {} - for version, i in browser.versions when version and versionrange[0] <= i <= versionrange[1] - support = stats[version] - usage = browser.usage_global[version] || 0 - version += '+' if browser.versions[i + 1] - - # 'p' means no-but-polyfill-available, which we can treat as no - if support[0] == "p" - support = "n" + support.slice(1) - - # Only add a new version result when browser support changes - if !current.version || current.support != support - current = version: version, support: support, usage: 0 - results.push current - - current.usage += usage - - results - -# Display a single feature's browser support -showFeature = (result, opts={}) -> - opts.long ?= !opts.short - opts.short ?= !opts.long - - percentages = [] - percentages.push resultmap.y + " #{result.usage_perc_y}%".green if result.usage_perc_y - percentages.push resultmap.a + " #{result.usage_perc_a}%".yellow if result.usage_perc_a - percentages = percentages.join(' ') - - status = if opts.long then " [#{data.statuses[result.status]}]" else '' - headerSep = if opts["oneline-browser"] then ": " else "\n" - process.stdout.write "#{result.title.bold} #{percentages}#{status}" + headerSep - - return if opts.oneline - - if opts.long - tags = result.categories.map((x) -> '#'+x.replace(/\W/g,'')).join(' ') - console.log wrap '\t' + result.description.trim() + ' ' + tags + '\n' - - out = [] - # console.log "columns", process.stdout.columns - out.push '\t' if opts.short && !opts["oneline-browser"] - - filter = (browser) -> - if opts.browser - browser in opts.browser.split(',') - else - agents[browser].type in types - - # Store which notes have been used in a result - need_note = {} - - for browser, stats of result.stats when filter browser - out.push "\t" unless opts.short - if opts.abbrev - out.push "#{agents[browser].abbr} " - else - out.push "#{agents[browser].browser} " - - results = makeResults(agents[browser], stats) - if results.length == 1 - results[0].version = null - - out.push "#{makeResult res, need_note}" for res in results - out.push "\n" unless opts.short - - console.log wrap out.join('') - - unless opts.short - for num, note of result.notes_by_num when need_note[num] - console.log wrap "\t\t#{supernums[num].yellow}#{note}" - console.log wrap "\t " + resultmap.i + " #{result.notes.replace(/[\r\n]+/g, ' ')}" if result.notes - - -slowFind = (query) -> - results = [] - for key, {title, description, keywords, categories} of data.data - matcher = (key + title + description + keywords + categories).toLowerCase().replace(/\W*/g, '') - results.push key if matcher.match(query) - results - - -do -> - if feat = data.data[searchkey] - showFeature feat, argv - else if (features = slowFind searchkey).length > 0 - argv.short ?= features.length > 1 - showFeature data.data[feat], argv for feat in features - else - console.error "#{searchkey}: not found" diff --git a/caniuse.decaffeinate.js b/caniuse.decaffeinate.js new file mode 100644 index 0000000..c60466e --- /dev/null +++ b/caniuse.decaffeinate.js @@ -0,0 +1,359 @@ +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * DS103: Rewrite code to no longer use __guard__ + * DS104: Avoid inline assignments + * DS204: Change includes calls to have a more natural evaluation order + * DS205: Consider reworking code to avoid use of IIFEs + * DS207: Consider shorter variations of null checks + * DS209: Avoid top-level return + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const data = require('caniuse-db/data.json'); +const colors = require('colors'); +const linewrap = require('linewrap'); +const os = require('os'); +const { WritableStreamBuffer } = require('stream-buffers'); +const argsParser = require('./args-parser'); + +function prepareArgv(argv) { + // allow for asString/toStreams('Service Workers'), for example. + if (typeof argv === 'string') { + return argsParser.parse([argv]); + } + + // allow for asString/toStreams(['Service Workers', 'URL API']), for example. + if (Array.isArray(argv)) { + return argsParser.parse(argv); + } + + return argv; +} + +function toStreams(argv, stdout, stderr) { + +argv = prepareArgv(argv); + +stdout = stdout || process.stdout; +stderr = stderr || process.stderr; + +const console = { + log: (s) => stdout.write(s + '\n'), + warn: (s) => stderr.write(s + '\n'), + error: (s) => stderr.write(s + '\n'), +}; + +let resultmap = { + y: "✔", + n: "✘", + a: "◒", + u: "‽", + i: "ⓘ", + w: "⚠" +}; +const supernums = "⁰¹²³⁴⁵⁶⁷⁸⁹"; + +if (os.platform() === 'win32') { + resultmap = { + y: "\u221A", + n: "\u00D7", + a: "\u0398", + u: "\u203D", + i: "\u24D8", + w: "\u26A0" + }; +} + +if (argv["ascii"]) { + resultmap = { + y: "[Yes]", + n: "[No]", + a: "[Partly]", + u: "[?!]", + i: "[Info]", + w: "[Warning]" + }; +} + +if (((Date.now() / 1000) - data.updated) > (30 * 60 * 60 * 24)) { + console.warn(`\ +${resultmap.w} Caniuse data is more than 30 days out of date! + Consider updating: npm install -g caniuse-cmd +\ +`.yellow); +} + +const searchkey = argv._.join('').toLowerCase().replace(/\W*/g, ''); +const { + agents +} = data; + +const xwrap = linewrap((process.stdout.columns || 80), { + skipScheme: 'ansi-color', + whitespace: 'line', + tabWidth: 2, + wrapLineIndent: 0, + wrapLineIndentBase: /\S/ +}); + +// Replace our scary braille spaces with real spaces +const wrap = str => xwrap(str).replace(/\u2800/g, ' '); + +if (argv["oneline-browser"]) { + argv.abbrev = true; + argv.short = true; + argv.current = true; +} + + +const types = []; +if (argv.desktop) { + types.push('desktop'); +} +if (argv.mobile) { + types.push('mobile'); +} + +const eras = Object.keys(data.eras); +const currentVersion = eras.indexOf("e0"); +const versionrange = [0, currentVersion]; +if (argv.future) { + versionrange[1] = Infinity; +} +if (argv.current) { + versionrange[0] = currentVersion; +} +if (argv.era) { + versionrange[0] = eras.indexOf(argv.era); +} + +// Generate the text for a single version result +// FIXME: gross output parameter +const makeResult = function(result, nums) { + let note; + if (nums == null) { + nums = {}; + } + const support = result.support[0]; + let out = ''; + // \u2800 is a braille space - the only kind of space I could find that + // doesn't get split by the word wrapper + out += (resultmap[support] || support) + "\u2800"; + if (result.version) { + out += result.version; + } + if (Array.from(result.support).includes("x")) { + out += "ᵖ"; + } + if (note = __guard__(result.support.match(/#(\d+)/), x => x[1])) { + nums[note] = true; + out += supernums[note]; + } + + if (argv.percentages && result.usage) { + if (out.slice(-1) !== "\u2800") { + out += " "; + } + out += `(${Math.round(result.usage * 1) / 1}%)`; + } + out += ' '; + switch (support) { + case "y": + return out.green; + case "n": + return out.red; + case "a": + return out.yellow; + default: + return out; + } +}; + +// Generate an array of version results for a browser +const makeResults = function(browser, stats) { + const results = []; + let current = {}; + for (let i = 0; i < browser.versions.length; i++) { + let version = browser.versions[i]; + if (version && (versionrange[0] <= i && i <= versionrange[1])) { + let support = stats[version]; + const usage = browser.usage_global[version] || 0; + if (browser.versions[i + 1]) { + version += '+'; + } + + // 'p' means no-but-polyfill-available, which we can treat as no + if (support[0] === "p") { + support = `n${support.slice(1)}`; + } + + // Only add a new version result when browser support changes + if (!current.version || (current.support !== support)) { + current = { + version, + support, + usage: 0 + }; + results.push(current); + } + + current.usage += usage; + } + } + + return results; +}; + +// Display a single feature's browser support +const showFeature = function(result, opts) { + if (opts == null) { + opts = {}; + } + if (opts.long == null) { + opts.long = !opts.short; + } + if (opts.short == null) { + opts.short = !opts.long; + } + + let percentages = []; + if (result.usage_perc_y) { + percentages.push(resultmap.y + ` ${result.usage_perc_y}%`.green); + } + if (result.usage_perc_a) { + percentages.push(resultmap.a + ` ${result.usage_perc_a}%`.yellow); + } + percentages = percentages.join(' '); + + const status = opts.long ? ` [${data.statuses[result.status]}]` : ''; + const headerSep = opts["oneline-browser"] ? ": " : "\n"; + stdout.write(`${result.title.bold} ${percentages}${status}` + headerSep); + + if (opts.oneline) { + return; + } + + if (opts.long) { + const tags = result.categories.map(x => `#${x.replace(/\W/g, '')}`).join(' '); + console.log(wrap(`\t${result.description.trim()} ${tags}\n`)); + } + + const out = []; + // console.log "columns", process.stdout.columns + if (opts.short && !opts["oneline-browser"]) { + out.push('\t'); + } + + const filter = function(browser) { + if (opts.browser) { + let needle; + return (needle = browser, Array.from(opts.browser.split(',')).includes(needle)); + } else { + return Array.from(types).includes(agents[browser].type); + } + }; + + // Store which notes have been used in a result + const need_note = {}; + + for (let browser in result.stats) { + const stats = result.stats[browser]; + if (filter(browser)) { + if (!opts.short) { + out.push("\t"); + } + if (opts.abbrev) { + out.push(`${agents[browser].abbr} `); + } else { + out.push(`${agents[browser].browser} `); + } + + const results = makeResults(agents[browser], stats); + if (results.length === 1) { + results[0].version = null; + } + + for (let res of Array.from(results)) { + out.push(`${makeResult(res, need_note)}`); + } + if (!opts.short) { + out.push("\n"); + } + } + } + + console.log(wrap(out.join(''))); + + if (!opts.short) { + for (let num in result.notes_by_num) { + const note = result.notes_by_num[num]; + if (need_note[num]) { + console.log(wrap(`\t\t${supernums[num].yellow}${note}`)); + } + } + if (result.notes) { + return console.log(wrap(`\t ${resultmap.i}${` ${result.notes.replace(/[\r\n]+/g, ' ')}`}`)); + } + } +}; + + +const slowFind = function(query) { + const results = []; + for (let key in data.data) { + const { + title, + description, + keywords, + categories + } = data.data[key]; + const matcher = (key + title + description + keywords + categories).toLowerCase().replace(/\W*/g, ''); + if (matcher.match(query)) { + results.push(key); + } + } + return results; +}; + +function __guard__(value, transform) { + return (typeof value !== 'undefined' && value !== null) ? transform(value) : undefined; +} + +return (function() { + let feat, features; + if (feat = data.data[searchkey]) { + return showFeature(feat, argv); + } else if ((features = slowFind(searchkey)).length > 0) { + if (argv.short == null) { + argv.short = features.length > 1; + } + return (() => { + const result = []; + for (feat of Array.from(features)) { + result.push(showFeature(data.data[feat], argv)); + } + return result; + })(); + } else { + return console.error(`${searchkey}: not found`); + } +})(); + +} + +function asString(argv) { + argv = prepareArgv(argv); + + const stdout = new WritableStreamBuffer(); + const stderr = new WritableStreamBuffer(); + + toStreams(argv, stdout, stderr); + + return stdout.getContentsAsString('utf8'); +}; + +module.exports = { + asString, + toStreams, +}; diff --git a/caniuse.js2coffee.js b/caniuse.js2coffee.js new file mode 100644 index 0000000..a6a73cc --- /dev/null +++ b/caniuse.js2coffee.js @@ -0,0 +1,376 @@ +var agents, argv, colors, currentVersion, data, eras, linewrap, makeResult, makeResults, open, os, osHomedir, path, resultmap, searchkey, showFeature, slowFind, supernums, types, versionrange, wrap, xwrap, + indexOf = [].indexOf || function(item) { + for (var i = 0, l = this.length; i < l; i++) { + if (i in this && this[i] === item) return i; + } + return -1; + }; + +data = require('caniuse-db/data.json'); + +colors = require('colors'); + +linewrap = require('linewrap'); + +open = require('open'); + +path = require('path'); + +osHomedir = require('os-homedir'); + +os = require('os'); + +argv = require('yargs').option('short', { + alias: 's', + type: 'boolean', + "default": void 0, + describe: "Short output: show browsers on one line and don't display notes or description (default when displaying multiple results)" +}).option('long', { + alias: 'l', + type: 'boolean', + "default": void 0, + describe: "Long output: show more information (default when displaying a single result)" +}).option('oneline', { + alias: '1', + type: 'boolean', + "default": false, + describe: "One-line output: just global percentages, no per-browser info" +}).option('oneline-browser', { + alias: '2', + type: 'boolean', + "default": false, + describe: "One-line output with browser info, implies --abbrev and --current" +}).option('abbrev', { + alias: 'a', + type: 'boolean', + "default": false, + describe: "Abbreviate browser names" +}).option('percentages', { + alias: 'p', + type: 'boolean', + "default": false, + describe: "Include browser version usage percentages" +}).option('future', { + alias: 'f', + type: 'boolean', + "default": false, + describe: "Include future browser versions" +}).option('current', { + alias: 'c', + type: 'boolean', + "default": false, + describe: "Don't include old browser versions, equivalent to --era e0" +}).option('era', { + alias: 'e', + type: 'string', + describe: "How many versions back to go, e0 to " + (Object.keys(data.eras)[0]) +}).option('mobile', { + alias: 'm', + type: 'boolean', + "default": false, + describe: "Include mobile browsers" +}).option('desktop', { + alias: 'd', + type: 'boolean', + "default": true, + describe: "Include desktop browsers" +}).option('browser', { + alias: 'b', + type: 'string', + describe: "Show results for these browsers, comma-separated (" + (Object.keys(data.agents)) + ")" +}).option('ascii', { + alias: 'A', + type: 'boolean', + "default": false, + describe: "UTF-8 symbols replacement with ASCII description" +}).option('web', { + alias: 'w', + type: 'boolean', + "default": false, + describe: "Go to the search page on caniuse.com" +}).option('config', { + alias: 'C', + type: 'string', + "default": path.join(osHomedir(), '.caniuse.json'), + describe: "Specify a config file with default options" +}).config('config').help('help').argv; + +resultmap = { + y: "✔", + n: "✘", + a: "◒", + u: "‽", + i: "ⓘ", + w: "⚠" +}; + +supernums = "⁰¹²³⁴⁵⁶⁷⁸⁹"; + +if (os.platform() === 'win32') { + resultmap = { + y: "\u221A", + n: "\u00D7", + a: "\u0398", + u: "\u203D", + i: "\u24D8", + w: "\u26A0" + }; +} + +if (argv["ascii"]) { + resultmap = { + y: "[Yes]", + n: "[No]", + a: "[Partly]", + u: "[?!]", + i: "[Info]", + w: "[Warning]" + }; +} + +if ((Date.now() / 1000 - data.updated) > 30 * 60 * 60 * 24) { + console.warn((resultmap.w + " Caniuse data is more than 30 days out of date!\n Consider updating: npm install -g caniuse-cmd\n").yellow); +} + +if (argv.web) { + return open("http://caniuse.com/#search=" + (encodeURIComponent(argv._.join(' ')))); +} + +searchkey = argv._.join('').toLowerCase().replace(/\W*/g, ''); + +agents = data.agents; + +xwrap = linewrap(process.stdout.columns || 80, { + skipScheme: 'ansi-color', + whitespace: 'line', + tabWidth: 2, + wrapLineIndent: 0, + wrapLineIndentBase: /\S/ +}); + +wrap = function(str) { + return xwrap(str).replace(/\u2800/g, ' '); +}; + +if (argv["oneline-browser"]) { + argv.abbrev = true; + argv.short = true; + argv.current = true; +} + +types = []; + +if (argv.desktop) { + types.push('desktop'); +} + +if (argv.mobile) { + types.push('mobile'); +} + +eras = Object.keys(data.eras); + +currentVersion = eras.indexOf("e0"); + +versionrange = [0, currentVersion]; + +if (argv.future) { + versionrange[1] = Infinity; +} + +if (argv.current) { + versionrange[0] = currentVersion; +} + +if (argv.era) { + versionrange[0] = eras.indexOf(argv.era); +} + +makeResult = function(result, nums) { + var note, out, ref, support; + if (nums == null) { + nums = {}; + } + support = result.support[0]; + out = ''; + out += (resultmap[support] || support) + "\u2800"; + if (result.version) { + out += result.version; + } + if (indexOf.call(result.support, "x") >= 0) { + out += "ᵖ"; + } + if (note = (ref = result.support.match(/#(\d+)/)) != null ? ref[1] : void 0) { + nums[note] = true; + out += supernums[note]; + } + if (argv.percentages && result.usage) { + if (out.slice(-1) !== "\u2800") { + out += " "; + } + out += "(" + (Math.round(result.usage * 1) / 1) + "%)"; + } + out += ' '; + switch (support) { + case "y": + return out.green; + case "n": + return out.red; + case "a": + return out.yellow; + default: + return out; + } +}; + +makeResults = function(browser, stats) { + var current, i, j, len, ref, results, support, usage, version; + results = []; + current = {}; + ref = browser.versions; + for (i = j = 0, len = ref.length; j < len; i = ++j) { + version = ref[i]; + if (!(version && (versionrange[0] <= i && i <= versionrange[1]))) { + continue; + } + support = stats[version]; + usage = browser.usage_global[version] || 0; + if (browser.versions[i + 1]) { + version += '+'; + } + if (support[0] === "p") { + support = "n" + support.slice(1); + } + if (!current.version || current.support !== support) { + current = { + version: version, + support: support, + usage: 0 + }; + results.push(current); + } + current.usage += usage; + } + return results; +}; + +showFeature = function(result, opts) { + var browser, filter, headerSep, j, len, need_note, note, num, out, percentages, ref, ref1, res, results, stats, status, tags; + if (opts == null) { + opts = {}; + } + if (opts.long == null) { + opts.long = !opts.short; + } + if (opts.short == null) { + opts.short = !opts.long; + } + percentages = []; + if (result.usage_perc_y) { + percentages.push(resultmap.y + (" " + result.usage_perc_y + "%").green); + } + if (result.usage_perc_a) { + percentages.push(resultmap.a + (" " + result.usage_perc_a + "%").yellow); + } + percentages = percentages.join(' '); + status = opts.long ? " [" + data.statuses[result.status] + "]" : ''; + headerSep = opts["oneline-browser"] ? ": " : "\n"; + process.stdout.write((result.title.bold + " " + percentages + status) + headerSep); + if (opts.oneline) { + return; + } + if (opts.long) { + tags = result.categories.map(function(x) { + return '#' + x.replace(/\W/g, ''); + }).join(' '); + console.log(wrap('\t' + result.description.trim() + ' ' + tags + '\n')); + } + out = []; + if (opts.short && !opts["oneline-browser"]) { + out.push('\t'); + } + filter = function(browser) { + var ref; + if (opts.browser) { + return indexOf.call(opts.browser.split(','), browser) >= 0; + } else { + return ref = agents[browser].type, indexOf.call(types, ref) >= 0; + } + }; + need_note = {}; + ref = result.stats; + for (browser in ref) { + stats = ref[browser]; + if (!(filter(browser))) { + continue; + } + if (!opts.short) { + out.push("\t"); + } + if (opts.abbrev) { + out.push(agents[browser].abbr + " "); + } else { + out.push(agents[browser].browser + " "); + } + results = makeResults(agents[browser], stats); + if (results.length === 1) { + results[0].version = null; + } + for (j = 0, len = results.length; j < len; j++) { + res = results[j]; + out.push("" + (makeResult(res, need_note))); + } + if (!opts.short) { + out.push("\n"); + } + } + console.log(wrap(out.join(''))); + if (!opts.short) { + ref1 = result.notes_by_num; + for (num in ref1) { + note = ref1[num]; + if (need_note[num]) { + console.log(wrap("\t\t" + supernums[num].yellow + note)); + } + } + if (result.notes) { + return console.log(wrap("\t " + resultmap.i + (" " + (result.notes.replace(/[\r\n]+/g, ' '))))); + } + } +}; + +slowFind = function(query) { + var categories, description, key, keywords, matcher, ref, ref1, results, title; + results = []; + ref = data.data; + for (key in ref) { + ref1 = ref[key], title = ref1.title, description = ref1.description, keywords = ref1.keywords, categories = ref1.categories; + matcher = (key + title + description + keywords + categories).toLowerCase().replace(/\W*/g, ''); + if (matcher.match(query)) { + results.push(key); + } + } + return results; +}; + +(function() { + var feat, features, j, len, results1; + if (feat = data.data[searchkey]) { + return showFeature(feat, argv); + } else if ((features = slowFind(searchkey)).length > 0) { + if (argv.short == null) { + argv.short = features.length > 1; + } + results1 = []; + for (j = 0, len = features.length; j < len; j++) { + feat = features[j]; + results1.push(showFeature(data.data[feat], argv)); + } + return results1; + } else { + return console.error(searchkey + ": not found"); + } +})(); + +// --- +// generated by coffee-script 1.9.2 \ No newline at end of file diff --git a/index.js b/index.js new file mode 100644 index 0000000..396cef8 --- /dev/null +++ b/index.js @@ -0,0 +1,8 @@ +const { toStreams, asString } = require('./caniuse.decaffeinate'); +const argsParser = require('./args-parser'); + +module.exports = { + toStreams, + asString, + argsParser, +}; diff --git a/package.json b/package.json index e499402..639c66d 100644 --- a/package.json +++ b/package.json @@ -23,15 +23,13 @@ }, "homepage": "https://github.com/sgentle/caniuse-cmd", "dependencies": { - "caniuse-db": "~1.0.0", - "coffee-script": "=1.9.1", - "colors": "^1.0.3", + "caniuse-db": "~1.0.30000885", + "colors": "^1.3.2", "linewrap": "^0.2.1", "open": "0.0.5", - "os-homedir": "^1.0.1", + "os-homedir": "^1.0.2", + "stream-buffers": "^3.0.2", "yargs": "git+https://github.com/sgentle/yargs.git#config-booleans" }, - "devDependencies": { - "mocha": "^2.2.1" - } + "devDependencies": {} }