@sap/cds-dk 10.0.5 → 10.0.7

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 (58) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/bin/export.js +1 -1
  3. package/bin/version.js +7 -3
  4. package/lib/build/plugins/hana/index.js +19 -2
  5. package/lib/import/asyncapi/parserContext.js +136 -54
  6. package/lib/init/projectReader.js +4 -2
  7. package/lib/init/template/ams/files/package.json.hbs +1 -1
  8. package/lib/init/template/nodejs/index.js +4 -2
  9. package/lib/init/template/test/files/test/test.xs.hbs +3 -2
  10. package/lib/init/template/xsuaa/index.js +11 -7
  11. package/node_modules/@cap-js/openapi/lib/compile/csdl.js +3 -3
  12. package/node_modules/@cap-js/openapi/lib/compile/csdl2openapi.js +111 -103
  13. package/node_modules/@cap-js/openapi/lib/compile/diagram.js +4 -4
  14. package/node_modules/@cap-js/openapi/lib/compile/types.d.ts +3 -1
  15. package/node_modules/@cap-js/openapi/package.json +3 -3
  16. package/node_modules/@sap/cds/CHANGELOG.md +16 -0
  17. package/node_modules/@sap/cds/lib/compile/for/nodejs.js +1 -0
  18. package/node_modules/@sap/cds/lib/env/defaults.js +1 -0
  19. package/node_modules/@sap/cds/lib/plugins.js +4 -2
  20. package/node_modules/@sap/cds/lib/srv/srv-handlers.js +1 -1
  21. package/node_modules/@sap/cds/libx/_runtime/common/Service.js +1 -1
  22. package/node_modules/@sap/cds/libx/_runtime/messaging/common-utils/authorizedRequest.js +3 -2
  23. package/node_modules/@sap/cds/libx/_runtime/remote/Service.js +1 -1
  24. package/node_modules/@sap/cds/package.json +1 -1
  25. package/node_modules/@sap/cds-compiler/CHANGELOG.md +12 -0
  26. package/node_modules/@sap/cds-compiler/lib/compiler/populate.js +1 -0
  27. package/node_modules/@sap/cds-compiler/lib/compiler/resolve.js +1 -1
  28. package/node_modules/@sap/cds-compiler/lib/model/csnUtils.js +13 -8
  29. package/node_modules/@sap/cds-compiler/package.json +1 -1
  30. package/node_modules/@sap/cds-mtxs/CHANGELOG.md +36 -0
  31. package/node_modules/@sap/cds-mtxs/bin/cds-mtx-migrate.js +32 -48
  32. package/node_modules/@sap/cds-mtxs/bin/cds-mtx.js +1 -0
  33. package/node_modules/@sap/cds-mtxs/cds-plugin.js +18 -0
  34. package/node_modules/@sap/cds-mtxs/lib/migration/migration.js +3 -408
  35. package/node_modules/@sap/cds-mtxs/package.json +1 -1
  36. package/node_modules/@sap/cds-mtxs/srv/cf/abstract-provisioning-service.js +5 -6
  37. package/node_modules/@sap/cds-mtxs/srv/extensibility/linter/annotations.js +5 -2
  38. package/node_modules/@sap/cds-mtxs/srv/extensibility/linter/index.js +6 -5
  39. package/node_modules/@sap/cds-mtxs/srv/extensibility-service.cds +0 -11
  40. package/node_modules/@sap/cds-mtxs/srv/extensibility-service.js +12 -22
  41. package/node_modules/@sap/cds-mtxs/srv/jobs-service.js +30 -24
  42. package/node_modules/@sap/cds-mtxs/srv/model-provider.js +2 -2
  43. package/node_modules/@sap/cds-mtxs/srv/plugins/hana/ctnr-mgr-base.js +5 -2
  44. package/node_modules/@sap/cds-mtxs/srv/plugins/hana/hdi.js +5 -3
  45. package/node_modules/@sap/cds-mtxs/srv/plugins/hana/srv-mgr.js +3 -2
  46. package/node_modules/@sap/cds-mtxs/srv/plugins/hana/tms.js +17 -0
  47. package/node_modules/@sap/cds-mtxs/srv/plugins/hana.js +14 -13
  48. package/node_modules/media-typer/README.md +15 -14
  49. package/node_modules/media-typer/index.js +0 -8
  50. package/node_modules/media-typer/package.json +16 -12
  51. package/node_modules/sax/lib/sax.js +27 -9
  52. package/node_modules/sax/package.json +1 -1
  53. package/node_modules/ws/package.json +1 -1
  54. package/package.json +4 -4
  55. package/lib/init/template/nodejs/files/.gitignore.hbs +0 -34
  56. package/node_modules/@sap/cds-mtxs/lib/migration/extension-project-builder.js +0 -129
  57. package/node_modules/@sap/cds-mtxs/lib/migration/extension-project.js +0 -89
  58. package/node_modules/@sap/cds-mtxs/lib/migration/mtx-adapter.js +0 -230
