@sap/cds-dk 4.6.4 → 4.8.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.
Files changed (74) hide show
  1. package/CHANGELOG.md +68 -1
  2. package/bin/activate.js +5 -1
  3. package/bin/add.js +2 -1
  4. package/bin/bind.js +121 -48
  5. package/bin/cds.js +8 -0
  6. package/bin/env.js +0 -2
  7. package/bin/repl.js +5 -2
  8. package/bin/watch.js +10 -7
  9. package/lib/bind/bindingResolver.js +26 -14
  10. package/lib/bind/bindingUtil.js +144 -0
  11. package/lib/bind/cfKeyProvider.js +2 -80
  12. package/lib/bind/kubernetesCredentialsProvider.js +157 -0
  13. package/lib/bind/userCdsrcJsonStorageProvider.js +7 -7
  14. package/lib/client/activate.js +16 -13
  15. package/lib/client/base_command.js +5 -1
  16. package/lib/client/helper/cf_helper.js +5 -2
  17. package/lib/client/params.js +16 -2
  18. package/lib/client/settings_manager.js +15 -8
  19. package/lib/compile/openapi/csdl2openapi.js +6 -8
  20. package/lib/compile/to-xsuaa.js +0 -14
  21. package/lib/import/utils/MetadataConverter.js +6 -4
  22. package/lib/import/utils/MultiMap.js +1 -0
  23. package/lib/import/v2parser.js +150 -64
  24. package/lib/import/v4parser.js +118 -56
  25. package/lib/index.js +6 -5
  26. package/lib/init/constants.js +11 -5
  27. package/lib/init/index.js +14 -7
  28. package/lib/init/template/_merging/existences.js +161 -0
  29. package/lib/init/template/approuter/files/default-env.json +9 -0
  30. package/lib/init/template/approuter/files/mta.yaml.hbs +48 -0
  31. package/lib/init/template/approuter/files/package.json +9 -0
  32. package/lib/init/template/approuter/files/xs-app.json +8 -0
  33. package/lib/init/template/approuter/index.js +66 -0
  34. package/lib/init/template/auditlog/files/dependencies.package.json +5 -0
  35. package/lib/init/template/auditlog/files/mta.yaml.hbs +13 -0
  36. package/lib/init/template/auditlog/index.js +38 -0
  37. package/lib/init/template/cf-manifest/index.js +1 -1
  38. package/lib/init/template/data/index.js +18 -6
  39. package/lib/init/template/hana/files/common/undeploy.json +5 -0
  40. package/lib/init/template/hana/files/java/package.json +3 -0
  41. package/lib/init/template/hana/files/mta.yaml.hbs +42 -0
  42. package/lib/init/template/hana/files/nodejs/dependencies.package.json +5 -0
  43. package/lib/init/template/hana/index.js +53 -24
  44. package/lib/init/template/java/index.js +1 -5
  45. package/lib/init/template/lint/index.js +17 -1
  46. package/lib/init/template/mta/files/mta.yaml.hbs +27 -216
  47. package/lib/init/template/mta/index.js +25 -17
  48. package/lib/init/template/mtx/files/cds.package.json +24 -0
  49. package/lib/init/template/mtx/files/dependencies.package.json +5 -0
  50. package/lib/init/template/mtx/files/mta.yaml.hbs +74 -0
  51. package/lib/init/template/mtx/files/xs-security.json.hbs +23 -9
  52. package/lib/init/template/mtx/index.js +126 -29
  53. package/lib/init/template/templateBase.js +14 -0
  54. package/lib/init/template/xsuaa/files/cds.package.json +9 -0
  55. package/lib/init/template/xsuaa/files/dependencies.package.json +6 -0
  56. package/lib/init/template/xsuaa/files/mta.yaml.hbs +17 -0
  57. package/lib/init/template/xsuaa/index.js +75 -0
  58. package/lib/init/util/fsUtil.js +18 -4
  59. package/lib/init/util/logger.js +3 -1
  60. package/lib/init/util/mvnArchetypeUtil.js +3 -1
  61. package/lib/init/{template/mta → util}/projectReader.js +26 -11
  62. package/lib/init/util/templateUtil.js +267 -3
  63. package/lib/lint/Linter.js +1 -2
  64. package/lib/lint/io.js +3 -12
  65. package/lib/util/exec.d.ts +54 -0
  66. package/lib/util/exec.js +210 -0
  67. package/lib/watch/livereload-server.js +43 -31
  68. package/lib/watch/node-watch.js +46 -20
  69. package/lib/watch/open.js +1 -1
  70. package/npm-shrinkwrap.json +3382 -9106
  71. package/package.json +8 -9
  72. package/readme.md +1 -1
  73. package/lib/init/template/mtx/package/cds.package.json +0 -29
  74. package/lib/init/template/mtx/package/dependencies.package.json +0 -9
