Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
sgentle committed Mar 15, 2015
0 parents commit b856619
Show file tree
Hide file tree
Showing 3 changed files with 252 additions and 0 deletions.
3 changes: 3 additions & 0 deletions bin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/usr/bin/env node
require('coffee-script/register');
require('./caniuse.coffee');
213 changes: 213 additions & 0 deletions caniuse.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
data = require 'caniuse-db/data.json'
colors = require 'colors'
linewrap = require 'linewrap'
open = require 'open'

argv = require 'yargs'
.option 'short',
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',
type: 'boolean'
default: undefined
describe: "Long output: show more information (default when displaying a single result)"
.option 'oneline',
type: 'boolean'
default: false
describe: "One-line output: just global percentages, no per-browser info"
.option 'oneline-browser',
type: 'boolean'
default: false
describe: "One-line output with browser info, implies --abbrev and --current"
.option 'abbrev',
type: 'boolean'
default: false
describe: "Abbreviate browser names"
.option 'percentages',
type: 'boolean'
default: false
describe: "Include browser version usage percentages"
.option 'future',
type: 'boolean'
default: false
describe: "Include future browser versions"
.option 'current',
type: 'boolean'
default: false
describe: "Don't include old browser versions, equivalent to --era e0"
.option 'era',
type: 'string'
describe: "How many versions back to go, e0 to #{Object.keys(data.eras)[0]}"
.option 'mobile',
type: 'boolean'
default: false
describe: "Include mobile browsers"
.option 'desktop',
type: 'boolean'
default: true
describe: "Include desktop browsers"
.option 'browser',
type: 'string'
describe: "Show results for these browsers, comma-separated (#{Object.keys(data.agents)})"
.option 'web',
type: 'boolean'
default: false
describe: "Go to the search page on caniuse.com"

.help 'help'
.argv

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

resultmap = y: "", n: "", a: "", u: ""
supernums = "⁰¹²³⁴⁵⁶⁷⁸⁹"

# 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 "#{result.usage_perc_y}%".green if result.usage_perc_y
percentages.push "#{result.usage_perc_a}%".yellow if result.usage_perc_y
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#{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"
36 changes: 36 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"name": "caniuse-cmd",
"version": "1.0.0",
"description": "caniuse for the command line",
"scripts": {
"test": "mocha"
},
"preferGlobal": true,
"bin": {
"caniuse": "./bin.js"
},
"repository": {
"type": "git",
"url": "https://github.com/sgentle/caniuse-cmd.git"
},
"keywords": [
"caniuse"
],
"author": "Sam Gentle <sam@samgentle.com>",
"license": "MIT",
"bugs": {
"url": "https://github.com/sgentle/caniuse-cmd/issues"
},
"homepage": "https://github.com/sgentle/caniuse-cmd",
"dependencies": {
"caniuse-db": "~1.0.0",
"coffee-script": "=1.9.1",
"colors": "^1.0.3",
"linewrap": "^0.2.1",
"open": "0.0.5",
"yargs": "~3.5.4"
},
"devDependencies": {
"mocha": "^2.2.1"
}
}

0 comments on commit b856619

Please sign in to comment.