@@ -7,14 +7,6 @@ const Jobs = 'cds.xt.Jobs', Tasks = 'cds.xt.Tasks'
7
7
 
8
8
  const { t0_ } = require('../lib/utils')
9
9
 
10
- const {
11
- queueSize = 100, clusterSize = 3, workerSize = 4, poolSize = 1
12
- } = {
13
- ...(cds.env.requires.multitenancy?.jobs ?? {}),
14
- ...(cds.env.requires['cds.xt.SaasProvisioningService']?.jobs ?? {}),
15
- ...(cds.env.requires['cds.xt.SmsProvisioningService']?.jobs ?? {})
16
- }
17
-
18
10
  const RUNNING = 'RUNNING', FINISHED = 'FINISHED', FAILED = 'FAILED', QUEUED = 'QUEUED', TIMEOUT = 'TIMEOUT'
19
11
 
20
12
  // A queue, implemented as a circular buffer for O(1) insert + delete
@@ -41,12 +33,15 @@ class Queue {
41
33
  return value
42
34
  }
43
35
  }
44
- const jobQueue = new Queue(queueSize)
45
- let runningJobs = new Map()
46
36
 
47
37
  module.exports = class JobsService extends cds.ApplicationService {
48
38
 
49
39
  async init() {
40
+
41
+ this._conf = this._config()
42
+ this.jobQueue = new Queue(this._conf.queueSize)
43
+ this.runningJobs = new Map()
44
+
50
45
  if (cds.requires.multitenancy?.diagnostics) _diagnostics4(this)
51
46
  cds.on('listening', () => _scheduled(this))
52
47
 
@@ -57,16 +52,16 @@ module.exports = class JobsService extends cds.ApplicationService {
57
52
  return jobs.map(job => ({ ...job, tasks: job.tasks.sort((a, b) => a.tenant.localeCompare(b.tenant))}))
58
53
  })
59
54
  this.on('config', () => {
60
- const conf = main.requires.extensibility, es = main.requires['cds.xt.ExtensibilityService']
55
+ const conf = main.requires['cds.xt.ExtensibilityService'], ext = main.requires.extensibility
61
56
  const allowlist = 'extension-allowlist', blocklist = 'namespace-blocklist'
62
57
  return {
63
58
  pool: main.requires.db.pool,
64
59
  poolMtx: cds.requires.db.pool,
65
60
  jobs: cds.requires.multitenancy.jobs,
66
61
  extensibility: {
67
- tenantCheckInterval: conf?.tenantCheckInterval,
68
- [allowlist]: conf?.[allowlist] ?? es?.[allowlist],
69
- [blocklist]: conf?.[blocklist] ?? es?.[blocklist]
62
+ tenantCheckInterval: conf?.tenantCheckInterval ?? ext?.tenantCheckInterval,
63
+ [allowlist]: conf?.[allowlist] ?? ext?.[allowlist],
64
+ [blocklist]: conf?.[blocklist] ?? ext?.[blocklist]
70
65
  }
71
66
  }
72
67
  })
@@ -74,6 +69,17 @@ module.exports = class JobsService extends cds.ApplicationService {
74
69
  return super.init()
75
70
  }
76
71
 
72
+ _config() {
73
+ const {
74
+ queueSize = 100, clusterSize = 3, workerSize = 4, poolSize = 1
75
+ } = {
76
+ ...(cds.env.requires.multitenancy?.jobs ?? {}),
77
+ ...(cds.env.requires['cds.xt.SaasProvisioningService']?.jobs ?? {}),
78
+ ...(cds.env.requires['cds.xt.SmsProvisioningService']?.jobs ?? {})
79
+ }
80
+ return { queueSize, clusterSize, workerSize, poolSize }
81
+ }
82
+
77
83
  async enqueue(service, op, clusters, args, onJobDone) {
78
84
  const _inspect = obj => obj && Object.values(obj).filter(Boolean).length > 0 ? inspect(obj, { depth: 5, colors: cds.utils.colors.enabled }) : []
79
85
  const inspected = Object.entries(args).reduce((acc, [k, v]) => {
@@ -112,9 +118,9 @@ module.exports = class JobsService extends cds.ApplicationService {
112
118
  if (tasks.length) {
113
119
  if (cds.services[service]) {
114
120
  const fn = task => cds.services[service].tx({ tenant: task.tenant }, tx => tx[op](task.tenant, ...Object.values(args)))
115
- jobQueue.enqueue({ job_ID, clusters: clustered, fn, onJobDone })
121
+ this.jobQueue.enqueue({ job_ID, clusters: clustered, fn, onJobDone })
116
122
  } else {
117
- jobQueue.enqueue({ job_ID, clusters: clustered, fn: () => {
123
+ this.jobQueue.enqueue({ job_ID, clusters: clustered, fn: () => {
118
124
  LOG.warn('service', service, 'is not available, skipping job')
119
125
  }, onJobDone })
120
126
  }
@@ -186,16 +192,16 @@ module.exports = class JobsService extends cds.ApplicationService {
186
192
  }
187
193
 
188
194
  async pickJob() {
189
- if (jobQueue.size === 0) return
195
+ if (this.jobQueue.size === 0) return
190
196
 
191
- const next = new Set(jobQueue.peek().clusters.flat().map(t => t.tenant).flat())
192
- const running = [...runningJobs.values()].flatMap(j => j.clusters.flat().map(t => t.tenant))
197
+ const next = new Set(this.jobQueue.peek().clusters.flat().map(t => t.tenant).flat())
198
+ const running = [...this.runningJobs.values()].flatMap(j => j.clusters.flat().map(t => t.tenant))
193
199
  if (running.some(t => next.has(t))) return
194
200
 
195
- const job = jobQueue.dequeue()
201
+ const job = this.jobQueue.dequeue()
196
202
  const { job_ID, clusters, fn, onJobDone } = job
197
203
  try {
198
- runningJobs.set(job_ID, job)
204
+ this.runningJobs.set(job_ID, job)
199
205
  await t0_(async () => {
200
206
  await UPDATE(Jobs, { ID: job_ID }).with({ status: RUNNING })
201
207
  await this.emit('jobUpdate', { job: { ID: job_ID, status: RUNNING }})
@@ -207,16 +213,16 @@ module.exports = class JobsService extends cds.ApplicationService {
207
213
  await this.emit('jobUpdate', { job: { ID: job_ID, status: FAILED, error: _errorMessage(e) }})
208
214
  })
209
215
  } finally {
210
- runningJobs.delete(job_ID)
216
+ this.runningJobs.delete(job_ID)
211
217
  }
212
218
  setImmediate(() => this.pickJob())
213
219
  }
214
220
 
215
221
  async _nextJob(clusters, fn, onJobDone) {
216
222
  if (clusters.length > 1) {
217
- await this.limiter(clusterSize, clusters, cluster => this.limiter(workerSize ?? poolSize, Array.from(cluster), fn, true))
223
+ await this.limiter(this._conf.clusterSize, clusters, cluster => this.limiter(this._conf.workerSize ?? this._conf.poolSize, Array.from(cluster), fn, true))
218
224
  } else {
219
- await this.limiter(workerSize ?? poolSize, Array.from(clusters[0]), fn, true)
225
+ await this.limiter(this._conf.workerSize ?? this._conf.poolSize, Array.from(clusters[0]), fn, true)
220
226
  }
221
227
 
222
228
  const { job_ID } = clusters[0][0] // all tasks have the same job ID -> just take the first
@@ -334,7 +334,7 @@ module.exports = class ModelProviderService extends cds.ApplicationService {
334
334
  async function _getETag(tenant, activated = true) {
335
335
  if (!main.requires.extensibility || main.requires.multitenancy && !tenant) return BASE_MODEL_ETAG
336
336
  try {
337
- const query = SELECT('max(timestamp) as TS').from('cds_xt_Extensions')
337
+ const query = SELECT('max(timestamp) as TS').from('cds.xt.Extensions')
338
338
  if (activated) query.where('activated=', 'database')
339
339
  const exts = await cds.db.run(query)
340
340
  if (!exts.length || !exts[0].TS) return BASE_MODEL_ETAG
@@ -377,7 +377,7 @@ module.exports = class ModelProviderService extends cds.ApplicationService {
377
377
  }
378
378
 
379
379
  async function getExtCsvs(req) {
380
- if (cds.env.requires['cds.xt.ExtensibilityService']?.activate?.['skip-csv']) return {}
380
+ if (cds.env.requires['cds.xt.ExtensibilityService']?.activate?.['skip-csv'] ?? main.env.requires.extensibility?.activate?.['skip-csv']) return {}
381
381
 
382
382
  const tenant = req.data.tenant || req.tenant
383
383
  if (tenant) cds.context = { tenant }
@@ -68,7 +68,7 @@ class AbstractContainerManagerClient {
68
68
  conf.baseURL ??= url.startsWith('http') ? '' : this.sm_url + '/v1/'
69
69
 
70
70
  const { retries, maxRetryAfter } = cds.requires?.multitenancy?.serviceManager ?? cds.requires?.multitenancy?.containerManager ?? {}
71
- return fetchResiliently(conf.baseURL + url, conf, { retries: retries ?? 10, maxRetryAfter: maxRetryAfter ?? 5000, retryUntil, failures })
71
+ return fetchResiliently(conf.baseURL + url, conf, { retriesLeft: retries ?? 10, maxRetryAfter: maxRetryAfter ?? 5000, retryUntil, failures })
72
72
  }
73
73
 
74
74
  _poll = async (location, conf = {}) => {
@@ -89,9 +89,12 @@ class AbstractContainerManagerClient {
89
89
  return new Promise(_next)
90
90
  }
91
91
 
92
+ // base implementation used by srv-mgr
92
93
  _succeeded = (response) => response.data?.state === 'succeeded'
93
94
  _failed = (response) => response.data?.state === 'failed'
94
- _pollError = (response) => response.data.errors[0] ?? response.data.errors
95
+ _pollError = (response) =>
96
+ response.data?.errors?.[0] ?? response.data.errors
97
+ ?? { error: 'Unknown Error', description: `Polling failed with state ${response.data?.state ?? 'unknown'}. Last operation ${response.data?.id}` }
95
98
 
96
99
  static _errorMessage = (e, action, tenant) => {
97
100
  const msg = `Error ${action} tenant ${tenant}: ${e.response?.data?.error ?? e.code ?? e.message ?? 'unknown error'}`
@@ -13,7 +13,7 @@ exports._logDirectory = async () => {
13
13
  await mkdirp(defaultDir)
14
14
  return defaultDir
15
15
  } catch (e) {
16
- if (e.code !== 'EACCES') throw e
16
+ if (e.code !== 'EACCES' && e.code !== 'EROFS' && e.code !== 'ENOENT') throw e
17
17
  LOG?.(`using temporary directory ${TEMP_DIR} for deployment logs`)
18
18
  return join(TEMP_DIR, 'logs')
19
19
  }
@@ -86,9 +86,10 @@ exports.deploy = async (hana, tenant, cwd, options, deployEnv) => {
86
86
  */
87
87
  exports._hdi_env4 = async (t,container,options,deployEnv)=>{
88
88
 
89
+ let vcapFromFile
89
90
  if (process.env.VCAP_SERVICES_FILE_PATH) {
90
91
  try {
91
- process.env.VCAP_SERVICES = await fs.read(process.env.VCAP_SERVICES_FILE_PATH, 'utf-8')
92
+ vcapFromFile = await fs.read(process.env.VCAP_SERVICES_FILE_PATH, 'utf-8')
92
93
  } catch (e) {
93
94
  LOG.warn(`Could not read or parse VCAP_SERVICES_FILE_PATH at ${process.env.VCAP_SERVICES_FILE_PATH}: ${e.message}`)
94
95
  }
@@ -104,7 +105,8 @@ exports._hdi_env4 = async (t,container,options,deployEnv)=>{
104
105
  ...deployEnv // Although VCAP is in here, it will be overwritten
105
106
  }
106
107
 
107
- const { hana=[], 'user-provided':up=[] } = _parse_env (process.env, 'VCAP_SERVICES')
108
+ const vcapEnv = vcapFromFile ? { VCAP_SERVICES: vcapFromFile } : process.env
109
+ const { hana=[], 'user-provided':up=[] } = _parse_env (vcapEnv, 'VCAP_SERVICES')
108
110
  const { hana: customEnvHana=[], 'user-provided':customEnvUp=[] } = _parse_env(deployEnv ?? {}, 'VCAP_SERVICES')
109
111
 
110
112
  const vcapFromEnv = {
@@ -126,6 +126,7 @@ class ServiceManagerClient extends AbstractContainerManagerClient {
126
126
 
127
127
  get = async (tenant, options = {}) => {
128
128
  const { invalidCredentials, retryUntil } = options
129
+ if (invalidCredentials && cacheBindings) delete this._bindingsCache[tenant]
129
130
  try {
130
131
  const previousFailures = this.failures.has(tenant) ? this.failures.get(tenant).count : 0
131
132
  const [binding] = await this._bindings4([tenant], { ...options, tenant, failures: previousFailures, retryUntil })
@@ -292,9 +293,9 @@ class ServiceManagerClient extends AbstractContainerManagerClient {
292
293
  }
293
294
  fetched.push(...directMatches)
294
295
  }
295
- const cacheMisses = Object.fromEntries(fetched.filter(b => b.labels?.tenant_id).map(b => [b.labels.tenant_id[0], b]))
296
- Object.assign(this._bindingsCache, cacheMisses)
297
296
  if (useCache) {
297
+ const cacheMisses = Object.fromEntries(fetched.filter(b => b.labels?.tenant_id).map(b => [b.labels.tenant_id[0], b]))
298
+ Object.assign(this._bindingsCache, cacheMisses)
298
299
  return tenants.map(t => this._bindingsCache[t])
299
300
  }
300
301
  return fetched
@@ -17,6 +17,23 @@ class TMSClient extends AbstractContainerManagerClient {
17
17
  this.tmsHost = credentials.baseurl
18
18
 
19
19
  this.credentialCache = {}
20
+
21
+ // clusterSize > 1 not supported yet for TMS
22
+ const {
23
+ clusterSize
24
+ } = {
25
+ ...(cds.env.requires.multitenancy?.jobs ?? {}),
26
+ ...(cds.env.requires['cds.xt.SaasProvisioningService']?.jobs ?? {}),
27
+ ...(cds.env.requires['cds.xt.SmsProvisioningService']?.jobs ?? {})
28
+ }
29
+
30
+ if (clusterSize && clusterSize > 1) {
31
+ LOG.warn(`Cluster size of ${clusterSize} is not supported for TMS. Defaulting to 1.`)
32
+ }
33
+
34
+ cds.utils.merge(cds.env.requires, { multitenancy: { jobs: { clusterSize: 1 } } })
35
+ cds.utils.merge(cds.env.requires, { 'cds.xt.SaasProvisioningService': { jobs: { clusterSize: 1 } } })
36
+ cds.utils.merge(cds.env.requires, { 'cds.xt.SmsProvisioningService': { jobs: { clusterSize: 1 } } })
20
37
  }
21
38
 
22
39
  static defaultInstance() {
@@ -15,8 +15,6 @@ const resources = new Map()
15
15
 
16
16
  const { deepMerge } = require('../../lib/utils')
17
17
 
18
- const migration = require('../../lib/migration/migration')
19
-
20
18
  if (db?.kind === 'hana') {
21
19
  if (!db.credentials?.sm_url && !db.credentials?.baseurl) cds.error('No Service Manager credentials found. Make sure the application is bound to a BTP Service Manager instance.')
22
20
 
@@ -89,20 +87,24 @@ if (db?.kind === 'hana') {
89
87
  })
90
88
  ds.on ('tenantsByDb', async req => {
91
89
  const tenantsInT0 = await ds.getTenants()
92
- const mtxTenants = await migration.getMissingMtxTenants(tenantsInT0)
93
- const tenants = req.data.tenants ?? [...tenantsInT0, ...mtxTenants]
90
+ const tenants = req.data.tenants ?? [...tenantsInT0]
94
91
  const hana = require('./hana/hdi-ctnr-mgr').defaultInstance() // TODO tms more generic handling -> new functions hana.toTenantId + hana.toDbId
95
92
  const toTenantId = t => t.tenant_id ?? t.labels.tenant_id[0]
96
93
  const smTenants = (await hana.getAll(tenants.length > 0 ? tenants : '*')).filter(Boolean).filter(t => toTenantId(t) !== t0)
94
+ const byDb = {}
97
95
  if (tenants.length !== smTenants.length) {
98
96
  const smSet = new Set(smTenants.map(toTenantId))
99
97
  const inconsistent = tenants.filter(t => !smSet.has(t))
100
98
  if (!inconsistent.length)
101
99
  LOG.warn('Tenants', smTenants.map(toTenantId).join(', '), 'are subscribed in Service Manager but not in t0. Make sure to re-subscribe the tenants.')
102
- else if (inconsistent.length === 1)
100
+ else if (inconsistent.length === 1) {
103
101
  LOG.warn('Warning: Tenant', inconsistent[0], 'does not exist in Service Manager any more and is therefore ignored. Make sure to unsubscribe the tenant.')
104
- else
102
+ byDb['no-db'] = inconsistent
103
+ }
104
+ else {
105
105
  LOG.warn('Warning: Tenants', inconsistent.join(', '), 'do not exist in Service Manager any more and are therefore ignored. Make sure to unsubscribe the tenants.')
106
+ byDb['no-db'] = inconsistent
107
+ }
106
108
  }
107
109
  const tenantToDbUrl = smTenants.reduce((res, t) => {
108
110
  const id = toTenantId(t)
@@ -110,7 +112,7 @@ if (db?.kind === 'hana') {
110
112
  return { ...res, [id]: `${t.credentials.host}:${t.credentials.port}` }
111
113
  }
112
114
  , {})
113
- const byDb = {}
115
+
114
116
  for (const tenant of Object.keys(tenantToDbUrl)) {
115
117
  const dbUrl = tenantToDbUrl[tenant]
116
118
  if (!byDb[dbUrl]) byDb[dbUrl] = new Set
@@ -129,11 +131,6 @@ if (db?.kind === 'hana') {
129
131
  }
130
132
  return byDb
131
133
  })
132
-
133
- // check migration before upgrade
134
- ds.before('upgrade', async (req) => {
135
- await migration.checkMigration(req)
136
- })
137
134
  })
138
135
  })
139
136
 
@@ -178,7 +175,11 @@ async function resources4(out) {
178
175
  throw error
179
176
  }
180
177
  }
181
- if (cache) resources.set(out, _resources4(out).catch(e => { resources.delete(out); throw e }))
178
+ if (cache) {
179
+ const p = _resources4(out).catch(e => { resources.delete(out); throw e })
180
+ resources.set(out, p)
181
+ return p
182
+ }
182
183
  return _resources4(out)
183
184
  }
184
185
  module.exports.resources4 = resources4 // required in abstract provisioning service to prepare shared deployment directory
@@ -1,18 +1,18 @@
1
1
  # media-typer
2
2
 
3
- [![NPM Version][npm-version-image]][npm-url]
4
- [![NPM Downloads][npm-downloads-image]][npm-url]
3
+ [![NPM Version][npm-image]][npm-url]
4
+ [![NPM Downloads][downloads-image]][downloads-url]
5
5
  [![Node.js Version][node-version-image]][node-version-url]
6
- [![Build Status][travis-image]][travis-url]
6
+ [![Build Status][ci-image]][ci-url]
7
7
  [![Test Coverage][coveralls-image]][coveralls-url]
8
8
 
9
9
  Simple RFC 6838 media type parser.
10
10
 
11
- This module will parse a given media type into it's component parts, like type,
11
+ This module will parse a given media type into its component parts, like type,
12
12
  subtype, and suffix. A formatter is also provided to put them back together and
13
13
  the two can be combined to normalize media types into a canonical form.
14
14
 
15
- If you are looking to parse the string that represents a media type and it's
15
+ If you are looking to parse the string that represents a media type and its
16
16
  parameters in HTTP (for example, the `Content-Type` header), use the
17
17
  [content-type module](https://www.npmjs.com/package/content-type).
18
18
 
@@ -75,19 +75,20 @@ If any of the given object values are invalid, then a `TypeError` is thrown.
75
75
  var valid = typer.test('image/svg+xml')
76
76
  ```
77
77
 
78
- Validate a media type string. This will return `true` is the string is a well-
78
+ Validate a media type string. This will return `true` if the string is a well-
79
79
  formatted media type, or `false` otherwise.
80
80
 
81
81
  ## License
82
82
 
83
83
  [MIT](LICENSE)
84
84
 
85
- [coveralls-image]: https://badgen.net/coveralls/c/github/jshttp/media-typer/master
86
- [coveralls-url]: https://coveralls.io/r/jshttp/media-typer?branch=master
87
- [node-version-image]: https://badgen.net/npm/node/media-typer
88
- [node-version-url]: https://nodejs.org/en/download
89
- [npm-downloads-image]: https://badgen.net/npm/dm/media-typer
85
+ [ci-image]: https://img.shields.io/github/workflow/status/jshttp/media-typer/ci/master?label=ci
86
+ [ci-url]: https://github.com/jshttp/media-typer/actions/workflows/ci.yml
87
+ [npm-image]: https://img.shields.io/npm/v/media-typer.svg
90
88
  [npm-url]: https://npmjs.org/package/media-typer
91
- [npm-version-image]: https://badgen.net/npm/v/media-typer
92
- [travis-image]: https://badgen.net/travis/jshttp/media-typer/master
93
- [travis-url]: https://travis-ci.org/jshttp/media-typer
89
+ [node-version-image]: https://img.shields.io/node/v/media-typer.svg
90
+ [node-version-url]: https://nodejs.org/en/
91
+ [coveralls-image]: https://img.shields.io/coveralls/jshttp/media-typer/master.svg
92
+ [coveralls-url]: https://coveralls.io/r/jshttp/media-typer?branch=master
93
+ [downloads-image]: https://img.shields.io/npm/dm/media-typer.svg
94
+ [downloads-url]: https://npmjs.org/package/media-typer
@@ -83,10 +83,6 @@ function format (obj) {
83
83
  */
84
84
 
85
85
  function test (string) {
86
- if (!string) {
87
- throw new TypeError('argument string is required')
88
- }
89
-
90
86
  if (typeof string !== 'string') {
91
87
  throw new TypeError('argument string is required to be a string')
92
88
  }
@@ -103,10 +99,6 @@ function test (string) {
103
99
  */
104
100
 
105
101
  function parse (string) {
106
- if (!string) {
107
- throw new TypeError('argument string is required')
108
- }
109
-
110
102
  if (typeof string !== 'string') {
111
103
  throw new TypeError('argument string is required to be a string')
112
104
  }
@@ -1,20 +1,24 @@
1
1
  {
2
2
  "name": "media-typer",
3
3
  "description": "Simple RFC 6838 media type parser and formatter",
4
- "version": "1.1.0",
4
+ "version": "1.1.1",
5
5
  "author": "Douglas Christopher Wilson <doug@somethingdoug.com>",
6
6
  "license": "MIT",
7
7
  "repository": "jshttp/media-typer",
8
+ "funding": {
9
+ "type": "opencollective",
10
+ "url": "https://opencollective.com/express"
11
+ },
8
12
  "devDependencies": {
9
- "eslint": "5.16.0",
10
- "eslint-config-standard": "12.0.0",
11
- "eslint-plugin-import": "2.17.2",
12
- "eslint-plugin-markdown": "1.0.0",
13
- "eslint-plugin-node": "8.0.1",
14
- "eslint-plugin-promise": "4.1.1",
15
- "eslint-plugin-standard": "4.0.0",
16
- "mocha": "6.1.4",
17
- "nyc": "14.0.0"
13
+ "eslint": "7.23.0",
14
+ "eslint-config-standard": "14.1.1",
15
+ "eslint-plugin-import": "2.22.1",
16
+ "eslint-plugin-markdown": "1.0.2",
17
+ "eslint-plugin-node": "11.1.0",
18
+ "eslint-plugin-promise": "4.3.1",
19
+ "eslint-plugin-standard": "4.1.0",
20
+ "mocha": "9.2.0",
21
+ "nyc": "15.1.0"
18
22
  },
19
23
  "files": [
20
24
  "LICENSE",
@@ -27,7 +31,7 @@
27
31
  "scripts": {
28
32
  "lint": "eslint --plugin markdown --ext js,md .",
29
33
  "test": "mocha --reporter spec --check-leaks --bail test/",
30
- "test-cov": "nyc --reporter=html --reporter=text npm test",
31
- "test-travis": "nyc --reporter=text npm test"
34
+ "test-ci": "nyc --reporter=lcov --reporter=text npm test",
35
+ "test-cov": "nyc --reporter=html --reporter=text npm test"
32
36
  }
33
37
  }
@@ -381,8 +381,8 @@
381
381
 
382
382
  // this really needs to be replaced with character classes.
383
383
  // XML allows all manner of ridiculous numbers and digits.
384
- var CDATA = '[CDATA['
385
- var DOCTYPE = 'DOCTYPE'
384
+ var CDATAre = /^\[CDATA\[$/i
385
+ var DOCTYPEre = /^DOCTYPE$/i
386
386
  var XML_NAMESPACE = 'http://www.w3.org/XML/1998/namespace'
387
387
  var XMLNS_NAMESPACE = 'http://www.w3.org/2000/xmlns/'
388
388
  var rootNS = { xml: XML_NAMESPACE, xmlns: XMLNS_NAMESPACE }
@@ -464,15 +464,15 @@
464
464
  SCRIPT_ENDING: S++, // <script> ... <
465
465
  }
466
466
 
467
- sax.XML_ENTITIES = {
467
+ sax.XML_ENTITIES = Object.assign(Object.create(null), {
468
468
  amp: '&',
469
469
  gt: '>',
470
470
  lt: '<',
471
471
  quot: '"',
472
472
  apos: "'",
473
- }
473
+ })
474
474
 
475
- sax.ENTITIES = {
475
+ sax.ENTITIES = Object.assign(Object.create(null), {
476
476
  amp: '&',
477
477
  gt: '>',
478
478
  lt: '<',
@@ -726,7 +726,7 @@
726
726
  clubs: 9827,
727
727
  hearts: 9829,
728
728
  diams: 9830,
729
- }
729
+ })
730
730
 
731
731
  Object.keys(sax.ENTITIES).forEach(function (key) {
732
732
  var e = sax.ENTITIES[key]
@@ -1137,7 +1137,8 @@
1137
1137
  isNaN(num) ||
1138
1138
  numStr.toLowerCase() !== entity ||
1139
1139
  num < 0 ||
1140
- num > 0x10ffff
1140
+ num > 0x10ffff ||
1141
+ !isXmlChar(num)
1141
1142
  ) {
1142
1143
  strictFail(parser, 'Invalid character entity')
1143
1144
  return '&' + parser.entity + ';'
@@ -1146,6 +1147,23 @@
1146
1147
  return String.fromCodePoint(num)
1147
1148
  }
1148
1149
 
1150
+ // Returns true if `num` is a code point that matches the XML `Char`
1151
+ // production, false otherwise. Character references that resolve to a
1152
+ // character outside this range (e.g. surrogates or restricted control
1153
+ // characters) are not well-formed.
1154
+ // https://www.w3.org/TR/REC-xml/#NT-Char
1155
+ // https://www.w3.org/TR/REC-xml/#wf-Legalchar
1156
+ function isXmlChar(num) {
1157
+ return (
1158
+ num === 0x9 ||
1159
+ num === 0xa ||
1160
+ num === 0xd ||
1161
+ (num >= 0x20 && num <= 0xd7ff) ||
1162
+ (num >= 0xe000 && num <= 0xfffd) ||
1163
+ (num >= 0x10000 && num <= 0x10ffff)
1164
+ )
1165
+ }
1166
+
1149
1167
  function beginWhiteSpace(parser, c) {
1150
1168
  if (c === '<') {
1151
1169
  parser.state = S.OPEN_WAKA
@@ -1317,12 +1335,12 @@
1317
1335
  parser.state = S.DOCTYPE_DTD
1318
1336
  parser.doctype += '<!' + parser.sgmlDecl + c
1319
1337
  parser.sgmlDecl = ''
1320
- } else if ((parser.sgmlDecl + c).toUpperCase() === CDATA) {
1338
+ } else if (CDATAre.test(parser.sgmlDecl + c)) {
1321
1339
  emitNode(parser, 'onopencdata')
1322
1340
  parser.state = S.CDATA
1323
1341
  parser.sgmlDecl = ''
1324
1342
  parser.cdata = ''
1325
- } else if ((parser.sgmlDecl + c).toUpperCase() === DOCTYPE) {
1343
+ } else if (DOCTYPEre.test(parser.sgmlDecl + c)) {
1326
1344
  parser.state = S.DOCTYPE
1327
1345
  if (parser.doctype || parser.sawRoot) {
1328
1346
  strictFail(
@@ -2,7 +2,7 @@
2
2
  "name": "sax",
3
3
  "description": "An evented streaming XML parser in JavaScript",
4
4
  "author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me/)",
5
- "version": "1.6.0",
5
+ "version": "1.6.1",
6
6
  "main": "lib/sax.js",
7
7
  "license": "BlueOak-1.0.0",
8
8
  "scripts": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ws",
3
- "version": "8.21.1",
3
+ "version": "8.21.2",
4
4
  "description": "Simple to use, blazing fast and thoroughly tested websocket client and server for Node.js",
5
5
  "keywords": [
6
6
  "HyBi",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sap/cds-dk",
3
- "version": "10.0.5",
3
+ "version": "10.0.7",
4
4
  "description": "Command line client and development toolkit for the SAP Cloud Application Programming Model",
5
5
  "homepage": "https://cap.cloud.sap/",
6
6
  "keywords": [
@@ -20,10 +20,10 @@
20
20
  "@cap-js/asyncapi": "^1.0.0",
21
21
  "@cap-js/openapi": "^1.0.0",
22
22
  "@cap-js/sqlite": "^3",
23
- "@sap/cds": ">=9",
24
- "@sap/cds-mtxs": ">=3",
23
+ "@sap/cds": "^10",
24
+ "@sap/cds-mtxs": "^4",
25
25
  "@sap/hdi-deploy": "^5",
26
- "express": "^4.22.1 || ^5",
26
+ "express": "^5",
27
27
  "hdb": "^2.0.0",
28
28
  "livereload-js": "^4.0.1",
29
29
  "mustache": "^4.0.1",
@@ -1,34 +0,0 @@
1
- # CAP {{ projectName }}
2
- _out
3
- *.db
4
- *.sqlite
5
- connection.properties
6
- default-*.json
7
- .cdsrc-private.json
8
- gen/
9
- node_modules/
10
- target/
11
-
12
- # Web IDE, App Studio
13
- .che/
14
- .gen/
15
-
16
- # MTA
17
- *_mta_build_tmp
18
- *.mtar
19
- mta_archives/
20
-
21
- # Other
22
- .DS_Store
23
- *.orig
24
- *.log
25
-
26
- *.iml
27
- *.flattened-pom.xml
28
-
29
- # IDEs
30
- # .vscode
31
- # .idea
32
-
33
- # @cap-js/cds-typer
34
- @cds-models