@sap/cds-dk 9.4.3 → 9.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +115 -0
- package/bin/compile/index.js +1 -1
- package/bin/env.js +3 -3
- package/bin/export.js +1 -1
- package/bin/help.js +0 -1
- package/bin/import.js +8 -3
- package/bin/repl.js +7 -11
- package/bin/up.js +159 -23
- package/bin/util/containerize.js +79 -25
- package/bin/version.js +4 -4
- package/lib/bind/k8s.js +1 -1
- package/lib/build/plugins/helm/files/templates/_deployment_helpers.tpl +1 -1
- package/lib/build/plugins/helm/index.js +1 -1
- package/lib/build/provider/hana/2migration.js +16 -24
- package/lib/build/provider/hana/index.js +1 -1
- package/lib/build/provider/hana/template/.hdiconfig-all +7 -1
- package/lib/build/provider/hana/template/package.json +1 -1
- package/lib/build/provider/internalBuildPlugin.js +15 -1
- package/lib/build/provider/java/index.js +12 -1
- package/lib/build/provider/mtx-sidecar/index.js +2 -1
- package/lib/build/provider/nodejs/index.js +2 -1
- package/lib/build/util.js +36 -19
- package/lib/compile/to_openapi.js +1 -5
- package/lib/import/common.js +9 -2
- package/lib/import/odata/ParserContext.js +1 -0
- package/lib/import/odata/v4parser.js +57 -25
- package/lib/import/openapi/importOpenAPI.js +6 -1
- package/lib/init/constants.js +1 -1
- package/lib/init/index.js +20 -6
- package/lib/init/merge.js +16 -0
- package/lib/init/projectReader.js +34 -8
- package/lib/init/registries/mta.js +2 -2
- package/lib/init/template/ams/index.js +3 -3
- package/lib/init/template/app-frontend/files/app-package.json.hbs +1 -7
- package/lib/init/template/app-frontend/files/ui5.yaml.hbs +21 -1
- package/lib/init/template/app-frontend/index.js +2 -6
- package/lib/init/template/application-logging/index.js +11 -16
- package/lib/init/template/approuter/files/mta.yaml.hbs +0 -2
- package/lib/init/template/approuter/index.js +13 -10
- package/lib/init/template/attachments/index.js +4 -2
- package/lib/init/template/audit-logging/index.js +4 -2
- package/lib/init/template/cloud-logging/index.js +6 -5
- package/lib/init/template/connectivity/index.js +2 -2
- package/lib/init/template/console/files/package.json +5 -0
- package/lib/init/template/console/index.js +25 -0
- package/lib/init/template/containerize/index.js +4 -6
- package/lib/init/template/data/as-json.js +18 -20
- package/lib/init/template/destination/index.js +4 -2
- package/lib/init/template/dynatrace/files/package.json.hbs +2 -2
- package/lib/init/template/dynatrace/index.js +4 -4
- package/lib/init/template/enterprise-messaging/files/mta.yaml.hbs +3 -1
- package/lib/init/template/enterprise-messaging/index.js +4 -2
- package/lib/init/template/enterprise-messaging-shared/index.js +4 -2
- package/lib/init/template/github-actions/files/workflows/cf.yaml.hbs +16 -1
- package/lib/init/template/github-actions/files/workflows/release.yaml.hbs +2 -2
- package/lib/init/template/github-actions/files/workflows/test.yaml.hbs +20 -0
- package/lib/init/template/github-actions/index.js +7 -10
- package/lib/init/template/hana/files/db/package.json +2 -2
- package/lib/init/template/hana/files/mta.yaml.hbs +0 -4
- package/lib/init/template/hana/index.js +7 -9
- package/lib/init/template/helm/index.js +8 -10
- package/lib/init/template/helm-unified-runtime/index.js +1 -4
- package/lib/init/template/html5-repo/files/app-package.json.hbs +1 -7
- package/lib/init/template/html5-repo/files/ui5.yaml.hbs +21 -1
- package/lib/init/template/html5-repo/index.js +14 -18
- package/lib/init/template/ias/files/values.yaml.hbs +6 -6
- package/lib/init/template/ias/index.js +13 -21
- package/lib/init/template/java/index.js +14 -0
- package/lib/init/template/kafka/index.js +4 -2
- package/lib/init/template/{containerize → kyma}/files/containerize.yaml.hbs +17 -2
- package/lib/init/template/kyma/index.js +129 -5
- package/lib/init/template/malware-scanner/files/mta.yaml.hbs +3 -1
- package/lib/init/template/malware-scanner/files/values.yaml +3 -1
- package/lib/init/template/malware-scanner/index.js +4 -2
- package/lib/init/template/multitenancy/files/mta.yaml.hbs +1 -3
- package/lib/init/template/multitenancy/files/values.yaml.hbs +8 -0
- package/lib/init/template/multitenancy/index.js +15 -7
- package/lib/init/template/nodejs/files/.vscode/extensions.json +0 -3
- package/lib/init/template/nodejs/files/package.json.hbs +1 -1
- package/lib/init/template/pipeline/files/app-package.json.hbs +1 -7
- package/lib/init/template/pipeline/files/ui5.yaml.hbs +21 -1
- package/lib/init/template/pipeline/index.js +1 -2
- package/lib/init/template/portal/files/mta.yaml.hbs +5 -3
- package/lib/init/template/portal/index.js +8 -8
- package/lib/init/template/postgres/index.js +2 -2
- package/lib/init/template/redis/index.js +2 -3
- package/lib/init/template/redis-messaging/index.js +2 -3
- package/lib/init/template/sample/files/_i18n/i18n_de.properties +21 -0
- package/lib/init/template/sample/files/_i18n/i18n_en.properties +21 -0
- package/lib/init/template/sample/files/_i18n/i18n_fr.properties +21 -0
- package/lib/init/template/sample/files/_i18n/messages_de.properties +34 -0
- package/lib/init/template/sample/files/_i18n/messages_en.properties +34 -0
- package/lib/init/template/sample/files/_i18n/messages_fr.properties +34 -0
- package/lib/init/template/sample/files/app/_i18n/i18n.properties +13 -25
- package/lib/init/template/sample/files/app/_i18n/i18n_de.properties +13 -25
- package/lib/init/template/sample/files/app/admin-authors/fiori-service.cds +52 -0
- package/lib/init/template/sample/files/app/admin-authors/webapp/Component.js.hbs +3 -0
- package/lib/init/template/sample/files/app/admin-authors/webapp/i18n/i18n.properties +3 -0
- package/lib/init/template/sample/files/app/admin-authors/webapp/i18n/i18n_de.properties +3 -0
- package/lib/init/template/sample/files/app/admin-authors/webapp/i18n/i18n_en.properties +3 -0
- package/lib/init/template/sample/files/app/admin-authors/webapp/manifest.json +130 -0
- package/lib/init/template/sample/files/app/admin-books/fiori-service.cds +81 -88
- package/lib/init/template/sample/files/app/admin-books/webapp/Component.js.hbs +3 -0
- package/lib/init/template/sample/files/app/admin-books/webapp/i18n/i18n.properties +3 -3
- package/lib/init/template/sample/files/app/admin-books/webapp/i18n/i18n_de.properties +3 -3
- package/lib/init/template/sample/files/app/admin-books/webapp/i18n/i18n_en.properties +3 -3
- package/lib/init/template/sample/files/app/admin-books/webapp/manifest.json +24 -48
- package/lib/init/template/sample/files/app/appconfig/fioriSandboxConfig.json +56 -5
- package/lib/init/template/sample/files/app/browse/fiori-service.cds +30 -30
- package/lib/init/template/sample/files/app/browse/webapp/Component.js.hbs +3 -0
- package/lib/init/template/sample/files/app/browse/webapp/i18n/i18n.properties +3 -4
- package/lib/init/template/sample/files/app/browse/webapp/i18n/i18n_de.properties +3 -3
- package/lib/init/template/sample/files/app/browse/webapp/i18n/i18n_en.properties +3 -4
- package/lib/init/template/sample/files/app/browse/webapp/manifest.json +19 -24
- package/lib/init/template/sample/files/app/common.cds +127 -158
- package/lib/init/template/sample/files/app/fiori-apps.html +50 -0
- package/lib/init/template/sample/files/app/genres/fiori-service.cds +33 -0
- package/lib/init/template/sample/files/app/genres/tree-view.cds +42 -0
- package/lib/init/template/sample/files/app/genres/value-help.cds +6 -0
- package/lib/init/template/sample/files/app/genres/webapp/Component.js.hbs +3 -0
- package/lib/init/template/sample/files/app/genres/webapp/i18n/i18n.properties +3 -0
- package/lib/init/template/sample/files/app/genres/webapp/i18n/i18n_de.properties +3 -0
- package/lib/init/template/sample/files/app/genres/webapp/i18n/i18n_en.properties +3 -0
- package/lib/init/template/sample/files/app/genres/webapp/manifest.json +126 -0
- package/lib/init/template/sample/files/app/services.cds +6 -2
- package/lib/init/template/sample/files/db/currencies.cds +13 -0
- package/lib/init/template/sample/files/db/data/sap.capire.bookshop-Books.csv +5 -5
- package/lib/init/template/sample/files/db/data/{sap.capire.bookshop-Books_texts.csv → sap.capire.bookshop-Books.texts.csv} +4 -4
- package/lib/init/template/sample/files/db/data/sap.capire.bookshop-Genres.csv +42 -15
- package/lib/init/template/sample/files/db/data/sap.capire.bookshop-Genres.texts.csv +43 -0
- package/lib/init/template/sample/files/db/data/sap.common-Currencies.csv +12 -0
- package/lib/init/template/sample/files/db/data/sap.common-Currencies.texts.csv +15 -0
- package/lib/init/template/sample/files/db/hana/index.cds +10 -0
- package/lib/init/template/sample/files/db/schema.cds +35 -22
- package/lib/init/template/sample/files/db/sqlite/index.cds +10 -0
- package/lib/init/template/sample/files/package.json.hbs +14 -1
- package/lib/init/template/sample/files/srv/access-control.cds +3 -0
- package/lib/init/template/sample/files/srv/admin-service.cds +3 -2
- package/lib/init/template/sample/files/srv/cat-service.cds +7 -11
- package/lib/init/template/sample/index.js +40 -18
- package/lib/init/template/sqlite/files/package.json.hbs +13 -0
- package/lib/init/template/sqlite/index.js +1 -1
- package/lib/init/template/telemetry/index.js +1 -3
- package/lib/init/template/typescript/files/package.json +1 -1
- package/lib/init/template/workzone-standard/files/mta.yaml.hbs +0 -5
- package/lib/init/template/workzone-standard/index.js +0 -1
- package/lib/init/template/xsuaa/files/mta.yaml.hbs +4 -0
- package/lib/init/template/xsuaa/index.js +7 -6
- package/lib/lint/Linter.js +10 -4
- package/lib/lint/eslintHelp.json +1 -1
- package/lib/mtx/tenant_action.js +12 -4
- package/lib/util/checksum.js +41 -0
- package/lib/util/fs.js +8 -1
- package/lib/util/glob.js +26 -13
- package/lib/util/question.js +60 -7
- package/npm-shrinkwrap.json +141 -118
- package/package.json +2 -2
- package/lib/init/template/app-frontend/files/ui5-deploy.yaml.hbs +0 -25
- package/lib/init/template/github-actions/files/cf-setup/action.yaml +0 -53
- package/lib/init/template/html5-repo/files/ui5-deploy.yaml.hbs +0 -25
- package/lib/init/template/pipeline/files/ui5-deploy.yaml.hbs +0 -25
- package/lib/init/template/sample/files/app/admin-books/webapp/Component.js +0 -8
- package/lib/init/template/sample/files/app/browse/webapp/Component.js +0 -7
- package/lib/init/template/sample/files/app/index.html +0 -32
- package/lib/init/template/sqlite/files/package.json +0 -5
- /package/lib/init/template/{helm → kyma}/files/Chart.yaml.hbs +0 -0
- /package/lib/init/template/{helm → kyma}/files/values.schema.json +0 -0
- /package/lib/init/template/{helm → kyma}/files/values.yaml.hbs +0 -0
|
@@ -3,6 +3,7 @@ const { exists, read } = cds.utils
|
|
|
3
3
|
const { readProject } = require('../../projectReader')
|
|
4
4
|
const { merge } = require('../../merge')
|
|
5
5
|
const { srv4, xsuaa: xsuaaDefault, xsuaa4, mtxSidecar4 } = require('../../registries/mta')
|
|
6
|
+
const KymaTemplate = require('../kyma')
|
|
6
7
|
|
|
7
8
|
module.exports = class XsuaaTemplate extends require('../../plugin') {
|
|
8
9
|
|
|
@@ -33,7 +34,7 @@ module.exports = class XsuaaTemplate extends require('../../plugin') {
|
|
|
33
34
|
|
|
34
35
|
async combine() {
|
|
35
36
|
const project = readProject()
|
|
36
|
-
const { addMultitenancy, addMta, hasMta,
|
|
37
|
+
const { addMultitenancy, hasMultitenancy, addMta, hasMta, addKyma, isJava, srvPath, hasKyma } = project
|
|
37
38
|
|
|
38
39
|
const cds = require('../../../../lib')
|
|
39
40
|
const xsSecurity = await (async () => {
|
|
@@ -53,16 +54,14 @@ module.exports = class XsuaaTemplate extends require('../../plugin') {
|
|
|
53
54
|
additions.push(xsuaa)
|
|
54
55
|
if (addMta) {
|
|
55
56
|
const srv = srv4(srvPath)
|
|
56
|
-
additions.push(srv)
|
|
57
57
|
relationships.push({
|
|
58
58
|
insert: [xsuaa, 'name'],
|
|
59
59
|
into: [srv, 'requires', 'name']
|
|
60
60
|
})
|
|
61
61
|
}
|
|
62
|
-
if (
|
|
62
|
+
if (hasMultitenancy) {
|
|
63
63
|
const mtxSidecar = mtxSidecar4(isJava ? 'mtx/sidecar' : 'gen/mtx/sidecar')
|
|
64
|
-
|
|
65
|
-
overwrites.push({ item: [mtxSidecar, 'parameters.tenant-mode'], withValue: 'shared' })
|
|
64
|
+
overwrites.push({ item: [xsuaa, 'parameters.config.tenant-mode'], withValue: 'shared' })
|
|
66
65
|
relationships.push({
|
|
67
66
|
insert: [xsuaa, 'name'],
|
|
68
67
|
into: [mtxSidecar, 'requires', 'name']
|
|
@@ -84,7 +83,7 @@ module.exports = class XsuaaTemplate extends require('../../plugin') {
|
|
|
84
83
|
await merge(__dirname, 'files/mta.yaml.hbs').into('mta.yaml', { project, additions, overwrites, relationships })
|
|
85
84
|
}
|
|
86
85
|
|
|
87
|
-
if (
|
|
86
|
+
if (addKyma || (addMultitenancy && hasKyma)) {
|
|
88
87
|
const overwrites = addMultitenancy ? [{ item: 'xsuaa.parameters.tenant-mode', withValue: 'shared' }] : []
|
|
89
88
|
await merge(__dirname, 'files/values.yaml.hbs').into('chart/values.yaml', { with: project, overwrites })
|
|
90
89
|
await merge({
|
|
@@ -94,6 +93,8 @@ module.exports = class XsuaaTemplate extends require('../../plugin') {
|
|
|
94
93
|
}
|
|
95
94
|
}
|
|
96
95
|
}).into('chart/values.yaml')
|
|
96
|
+
await KymaTemplate.mergeDependency('service-instance', 'xsuaa')
|
|
97
|
+
|
|
97
98
|
}
|
|
98
99
|
}
|
|
99
100
|
}
|
package/lib/lint/Linter.js
CHANGED
|
@@ -65,10 +65,16 @@ async function findConfigPath (currentDir = '.') {
|
|
|
65
65
|
let configDir = path.resolve(currentDir)
|
|
66
66
|
while (configDir && configDir !== path.dirname(configDir)) {
|
|
67
67
|
for (const configFile of configFiles) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
68
|
+
try {
|
|
69
|
+
const configPath = path.join(configDir, configFile)
|
|
70
|
+
const config = await tryRequire(configPath)
|
|
71
|
+
if ((configFile !== 'package.json' || config?.eslintConfig) && isfile(configPath)) {
|
|
72
|
+
return configPath
|
|
73
|
+
}
|
|
74
|
+
} catch {
|
|
75
|
+
// attempting to load config files may fail for various reasons we can not easily verify by error code, for example
|
|
76
|
+
// "Cannot use import statement outside a module" in a TS context, or attempting to read .mts files without properly setting them up.
|
|
77
|
+
// We just ignore these errors and treat them as "no valid config found so far, continue searching", lest the exception flys up.
|
|
72
78
|
}
|
|
73
79
|
}
|
|
74
80
|
configDir = path.dirname(configDir)
|
package/lib/lint/eslintHelp.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "9.
|
|
2
|
+
"version": "9.39.2",
|
|
3
3
|
"help": "\n# SYNOPSIS\n\n *cds lint* [options] file.js [file.js] [dir]\n\n Runs environment checks and/or checks the specified models\n based on the ESLint framework\n\n# OPTIONS\n \n Basic configuration:\n --no-config-lookup Disable look up for eslint.config.js\n -c, --config path::String Use this configuration instead of eslint.config.js, eslint.config.mjs, or eslint.config.cjs\n --inspect-config Open the config inspector with the current configuration\n --ext [String] Specify additional file extensions to lint\n --global [String] Define global variables\n --parser String Specify the parser to be used\n --parser-options Object Specify parser options\n \n Specify Rules and Plugins:\n --plugin [String] Specify plugins\n --rule Object Specify rules\n \n Fix Problems:\n --fix Automatically fix problems\n --fix-dry-run Automatically fix problems without saving the changes to the file system\n --fix-type Array Specify the types of fixes to apply (directive, problem, suggestion, layout)\n \n Ignore Files:\n --no-ignore Disable use of ignore files and patterns\n --ignore-pattern [String] Patterns of files to ignore\n \n Use stdin:\n --stdin Lint code provided on <STDIN> - default: false\n --stdin-filename String Specify filename to process STDIN as\n \n Handle Warnings:\n --quiet Report errors only - default: false\n --max-warnings Int Number of warnings to trigger nonzero exit code - default: -1\n \n Output:\n -o, --output-file path::String Specify file to write report to\n -f, --format String Use a specific output format - default: stylish\n --color, --no-color Force enabling/disabling of color\n \n Inline configuration comments:\n --no-inline-config Prevent comments from changing config or rules\n --report-unused-disable-directives Adds reported errors for unused eslint-disable and eslint-enable directives\n --report-unused-disable-directives-severity String Chooses severity level for reporting unused eslint-disable and eslint-enable directives - either: off, warn, error, 0, 1, or 2\n --report-unused-inline-configs String Adds reported errors for unused eslint inline config comments - either: off, warn, error, 0, 1, or 2\n \n Caching:\n --cache Only check changed files - default: false\n --cache-file path::String Path to the cache file. Deprecated: use --cache-location - default: .eslintcache\n --cache-location path::String Path to the cache file or directory\n --cache-strategy String Strategy to use for detecting changed files in the cache - either: metadata or content - default: metadata\n \n Suppressing Violations:\n --suppress-all Suppress all violations - default: false\n --suppress-rule [String] Suppress specific rules\n --suppressions-location path::String Specify the location of the suppressions file\n --prune-suppressions Prune unused suppressions - default: false\n --pass-on-unpruned-suppressions Ignore unused suppressions - default: false\n \n Miscellaneous:\n --init Run config initialization wizard - default: false\n --env-info Output execution environment information - default: false\n --no-error-on-unmatched-pattern Prevent errors when pattern is unmatched\n --exit-on-fatal-error Exit with exit code 2 in case of fatal error - default: false\n --no-warn-ignored Suppress warnings when the file list includes ignored files\n --pass-on-no-patterns Exit with exit code 0 in case no file patterns are passed\n --debug Output debugging information\n -h, --help Show help\n -v, --version Output the version number\n --print-config path::String Print the configuration for the given file\n --stats Add statistics to the lint report - default: false\n --flag [String] Enable a feature flag\n --mcp Start the ESLint MCP server\n --concurrency Int|String Number of linting threads, auto to choose automatically, off for no multithreading - default: off\n \n",
|
|
4
4
|
"options": [
|
|
5
5
|
"--config",
|
package/lib/mtx/tenant_action.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const cds = require('../cds');
|
|
2
2
|
const { ParamCollection } = require('./params');
|
|
3
3
|
const AuthManager = require('./auth_manager');
|
|
4
|
+
const { localhostRegex } = require('./util/urls');
|
|
4
5
|
|
|
5
6
|
require('../util/axios').pruneErrors();
|
|
6
7
|
const { getMessage } = require('./util/logging');
|
|
@@ -15,6 +16,9 @@ const COMMANDS = {
|
|
|
15
16
|
unsubscribe: 'from'
|
|
16
17
|
};
|
|
17
18
|
|
|
19
|
+
const DEFAULT_SUBSCRIBE_USER = 'yves';
|
|
20
|
+
const DEFAULT_SUBSCRIBE_PASSWORD = '';
|
|
21
|
+
|
|
18
22
|
module.exports = class TenantAction {
|
|
19
23
|
|
|
20
24
|
// TODO JSDoc
|
|
@@ -33,12 +37,19 @@ module.exports = class TenantAction {
|
|
|
33
37
|
async run(paramValues, { tenant, local } = {}) {
|
|
34
38
|
let params = new ParamCollection(paramValues);
|
|
35
39
|
params.set('skipToken', true); // Token would have insufficient scopes for this command.
|
|
40
|
+
|
|
36
41
|
if (local) {
|
|
37
42
|
// Connect to locally-served MTXS
|
|
38
43
|
await this.runWithServer(params, tenant);
|
|
39
44
|
} else {
|
|
40
|
-
// Connect to running MTXS server
|
|
41
45
|
params = await AuthManager.login(params.toEntries());
|
|
46
|
+
// subscribe: use 'yves' as default username against localhost if no username is provided
|
|
47
|
+
if (this.command === 'subscribe' && !params.has('username') && params.has('appUrl') && localhostRegex.test(params.get('appUrl'))) {
|
|
48
|
+
params.set('username', DEFAULT_SUBSCRIBE_USER);
|
|
49
|
+
params.set('password', DEFAULT_SUBSCRIBE_PASSWORD);
|
|
50
|
+
params = await AuthManager.login(params.toEntries()); // set reqAuth param
|
|
51
|
+
}
|
|
52
|
+
// Connect to running MTXS server
|
|
42
53
|
await this.runClientOnly(params, tenant);
|
|
43
54
|
}
|
|
44
55
|
console.log(`${capitalize(this.command)} successful.`);
|
|
@@ -80,9 +91,6 @@ module.exports = class TenantAction {
|
|
|
80
91
|
}
|
|
81
92
|
|
|
82
93
|
const { cds_mtx } = require(libPath);
|
|
83
|
-
if (!cds_mtx) {
|
|
84
|
-
throw '@sap/cds-mtxs outdated. Please upgrade to @sap/cds-mtxs@>=1.7.0 and re-run this command.';
|
|
85
|
-
}
|
|
86
94
|
const body = params.get('body')
|
|
87
95
|
return cds_mtx(this.command, tenant, body);
|
|
88
96
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
const cds = require('../../lib/cds')
|
|
2
|
+
const { read, stat } = cds.utils
|
|
3
|
+
const crypto = require('crypto')
|
|
4
|
+
const { getFiles } = require('../build/util')
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Calculate a checksum for a directory, excluding specified patterns.
|
|
8
|
+
* @param {string} dirPath - The directory path to calculate checksum for.
|
|
9
|
+
* @param {(file: string) => boolean} [filter] - the filter function to apply to the found files
|
|
10
|
+
* @param {string} [hashFunction='sha256'] - The hash function to use (default is 'sha256').
|
|
11
|
+
* @returns {Promise<string>} - The checksum as a hex string.
|
|
12
|
+
*/
|
|
13
|
+
async function calcDirChecksum(dirPath, filter = [], hashFunction = 'sha256', optionalFiles = []) {
|
|
14
|
+
const hash = crypto.createHash(hashFunction)
|
|
15
|
+
|
|
16
|
+
let stats
|
|
17
|
+
try {
|
|
18
|
+
stats = await stat(dirPath)
|
|
19
|
+
} catch {
|
|
20
|
+
return hash.digest('hex')
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (stats.isFile()) {
|
|
24
|
+
hash.update(await read(dirPath, "binary"))
|
|
25
|
+
return hash.digest('hex')
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const files = [...(await getFiles(dirPath, filter, [], true)), ...optionalFiles].sort()
|
|
29
|
+
for (const file of files) {
|
|
30
|
+
try {
|
|
31
|
+
hash.update(file)
|
|
32
|
+
hash.update(await read(file, "binary"))
|
|
33
|
+
} catch {
|
|
34
|
+
// ignore
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return hash.digest('hex')
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
module.exports = { calcDirChecksum }
|
package/lib/util/fs.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
const { parse } = require('node:path')
|
|
2
|
+
|
|
1
3
|
const YAML = require('yaml')
|
|
2
4
|
const { read, write } = require('../cds').utils
|
|
3
|
-
const JSONC = require('./jsonc')
|
|
5
|
+
const JSONC = require('./jsonc')
|
|
4
6
|
|
|
5
7
|
// REVISIT: Consider merging with template util
|
|
6
8
|
|
|
@@ -59,4 +61,9 @@ module.exports = new class FsUtil {
|
|
|
59
61
|
const json = await this.readJSON(src, project)
|
|
60
62
|
await write(dst, json, { spaces: 2 })
|
|
61
63
|
}
|
|
64
|
+
|
|
65
|
+
isRoot(folder) {
|
|
66
|
+
const { root, dir } = parse(folder)
|
|
67
|
+
return root === dir
|
|
68
|
+
}
|
|
62
69
|
}
|
package/lib/util/glob.js
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
const path = require('node:path');
|
|
2
2
|
const { join } = path;
|
|
3
|
-
const { existsSync } = require('node:fs');
|
|
4
3
|
const { readdir } = require('node:fs').promises;
|
|
5
4
|
|
|
5
|
+
const IGNORE_DIRS = new Set(['node_modules', '.git', '.hg', '.svn', 'dist', 'target', 'build', 'out']);
|
|
6
|
+
|
|
7
|
+
|
|
6
8
|
/**
|
|
7
9
|
* Returns an AsyncIterator of those (recursive) subdirectories that match the glob pattern.
|
|
8
|
-
*
|
|
9
|
-
* @param
|
|
10
|
-
* @
|
|
10
|
+
* Skips common large directories (node_modules, .git, .hg, .svn, dist, target, build, out).
|
|
11
|
+
* @param {string} pattern - The glob pattern to match against.
|
|
12
|
+
* @param {string} cwd - The current working directory to start the search from.
|
|
13
|
+
* @returns An array of relative paths that match the glob pattern.
|
|
11
14
|
*/
|
|
12
15
|
async function* glob(pattern, { cwd } = { cwd: process.cwd() }) {
|
|
13
16
|
if (/\{.*}/.test(pattern)) {
|
|
@@ -18,32 +21,42 @@ async function* glob(pattern, { cwd } = { cwd: process.cwd() }) {
|
|
|
18
21
|
}
|
|
19
22
|
return globNative(pattern, { cwd });
|
|
20
23
|
}
|
|
21
|
-
yield* (await globArray(pattern,
|
|
24
|
+
yield* (await globArray(pattern, cwd));
|
|
22
25
|
}
|
|
23
26
|
|
|
24
27
|
/**
|
|
25
28
|
* Returns those subdirectories, recursively, that match the glob pattern.
|
|
26
|
-
*
|
|
27
|
-
* @param
|
|
29
|
+
* Skips common large directories (node_modules, .git, .hg, .svn, dist, target, build, out).
|
|
30
|
+
* @param {string} pattern - The glob pattern to match against.
|
|
31
|
+
* @param {string} cwd - The current working directory to start the search from.
|
|
28
32
|
* @returns {Promise<string[]>} - An array of relative paths that match the glob pattern.
|
|
29
33
|
*/
|
|
30
|
-
async function globArray(pattern,
|
|
34
|
+
async function globArray(pattern, cwd) {
|
|
31
35
|
const regex = globToRegex(pattern);
|
|
32
36
|
return (await subdirs(cwd))
|
|
33
37
|
.map(fullPath => path.relative(cwd, fullPath))
|
|
34
|
-
.filter(relativePath => regex.test(relativePath));
|
|
38
|
+
.filter(relativePath => regex.test(relativePath.replace(/\\/g, '/')));
|
|
35
39
|
}
|
|
36
40
|
|
|
37
41
|
/**
|
|
38
42
|
* Recursively returns all subdirectories of a given directory.
|
|
39
43
|
* Returns only non-hidden directories (those not starting with a dot).
|
|
40
|
-
*
|
|
44
|
+
* Skips common large directories like node_modules, .git, etc.
|
|
45
|
+
* @param {string} dir - The directory to search in.
|
|
41
46
|
* @returns {Promise<String[]>} - An array of paths to subdirectories.
|
|
42
47
|
*/
|
|
43
48
|
async function subdirs(dir) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
49
|
+
let entries;
|
|
50
|
+
try {
|
|
51
|
+
entries = await readdir(dir, { withFileTypes: true });
|
|
52
|
+
} catch (err) {
|
|
53
|
+
return [];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const children = entries.filter(child =>
|
|
57
|
+
child.isDirectory() && !child.name.startsWith('.') && !IGNORE_DIRS.has(child.name)
|
|
58
|
+
);
|
|
59
|
+
|
|
47
60
|
return (await Promise.all(
|
|
48
61
|
children.map(async child => {
|
|
49
62
|
const childPath = join(dir, child.name);
|
package/lib/util/question.js
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
const readline = require('node:readline')
|
|
2
|
+
const { Writable } = require('node:stream')
|
|
2
3
|
|
|
3
|
-
async function ask4(...args) {
|
|
4
|
+
async function ask4([...args], { redacted = false } = {}) {
|
|
5
|
+
var mutableStdout = new Writable({
|
|
6
|
+
write: function (chunk, encoding, callback) {
|
|
7
|
+
if (!redacted)
|
|
8
|
+
process.stdout.write(chunk, encoding);
|
|
9
|
+
callback();
|
|
10
|
+
}
|
|
11
|
+
});
|
|
4
12
|
|
|
5
13
|
// If not in interactive mode, read all input at once.
|
|
6
14
|
if (!process.stdin.isTTY) {
|
|
@@ -13,19 +21,64 @@ async function ask4(...args) {
|
|
|
13
21
|
}
|
|
14
22
|
|
|
15
23
|
const answers = []
|
|
16
|
-
const rl = readline.createInterface({
|
|
24
|
+
const rl = readline.createInterface({
|
|
25
|
+
input: process.stdin,
|
|
26
|
+
output: mutableStdout,
|
|
27
|
+
terminal: true
|
|
28
|
+
})
|
|
17
29
|
|
|
18
30
|
const askQuestion = question =>
|
|
19
|
-
new Promise(resolve =>
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
31
|
+
new Promise(resolve => {
|
|
32
|
+
if (redacted && process.stdin.isTTY) {
|
|
33
|
+
// Set raw mode to intercept keystrokes
|
|
34
|
+
process.stdin.setRawMode(true)
|
|
35
|
+
process.stdout.write(question)
|
|
36
|
+
|
|
37
|
+
let answer = ''
|
|
38
|
+
const onData = (char) => {
|
|
39
|
+
const byte = char.toString()
|
|
40
|
+
|
|
41
|
+
// Enter key
|
|
42
|
+
if (byte === '\n' || byte === '\r') {
|
|
43
|
+
process.stdin.setRawMode(false)
|
|
44
|
+
process.stdin.removeListener('data', onData)
|
|
45
|
+
process.stdout.write('\n')
|
|
46
|
+
answers.push(answer)
|
|
47
|
+
resolve()
|
|
48
|
+
}
|
|
49
|
+
// Backspace/Delete
|
|
50
|
+
else if (byte === '\b' || byte === '\x7f') {
|
|
51
|
+
if (answer.length > 0) {
|
|
52
|
+
answer = answer.slice(0, -1)
|
|
53
|
+
process.stdout.write('\b \b')
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
// Ctrl+C
|
|
57
|
+
else if (byte === '\x03') {
|
|
58
|
+
process.stdin.setRawMode(false)
|
|
59
|
+
process.exit()
|
|
60
|
+
}
|
|
61
|
+
// Regular character
|
|
62
|
+
else if (byte >= ' ' || byte === '\t') {
|
|
63
|
+
answer += byte
|
|
64
|
+
process.stdout.write('*')
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
process.stdin.on('data', onData)
|
|
69
|
+
} else {
|
|
70
|
+
rl.question(question, answer => {
|
|
71
|
+
answers.push(answer)
|
|
72
|
+
resolve()
|
|
73
|
+
})
|
|
74
|
+
}
|
|
75
|
+
})
|
|
23
76
|
|
|
24
77
|
for (const question of args) {
|
|
25
78
|
await askQuestion(question)
|
|
26
79
|
}
|
|
27
80
|
rl.close()
|
|
28
|
-
return
|
|
81
|
+
return args.length == 1 ? answers[0] : answers
|
|
29
82
|
}
|
|
30
83
|
|
|
31
84
|
module.exports = { ask4 }
|