surfingkeys-conf/gulpfile.js

240 lines
7.7 KiB
JavaScript
Raw Normal View History

2017-12-02 02:48:58 +00:00
const gulp = require("gulp")
2019-03-07 22:13:49 +00:00
const { parallel, series } = require("gulp")
const parcel = require("gulp-parcel")
2017-12-02 02:48:58 +00:00
const replace = require("gulp-replace")
const rename = require("gulp-rename")
const eslint = require("gulp-eslint")
2019-03-10 03:28:48 +00:00
const file = require("gulp-file")
2017-12-02 02:48:58 +00:00
const path = require("path")
const del = require("del")
const os = require("os")
2019-03-10 03:28:48 +00:00
const fs = require("fs").promises
const fetch = require("node-fetch")
2017-12-02 02:48:58 +00:00
const { spawn } = require("child_process")
const { URL } = require("url")
2017-08-28 03:24:24 +00:00
const compl = require("./completions")
const conf = require("./conf")
const keys = require("./keys")
const util = require("./util")
2017-12-02 02:48:58 +00:00
const paths = {
scripts: ["conf.priv.js", "completions.js", "conf.js", "actions.js", "help.js", "keys.js", "util.js"],
entry: "conf.js",
2017-12-02 02:48:58 +00:00
gulpfile: ["gulpfile.js"],
readme: ["README.tmpl.md"],
2019-03-10 03:28:48 +00:00
assets: "assets",
2017-12-02 02:48:58 +00:00
screenshots: "assets/screenshots",
2019-03-10 03:28:48 +00:00
favicons: "assets/favicons",
2017-12-02 02:48:58 +00:00
}
2017-08-28 03:24:24 +00:00
// This notice will be injected into the generated README.md file
const disclaimer = `\
<!--
NOTICE:
This is an automatically generated file - Do not edit it directly.
The source file is README.tmpl.md
2017-12-02 02:48:58 +00:00
-->`
2017-12-02 02:48:58 +00:00
gulp.task("gulp-autoreload", () => {
let p
const spawnChildren = function spawnChildren() {
if (p) p.kill()
p = spawn("gulp", ["lint-gulpfile", "install", "watch-nogulpfile"], { stdio: "inherit" })
}
gulp.watch("gulpfile.js", spawnChildren)
spawnChildren()
})
2019-03-10 03:28:48 +00:00
gulp.task("clean", () => del(["build", ".cache", ".tmp-gulp-compile-*", paths.favicons]))
2017-08-28 03:24:24 +00:00
2019-03-07 22:13:49 +00:00
gulp.task("lint", () => gulp
.src([].concat(paths.scripts, paths.gulpfile))
.pipe(eslint())
.pipe(eslint.format()))
gulp.task("lint-gulpfile", () => gulp
.src(paths.gulpfile)
.pipe(eslint())
.pipe(eslint.format()))
// gulp.task("check-priv", async () => {
// try {
// fs.statSync("./conf.priv.js")
// } catch (e) {
// // eslint-disable-next-line no-console
// console.log("Creating ./conf.priv.js based on ./conf.priv.example.js")
// fs.copyFileSync("./conf.priv.example.js", "./conf.priv.js", fs.constants.COPYFILE_EXCL)
// }
// })
2017-08-28 03:24:24 +00:00
2019-03-10 03:28:48 +00:00
gulp.task("docs", parallel(async () => {
2017-12-02 02:48:58 +00:00
const screens = {}
let screenshotList = ""
2019-03-10 03:28:48 +00:00
const screenshots = await fs.readdir(path.join(__dirname, paths.screenshots))
screenshots.forEach((s) => {
const name = path.basename(s, ".png").split("-")
const alias = name[0]
2017-12-02 02:48:58 +00:00
if (!screens[alias]) {
screens[alias] = []
}
screens[alias].push(path.join(paths.screenshots, path.basename(s)))
})
2019-03-10 03:28:48 +00:00
let complTable = Object.keys(compl).sort((a, b) => {
if (a < b) return -1
if (a > b) return 1
return 0
})
let keysTable = Object.keys(keys.maps).sort((a, b) => {
if (a === "global") return -1
if (b === "global") return 1
2017-12-02 02:48:58 +00:00
if (a < b) return -1
if (a > b) return 1
return 0
2019-03-10 03:28:48 +00:00
})
complTable = await complTable.reduce(async (acc1p, k) => {
const acc1 = await acc1p
2017-12-02 02:48:58 +00:00
const c = compl[k]
2019-03-10 03:28:48 +00:00
const u = new URL(c.domain ? `https://${c.domain}` : c.search)
// const domain = (u.hostname === "cse.google.com") ? "Google Custom Search" : u.hostname
const domain = u.hostname
2017-12-02 02:48:58 +00:00
let s = ""
if (screens[c.alias]) {
screens[c.alias].forEach((url, i) => {
const num = (i > 0) ? ` ${i + 1}` : ""
2019-03-10 03:28:48 +00:00
s += `<a href="#${c.name}${num.replace(" ", "-")}">:framed_picture:</a>`
2017-12-02 02:48:58 +00:00
screenshotList += `##### ${c.name}${num}\n`
screenshotList += `![${c.name} screenshot](./${url})\n\n`
})
}
2019-03-10 03:28:48 +00:00
const faviconExt = c.favicon ? path.extname(new URL(c.favicon).pathname) : ".ico"
const favicon = `<img src="./assets/favicons/${u.hostname}${faviconExt}" width="16px"> `
return `${acc1}
<tr>
<td><a href="${u.protocol}//${domain}">${favicon}</a></td>
<td><code>${c.alias}</code></td>
<td>${c.name}</td>
<td><a href="${u.protocol}//${domain}">${domain}</a></td>
<td>${s}</td>
</tr>`
}, Promise.resolve(""))
keysTable = await keysTable.reduce(async (acc1p, domain) => {
const acc1 = await acc1p
const header = "<tr><td><strong>Mapping</strong></td><td><strong>Description</strong></td></tr>"
const c = keys.maps[domain]
const maps = c.reduce((acc2, map) => {
2018-11-16 09:04:51 +00:00
let leader = ""
if (typeof map.leader !== "undefined") {
leader = map.leader // eslint-disable-line prefer-destructuring
} else if (domain === "global") {
leader = ""
} else {
leader = conf.siteleader
}
const mapStr = util.escape(`${leader}${map.alias}`.replace(" ", "<space>"))
return `${acc2}<tr><td><code>${mapStr}</code></td><td>${map.description}</td></tr>\n`
}, "")
2019-03-10 03:28:48 +00:00
let domainStr = "<strong>global</strong>"
const favicon = `<img src="./assets/favicons/${domain}.ico" width="16px"> `
if (domain !== "global") {
domainStr = `<a href="//${domain}">${favicon}${domain}</a>`
}
return `${acc1}<tr><th colspan="2">${domainStr}</th></tr>${header}\n${maps}`
2019-03-10 03:28:48 +00:00
}, Promise.resolve(""))
2017-12-02 02:48:58 +00:00
return gulp.src(["./README.tmpl.md"])
.pipe(replace("<!--{{DISCLAIMER}}-->", disclaimer))
.pipe(replace("<!--{{COMPL_COUNT}}-->", Object.keys(compl).length))
.pipe(replace("<!--{{COMPL_TABLE}}-->", complTable))
.pipe(replace("<!--{{KEYS_MAPS_COUNT}}-->", Object.keys(keys.maps).reduce((acc, m) => acc + m.length, 0)))
.pipe(replace("<!--{{KEYS_SITES_COUNT}}-->", Object.keys(keys.maps).length))
.pipe(replace("<!--{{KEYS_TABLE}}-->", keysTable))
.pipe(replace("<!--{{SCREENSHOTS}}-->", screenshotList))
2017-12-02 02:48:58 +00:00
.pipe(rename("README.md"))
.pipe(gulp.dest("."))
2019-03-10 03:28:48 +00:00
}))
const getFavicon = async ({ domain, favicon }, timeout = 5000) => {
// const url = `https://${domain}/favicon.ico`
const url = favicon
// const ico = await fetch(
let data
const ext = path.extname(new URL(favicon).pathname)
try {
const res = await fetch(url, { timeout })
if (!res.ok) {
throw new Error(`request to ${url} failed with code ${res.status}`)
}
data = await res.buffer()
} catch (e) {
// transparent pixel
data = Buffer.from(
"AAABAAEAAQEAAAEAIAAwAAAAFgAAACgAAAABAAAAAgAAAAEAIAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAA==",
"base64"
)
}
return {
name: `${domain}${ext}`,
source: data,
}
}
gulp.task("favicons", async () => {
const sites = [].concat(
// search engine completions
Object.entries(compl)
.map(([, v]) => ({
domain: new URL(v.domain ? `https://${v.domain}` : v.search).hostname,
favicon: v.favicon ? v.favicon : `${new URL(v.domain ? `https://${v.domain}` : v.search).origin}/favicon.ico`,
})),
// site-specific keybindings
Object.keys(keys.maps)
.filter(k => k !== "global")
.map(k => ({
domain: k,
favicon: `${new URL(`https://${k}`).origin}/favicon.ico`,
})),
)
.filter((e, i, arr) => i === arr.indexOf(e)) // Keep only first occurrence of each element
const favicons = (await Promise.all(sites.map(async site => getFavicon(site))))
.filter(e => e !== undefined)
return file(favicons, { src: true })
.pipe(gulp.dest(paths.favicons))
2017-12-02 02:48:58 +00:00
})
2019-03-10 03:28:48 +00:00
gulp.task("docs-full", parallel("docs", "favicons"))
2019-03-07 22:13:49 +00:00
gulp.task("build",
series(
2019-03-10 03:28:48 +00:00
parallel(/* "check-priv", */"clean", "lint", "lint-gulpfile", "docs-full"),
2019-03-07 22:13:49 +00:00
() => gulp
.src(paths.entry, { read: false })
.pipe(parcel())
.pipe(rename(".surfingkeys"))
.pipe(gulp.dest("build"))
))
gulp.task("install",
series("build",
() => gulp.src("build/.surfingkeys").pipe(gulp.dest(os.homedir()))))
gulp.task("watch", () => {
gulp.watch([].concat(paths.scripts, paths.gulpfile), parallel("install"))
})
gulp.task("watch-nogulpfile", async () => parallel(
2019-03-10 03:28:48 +00:00
gulp.watch([].concat(paths.scripts), parallel("docs", "install")),
gulp.watch(paths.readme, parallel("docs"))
2019-03-07 22:13:49 +00:00
))
gulp.task("default", parallel("build"))