@@ -0,0 +1,9 @@
1
+ {
2
+ "destinations": [
3
+ {
4
+ "name": "srv-api",
5
+ "url": "http://localhost:4004",
6
+ "forwardAuthToken": true
7
+ }
8
+ ]
9
+ }
@@ -0,0 +1,48 @@
1
+ ---
2
+ modules:
3
+ - name: {{cap.appName}}-srv
4
+ type: {{cap.pLanguage}}
5
+ requires:
6
+ - name: {{cap.appName}}-uaa
7
+
8
+ - name: {{cap.appName}}
9
+ type: approuter.nodejs
10
+ path: {{& ui.appPath}} # from cds.env.folders. Consider also cds.env.build.target --> gen/app
11
+ parameters:
12
+ keep-existing-routes: true
13
+ disk-quota: 256M
14
+ memory: 256M
15
+ # hosts: # additional tenant specific hostnames (only for Canary)
16
+ ## the developer will do this via an extension descriptor:
17
+ # - <paas-subdomain >${tenant-delimiter}${host}
18
+ # - <saas-subdomain1>${tenant-delimiter}${host}
19
+ # - ...
20
+ {{#cap.isMultitenant}}
21
+ properties:
22
+ TENANT_HOST_PATTERN: "^(.*)-${default-uri}"
23
+ {{/cap.isMultitenant}}
24
+ requires:
25
+ - name: srv-api
26
+ group: destinations
27
+ properties:
28
+ name: srv-api # this is a name which must be used in xs-app.json as well
29
+ url: ~{srv-url}
30
+ forwardAuthToken: true
31
+ {{#cap.isMultitenant}}
32
+ - name: mtx-api # in here always, but really used only if mtx client is used (our recommendation is that they contact cds-mtx via the approuter)
33
+ group: destinations
34
+ properties:
35
+ name: mtx-api # this is a name which must be used in xs-app.json as well
36
+ url: ~{mtx-url}
37
+ {{/cap.isMultitenant}}
38
+
39
+ resources:
40
+ - name: {{cap.appName}}-uaa{{#cap.isMultitenant}}-mt{{/cap.isMultitenant}}
41
+ type: org.cloudfoundry.managed-service
42
+ parameters:
43
+ service: xsuaa
44
+ service-plan: application
45
+ path: ./xs-security.json
46
+ config:
47
+ xsappname: {{cap.appName}}-${org}-${space}
48
+ tenant-mode: {{#cap.isMultitenant}}shared{{/cap.isMultitenant}}{{^cap.isMultitenant}}dedicated{{/cap.isMultitenant}}
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "approuter",
3
+ "dependencies": {
4
+ "@sap/approuter": "^10"
5
+ },
6
+ "scripts": {
7
+ "start": "node node_modules/@sap/approuter/approuter.js"
8
+ }
9
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "routes": [
3
+ {
4
+ "source": "^.*$",
5
+ "destination": "srv-api"
6
+ }
7
+ ]
8
+ }
@@ -0,0 +1,66 @@
1
+ const TemplateBase = require('../templateBase');
2
+ const ProjectReader = require('../../util/projectReader');
3
+ const { fse } = require('@sap/cds-foss');
4
+ const path = require('path');
5
+ const { OPTION_XSUAA } = require('../../constants');
6
+ const { srvNode, srvJava, approuter, xsuaa } = require('../_merging/existences');
7
+
8
+ module.exports = class ApprouterTemplate extends TemplateBase {
9
+ constructor(projectPath, generator) {
10
+ super(projectPath, generator, __dirname);
11
+ this.projectReader = new ProjectReader(this);
12
+ }
13
+
14
+ async getDependencies() {
15
+ return [OPTION_XSUAA];
16
+ }
17
+
18
+ async runMTAMerging() {
19
+ const projectDescriptor = await this.projectReader.read(this.options);
20
+ const mtaYAMLPath = path.join(this.projectPath, 'mta.yaml');
21
+ if (!fse.existsSync(mtaYAMLPath)) return;
22
+ const srv = projectDescriptor.cap.isNodejs ? srvNode : srvJava
23
+ await this.templateUtil.mergeYAML(
24
+ mtaYAMLPath,
25
+ `${__dirname}/files/mta.yaml.hbs`,
26
+ projectDescriptor,
27
+ {
28
+ existences: [srv, approuter, xsuaa],
29
+ relationships: [{
30
+ in: srv.ref,
31
+ inKeyPath: ["requires"],
32
+ into: "name",
33
+ existences: [xsuaa.ref],
34
+ existenceKeyPath: ["name"],
35
+ }, {
36
+ in: approuter.ref,
37
+ inKeyPath: ["requires"],
38
+ into: "name",
39
+ existences: [xsuaa.ref],
40
+ existenceKeyPath: ["name"],
41
+ }],
42
+ }
43
+ );
44
+ }
45
+
46
+ async run() {
47
+ const projectDescriptor = await this.projectReader.read(this.options);
48
+ const appPath = path.join(this.projectPath, projectDescriptor.ui.appPath)
49
+
50
+ await this.templateUtil.mergeJSON(
51
+ `${appPath}/package.json`,
52
+ `${__dirname}/files/package.json`
53
+ );
54
+
55
+ await this.templateUtil.mergeJSON(
56
+ `${appPath}/xs-app.json`,
57
+ `${__dirname}/files/xs-app.json`
58
+ );
59
+
60
+ await this.templateUtil.mergeJSON(
61
+ `${appPath}/default-env.json`,
62
+ `${__dirname}/files/default-env.json`
63
+ );
64
+ await this.runMTAMerging()
65
+ }
66
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "dependencies": {
3
+ "@sap/audit-logging": "^5"
4
+ }
5
+ }
@@ -0,0 +1,13 @@
1
+ ---
2
+ modules:
3
+ - name: {{cap.appName}}-srv
4
+ type: {{cap.pLanguage}}
5
+ requires:
6
+ - name: {{cap.appName}}-auditlog
7
+
8
+ resources:
9
+ - name: {{cap.appName}}-auditlog
10
+ type: org.cloudfoundry.managed-service
11
+ parameters:
12
+ service: auditlog-api
13
+ service-plan: default
@@ -0,0 +1,38 @@
1
+ const TemplateBase = require('../templateBase');
2
+ const ProjectReader = require('../../util/projectReader');
3
+ const { fse } = require('@sap/cds-foss');
4
+ const path = require('path');
5
+ const { srvNode, srvJava, auditlog } = require('../_merging/existences');
6
+
7
+ module.exports = class AuditlogTemplate extends TemplateBase {
8
+ constructor(projectPath, generator) {
9
+ super(projectPath, generator, __dirname);
10
+ this.projectReader = new ProjectReader(this);
11
+ }
12
+
13
+ async runMTAMerging() {
14
+ const projectDescriptor = await this.projectReader.read(this.options);
15
+ const mtaYAMLPath = path.join(this.projectPath, 'mta.yaml');
16
+ if (!fse.existsSync(mtaYAMLPath)) return;
17
+ const srv = projectDescriptor.cap.isNodejs ? srvNode : srvJava
18
+ await this.templateUtil.mergeYAML(
19
+ mtaYAMLPath,
20
+ `${__dirname}/files/mta.yaml.hbs`,
21
+ projectDescriptor,
22
+ {
23
+ existences: [srv, auditlog],
24
+ relationships: [{
25
+ in: srv.ref,
26
+ inKeyPath: ["requires"],
27
+ into: "name",
28
+ existences: [auditlog.ref],
29
+ existenceKeyPath: ["name"],
30
+ }],
31
+ }
32
+ );
33
+ }
34
+
35
+ async run() {
36
+ await this.runMTAMerging()
37
+ }
38
+ }
@@ -1,6 +1,6 @@
1
1
  const path = require('path')
2
2
  const TemplateBase = require('../templateBase');
3
- const ProjectReader = require('../mta/projectReader')
3
+ const ProjectReader = require('../../util/projectReader');
4
4
 
5
5
  const { OPTION_CF_MANIFEST } = require('../../constants')
6
6
  const MANIFEST = 'manifest'
@@ -11,16 +11,12 @@ module.exports = class DataTemplate extends TemplateBase {
11
11
  async run() {
12
12
  const env = await this.getEnv();
13
13
 
14
- const prefix = (typeof this.options.for === 'string') // --for <prefix>
15
- ? this.options.for
16
- : '';
17
- const prefixedWith = (definition) => definition.name === prefix || definition.name.startsWith(prefix);
18
-
19
14
  let dest = (typeof this.options.out === 'string') // target folder
20
15
  ? this.options.out
21
16
  : getDefaultTargetFolder(env, this.projectPath);
22
17
  dest = resolve(this.projectPath, dest);
23
18
 
19
+ const nameFilter = asRegex(this.options.for)
24
20
  const force = this.options.force;
25
21
  const logger = this.logger;
26
22
 
@@ -35,7 +31,7 @@ module.exports = class DataTemplate extends TemplateBase {
35
31
  csn = cds.reflect(csn); // reflected model (adds additional helper functions)
36
32
 
37
33
  csn.all('entity')
38
- .filter(prefixedWith)
34
+ .filter (e => e.name.match(nameFilter)) // --for prefix|regex
39
35
  .filter (e => !e.query) // exclude entities with queries (projection on, select from ...)
40
36
  .filter (e => e.name !== 'DRAFT.DraftAdministrativeData' && !e.name.endsWith('.drafts')) // exclude draft stuff
41
37
  .forEach(e => processEntity(e, dest, this.projectPath, csn, force, logger));
@@ -53,6 +49,22 @@ function includeExternalEntities(model, logger) {
53
49
  return model
54
50
  }
55
51
 
52
+ function asRegex(spec) {
53
+ if (typeof spec === 'string') {
54
+ try {
55
+ if (spec.match(/[\^$|*]/))
56
+ return new RegExp(spec)
57
+ else { // no meta chars -> prefix semantics
58
+ spec = spec.replace(/\./g, '\\.') // escape dot
59
+ return new RegExp('^'+spec+'.*')
60
+ }
61
+ } catch (err) {
62
+ throw new Error (err.message) // user error, so cut off stack trace
63
+ }
64
+ }
65
+ return /.*/
66
+ }
67
+
56
68
  function processEntity (entity, dest, projectPath, csn, force, logger) {
57
69
  let dataFileName;
58
70
  const namespace = getNamespace(csn, entity.name);
@@ -0,0 +1,5 @@
1
+ [
2
+ "src/gen/**/*.hdbview",
3
+ "src/gen/**/*.hdbindex",
4
+ "src/gen/**/*.hdbconstraint"
5
+ ]
@@ -3,6 +3,9 @@
3
3
  "dependencies": {
4
4
  "@sap/hdi-deploy": "^4"
5
5
  },
6
+ "engines": {
7
+ "node": "^16"
8
+ },
6
9
  "scripts": {
7
10
  "start": "node node_modules/@sap/hdi-deploy/deploy.js"
8
11
  }
@@ -0,0 +1,42 @@
1
+ ---
2
+ modules:
3
+ - name: {{cap.appName}}-srv
4
+ type: {{cap.pLanguage}}
5
+ requires:
6
+ - name: {{cap.appName}}-db
7
+
8
+ {{^cap.isMultitenant}}
9
+ - name: {{cap.appName}}-db-deployer
10
+ type: hdb
11
+ path: {{& cap.db.0.path}}
12
+ parameters:
13
+ buildpack: nodejs_buildpack
14
+ requires:
15
+ - name: {{cap.appName}}-db
16
+ {{/cap.isMultitenant}}
17
+
18
+ {{#cap.hasRequires}}
19
+ resources:
20
+ {{#cap.requires}}
21
+ {{#resource.isHana}}
22
+ - name: {{cap.appName}}-db
23
+ {{#resource.isPlainHana}}
24
+ type: com.sap.xs.hdi-container
25
+ parameters:
26
+ service: {{resource.service}} # or 'hanatrial' on trial landscapes
27
+ {{/resource.isPlainHana}}
28
+ {{#resource.isManagedHana}} {{! enable automatic switching to 'hanatrial' on trial accounts}}
29
+ type: org.cloudfoundry.managed-service
30
+ parameters:
31
+ service: {{resource.service}}
32
+ {{/resource.isManagedHana}}
33
+ service-plan: {{resource.vcap.plan}}
34
+ {{#resource.vcap.name}}
35
+ service-name: {{resource.vcap.name}}
36
+ {{/resource.vcap.name}}
37
+ properties:
38
+ hdi-service-name: ${service-name}
39
+ {{/resource.isHana}}
40
+
41
+ {{/cap.requires}}
42
+ {{/cap.hasRequires}}
@@ -0,0 +1,5 @@
1
+ {
2
+ "dependencies": {
3
+ "hdb": "^0.18.3"
4
+ }
5
+ }
@@ -1,34 +1,22 @@
1
1
  const path = require('path');
2
2
 
3
+ const { fse } = require('@sap/cds-foss');
4
+
3
5
  const commandUtil = require('../../util/commandUtil');
4
6
  const mvnArchetypes = require('../../util/mvnArchetypeUtil');
5
7
  const term = require('../../../util/term');
8
+ const ProjectReader = require('../../util/projectReader');
6
9
 
7
10
  const TemplateBase = require('../templateBase');
8
11
 
9
12
  const { PROJECT_TYPE, OPTION_JAVA, KIND_SQL, URLS, KIND_HANA } = require('../../constants');
10
13
  const { nullLogger } = require('../../util/logger');
11
-
14
+ const { srvNode, srvJava, hdbDeployer, serviceManager, hdiContainer } = require('../_merging/existences');
12
15
 
13
16
  module.exports = class HanaTemplate extends TemplateBase {
14
17
  constructor(projectPath, generator) {
15
18
  super(projectPath, generator, __dirname);
16
- }
17
-
18
- async checkEnabled() {
19
- if (this.options.force) {
20
- return true;
21
- }
22
-
23
- const env = await this.getEnv();
24
-
25
- const hdiConfigPath = path.join(this.projectPath, env.folders.db, 'src/.hdiconfig');
26
- if (await this.fsUtil.pathExists(hdiConfigPath)) {
27
- const configFilePath = path.join(env.folders.db, 'src/.hdiconfig');
28
- throw new Error(`Database config file ${configFilePath} already exists. Use --force to overwrite.`);
29
- }
30
-
31
- return true;
19
+ this.projectReader = new ProjectReader(this);
32
20
  }
33
21
 
34
22
  // read env from project
@@ -42,28 +30,69 @@ module.exports = class HanaTemplate extends TemplateBase {
42
30
  }
43
31
  }
44
32
 
33
+ async runMTAMerging() {
34
+ const projectDescriptor = await this.projectReader.read(this.options);
35
+
36
+ const mtaYAMLPath = path.join(this.projectPath, 'mta.yaml');
37
+ if (!fse.existsSync(mtaYAMLPath)) {
38
+ console.warn(`There is no MTA file in your project. Run \`cds add mta\` to add an MTA file or create the HANA services yourself.`)
39
+ return;
40
+ }
41
+ const srv = projectDescriptor.cap.isNodejs ? srvNode : srvJava
42
+ const deployer = projectDescriptor.cap.isMultitenant ? null : hdbDeployer
43
+ const db = projectDescriptor.cap.isMultitenant ? serviceManager : hdiContainer
44
+ await this.templateUtil.mergeYAML(
45
+ mtaYAMLPath,
46
+ `${__dirname}/files/mta.yaml.hbs`,
47
+ projectDescriptor,
48
+ {
49
+ existences: [srv, deployer, db],
50
+ relationships: [{
51
+ in: srv.ref,
52
+ inKeyPath: ["requires"],
53
+ into: "name",
54
+ existences: [db.ref],
55
+ existenceKeyPath: ["name"],
56
+ },
57
+ !projectDescriptor.cap.isMultitenant && projectDescriptor.cap.isNodejs ?
58
+ {
59
+ in: deployer.ref,
60
+ inKeyPath: ["requires"],
61
+ into: "name",
62
+ existences: [db.ref],
63
+ existenceKeyPath: ["name"],
64
+ } : null],
65
+ }
66
+ );
67
+ }
68
+
45
69
  async run() {
46
70
  const env = await this.getEnv();
47
71
 
48
- await this.templateUtil.copyFiles('common', path.join(this.projectPath, env.folders.db), {
49
- projectName: this.projectName
50
- }, this.options.force);
72
+ const hdiConfigPath = path.join(this.projectPath, env.folders.db, 'src', '.hdiconfig');
73
+ const hdiConfigTemplatePath = path.join(__dirname, 'files', 'common', 'src', '.hdiconfig');
74
+ await this.templateUtil.mergeJSON(hdiConfigPath, hdiConfigTemplatePath);
75
+
76
+ const undeployJSONPath = path.join(this.projectPath, env.folders.db, 'undeploy.json');
77
+ const undeployJSONTemplatePath = path.join(__dirname, 'files', 'common', 'undeploy.json');
78
+ await this.templateUtil.mergeJSON(undeployJSONPath, undeployJSONTemplatePath);
51
79
 
52
- const cdsrcJsonPath = path.join(this.projectPath, '.cdsrc.json');
53
80
  const projectType = await this.getProjectType();
54
81
  switch (projectType) {
55
- case PROJECT_TYPE.java:
82
+ case PROJECT_TYPE.java: {
56
83
  await this.templateUtil.copyFiles('java', path.join(this.projectPath, env.folders.db), {}, this.options.force);
57
84
  await this._updatePomXml();
85
+ const cdsrcJsonPath = path.join(this.projectPath, '.cdsrc.json');
58
86
  await this._updateCdsrcJson(cdsrcJsonPath, env.folders.db, env);
59
87
  break;
60
-
88
+ }
61
89
  case PROJECT_TYPE.nodejs:
62
90
  await this._updatePackageJson(path.join(this.projectPath, 'package.json'), env.folders.db, env);
63
91
  break;
64
92
 
65
93
  default: break;
66
94
  }
95
+ await this.runMTAMerging()
67
96
  }
68
97
 
69
98
  async _updatePomXml() {
@@ -158,6 +187,6 @@ module.exports = class HanaTemplate extends TemplateBase {
158
187
  }
159
188
 
160
189
  _isUsingHana(db, env) {
161
- return env.get(`requires.${db}.kind`) === KIND_HANA || env.get(`requires.${db}.dialect`) === KIND_HANA || env.get(`requires.${db}.use`) === KIND_HANA;
190
+ return [`kind`, `dialect`, `use`].map(p => env.get(`requires.${db}.${p}`)).includes(KIND_HANA)
162
191
  }
163
192
  }
@@ -9,7 +9,7 @@ const mvnArchetypeUtil = require('../../util/mvnArchetypeUtil');
9
9
  const term = require('../../../util/term');
10
10
 
11
11
  const TemplateBase = require('../templateBase');
12
- const { COMMAND_ADD, URLS, OPTION_JAVA, OPTION_NODEJS, OPTION_MTX } = require('../../constants');
12
+ const { COMMAND_ADD, URLS, OPTION_JAVA, OPTION_NODEJS } = require('../../constants');
13
13
  const { nullLogger } = require('../../util/logger');
14
14
 
15
15
 
@@ -27,10 +27,6 @@ module.exports = class JavaTemplate extends TemplateBase {
27
27
  throw new Error(`Only one runtime per project is supported. Specify either ${OPTION_JAVA} or ${OPTION_NODEJS}.`);
28
28
  }
29
29
 
30
- if (this.options.add.has(OPTION_MTX)) {
31
- throw new Error(`The '${OPTION_MTX}' option can only be used for Node.js projects as of yet.`);
32
- }
33
-
34
30
  return true;
35
31
  }
36
32
 
@@ -9,10 +9,15 @@ const readline = require("readline");
9
9
 
10
10
  const { OPTION_LINT_DEV, OPTION_LINT_GLOBAL } = require("../../constants");
11
11
  const { mkdirp, fs } = require("@sap/cds/lib/utils");
12
- const { getConfigPath } = require("@sap/eslint-plugin-cds/lib/api");
12
+ const { getConfigPath, getFileExtensions } = require("@sap/eslint-plugin-cds/lib/api");
13
13
  const generators = require("../../../lint/generators");
14
14
 
15
15
  const IS_WIN = os.platform() === "win32";
16
+ const ALLOWED_FILE_EXTENSIONS = getFileExtensions();
17
+ const VSCODE_FILE_ASSOCIATIONS = {
18
+ "csv": [ "csv", "csv (semicolon)", "tsv", "tab" ]
19
+ }
20
+
16
21
  module.exports = class LintTemplate extends TemplateBase {
17
22
  constructor(projectPath, generator) {
18
23
  super(projectPath, generator, __dirname);
@@ -68,10 +73,21 @@ module.exports = class LintTemplate extends TemplateBase {
68
73
  }
69
74
 
70
75
  // Generate VS Code extension settings
76
+ const extensions = ALLOWED_FILE_EXTENSIONS.map((ext) => {
77
+ return path.extname(ext).replace('.', '');
78
+ })
79
+ extensions.forEach((ext) => {
80
+ if (ext in VSCODE_FILE_ASSOCIATIONS) {
81
+ VSCODE_FILE_ASSOCIATIONS[ext].forEach((assoc) => {
82
+ extensions.push(assoc)
83
+ })
84
+ }
85
+ });
71
86
  await io.sanitizeVscodeSettings(
72
87
  this.projectPath,
73
88
  path.join(this.projectPath, ".vscode/settings.json"),
74
89
  this.lintType,
90
+ extensions,
75
91
  this.customRuleExample
76
92
  );
77
93
  }