Merge branch 'main' of git.zomo.dev:zomo/browser-scripts-builder into main

This commit is contained in:
2022-06-10 21:59:10 -05:00
9 changed files with 406 additions and 182 deletions

View File

@@ -1,34 +1,32 @@
import { build, BuildFailure } from 'esbuild'
import { existsSync, readFileSync, writeFileSync, unlinkSync } from 'fs'
import { DistPath, ScriptPath } from './paths'
import { buildSync, BuildFailure, BuildOptions } from 'esbuild'
import { existsSync, writeFileSync, unlinkSync } from 'fs'
import { DistPath, ScriptBase, ScriptPath } from './paths'
import { UserScriptMetaFull } from './types'
import readMeta from './readmeta'
import { format, Options } from 'prettier'
import { CLIArgs } from './main'
export default async function (
export default function (
name: string,
watchCallback:
| ((meta: UserScriptMetaFull, error: string | null) => void)
| false = false
): Promise<[UserScriptMetaFull, string | null]> {
watchCallback: (meta: UserScriptMetaFull, error: string | null) => void,
PrettierConfig: Options,
CLIArgs: CLIArgs
): [UserScriptMetaFull, string | null] {
//read meta file
let [metaJson, metaString] = readMeta(name)
let outPath = DistPath(name)
let pathDist = DistPath(name)
let error: string | null = null
console.log('build watch?', !watchCallback ? false : 'obj')
try {
await build({
let result = runEsbuild(
{
entryPoints: [ScriptPath(name).main],
outfile: outPath,
outfile: pathDist,
target: 'esnext',
platform: 'node',
format: 'esm',
bundle: true,
minify: false,
minify: CLIArgs.minify,
define: {
UserScriptName: `'${metaJson.name}'`,
@@ -39,21 +37,148 @@ export default async function (
UserScriptSupportURL: `'${metaJson.supportURL}'`,
UserScriptHomepageURL: `'${metaJson.homepageURL}'`,
},
})
} catch (err) {
console.error(name, err)
error = (err as BuildFailure).message
}
},
result => {
let error = runPostEsbuild(
name,
result,
metaString,
CLIArgs,
PrettierConfig
)
watchCallback(metaJson, error)
},
CLIArgs
)
//add UserScript header
if (existsSync(outPath)) {
if (!error) {
let content = readFileSync(outPath).toString()
writeFileSync(outPath, metaString + content)
} else {
unlinkSync(outPath)
}
}
let error = runPostEsbuild(
name,
result,
metaString,
CLIArgs,
PrettierConfig
)
return [metaJson, error]
}
function doErrorFile(
pathError: string,
pathOutFile: string,
error: string | null
) {
if (error !== null) {
writeFileSync(pathError, `${new Date().toISOString()}\n\n${error}`)
if (existsSync(pathOutFile)) {
unlinkSync(pathOutFile)
}
} else if (existsSync(pathError)) {
unlinkSync(pathError)
}
}
interface RunEsbuildResult {
content: string | null
error: string | null
errorRaw?: BuildFailure
}
function runEsbuild(
opts: BuildOptions,
watchCallback: (result: RunEsbuildResult) => void,
CLIArgs: CLIArgs
): RunEsbuildResult {
opts.write = false
if (CLIArgs.watch) {
opts.watch = {
onRebuild(err, res) {
if (err) {
watchCallback({
content: null,
error: (err as BuildFailure).message,
errorRaw: err,
})
} else if (res) {
let content = ''
if (res.outputFiles && res.outputFiles.length > 0) {
content = res.outputFiles[0].text
}
if (content === '') {
watchCallback({
content: null,
error: 'No output',
})
}
watchCallback({
content,
error: null,
})
} else {
watchCallback({
content: null,
error: 'No result',
})
}
},
}
}
try {
let res = buildSync(opts)
let content = ''
if (res.outputFiles && res.outputFiles.length > 0) {
content = clearFilenameComments(res.outputFiles[0].text)
}
if (content === '') {
return {
content: null,
error: 'No output',
}
}
return {
content,
error: null,
}
} catch (err) {
return {
content: null,
error: (err as BuildFailure).message,
}
}
}
function runPostEsbuild(
name: string,
result: RunEsbuildResult,
metaString: string,
CLIArgs: CLIArgs,
PrettierConfig: Options
) {
let error: string | null = null
let path = ScriptPath(name)
let pathDist = DistPath(name)
if (result.error) {
console.error(name, result.errorRaw || result.error)
error = result.error
} else if (result.content) {
let content = metaString + result.content
if (CLIArgs.prettier) {
content = format(content, PrettierConfig)
}
writeFileSync(pathDist, content)
} else {
console.error(name, 'No output')
}
doErrorFile(path.error, pathDist, error)
return error
}
//remove all filename comments
function clearFilenameComments(content: string): string {
let regexp = new RegExp(`//\\s*${ScriptBase}/.*(?:\\n|$)`, 'g')
return content.replace(regexp, '')
}

View File

@@ -1,22 +1,23 @@
import {
existsSync,
lstatSync,
readdirSync,
unlinkSync,
writeFileSync,
} from 'fs'
import { existsSync, lstatSync, readdirSync, unlinkSync } from 'fs'
import commandLineArgs from 'command-line-args'
import { DistBase, DistPath, ScriptBase, ScriptPath } from './paths'
import { resolveConfig } from 'prettier'
import { DistBase, ScriptBase, ScriptPath } from './paths'
import { readmeData, updateReadmeFile } from './readmefile'
import runBuild from './build'
import { UserScriptMetaFull } from './types'
const CLIArgs = commandLineArgs([
{ name: 'watch', alias: 'w', type: Boolean },
]) as {
export interface CLIArgs {
watch: boolean
minify: boolean
prettier: boolean
}
const CLIArgs = commandLineArgs([
{ name: 'watch', alias: 'w', type: Boolean, defaultValue: false },
{ name: 'minify', alias: 'm', type: Boolean, defaultValue: false },
{ name: 'prettier', alias: 'p', type: Boolean, defaultValue: false },
]) as CLIArgs
//if package.json doesn't exist then there is no point in continuing
if (!existsSync('package.json') || !lstatSync('package.json').isFile()) {
console.error('package.json not found, unwilling to run')
@@ -26,66 +27,54 @@ if (!existsSync('package.json') || !lstatSync('package.json').isFile()) {
//delete compiled scripts
readdirSync(DistBase).forEach(file => unlinkSync(`${DistBase}/${file}`))
//compile scripts
;(async () => {
let scripts = readdirSync(ScriptBase)
let scriptMeta: readmeData[] = []
for (let name of scripts) {
let path = ScriptPath(name)
if (
!name.endsWith('_') &&
existsSync(path.dir) &&
lstatSync(path.dir).isDirectory() &&
existsSync(path.main) &&
lstatSync(path.main).isFile()
) {
let id = scriptMeta.length
function postWatchUpdate(
meta: UserScriptMetaFull,
error: string | null
) {
console.log('watch callback')
scriptMeta[id] = { meta, error }
doErrorFile(path.error, DistPath(name), error)
console.log('WATCH', name, meta.version)
updateReadmeFile(scriptMeta)
}
let [meta, error] = await runBuild(
name,
CLIArgs.watch ? postWatchUpdate : false
)
scriptMeta[id] = { meta, error }
console.log(name, meta.version)
doErrorFile(path.error, DistPath(name), error)
}
//read prettierrc file and make sure `babel` is the configured parser
const PrettierConfig = (() => {
let config = resolveConfig.sync(process.cwd()) || {}
return {
...config,
parser: 'babel',
}
updateReadmeFile(scriptMeta)
console.log('\nFinished Compiling\n')
if (CLIArgs.watch) console.log('Listening for Changes\n')
})()
function doErrorFile(
pathError: string,
pathOutFile: string,
error: string | null
) {
if (error !== null) {
writeFileSync(pathError, `${new Date().toISOString()}\n\n${error}`)
//compile scripts
let scripts = readdirSync(ScriptBase)
let scriptMeta: readmeData[] = []
if (existsSync(pathOutFile)) {
unlinkSync(pathOutFile)
for (let name of scripts) {
let path = ScriptPath(name)
if (
!name.endsWith('_') &&
existsSync(path.dir) &&
lstatSync(path.dir).isDirectory() &&
existsSync(path.main) &&
lstatSync(path.main).isFile()
) {
let id = scriptMeta.length
function postWatchUpdate(
meta: UserScriptMetaFull,
error: string | null
) {
scriptMeta[id] = { meta, error }
console.log('WATCH', name, meta.version)
updateReadmeFile(scriptMeta)
}
} else if (existsSync(pathError)) {
unlinkSync(pathError)
let [meta, error] = runBuild(
name,
postWatchUpdate,
PrettierConfig,
CLIArgs
)
scriptMeta[id] = { meta, error }
console.log(name, meta.version)
}
}
updateReadmeFile(scriptMeta)
console.log(
`\nFinished Compiling\n${CLIArgs.watch ? 'Listening for Changes\n' : ''}`
)