@sap/cds-dk
Version:
Command line client and development toolkit for the SAP Cloud Application Programming Model
100 lines (82 loc) • 3.44 kB
JavaScript
const cds = require('../../../cds')
const { read, write, exists, copy, path:{join, relative}, readdir, rimraf } = cds.utils
const { mkdir, symlink } = require('fs/promises')
const { renderAndCopy } = require('../../template')
const projectReader = require('../../projectReader')
const npmPackageRegex = /^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/i
module.exports = class ExtensionProjectTemplate extends require('../../plugin') {
static help() {
return 'Extension project'
}
options() {
return {
'base': {
type: 'string',
short: 'p',
help: `The project to extend.`
}
}
}
async run() {
let { base, force } = cds.cli.options
if (typeof base === 'string' && !base.match(npmPackageRegex)) throw `Illegal package name: ${base}`
if (typeof base !== 'string' || !base?.length) base = '@capire/bookshop'
const pkgJson = exists('package.json') ? await read('package.json') : { name: 'my-extension-project' }
if (!pkgJson.extends || force) {
pkgJson.extends = base
}
if (!pkgJson.workspaces?.includes('.base')) {
pkgJson.workspaces ??= []
pkgJson.workspaces.push('.base')
}
await write('package.json', pkgJson, { spaces: 2 })
if (!exists('.base/package.json') || force) {
await write('.base/package.json', {name: base})
}
await nodeModulesLink(base)
// remove empty and irrelevant folders
await Promise.all([ rmIfEmpty('db') ])
}
async addSample() {
const proj = projectReader.readProject()
const base = proj.extendsApp
if (!base) throw 'No project to extend found in package.json. Create a new extension project with "cds init extension"'
const projectSimple = base.replace(/^.*?\//, '')
const extensionNamespace = `${namespacify(proj.appName)}.${namespacify(projectSimple)}`
const { force } = cds.cli.options
if (!exists('.base/index.cds') || force) {
await copy(join(__dirname, 'files/.base/index.cds'), '.base/index.cds')
}
if (!exists('app/extension.cds') || force) {
await renderAndCopy(join(__dirname, 'files/app'), 'app', {
basePackage: base,
extensionNamespace
})
}
if (!exists('test/data') || force) {
await copy(join(__dirname, 'files/test/data/my.bookshop-Books.csv'), 'test/data/my.bookshop-Books.csv')
await copy(join(__dirname, 'files/test/data/Authors.csv'), `test/data/${extensionNamespace}-x_Authors.csv`)
}
}
// async finalize() {
// console.log(`For information on project "Piper" and its pipelines see ${URLS.PIPELINE_HELP}`);
// }
}
function namespacify(s) {
return s.replace(/[/.-]/g, '_').replace(/[@]/g, '').toLowerCase()
}
async function rmIfEmpty(s) {
exists(s) && !(await readdir(s)).length && await rimraf(s)
}
// Allow subsequent templates like `cds add handler` to resolve the model w/o `npm i`.
// So create a symlink from node_modules to .base, anticipating what `npm i` would do.
async function nodeModulesLink(base) {
const link = join(cds.root, 'node_modules', base)
if (exists(link)) return
const scope = base.indexOf('/') > 0 && base.split('/')[0] // @scope/pkg
const target = join(cds.root, 'node_modules', scope||'')
await mkdir(target, { recursive: true })
const relTarget = relative(target, join(cds.root, '.base'))
// console.log(`> linking ${relTarget} to ${link}`)
await symlink(relTarget, link, 'junction')
}