platform/templates/apply.js

117 lines
3.7 KiB
JavaScript
Raw Normal View History

const { join } = require("path")
const { readFileSync, writeFileSync, existsSync, readdirSync, lstatSync, copyFileSync, mkdirSync, rmSync } = require('fs')
const { spawnSync } = require('child_process')
function update (current, template) {
if (template !== undefined && Object.keys(template).length > 0) {
let value = current ?? {}
for (const [k, v] of Object.entries(template)) {
if(value[k] !== v) {
console.log('updating ', k, 'to', v)
}
value[k] = v
}
return value
}
return current
}
function copyFiles(source, target, replaces) {
const files = readdirSync(source)
for (const f of files) {
const sourceFile = join(source, f)
const targetFile = join(target, f)
if (lstatSync(sourceFile).isDirectory()) {
if (!existsSync(targetFile)) {
mkdirSync(targetFile, {recursive: true})
}
copyFiles(sourceFile, targetFile, replaces)
} else {
if( f.startsWith('~')) {
// File should be removed from target folder
const newTargetFile = join(target, f.substring(1))
if (existsSync(newTargetFile)) {
rmSync(newTargetFile)
}
} else {
if( replaces.includes(targetFile) && existsSync(targetFile)) {
// We need replace content of file as defined.
rmSync(targetFile)
}
if (!existsSync(targetFile)) {
// Copy if not exists.
copyFileSync(sourceFile, targetFile)
}
}
}
}
}
function updatePackage(packageRoot, templates) {
const pkgFile = join(packageRoot, 'package.json')
const packageSource = readFileSync(pkgFile)
const currentPackage = JSON.parse(packageSource)
let template
for (const t of templates) {
if( t.isDefault) {
template = t
}
// Allow to configure explicit template selection
if( currentPackage.template === t.package.name) {
template = t
break
}
if (t.package.peerDependencies !== undefined) {
const peers = Object.keys(t.package.peerDependencies)
const deps = Object.keys(currentPackage.dependencies ?? {})
const devDeps = Object.keys(currentPackage.devDependencies ?? {})
if( peers.length > 0 && (peers.every((v) => deps.includes(v)) || peers.every((v) => devDeps.includes(v)))) {
// If we had every peer dep in package.
template = t
}
}
}
console.log('updating => ', currentPackage.name, ' with template', template.package.name)
const packageJson = template.package
currentPackage.devDependencies = update(currentPackage.devDependencies, packageJson.devDependencies )
currentPackage.dependencies = update(currentPackage.dependencies, packageJson.dependencies )
currentPackage.scripts = update(currentPackage.scripts, packageJson.scripts )
const newPackage = JSON.stringify(currentPackage, undefined, 2)
if (packageSource !== newPackage) {
writeFileSync(pkgFile, newPackage.trim() + '\n')
}
// Copy missing files.
copyFiles(template.root, packageRoot, (template.package['#replaces'] ?? []).map(f => join(packageRoot, f)) )
}
function listPackages() {
const out = spawnSync('rush', ['list', '--json'], { encoding : 'utf8' }).stdout
const projects = JSON.parse(out)
return projects.projects.map(it => it.fullPath)
}
console.log('running at:', __dirname)
const templates = readdirSync(__dirname)
.map(d => join(__dirname, d))
.filter(d => lstatSync(d).isDirectory() && existsSync(join(d, 'package.json')) )
.map(d => ({
root: d,
isDefault: d.endsWith('default'),
package: JSON.parse(readFileSync(join(d, 'package.json')))
}))
console.log('Detected templates:', templates.map(t => (t.package.name + ':' + t.package.version)))
const projects = listPackages()
for (const p of projects) {
updatePackage(p, templates)
}