virt2/api/soft/CodeMirror/bin/cm.js

217 lines
7.0 KiB
JavaScript
Executable File

#!/usr/bin/env node
const child = require("child_process"), fs = require("fs"), fsp = fs.promises, path = require("path")
let root = path.join(__dirname, "..")
class Pkg {
constructor(name) {
this.name = name
this.dir = path.join(root, name)
this.json = require(path.join(this.dir, "package.json"))
}
}
const packageFile = path.join(root, "package.json"), packageJSON = JSON.parse(fs.readFileSync(packageFile, "utf8"))
const packages = [], packageNames = Object.create(null)
for (let exp of Object.keys(packageJSON.exports)) {
let pkg = new Pkg(/\.\/(.*)/.exec(exp)[1])
packages.push(pkg)
packageNames[pkg.name] = pkg
}
function external(id) { return id != "tslib" && !/^\.?\//.test(id) }
function start() {
let command = process.argv[2]
let args = process.argv.slice(3)
let cmdFn = {
packages: listPackages,
build,
devserver,
release,
"--help": () => help(0)
}[command]
if (!cmdFn || cmdFn.length > args.length) help(1)
new Promise(r => r(cmdFn.apply(null, args))).catch(e => error(e))
}
function help(status) {
console.log(`Usage:
cm packages Emit a list of all pkg names
cm build Build the bundle files
cm devserver Start a dev server on port 8090
cm release Create commits to tag a release
cm --help`)
process.exit(status)
}
function error(err) {
console.error(err)
process.exit(1)
}
function run(cmd, args, wd = root) {
return child.execFileSync(cmd, args, {cwd: wd, encoding: "utf8", stdio: ["ignore", "pipe", process.stderr]})
}
function listPackages() {
console.log(packages.map(p => p.name).join("\n"))
}
async function runRollup(configs) {
for (let config of Array.isArray(configs) ? configs : [configs]) {
let bundle = await require("rollup").rollup(config)
let result = await bundle.generate(config.output)
let dir = path.dirname(config.output.file)
await fsp.mkdir(dir, {recursive: true}).catch(() => null)
for (let file of result.output) {
await fsp.writeFile(path.join(dir, file.fileName), file.code || file.source)
if (file.map)
await fsp.writeFile(path.join(dir, file.fileName + ".map"), file.map.toString())
}
}
}
function rollupConfig(pkg) {
return {
input: path.join(pkg.dir, pkg.json.types + ".js"),
external,
output: {
format: "esm",
file: path.join(pkg.dir, "dist", "index.js"),
sourcemap: true,
externalLiveBindings: false
}
}
}
async function build() {
console.info("Running TypeScript compiler...")
let t0 = Date.now()
tsBuild()
console.info(`Done in ${Date.now() - t0}ms`)
console.info("Building bundles...")
t0 = Date.now()
await runRollup(packages.map(rollupConfig))
console.log(`Done in ${Date.now() - t0}ms`)
}
function startServer() {
let serve = path.join(root, "demo")
let moduleserver = new (require("esmoduleserve/moduleserver"))({root: serve, maxDepth: 2})
let serveStatic = require("serve-static")(serve)
require("http").createServer((req, resp) => {
moduleserver.handleRequest(req, resp) || serveStatic(req, resp, err => {
resp.statusCode = 404
resp.end('Not found')
})
}).listen(8090, process.env.OPEN ? undefined : "127.0.0.1")
console.log("Dev server listening on 8090")
}
const watchConfig = {clearScreen: false}
function tsWatch() {
const ts = require("typescript")
const formatHost = {
getCanonicalFileName: path => path,
getCurrentDirectory: ts.sys.getCurrentDirectory,
getNewLine: () => "\n"
}
ts.createWatchProgram(ts.createWatchCompilerHost(
path.join(root, "tsconfig.json"),
{},
ts.sys,
ts.createEmitAndSemanticDiagnosticsBuilderProgram,
diag => console.error(ts.formatDiagnostic(diag, formatHost)),
diag => console.info(ts.flattenDiagnosticMessageText(diag.messageText, "\n"))
))
}
function tsBuild() {
const ts = require("typescript")
const formatHost = {
getCanonicalFileName: path => path,
getCurrentDirectory: ts.sys.getCurrentDirectory,
getNewLine: () => "\n"
}
let conf = ts.getParsedCommandLineOfConfigFile(path.join(root, "tsconfig.json"), {}, ts.sys)
let program = ts.createProgram(conf.fileNames, conf.options)
let emitResult = program.emit()
for (let diag of ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics))
console.error(ts.formatDiagnostic(diag, formatHost))
if (emitResult.emitSkipped) error("TS build failed")
}
function devserver() {
tsWatch()
console.log("Watching...")
for (let pkg of packages) {
let watcher = require("rollup").watch(Object.assign(rollupConfig(pkg), watchConfig))
watcher.on("event", event => {
if (event.code == "START") console.info("Start bundling " + pkg.name + "...")
else if (event.code == "END") console.info("Finished bundling " + pkg.name)
else if (event.code == "ERROR") console.error("Bundling error: " + event.error)
})
}
startServer()
}
function changelog(since) {
let commits = run("git", ["log", "--format=%B", "--reverse", since + "..master"])
let result = {fix: [], feature: [], breaking: []}
let re = /\n\r?\n(BREAKING|FIX|FEATURE):\s*([^]*?)(?=\r?\n\r?\n|\r?\n?$)/g, match
while (match = re.exec(commits)) result[match[1].toLowerCase()].push(match[2].replace(/\r?\n/g, " "))
return result
}
function bumpVersion(version, changes) {
let [major, minor, patch] = version.split(".")
if (changes.breaking.length && major != "0") return `${Number(major) + 1}.0.0`
if (changes.feature.length || changes.breaking.length) return `${major}.${Number(minor) + 1}.0`
if (changes.fix.length) return `${major}.${minor}.${Number(patch) + 1}`
throw new Error("No new release notes!")
}
function releaseNotes(changes, version) {
let pad = n => n < 10 ? "0" + n : n
let d = new Date, date = d.getFullYear() + "-" + pad(d.getMonth() + 1) + "-" + pad(d.getDate())
let types = {breaking: "Breaking changes", fix: "Bug fixes", feature: "New features"}
let refTarget = "https://codemirror.net/6/docs/ref/"
let head = `## ${version} (${date})\n\n`, body = ""
for (let type in types) {
let messages = changes[type]
if (messages.length) body += `### ${types[type]}\n\n`
messages.forEach(message => body += message.replace(/\]\(##/g, "](" + refTarget + "#") + "\n\n")
}
return {head, body}
}
function setModuleVersion(version) {
fs.writeFileSync(packageFile, fs.readFileSync(packageFile, "utf8").replace(/"version":\s*".*?"/, `"version": "${version}"`))
}
function release() {
let currentVersion = packageJSON.version
let changes = changelog(currentVersion)
let newVersion = bumpVersion(currentVersion, changes)
console.log(`Creating @codemirror/next ${newVersion}`)
let notes = releaseNotes(changes, newVersion)
setModuleVersion(newVersion)
let log = path.join(root, "CHANGELOG.md")
fs.writeFileSync(log, notes.head + notes.body + fs.readFileSync(log, "utf8"))
run("git", ["add", "package.json"])
run("git", ["add", "CHANGELOG.md"])
run("git", ["commit", "-m", `Mark version ${newVersion}`])
run("git", ["tag", newVersion, "-m", `Version ${newVersion}\n\n${notes.body}`, "--cleanup=verbatim"])
}
start()