Skip to content

Validate names#129

Draft
eric-pSAP wants to merge 6 commits into
mainfrom
validateNames
Draft

Validate names#129
eric-pSAP wants to merge 6 commits into
mainfrom
validateNames

Conversation

@eric-pSAP
Copy link
Copy Markdown
Contributor

@eric-pSAP eric-pSAP commented May 21, 2026

Validate that elements are below 128 characters. Prereq: #125

@hyperspace-insights
Copy link
Copy Markdown
Contributor

Summary

The following content is AI-generated and provides a summary of the pull request:


Add Notification Type Compilation from CDS Model with Element Name Validation

New Feature

✨ Introduces a new lib/compile.js module that derives notification types directly from CDS model definitions annotated with @notification. This enables notification types to be compiled at runtime and build time from the CDS model, merged with any existing JSON type files. A validation step throws an error if any event element name exceeds 128 characters.

Changes

  • lib/compile.js (new): Core module that traverses CDS model definitions, extracts @notification-annotated events, resolves i18n labels ({i18n>KEY}), resolves enum references in delivery channels, and validates that element names do not exceed 128 characters.
  • cds-plugin.js: Refactored to load notification types by merging CDS model-derived types (via notificationTypesFromModel) with types from the optional JSON file, replacing the previous JSON-only approach. Style: removed semicolons throughout.
  • lib/build.js: Build plugin updated to use notificationTypesFromModel to generate notification-types.json from the CDS model (merged with optional JSON file). Simplified hasTask() to check only for the notifications config entry.
  • tests/bookshop/srv/notifications.cds (new): Sample BookOrdered event with full @notification annotations using i18n references, used as a test fixture.
  • tests/bookshop/srv/_i18n/i18n.properties (new): i18n properties file for the bookshop test fixture providing English labels for the BookOrdered event templates.
  • tests/bookshop/srv/notification-types.json: Updated to only contain the BookReturned type (simplified template), as BookOrdered is now sourced from the CDS model.
  • tests/integration/bookshop.test.js: Added new integration tests verifying that CDS and JSON notification types are merged, that i18n values are resolved in templates, and that oversized element names throw an error. Removed semicolons.
  • tests/unit/lib/compile.test.js (new): Comprehensive unit tests for notificationTypesFromModel, covering null models, annotation parsing, enum resolution, i18n resolution, namespace stripping, and element name length validation edge cases.
  • tests/unit/lib/plugin.test.js (new): Unit tests for the cds.on("loaded") hook in cds-plugin.js, verifying recipient injection behavior.
  • tests/unit/lib/notificationTypes.test.js, tests/unit/lib/utils.test.js, tests/unit/lib/notifications.test.js, tests/unit/srv/notifyToRest.test.js, tests/unit/lib/content-deployment.test.js: Migrated remaining it(...) calls to test(...) and removed trailing semicolons for consistency.

  • 🔄 Regenerate and Update Summary
  • ✏️ Insert as PR Description (deletes this comment)
  • 🗑️ Delete comment
PR Bot Information

Version: 1.20.51

  • File Content Strategy: Full file content
  • Output Template: Default Template
  • Event Trigger: pull_request.opened
  • Correlation ID: dffe0143-1e88-46b8-a603-a0cccf70f16f
  • LLM: anthropic--claude-4.6-sonnet
  • Summary Prompt: Default Prompt

Copy link
Copy Markdown
Contributor

@hyperspace-insights hyperspace-insights Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR introduces a solid new lib/compile.js module that derives notification types directly from the CDS model and adds 128-character element name validation. There are a few issues to address: a potential runtime TypeError in resolveEnum(...).toUpperCase() when the channel value isn't a string, an unhandled promise rejection risk in the served async callback if cds.load or notificationTypesFromModel throws, and a missing top-level const cds = require('@sap/cds') in the unit test file that will cause a ReferenceError in the subtitle i18n test.

PR Bot Information

Version: 1.20.51

  • File Content Strategy: Full file content
  • Correlation ID: dffe0143-1e88-46b8-a603-a0cccf70f16f
  • LLM: anthropic--claude-4.6-sonnet
  • Event Trigger: pull_request.opened

