commit
a0b8f9aa42
|
@ -0,0 +1,3 @@
|
||||||
|
# Binaries
|
||||||
|
/caniuse
|
||||||
|
/caniuse.exe
|
|
@ -0,0 +1,19 @@
|
||||||
|
Copyright (c) 2022 John Olheiser
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
|
@ -0,0 +1,9 @@
|
||||||
|
# caniuse
|
||||||
|
|
||||||
|
CLI for [caniuse](https://caniuse.com)
|
||||||
|
|
||||||
|
Retrieves data from the [repository](https://github.com/Fyrd/caniuse)
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[MIT](LICENSE)
|
|
@ -0,0 +1,5 @@
|
||||||
|
module go.jolheiser.com/caniuse
|
||||||
|
|
||||||
|
go 1.19
|
||||||
|
|
||||||
|
require github.com/peterbourgon/ff/v3 v3.3.0
|
|
@ -0,0 +1,2 @@
|
||||||
|
github.com/peterbourgon/ff/v3 v3.3.0 h1:PaKe7GW8orVFh8Unb5jNHS+JZBwWUMa2se0HM6/BI24=
|
||||||
|
github.com/peterbourgon/ff/v3 v3.3.0/go.mod h1:zjJVUhx+twciwfDl0zBcFzl4dW8axCRyXE/eKY9RztQ=
|
|
@ -0,0 +1,45 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
const downloadURL = "https://raw.githubusercontent.com/Fyrd/caniuse/main/data.json"
|
||||||
|
|
||||||
|
// Download downloads caniuse data to path
|
||||||
|
func Download(path string) error {
|
||||||
|
res, err := http.Get(downloadURL)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not get data: %v", err)
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
if res.StatusCode != 200 {
|
||||||
|
return fmt.Errorf("could not download data: %s", res.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
fi, err := os.Create(path)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not create %q: %v", path, err)
|
||||||
|
}
|
||||||
|
defer fi.Close()
|
||||||
|
|
||||||
|
_, err = io.Copy(fi, res.Body)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func Load(path string) (Data, error) {
|
||||||
|
var data Data
|
||||||
|
|
||||||
|
fi, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return data, fmt.Errorf("could not read data: %v", err)
|
||||||
|
}
|
||||||
|
defer fi.Close()
|
||||||
|
|
||||||
|
return data, json.NewDecoder(fi).Decode(&data)
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/peterbourgon/ff/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
resultmap = map[string]string{
|
||||||
|
"y": "✔",
|
||||||
|
"n": "✘",
|
||||||
|
"a": "◒",
|
||||||
|
"u": "‽",
|
||||||
|
"i": "ⓘ",
|
||||||
|
"w": "⚠",
|
||||||
|
}
|
||||||
|
supernums = "⁰¹²³⁴⁵⁶⁷⁸⁹"
|
||||||
|
refresh = time.Hour * 24 * 30
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
fs := flag.NewFlagSet("caniuse", flag.ContinueOnError)
|
||||||
|
|
||||||
|
if err := ff.Parse(fs, os.Args[1:],
|
||||||
|
ff.WithEnvVarPrefix("CANIUSE"),
|
||||||
|
); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if fs.NArg() != 1 {
|
||||||
|
fmt.Println("caniuse requires one argument")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := loadData()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("could not load data: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadData() (Data, error) {
|
||||||
|
var data Data
|
||||||
|
|
||||||
|
cache, err := os.UserCacheDir()
|
||||||
|
if err != nil {
|
||||||
|
return data, fmt.Errorf("could not determine cache dir: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
caniuseCache := filepath.Join(cache, "caniuse")
|
||||||
|
if err := os.MkdirAll(caniuseCache, os.ModePerm); err != nil {
|
||||||
|
return data, fmt.Errorf("could not create dir %q: %v", caniuseCache, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
dataPath := filepath.Join(caniuseCache, "data.json")
|
||||||
|
fi, err := os.Stat(dataPath)
|
||||||
|
if err != nil && !errors.Is(err, fs.ErrNotExist) {
|
||||||
|
return data, fmt.Errorf("could not stat %q: %v", dataPath, err)
|
||||||
|
} else if errors.Is(err, fs.ErrNotExist) || time.Since(fi.ModTime()) > refresh {
|
||||||
|
if err := Download(dataPath); err != nil {
|
||||||
|
return data, fmt.Errorf("could not download data: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Load(dataPath)
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
type Data struct {
|
||||||
|
Eras map[string]string `json:"eras"`
|
||||||
|
Agents map[string]struct {
|
||||||
|
Browser string `json:"browser"`
|
||||||
|
LongName string `json:"long_name"`
|
||||||
|
Abbr string `json:"abbr"`
|
||||||
|
Prefix string `json:"prefix"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
UsageGlobal map[string]float64 `json:"usage_global"`
|
||||||
|
Versions []string `json:"versions"`
|
||||||
|
} `json:"agents"`
|
||||||
|
Statuses struct {
|
||||||
|
Rec string `json:"rec"`
|
||||||
|
Pr string `json:"pr"`
|
||||||
|
Cr string `json:"cr"`
|
||||||
|
Wd string `json:"wd"`
|
||||||
|
Ls string `json:"ls"`
|
||||||
|
Other string `json:"other"`
|
||||||
|
Unoff string `json:"unoff"`
|
||||||
|
} `json:"statuses"`
|
||||||
|
Cats map[string][]string `json:"cats"`
|
||||||
|
Data map[string]struct {
|
||||||
|
Title string `json:"title"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Spec string `json:"spec"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
Links []struct {
|
||||||
|
URL string `json:"url"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
} `json:"links"`
|
||||||
|
Categories []string `json:"categories"`
|
||||||
|
Stats map[string]map[string]stat `json:"stats"`
|
||||||
|
Notes string `json:"notes"`
|
||||||
|
NotesByNum map[string]string `json:"notes_by_num"`
|
||||||
|
UsagePercY float64 `json:"usage_perc_y"`
|
||||||
|
UsagePercA float64 `json:"usage_perc_a"`
|
||||||
|
UCPrefix bool `json:"ucprefix"`
|
||||||
|
Parent string `json:"parent"`
|
||||||
|
Keywords string `json:"keywords"`
|
||||||
|
IEID string `json:"ie_id"`
|
||||||
|
ChromeID string `json:"chrome_id"`
|
||||||
|
FirefoxID string `json:"firefox_id"`
|
||||||
|
WebkitID string `json:"webkit_id"`
|
||||||
|
} `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type stat string
|
||||||
|
|
||||||
|
func (s stat) Bool() bool {
|
||||||
|
return s == "y"
|
||||||
|
}
|
Loading…
Reference in New Issue