@sap/cds-dk
Advanced tools
Comparing version 7.6.1 to 7.7.0
@@ -80,3 +80,3 @@ #!/usr/bin/env node | ||
const { options:o=[], flags:f=[], shortcuts:s=[] } = task | ||
const _global = /^--(profile|production|sql|odata|build-.*|cdsc-.*|odata-.*|folders-.*)$/ | ||
const _global = /^--(profile|production|sql|odata|add-.*|build-.*|cdsc-.*|odata-.*|folders-.*)$/ | ||
const _flags = { '--production':true } | ||
@@ -83,0 +83,0 @@ const options = {}, args = [] |
@@ -92,26 +92,27 @@ /* eslint-disable no-console */ | ||
function _markdown (versions) { | ||
console.log() | ||
const pkg = { name:'', repository:'', version:'' }; try { | ||
Object.assign (pkg, require (resolve('package.json'))) | ||
} catch (e) {/* ignored */} | ||
console.log ('|', pkg.name, '|', pkg.repository.url || pkg.repository || 'https://github.com/<your/repo>', '|') | ||
console.log ('|:---------------------- | ----------- |') | ||
if (require('../lib').env['project-nature'] === 'nodejs') { | ||
console.log ('|', v('Node.js'), '|') | ||
console.log ('|', v('@sap/cds'), '|') | ||
} else { | ||
console.log ('|', v('CAP Java Runtime'), '|') | ||
const repo = pkg.repository.url || pkg.repository || 'https://github.com/<your/repo>' | ||
const valLength = Math.max(repo.length, versions.home.length) | ||
console.log () | ||
console.log ('|', $(pkg.name, repo), '|') | ||
console.log ('|', $('----------------------', '-'.repeat(valLength)), '|') | ||
Object.keys(versions) | ||
.filter(mod => mod != pkg.name) | ||
.sort() | ||
.forEach(id => console.log ('|', $(id, versions[id]), '|')) | ||
// TODO get CAP Java version from mvn | ||
// if (require('../lib').env['project-nature'] === 'java') { | ||
// console.log ('|', $('CAP Java Runtime'), '|') | ||
// } | ||
console.log() | ||
function $ (key, val=MISSING) { | ||
return ( key + ' '.repeat(22)).slice(0,22) | ||
+' | '+ (val + ' '.repeat(valLength)).slice(0,valLength) | ||
} | ||
console.log ('|', v('@sap/cds-compiler'), '|') | ||
console.log ('|', v('@sap/cds-dk'), '|') | ||
console.log ('|', v('@sap/cds-dk (global)'), '|') | ||
console.log ('|', v('@sap/eslint-plugin-cds'), '|') | ||
console.log ('|', v('@sap/cds-mtxs'), '|') | ||
console.log ('|', v('@cap-js/cds-types'), '|') | ||
function v (component) { | ||
const version = versions [component] || MISSING | ||
return (component + ' ').slice(0,22) | ||
+' | '+ (version + ' ').slice(0,11) | ||
} | ||
console.log() | ||
} | ||
@@ -118,0 +119,0 @@ |
@@ -81,2 +81,8 @@ const watchOnlyOptions = ['--ext', '--livereload', '--open'] | ||
}={}) { | ||
if (cwd && !cds.utils.exists(cwd)) try { // try module name like `@capire/bookshop` | ||
cwd = require.resolve(cwd+'/package.json').slice(0,-13) | ||
} catch (err) { | ||
throw `Error: No such folder or package: '${cwd}'` | ||
} | ||
if (!Object.keys(options).includes('with-mocks')) args.push ('--with-mocks') | ||
@@ -83,0 +89,0 @@ if (!Object.keys(options).find(a => /^in-memory\??$/.test(a))) args.push ('--in-memory?') |
@@ -12,2 +12,3 @@ const fs = require('fs') | ||
const DEBUG = cds.debug('cli|build') | ||
const LOG_LIMIT = 30 | ||
@@ -42,3 +43,3 @@ class BuildTaskEngine { | ||
if (unresolved.length > 0) { | ||
throw new BuildError(`Required CDS models [${unresolved.join(', ')}] cannot be resolved. Make sure up-to-date versions of the missing modules are installed.`) | ||
throw new BuildError(`Required CDS models [${unresolved.join(', ')}] cannot be resolved. Use the 'npm install' command to install up-to-date versions of the missing packages.`) | ||
} | ||
@@ -226,5 +227,6 @@ | ||
const term = require('../util/term') | ||
if (!process.env.DEBUG && files.length > 20) { | ||
files.length = 20 | ||
files.push('...') | ||
if (!process.env.DEBUG && files.length > LOG_LIMIT) { | ||
const length = files.length | ||
files.length = LOG_LIMIT | ||
files.push(`... ${length - files.length} more. Run with DEBUG=build to show all files.`) | ||
} | ||
@@ -231,0 +233,0 @@ console.log(`done > wrote output to:\n ${term.secondary(files.join("\n "))}\n`) |
@@ -16,2 +16,7 @@ const fs = require('fs') | ||
} | ||
['for', 'src', 'dest'].forEach(key => { | ||
if (options[key] && typeof options[key] !== 'string') { | ||
throw new BuildError(`Invalid build options - property '${key}' must be a string`) | ||
} | ||
}) | ||
this._buildOptions = options | ||
@@ -18,0 +23,0 @@ this._context = { options, tasks: [] } // resolved tasks |
@@ -55,3 +55,3 @@ const path = require('path') | ||
_isOdataProtocol(srv) { | ||
if ('_serves_odata' in srv) return srv._serves_odata // >= cds 7.4.0 | ||
let yes = srv._serves_odata; if (yes) return typeof yes === 'function' ? yes.call(srv) : yes // >= cds 7.4.0 | ||
let protocols = cds.service.protocols4?.(srv) // >= cds 7.4.0 | ||
@@ -58,0 +58,0 @@ if (!protocols) { // @sap/cds < 7.3.0 |
@@ -186,3 +186,3 @@ const fs = require('fs') | ||
// profile has been set, but cannot be resolved | ||
throw new BuildError('MTX configuration cannot be resolved. Make sure up-to-date versions of @sap/cds-mtxs and @sap/cds are installed.') | ||
throw new BuildError("MTX configuration cannot be resolved. Use the 'npm install' command to install up-to-date versions of @sap/cds-mtxs and @sap/cds.") | ||
} | ||
@@ -268,3 +268,3 @@ throw new BuildError(`Invalid MTX sidecar configuration - profile 'mtx-sidecar' not set.`) | ||
case BUILD_TASK_HANA: | ||
task.src = task.src || normalizePath(cds.env.folders.db) | ||
task.src ||= normalizePath(cds.env.folders.db) | ||
break | ||
@@ -275,16 +275,19 @@ case BUILD_TASK_JAVA: | ||
case BUILD_TASK_NODE_CF: | ||
task.src = task.src || normalizePath(cds.env.folders.srv) | ||
task.src ||= normalizePath(cds.env.folders.srv) | ||
break | ||
case BUILD_TASK_FIORI: | ||
task.src = task.src || normalizePath(cds.env.folders.app) | ||
task.src ||= normalizePath(cds.env.folders.app) | ||
break | ||
case BUILD_TASK_MTX_SIDECAR: | ||
task.src = task.src || MTX_SIDECAR_FOLDER | ||
task.src ||= MTX_SIDECAR_FOLDER | ||
break | ||
case BUILD_TASK_MTX_EXTENSION: | ||
task.src = task.src || "." | ||
if (task.src && task.src !== cds.root) { | ||
throw new BuildError("Invalid 'src' property value for build task 'mtx-extension', the only allowed value is '.'") | ||
} | ||
task.src ||= "." | ||
break | ||
case BUILD_TASK_MTX: | ||
// mtxs with nodejs, but without sidecar | ||
task.src = task.src || normalizePath(cds.env.folders.srv) | ||
task.src ||= normalizePath(cds.env.folders.srv) | ||
break | ||
@@ -302,4 +305,3 @@ default: | ||
} | ||
const toggles = cds.env.features.folders | ||
const allowList = new RegExp(`^@sap/cds${toggles ? '|^' + toggles.replace('*', '') : ''}`) | ||
const allowList = new RegExp(`^@sap/cds${cds.env.requires.toggles ? '|^' + cds.env.features.folders.replace('*', '') : ''}`) | ||
task.options = task.options || {} | ||
@@ -343,3 +345,3 @@ let defaultModelPaths = [] | ||
/** | ||
* Determines the module folder from the past list that may represent files or folders w or w/o .cds file extension. | ||
* Determines the module folder from the given list that may represent files or folders w or w/o .cds file extension. | ||
* @param {Array} filesOrFolders | ||
@@ -346,0 +348,0 @@ */ |
@@ -5,4 +5,5 @@ const path = require('path') | ||
const InternalBuildPlugin = require('../internalBuildPlugin') | ||
const ResourcesTarBuilder = require('../mtx/resourcesTarBuilder') | ||
const ExtensionCompilation = require('./extensionCompilation') | ||
const { FOLDER_GEN, EXTENSION_POINT_VALIDATION } = require('../../constants') | ||
const ResourcesTarBuilder = require('../mtx/resourcesTarBuilder') | ||
const { BuildError, BuildMessage } = require('../../util') | ||
@@ -20,14 +21,23 @@ const DEBUG = cds.debug('cli|build') | ||
async build() { | ||
const { src, dest } = this.task | ||
const { dest } = this.task | ||
const destExt = path.join(dest, 'ext') | ||
// check existence of appPackage folder only | ||
// REVISIT: cds.resolve will fail as no index.csn file exists in this folder for the extension migration use case | ||
let model | ||
let extensionModel | ||
// REVISIT: check existence of SaaS app package folder only | ||
// cds.resolve will fail as no index.csn file exists in this folder for the extension migration use case | ||
// a compilation error is thrown anyhow if any base model refs cannot be resolved | ||
const appPackageFolder = this._getAppPackageFolder() | ||
if (!fs.existsSync(path.join(src, appPackageFolder))) { | ||
throw new BuildError(`The SaaS application base model '${appPackageFolder}' is missing. Have you run the 'cds pull' command?`) | ||
} | ||
const saasPkgPath = MtxExtensionBuildPlugin._getSaasPkgPath() | ||
const extensionCompilation = new ExtensionCompilation(this) | ||
// full compile of the extension using base model - ensuring consistency | ||
const model = await this.model() | ||
try { | ||
model = await this.model() | ||
} catch (e) { | ||
if (extensionCompilation.isDuplicateDefinitionError(e)) { | ||
// clear compilation errors and recompile with removed duplicate resources | ||
this.messages.length = 0 | ||
model = await extensionCompilation.recompileWithoutDuplicates(e.messages, saasPkgPath) | ||
} | ||
} | ||
@@ -37,11 +47,15 @@ if (model) { | ||
const options = { ...this.options(), flavor: 'parsed' } | ||
const extModel = await cds.load(this._resolveExtensionFiles(model), options) | ||
if (extModel.requires) { | ||
extModel.requires.length = 0 | ||
const extensionFiles = extensionCompilation.resolveExtensionFiles(model, saasPkgPath) | ||
if (extensionFiles.length > 0) { | ||
extensionModel = await cds.load(extensionFiles, options) | ||
if (extensionModel.requires) { | ||
extensionModel.requires.length = 0 | ||
} | ||
} | ||
} | ||
if (extensionModel) { | ||
// IMPORTANT NOTE: perform all model operations before the linter is called as the linter | ||
// will modify the model causing the creation of 'unresolved' associations | ||
await this.compileToJson(extModel, path.join(destExt, 'extension.csn')) | ||
await this.collectLanguageBundles(extModel, path.join(destExt, 'i18n')) | ||
await this.compileToJson(extensionModel, path.join(destExt, 'extension.csn')) | ||
await this.collectLanguageBundles(extensionModel, path.join(destExt, 'i18n')) | ||
@@ -56,7 +70,5 @@ // perform SQL backend validation to prevent extension deployment problems later on | ||
await Promise.all( | ||
files | ||
.filter(file => /\.csv$/.test(file)) | ||
.map(csv => { | ||
return this.copy(csv).to(path.join(dataDest, path.basename(csv))) | ||
}) | ||
files.filter(file => /\.csv$/.test(file)).map(csv => { | ||
return this.copy(csv).to(path.join(dataDest, path.basename(csv))) | ||
}) | ||
) | ||
@@ -68,6 +80,6 @@ } | ||
// throws error in case of linting errors | ||
this._lintExtModel(extModel, model) | ||
this._lintExtModel(extensionModel, model, saasPkgPath) | ||
} catch (error) { | ||
// cleanup existing files in case of an error | ||
await fs.promises.rm(this.task.dest, { recursive: true }) | ||
await fs.promises.rm(dest, { recursive: true }) | ||
throw error | ||
@@ -78,11 +90,8 @@ } | ||
const packageJson = path.join(src, 'package.json') | ||
if (!fs.existsSync(packageJson)) { | ||
throw new BuildError(`package.json file not found in ${src}`) | ||
} | ||
await this.copy(packageJson).to(path.join(destExt, 'package.json')) | ||
// existence already checked | ||
await this.copy(path.join(cds.root, 'package.json')).to(path.join(destExt, 'package.json')) | ||
// copy handlers | ||
const folders = [path.join(src, cds.env.folders.srv, 'handlers')] | ||
await this.copyNativeContent(src, destExt, res => { | ||
const folders = [path.join(cds.root, cds.env.folders.srv, 'handlers')] | ||
await this.copyNativeContent(cds.root, destExt, res => { | ||
if (fs.statSync(res).isDirectory()) { | ||
@@ -97,18 +106,6 @@ return folders.some(folder => folder.startsWith(res)) | ||
// add all resources contained in 'gen/ext' folder | ||
await new ResourcesTarBuilder(this).writeTarFile(path.join(this.task.dest, 'extension.tgz'), destExt) | ||
return new ResourcesTarBuilder(this).writeTarFile(path.join(dest, 'extension.tgz'), destExt) | ||
} | ||
_resolveExtensionFiles(model) { | ||
const node_modules = path.join(this.task.src, 'node_modules') | ||
const paths = model['$sources'].reduce((acc, file) => { | ||
if (file.startsWith(this.task.src) && !file.startsWith(node_modules)) { | ||
acc.push(file) | ||
} | ||
return acc | ||
}, []) | ||
return paths | ||
} | ||
_lintExtModel(extModel, model) { | ||
_lintExtModel(extModel, model, saasPkgPath) { | ||
const linter = this._linter() | ||
@@ -118,3 +115,3 @@ if (!linter) { | ||
} | ||
const env = cds.env.for('cds', path.join(this.task.src, this._getAppPackageFolder())) | ||
const env = cds.env.for('cds', saasPkgPath) | ||
DEBUG?.(`Saas extension point restrictions:\n${env.requires?.['cds.xt.ExtensibilityService']}`) | ||
@@ -145,5 +142,10 @@ | ||
} | ||
_getAppPackageFolder() { | ||
return path.join('node_modules', cds.env.extends || '_base'); | ||
static _getSaasPkgPath() { | ||
// cds.env.extends holds the SaaS app package name, also if the extends field is defined on root level | ||
const saasPkgPath = path.join(cds.root, 'node_modules', cds.env.extends || '_base') | ||
if (!fs.existsSync(saasPkgPath)) { | ||
throw new BuildError(`The SaaS application base model '${path.relative(cds.root, saasPkgPath)}' is missing. Did you run the 'cds pull' command?`) | ||
} | ||
return saasPkgPath | ||
} | ||
@@ -150,0 +152,0 @@ } |
@@ -6,3 +6,3 @@ const path = require('path') | ||
const NodejsBuildPlugin = require('../nodejs') | ||
const ResourcesTarProvider = require('../mtx/resourcesTarBuilder') | ||
const ResourcesTarBuilder = require('../mtx/resourcesTarBuilder') | ||
const { ERROR } = NodejsBuildPlugin | ||
@@ -68,3 +68,3 @@ const { relativePaths, BuildError, resolveRequiredSapModels, getI18nDefaultFolder } = require('../../util') | ||
if (!main) { | ||
throw new BuildError(`Invalid MTX sidecar configuration. Make sure that the profile 'mtx-sidecar' is configured and an up-to-date version of @sap/cds-mtxs is installed.`) | ||
throw new BuildError("Invalid MTX sidecar configuration. Make sure that the profile 'mtx-sidecar' is configured. Use 'npm install @sap/cds-mtxs' to install an up-to-date version.") | ||
} | ||
@@ -102,3 +102,3 @@ if (!this.hasBuildOption(MTX_SIDECAR_DB_VALIDATION, false) | ||
// resources are determined based on available database build task, SQLite as fallback | ||
await new ResourcesTarProvider(this).createTar(destMain, model) | ||
await new ResourcesTarBuilder(this).createTar(destMain, model) | ||
@@ -105,0 +105,0 @@ // copy package.json and .cdsrc.json from project root |
@@ -6,3 +6,3 @@ /* eslint-disable no-empty */ | ||
const EdmxBuildPlugin = require('../edmxBuildPlugin') | ||
const ResourcesTarProvider = require('./resourcesTarBuilder') | ||
const ResourcesTarBuilder = require('./resourcesTarBuilder') | ||
const { FOLDER_GEN } = require('../../constants') | ||
@@ -33,3 +33,3 @@ const { BuildError } = require('../../util') | ||
} | ||
return new ResourcesTarProvider(this).createTar(dest, model) | ||
return new ResourcesTarBuilder(this).createTar(dest, model) | ||
} | ||
@@ -36,0 +36,0 @@ |
@@ -37,3 +37,3 @@ const path = require('path') | ||
async writeTarFile(tarFile, root, resources) { | ||
const { tar } = require('../../../../lib').utils | ||
const { tar } = require('../../..').utils | ||
await tar.czfd(tarFile, root, resources) | ||
@@ -40,0 +40,0 @@ this.plugin.pushFile(tarFile) |
@@ -122,3 +122,3 @@ const fs = require('fs') | ||
const wildcards = cds.env.requires.toggles && cds.env.features.folders ? ['*', cds.env.features.folders] : '*' | ||
let paths = _pushModelPaths(cds.resolve(wildcards, false)) | ||
let paths = _filterModelPaths(cds.resolve(wildcards, false)) | ||
@@ -133,3 +133,3 @@ if (ws) { | ||
cds.env = cds.env.for('cds', cds.root) | ||
paths = paths.concat(_pushModelPaths(cds.resolve(cds.env.requires.toggles ? wildcards : '*', false)).map(p => path.join(workspace, p))) | ||
paths = paths.concat(_filterModelPaths(cds.resolve(cds.env.requires.toggles ? wildcards : '*', false)).map(p => path.join(workspace, p))) | ||
}) | ||
@@ -252,3 +252,3 @@ } finally { | ||
function _validateWsDependencies(wsRoot, dependencies, devDependencies) { | ||
const allDependencies = {...dependencies, ...devDependencies} | ||
const allDependencies = { ...dependencies, ...devDependencies } | ||
for (const name in allDependencies) { | ||
@@ -268,3 +268,8 @@ if (allDependencies[name] === '*') { | ||
function _pushModelPaths(...modelPaths) { | ||
/** | ||
* Returns a flat array of existing files and folders, trailing '/' or '\\' characters have been removed. | ||
* @param {...any} modelPaths array of files and folders - optionally nested | ||
* @returns | ||
*/ | ||
function _filterModelPaths(...modelPaths) { | ||
const model = new Set() | ||
@@ -271,0 +276,0 @@ // may contain nested arrays |
@@ -68,2 +68,3 @@ | ||
function mergePluginSchema(pluginSchema) { | ||
// contribution points also appear in schema file ./schemas/cds-rc.js | ||
return { | ||
@@ -70,0 +71,0 @@ into: async (targetSchema) => { |
@@ -8,2 +8,55 @@ module.exports = { | ||
properties: { | ||
// declaration for schema node for cds plugins contributing cds configuration | ||
schema: { | ||
type: "object", | ||
description: "Schema declaration for cds plugins contributing cds configuration", | ||
additionalProperties: false, | ||
properties: { | ||
cds: { | ||
type: "object", | ||
description: "Containing json schema declarations for root level entries under cds node.", | ||
patternProperties: { | ||
// new keyword must start with word character or opening brackets | ||
"^[\\[\\(\\w].*": { | ||
$ref: "https://json-schema.org/draft/2020-12/schema" | ||
} | ||
} | ||
}, | ||
buildTaskType: { | ||
type: "object", | ||
additionalProperties: false, | ||
required: ["name"], | ||
properties: { | ||
name: { | ||
type: "string", | ||
minLength: 1, | ||
description: "The name of the build task type." | ||
}, | ||
description: { | ||
type: "string", | ||
description: "The description of the build task type." | ||
} | ||
} | ||
}, | ||
databaseType: { | ||
type: "object", | ||
additionalProperties: false, | ||
required: ["name"], | ||
properties: { | ||
name: { | ||
type: "string", | ||
minLength: 1, | ||
description: "The name of the database type." | ||
}, | ||
description: { | ||
type: "string", | ||
description: "The description of the database type." | ||
} | ||
} | ||
} | ||
} | ||
}, | ||
// build specific schema | ||
@@ -119,2 +172,2 @@ build: { | ||
} | ||
} | ||
} |
@@ -322,2 +322,8 @@ const { getRegExpGroups } = require('./utils'); | ||
const property = {}; | ||
if ('$ref' in propertyContent) { | ||
const refPathParts = propertyContent['$ref'].split('/'); | ||
const propertyName = refPathParts[refPathParts.length - 1]; | ||
property['type'] = { 'ref': [refPathParts[3], propertyName] }; | ||
return property; | ||
} | ||
const inputType = this.getTypeFromArray(propertyContent.type); | ||
@@ -324,0 +330,0 @@ const cdsType = this.getDataType(inputType, propertyContent.format); |
@@ -6,2 +6,4 @@ const registered = new Map | ||
merge: require('./merge').merge, // fluent API | ||
removeFromYAML: require('./merge').removeFromYAML, | ||
removeFromYAMLArray: require('./merge').removeFromYAMLArray, | ||
readProject: require('./projectReader').readProject, | ||
@@ -8,0 +10,0 @@ mvn: { |
@@ -7,3 +7,3 @@ module.exports = { | ||
MAVEN_ARCHETYPE_VERSION: '2.5.0', | ||
MAVEN_ARCHETYPE_VERSION: '2.6.1', | ||
@@ -10,0 +10,0 @@ OPTIONS: Object.freeze({ |
@@ -144,3 +144,3 @@ const YAML = require('@sap/cds-foss').yaml | ||
const entryMap = new Map, templateEntryMap = new Map() | ||
const entryMap = new Map, templateEntryMap = new Map | ||
@@ -240,3 +240,3 @@ const { additions, overwrites, deletions, relationships } = semantics | ||
templateCollection.items.forEach((templateNode, templateIndex) => { | ||
templateCollection.items?.forEach((templateNode, templateIndex) => { | ||
if (YAML.isScalar(templateNode)) { | ||
@@ -418,16 +418,34 @@ if (!collection.items.map(item => item.value).includes(templateNode.value)) { | ||
const path = require('path') | ||
/** | ||
* @param {...(string | Object | YAML.Document)} src The source to merge from. | ||
* @returns {{ | ||
* into: (dst: (string | Object | YAML.Document), options?: {project?: Object, semantics?: MergingSemantics}) => Promise<any> | ||
* }} An object with an 'into' method to merge the sources into the specified destination. | ||
*/ | ||
const merge = (...src) => { | ||
return { into: (dst, { with: withProject, project, ...semantics } = {}) => { | ||
if (Object.keys(semantics).length === 0) semantics = undefined | ||
project ??= withProject // to allow { with: project } for a more fluent API | ||
const isYAML = typeof dst === 'string' && ['.yaml', '.yml', '.yaml.hbs', '.yml.hbs'].some(ext => dst.endsWith(ext)) | ||
const _merge = isYAML ? _mergeYAML : _mergeJSON | ||
const target = typeof dst === 'string' ? path.resolve(cds.root, dst) : dst | ||
if (typeof src[src.length-1] === 'string') { | ||
return _merge(target, path.join(...src), project, semantics) | ||
} else { | ||
return _merge(target, ...src, project, semantics) | ||
return { | ||
/** | ||
* Merges sources into the specified destination. | ||
* @param {(string | Object | YAML.Document)} dst File path or object to merge into. | ||
* @param {Object} [options] Merging options. | ||
* @param {Object} [options.project] Project descriptor used for Mustache replacements. | ||
* @param {MergingSemantics} [options.semantics] Merging algorithm semantics. | ||
* @returns {Promise} A promise resolving to the merged object. | ||
*/ | ||
into: (dst, { with: withProject, project, ...semantics } = {}) => { | ||
if (Object.keys(semantics).length === 0) semantics = undefined | ||
project ??= withProject // to allow { with: project } for a more fluent API | ||
const isYAML = typeof dst === 'string' && ['.yaml', '.yml', '.yaml.hbs', '.yml.hbs'].some(ext => dst.endsWith(ext)) | ||
const _merge = isYAML ? _mergeYAML : _mergeJSON | ||
const target = typeof dst === 'string' ? path.resolve(cds.root, dst) : dst | ||
if (typeof src[src.length-1] === 'string') { | ||
return _merge(target, path.join(...src), project, semantics) | ||
} else { | ||
return _merge(target, ...src, project, semantics) | ||
} | ||
} | ||
}} | ||
} | ||
} | ||
@@ -434,0 +452,0 @@ |
const cds = require('../cds') | ||
const { join, resolve, basename } = require('path') | ||
const { fs, exists, isdir } = cds.utils | ||
const { fs, exists, isdir, path } = cds.utils | ||
const { parseXml } = require('./xml') | ||
@@ -62,2 +62,3 @@ const { REGEX_JAVA_VERSION } = require('./constants') | ||
* @property {string} appPath The path to the app folder. | ||
* @property {string} approuterPath The path to the approuter folder. | ||
* @property {boolean} hasUIEmbedded Indicates if the project uses an embedded UI. | ||
@@ -116,4 +117,11 @@ * @property {boolean} hasUIModule Indicates if the project is using a modular UI. | ||
configFile: () => exists('pom.xml') ? '.cdsrc.json' : 'package.json', | ||
apps: () => (fs.readdirSync(path.resolve(cds.root, cds.env.folders.app))).filter(e => | ||
isdir(join(cds.root, cds.env.folders.app, e)) && e !== 'appconfig' && e !== '_i18n' && e !== 'router' | ||
).map(app => ({ app })), | ||
appUIPaths: () => (fs.readdirSync(path.resolve(cds.root, cds.env.folders.app))).filter(e => | ||
isdir(join(cds.root, cds.env.folders.app, e)) && e !== 'appconfig' && e !== '_i18n' && e !== 'router' | ||
), | ||
appPath: () => env.folders.app, | ||
appVersion: () => appVersion, | ||
approuterPath: () => join(env.folders.app, 'router'), | ||
appName: () => appName, | ||
@@ -120,0 +128,0 @@ cleanedAppName: () => appName.replaceAll('_', '-'), |
@@ -125,2 +125,17 @@ // Registry of sequence matchers in mta.yaml files | ||
const html5RepoHost = { | ||
in: 'resources', | ||
where: { 'parameters.service': 'html5-apps-repo', 'parameters.service-plan': 'app-host' } | ||
} | ||
const html5Runtime = { | ||
in: 'resources', | ||
where: { 'parameters.service': 'html5-apps-repo', 'parameters.service-plan': 'app-runtime' } | ||
} | ||
const appContent = { | ||
in: 'modules', | ||
where: { type: 'com.sap.application.content' } | ||
} | ||
module.exports = { | ||
@@ -151,3 +166,6 @@ srv4, | ||
applicationLogging, | ||
approuterExtensibility | ||
approuterExtensibility, | ||
html5RepoHost, | ||
html5Runtime, | ||
appContent | ||
} |
@@ -25,7 +25,7 @@ const cds = require('../../../cds') | ||
async run() { | ||
const { appPath } = readProject() | ||
const appPackageJSONPath = join(appPath, 'package.json') | ||
const { approuterPath } = readProject() | ||
const appPackageJSONPath = join(approuterPath, 'package.json') | ||
await merge(__dirname, 'files/package.json').into(appPackageJSONPath) | ||
await sort(appPackageJSONPath, 'dependencies') | ||
await merge(__dirname, 'files/default-env.json').into(appPath + '/default-env.json') | ||
await merge(__dirname, 'files/default-env.json').into(approuterPath + '/default-env.json') | ||
} | ||
@@ -35,3 +35,3 @@ | ||
const project = readProject(this.options) | ||
const { isNodejs, isJava, hasExtensibility, hasMultitenancy, hasMta, hasHelm, hasHelmUnifiedRuntime, srvPath, appPath } = project | ||
const { isNodejs, isJava, hasExtensibility, hasMultitenancy, hasMta, hasHelm, hasHelmUnifiedRuntime, srvPath, approuterPath } = project | ||
@@ -77,3 +77,3 @@ if (hasMta) { | ||
const xsAppPath = join(appPath, 'xs-app.json') | ||
const xsAppPath = join(approuterPath, 'xs-app.json') | ||
const additions = hasExtensibility ? [{ ...approuterExtensibility, at: 0 }] : [] | ||
@@ -80,0 +80,0 @@ await merge(__dirname, 'files/xs-app.json.hbs').into(xsAppPath, { project, additions }) |
@@ -15,6 +15,5 @@ const cds = require('../../../cds') | ||
async run() { | ||
// Disable setting cds.requires.connectivity for now. | ||
// const project = readProject() | ||
// const { configFile } = project | ||
// await merge(__dirname, 'files', 'package.json.hbs').into(configFile, { with: project }) | ||
const project = readProject() | ||
const { configFile } = project | ||
await merge(__dirname, 'files', 'package.json.hbs').into(configFile, { with: project }) | ||
} | ||
@@ -21,0 +20,0 @@ |
const { join } = require('path') | ||
const { exists, copy } = require('../../../cds').utils | ||
const cds = require('../../../cds') | ||
const { copy } = cds.utils | ||
const { readProject } = require('../../projectReader') | ||
const { merge } = require('../../merge') | ||
const { srv4, destination, html5RepoHost, html5Runtime, appContent, approuter } = require('../../registries/mta') | ||
@@ -12,14 +14,19 @@ module.exports = class Html5RepoTemplate extends require('../../plugin') { | ||
async canRun() { | ||
const project = readProject() | ||
const { hasMta, hasHelm, hasHelmUnifiedRuntime } = project | ||
if (!(hasHelm || hasHelmUnifiedRuntime) && hasMta) { | ||
throw `'cds add html5-repo' is not available for Cloud Foundry yet` | ||
} | ||
return true | ||
static hasInProduction(env) { | ||
return !!env.requires['html5-repo'] | ||
} | ||
static hasInProduction() { | ||
// REVISIT: Should be detectable without helm charts | ||
return exists(join('chart', 'templates', 'html5-apps-deployer-configmap.yaml')) | ||
async run() { | ||
const project = readProject() | ||
const { apps, appPath, configFile } = project | ||
await merge(__dirname, 'files', 'package.json.hbs').into(configFile, { with: project }) | ||
await Promise.all(apps.map(async ({app}) => { | ||
project.app = app | ||
await merge(__dirname, 'files/ui5.yaml.hbs').into(join(appPath, app, 'ui5.yaml'), { project }) | ||
})) | ||
await Promise.all(apps.map(async ({app}) => { | ||
project.app = app | ||
await merge(__dirname, 'files/app-package.json.hbs').into(join(appPath, app, 'package.json'), { project }) | ||
})) | ||
} | ||
@@ -29,3 +36,40 @@ | ||
const project = readProject() | ||
const { hasHelm, hasHelmUnifiedRuntime } = project | ||
const { srvPath, appPath, hasMta, hasHelm, hasHelmUnifiedRuntime, hasApprouter, apps } = project | ||
if (hasApprouter) { | ||
await Promise.all(apps.map(async ({app}) => { | ||
project.app = app | ||
await merge(__dirname, 'files/xs-app.json.hbs').into(join(appPath, app, 'xs-app.json'), { project }) | ||
})) | ||
} | ||
if (hasMta) { | ||
const srv = srv4(srvPath) | ||
project.apps = apps | ||
const appModules = project.apps.map(app => ( { | ||
in: 'modules', | ||
where: { type: 'html5', path: `${appPath}${app.app}` } | ||
})) | ||
const additions = [srv, appContent, destination, html5RepoHost, ...appModules] | ||
const relationships = [{ | ||
insert: [destination, 'name'], | ||
into: [appContent, 'requires', 'name'], | ||
}, { | ||
insert: [html5RepoHost, 'name'], | ||
into: [appContent, 'requires', 'name'], | ||
}] | ||
if (hasApprouter) { | ||
console.log('aaddd') | ||
additions.push(approuter, html5Runtime) | ||
relationships.push({ | ||
insert: [html5Runtime, 'name'], | ||
into: [approuter, 'requires', 'name'], | ||
}) | ||
} | ||
await merge(__dirname, 'files/mta.yaml.hbs').into('mta.yaml', { with: project, | ||
additions, | ||
relationships | ||
}) | ||
} | ||
if (hasHelm || hasHelmUnifiedRuntime) { | ||
@@ -32,0 +76,0 @@ await merge(__dirname, 'files/values.yaml.hbs').into('chart/values.yaml', { with: project }) |
const { join } = require('path') | ||
const cds = require('../../../cds') | ||
const { exists } = cds.utils | ||
const { bold } = require('../../../util/term') | ||
const { copyRenderedYAML } = require('../../../util/fs') | ||
@@ -22,2 +23,6 @@ const { readProject } = require('../../projectReader') | ||
} | ||
async finalize() { | ||
if (!exists('pom.xml')) console.log(`\nRun ${bold('npm update --package-lock-only')} to freeze dependencies.`) | ||
} | ||
} |
@@ -12,4 +12,3 @@ { | ||
"qwtel.sqlite-viewer", | ||
"humao.rest-client", | ||
"sdras.night-owl" | ||
"humao.rest-client" | ||
], | ||
@@ -16,0 +15,0 @@ // List of extensions recommended by VS Code that should not be recommended for users of this workspace. |
@@ -18,3 +18,3 @@ # Getting Started | ||
- Open a new terminal and run `cds watch` | ||
- Open a new terminal and run `cds watch` | ||
- (in VS Code simply choose _**Terminal** > Run Task > cds watch_) | ||
@@ -21,0 +21,0 @@ - Start adding content, for example, a [db/schema.cds](db/schema.cds). |
const { join } = require('path') | ||
const cds = require('../../../cds'), { exists, copy } = cds.utils | ||
const cds = require('../../../cds'), { exists, read, write, copy } = cds.utils | ||
const { env4, readProject } = require('../../projectReader') | ||
@@ -16,9 +16,19 @@ | ||
const language = exists('pom.xml') ? 'java' : 'nodejs' | ||
await Promise.all([ | ||
copy(join(__dirname, 'files', 'db')).to(db), | ||
copy(join(__dirname, 'files', 'app')).to(app), | ||
copy(join(__dirname, 'files', 'srv')).to(srv), | ||
copy(join(__dirname, 'files', language)).to(srv) | ||
]) | ||
await copy(join(__dirname, 'files', 'app')).to(app) | ||
const { appName, appPath, appUIPaths } = readProject() | ||
// manifest.json must be unique | ||
await Promise.all(appUIPaths.map(async p => { | ||
const manifest = await read(join(appPath, p, 'webapp/manifest.json')) | ||
manifest['sap.app'].id = appName + '.' + p | ||
await write(join(appPath, p, 'webapp/manifest.json'), manifest, { spaces: 2 }) | ||
})) | ||
} | ||
} |
@@ -195,2 +195,3 @@ // eslint-disable-next-line no-console | ||
const apps = await this._cfRequest('/v3/apps', { space_guids, organization_guids, names: app }); | ||
if (apps.resources.length < 1) throw `Cannot find app with name '${app}'` | ||
const guid = apps.resources[0].guid; | ||
@@ -197,0 +198,0 @@ const env = await this._cfRequest('/v3/apps/'+guid+'/env', { space_guids, organization_guids, names: app }); |
{ | ||
"name": "@sap/cds-dk", | ||
"version": "7.6.1", | ||
"version": "7.7.0", | ||
"description": "Command line client and development toolkit for the SAP Cloud Application Programming Model", | ||
@@ -5,0 +5,0 @@ "homepage": "https://cap.cloud.sap/", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1605977
375
35499
175