Comment thread lib/compile.js
if (def['@notification.deliveryChannels']?.length) {
type.DeliveryChannels = def['@notification.deliveryChannels'].map(ch => {
if (!ch.channel) return null
const entry = { Type: resolveEnum(ch.channel).toUpperCase() }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: resolveEnum may return a non-string, causing a TypeError on .toUpperCase()

resolveEnum returns val unchanged when it is not an object (e.g. a number), or when the object has neither = nor # (in which case the object itself is returned). In both cases calling .toUpperCase() on the result will throw TypeError: resolveEnum(...).toUpperCase is not a function at runtime.

Consider guarding with a String() coercion, or throwing a descriptive error when the resolved channel value is not a string.

Suggested change
const entry = { Type: resolveEnum(ch.channel).toUpperCase() }
const resolved = resolveEnum(ch.channel)
if (typeof resolved !== 'string') throw new Error(
`Event '${eventName}': deliveryChannel.channel resolved to a non-string value: ${JSON.stringify(resolved)}`
)
const entry = { Type: resolved.toUpperCase() }

Double-check suggestion before committing. Edit this comment for amendments.


Please provide feedback on the review comment by checking the appropriate box:

  • 🌟 Awesome comment, a human might have missed that.
  • ✅ Helpful comment
  • 🤷 Neutral
  • ❌ This comment is not helpful

@@ -0,0 +1,325 @@
const { notificationTypesFromModel } = require("../../../lib/compile")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The cds variable used in the afterEach and in the "Resolve {i18n>KEY} in subtitle field" test (line 235) refers to the top-level require('@sap/cds'), but it is never imported at the top of this file. The tests that call Object.defineProperty(cds, ...) directly (line 235, 237) will throw ReferenceError: cds is not defined because cds is only declared locally inside specific test blocks (lines 199, 215).

Should add const cds = require('@sap/cds') at the top of the file, and remove the redundant local declarations inside individual tests.

Suggested change
const { notificationTypesFromModel } = require("../../../lib/compile")
const cds = require('@sap/cds')
const { notificationTypesFromModel } = require("../../../lib/compile")

Double-check suggestion before committing. Edit this comment for amendments.


Please provide feedback on the review comment by checking the appropriate box:

  • 🌟 Awesome comment, a human might have missed that.
  • ✅ Helpful comment
  • 🤷 Neutral
  • ❌ This comment is not helpful

Comment thread cds-plugin.js
Comment on lines 19 to 40
else cds.once("served", async () => {
const { validateNotificationTypes, readFile } = require("./lib/utils");
const { createNotificationTypesMap } = require("./lib/notificationTypes");
const production = cds.env.profiles?.includes("production");
const { validateNotificationTypes, readFile } = require("./lib/utils")
const { createNotificationTypesMap } = require("./lib/notificationTypes")
const { notificationTypesFromModel } = require("./lib/compile")
const { path } = cds.utils
const production = cds.env.profiles?.includes("production")

const typesPath = cds.env.requires?.notifications?.types
const srvPath = path.join(cds.root, cds.env.folders.srv)
const model = await cds.load(srvPath)
const notificationTypes = [
...notificationTypesFromModel(model),
...( typesPath ? readFile(typesPath) : [] )
]

// read notification types
const notificationTypes = readFile(cds.env.requires?.notifications?.types);
if (validateNotificationTypes(notificationTypes)) {
if (!production) {
const notificationTypesMap = createNotificationTypesMap(notificationTypes, true);
cds.notifications = { local: { types: notificationTypesMap } };
const notificationTypesMap = createNotificationTypesMap(notificationTypes, true)
cds.notifications = { local: { types: notificationTypesMap } }
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: An error thrown by notificationTypesFromModel (e.g. the new 128-character validation) or by cds.load will result in an unhandled promise rejection inside the async callback — there is no try/catch. This can crash the process or silently swallow startup failures depending on the Node.js version, making the problem very hard to diagnose.

Consider wrapping the body in a try/catch and logging via cds.log('notifications').


Please provide feedback on the review comment by checking the appropriate box:

  • 🌟 Awesome comment, a human might have missed that.
  • ✅ Helpful comment
  • 🤷 Neutral
  • ❌ This comment is not helpful

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant