import { debug, deepAssign, FileTransformer, log } from "builder-util"
import { readFile } from "fs/promises"
import * as path from "path"
import { Configuration } from "./configuration"
import { Packager } from "./packager"
export const NODE_MODULES_PATTERN = `${path.sep}node_modules${path.sep}`
export function isElectronCompileUsed(info: Packager): boolean {
if (info.config.electronCompile != null) {
return info.config.electronCompile
}
return hasDep("electron-compile", info)
}
export function hasDep(name: string, info: Packager) {
const deps = info.metadata.dependencies
return deps != null && name in deps
}
export function createTransformer(srcDir: string, configuration: Configuration, extraMetadata: any, extraTransformer: FileTransformer | null): FileTransformer {
const mainPackageJson = path.join(srcDir, "package.json")
const isRemovePackageScripts = configuration.removePackageScripts !== false
const isRemovePackageKeywords = configuration.removePackageKeywords !== false
const packageJson = path.sep + "package.json"
return file => {
if (file === mainPackageJson) {
return modifyMainPackageJson(file, extraMetadata, isRemovePackageScripts, isRemovePackageKeywords)
}
if (file.endsWith(packageJson) && file.includes(NODE_MODULES_PATTERN)) {
return readFile(file, "utf-8")
.then(it =>
cleanupPackageJson(JSON.parse(it), {
isMain: false,
isRemovePackageScripts,
isRemovePackageKeywords,
})
)
.catch((e: any) => log.warn(e))
} else if (extraTransformer != null) {
return extraTransformer(file)
} else {
return null
}
}
}
export interface CompilerHost {
compile(file: string): any
saveConfiguration(): Promise<any>
}
export function createElectronCompilerHost(projectDir: string, cacheDir: string): Promise<CompilerHost> {
const electronCompilePath = path.join(projectDir, "node_modules", "electron-compile", "lib")
return require(path.join(electronCompilePath, "config-parser")).createCompilerHostFromProjectRoot(projectDir, cacheDir)
}
const ignoredPackageMetadataProperties = new Set(["dist", "gitHead", "build", "jspm", "ava", "xo", "nyc", "eslintConfig", "contributors", "bundleDependencies", "tags"])
interface CleanupPackageFileOptions {
readonly isRemovePackageScripts: boolean
readonly isRemovePackageKeywords: boolean
readonly isMain: boolean
}
function cleanupPackageJson(data: any, options: CleanupPackageFileOptions): any {
const deps = data.dependencies
const isRemoveBabel = deps != null && typeof deps === "object" && !Object.getOwnPropertyNames(deps).some(it => it.startsWith("babel"))
try {
let changed = false
for (const prop of Object.getOwnPropertyNames(data)) {
if (
prop[0] === "_" ||
ignoredPackageMetadataProperties.has(prop) ||
(options.isRemovePackageScripts && prop === "scripts") ||
(options.isRemovePackageKeywords && prop === "keywords") ||
(options.isMain && prop === "devDependencies") ||
(!options.isMain && prop === "bugs") ||
(isRemoveBabel && prop === "babel")
) {
delete data[prop]
changed = true
}
}
if (changed) {
return JSON.stringify(data, null, 2)
}
} catch (e: any) {
debug(e)
}
return null
}
async function modifyMainPackageJson(file: string, extraMetadata: any, isRemovePackageScripts: boolean, isRemovePackageKeywords: boolean) {
const mainPackageData = JSON.parse(await readFile(file, "utf-8"))
if (extraMetadata != null) {
deepAssign(mainPackageData, extraMetadata)
}
const serializedDataIfChanged = cleanupPackageJson(mainPackageData, {
isMain: true,
isRemovePackageScripts,
isRemovePackageKeywords,
})
if (serializedDataIfChanged != null) {
return serializedDataIfChanged
} else if (extraMetadata != null) {
return JSON.stringify(mainPackageData, null, 2)
}
return null
}