├── .gitattributes
├── .gitignore
├── .prettierrc
├── .editorconfig
├── api
├── text
│ └── index.js
├── crate
│ └── index.js
├── npm
│ └── index.js
├── measure-width.js
├── github
│ └── index.js
├── home
│ └── index.js
└── utils.js
├── package.json
├── LICENSE
├── vercel.json
└── README.md
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .DS_Store
3 | *.log
4 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "semi": false,
3 | "singleQuote": true,
4 | "bracketSpacing": true
5 | }
6 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 2
6 | end_of_line = lf
7 | charset = utf-8
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 |
11 | [*.md]
12 | trim_trailing_whitespace = false
13 |
--------------------------------------------------------------------------------
/api/text/index.js:
--------------------------------------------------------------------------------
1 | const { parse } = require('url')
2 | const { sendSVG, handleError, escape } = require('../utils')
3 |
4 | module.exports = handleError(async (req, res) => {
5 | const {
6 | query: { text = '' }
7 | } = parse(req.url, true)
8 | sendSVG(res, escape(text))
9 | })
10 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "version": "0.3.0",
4 | "name": "version-badge",
5 | "license": "MIT",
6 | "dependencies": {
7 | "axios": "^0.18.0",
8 | "express": "^4.15.3",
9 | "lru-cache": "^4.1.1",
10 | "marked": "^0.5.2",
11 | "pdfkit": "^0.8.3"
12 | },
13 | "devDependencies": {
14 | "semantic-release": "^15.13.2"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/api/crate/index.js:
--------------------------------------------------------------------------------
1 | const { parse } = require('url')
2 | const axios = require('axios')
3 | const { sendSVG, handleError } = require('../utils')
4 |
5 | module.exports = handleError(async (req, res) => {
6 | const {
7 | query: { name }
8 | } = parse(req.url, true)
9 | const { data } = await axios.get(`https://crates.io/api/v1/crates/${name}`)
10 | sendSVG(res, `v${data.crate.max_version}`)
11 | })
12 |
--------------------------------------------------------------------------------
/api/npm/index.js:
--------------------------------------------------------------------------------
1 | const { parse } = require('url')
2 | const axios = require('axios')
3 | const { sendSVG, handleError } = require('../utils')
4 |
5 | module.exports = handleError(async (req, res) => {
6 | const {
7 | query: { name, tag = 'latest' }
8 | } = parse(req.url, true)
9 | const { data } = await axios.get(`https://registry.npmjs.org/${name}`)
10 | sendSVG(res, `v${data['dist-tags'][tag]}`)
11 | })
12 |
--------------------------------------------------------------------------------
/api/measure-width.js:
--------------------------------------------------------------------------------
1 | const PDFDocument = require('pdfkit')
2 | const cache = require('lru-cache')({
3 | max: 128 * 1024 * 1024,
4 | length: src => src.length
5 | })
6 |
7 | const doc = new PDFDocument({ size: 'A4', layout: 'landscape' })
8 | doc.font('Helvetica')
9 | doc.fontSize(12)
10 |
11 | module.exports = str => {
12 | let width = cache.get(str)
13 | if (width) {
14 | return width
15 | }
16 |
17 | width = doc.widthOfString(str)
18 | cache.set(str, width)
19 | return width
20 | }
21 |
--------------------------------------------------------------------------------
/api/github/index.js:
--------------------------------------------------------------------------------
1 | const { parse } = require('url')
2 | const axios = require('axios')
3 | const { sendSVG, handleError } = require('../utils')
4 |
5 | module.exports = handleError(async (req, res) => {
6 | const {
7 | query: {
8 | owner,
9 | repo,
10 | file = 'package.json',
11 | branch = 'master',
12 | field = 'version'
13 | }
14 | } = parse(req.url, true)
15 | const { data } = await axios.get(
16 | `https://raw.githubusercontent.com/${owner}/${repo}/${branch}/${file}`
17 | )
18 | sendSVG(res, `v${data[field]}`)
19 | })
20 |
--------------------------------------------------------------------------------
/api/home/index.js:
--------------------------------------------------------------------------------
1 | const marked = require('marked')
2 | const axios = require('axios')
3 | const { handleError } = require('../utils')
4 |
5 | module.exports = handleError(async (req, res) => {
6 | const { data } = await axios.get(
7 | 'https://raw.githubusercontent.com/egoist/version-badge/master/README.md'
8 | )
9 | res.setHeader('content-type', 'text/html')
10 | res.end(`
11 |
12 |
Version Badge
13 |
14 |
20 | ${marked(data)}
21 | `)
22 | })
23 |
--------------------------------------------------------------------------------
/api/utils.js:
--------------------------------------------------------------------------------
1 | const measureWidth = require('./measure-width')
2 |
3 | exports.sendSVG = (res, text) => {
4 | res.setHeader('content-type', 'image/svg+xml')
5 | res.end(`
8 | `)
9 | }
10 |
11 | exports.handleError = fn => {
12 | return async (req, res) => {
13 | try {
14 | await fn(req, res)
15 | } catch (err) {
16 | console.error(err)
17 | if (err.response) {
18 | res.statusCode = err.response.status
19 | res.end(err.response.data)
20 | } else {
21 | res.statusCode = 500
22 | res.end(err.response.data)
23 | }
24 | }
25 | }
26 | }
27 |
28 | exports.escape = input => input
29 | .replace(/&/g, '&')
30 | .replace(/"/g, '"')
31 | .replace(/'/g, ''')
32 | .replace(//g, '>')
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) EGOIST <0x142857@gmail.com> (egoist.sh)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/vercel.json:
--------------------------------------------------------------------------------
1 | {
2 | "alias": ["version-badge.now.sh", "version-badge.egoist.sh"],
3 | "builds": [
4 | {
5 | "src": "api/*/index.js",
6 | "use": "@now/node"
7 | }
8 | ],
9 | "routes": [
10 | {
11 | "src": "/npm/(.+)\\.svg$",
12 | "dest": "/api/npm?name=$1"
13 | },
14 | {
15 | "src": "/npm/(.+)",
16 | "dest": "/api/npm?name=$1"
17 | },
18 | {
19 | "src": "/github/([^/]+)/([^/]+)\\.svg$",
20 | "dest": "/api/github?owner=$1&repo=$2"
21 | },
22 | {
23 | "src": "/gh/([^/]+)/([^/]+)\\.svg$",
24 | "dest": "/api/github?owner=$1&repo=$2"
25 | },
26 | {
27 | "src": "/github/([^/]+)/([^/]+)",
28 | "dest": "/api/github?owner=$1&repo=$2"
29 | },
30 | {
31 | "src": "/gh/([^/]+)/([^/]+)",
32 | "dest": "/api/github?owner=$1&repo=$2"
33 | },
34 | {
35 | "src": "/crate/(.+)",
36 | "dest": "/api/crate?name=$1"
37 | },
38 | {
39 | "src": "/text",
40 | "dest": "/api/text"
41 | },
42 | {
43 | "src": "/",
44 | "dest": "/api/home"
45 | },
46 | {
47 | "src": "/favicon.ico",
48 | "dest": "/api/404"
49 | }
50 | ]
51 | }
52 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # version-badge 
2 |
3 | > Display a version badge.
4 |
5 | ## What?
6 |
7 | Designed to be put right next to your project title:
8 |
9 | ```markdown
10 | # chalk 
11 | ```
12 |
13 | See the title of this README to get the idea :)
14 |
15 | Of course you can link the svg to anywhere like the npm page:
16 |
17 | ```markdown
18 | # chalk [](https://npmjs.com/package/chalk)
19 | ```
20 |
21 | > **Note:** To make this service keep working, you can [donate](https://github.com/egoist/donate) to support my work.
22 |
23 | ## Usage
24 |
25 | ### npm
26 |
27 | GET `/npm/:name`
28 |
29 | Query:
30 |
31 | - `tag`: Default `latest`. Release tag, eg: `beta`
32 |
33 | Examples:
34 |
35 | - https://version-badge.egoist.sh/npm/vue
36 | - https://version-badge.egoist.sh/npm/webpack
37 | - https://version-badge.egoist.sh/npm/poi?tag=next
38 |
39 | ### github
40 |
41 | Directly get the version from a file that's hosted on GitHub:
42 |
43 | GET `/github/:owner/:repo`
44 | Alias `/gh/:owner/:repo`
45 |
46 | Query:
47 |
48 | - `file`: Default `package.json`
49 | - `field`: Default `version`
50 | - `branch`: Default `master`
51 |
52 | Examples:
53 |
54 | - https://version-badge.egoist.sh/github/zeit/next.js
55 | - https://version-badge.egoist.sh/github/facebookincubator/create-react-app?file=packages/create-react-app/package.json
56 |
57 | ### rust crate
58 |
59 | GET `/crate/:name`
60 |
61 | Examples:
62 |
63 | - https://version-badge.egoist.sh/crate/rand
64 | - https://version-badge.egoist.sh/crate/clap
65 |
66 | ### text
67 |
68 | GET `/text?text=random_text`
69 |
70 | Examples:
71 |
72 | - https://version-badge.egoist.sh/text?text=beta
73 | - https://version-badge.egoist.sh/text?text=coming%20soon
74 |
75 | ## Prior Art
76 |
77 | I made this service because following one does not support npm (directly) and mono repos.
78 |
79 | - [npm-version-badge](https://github.com/teelaunch/npm-version-badge)
80 |
81 | ## License
82 |
83 | MIT © [EGOIST](github.com/EGOIST)
84 |
--------------------------------------------------------------------------------