Skip to content

feat: expose parsed NSML body as bodyNodes - #11

Open
rjmunro wants to merge 3 commits into
masterfrom
feat/body-nodes
Open

feat: expose parsed NSML body as bodyNodes#11
rjmunro wants to merge 3 commits into
masterfrom
feat/body-nodes

Conversation

@rjmunro

@rjmunro rjmunro commented Jul 28, 2026

Copy link
Copy Markdown
Member

About the Contributor

This pull request is posted on behalf of SVT.

Type of Contribution

This is a feature

Current Behavior

story() parses NSML and exposes <body> only as a re-serialized HTML string (body). Consumers (gateways/blueprints) must re-parse that string with regex or an HTML parser to read <pi>, <cc>, cue anchors, etc.

New Behavior

INewsStory also includes bodyNodes?: NsmlNode[] — a JSON-serializable tree of the parsed <body> children, built from the DOM already produced by htmlparser (no second parse).

  • body is unchanged for backwards compatibility
  • Whitespace-only text nodes are omitted from bodyNodes
  • Text and attribute values are unescaped (same as body)
  • README updated for @tv2media/inews, Promise API, and bodyNodes

Testing Instructions

yarn test

New cases cover a typical body with <pi> / <a> / <cc> (including entity unescaping) and an empty <body>.

Other Information

Follow-up for Sofie: bump sofie-inews-ftp-gateway to this revision and switch blueprints from regex on body to traversing bodyNodes. Gateway code that mutates body as a string (e.g. layout cue link injection) should keep bodyNodes in sync or stop relying on the string for those edits.

Status

  • Ready for review

rjmunro added 2 commits July 28, 2026 12:41
- Add NsmlNode types and optional bodyNodes on INewsStory
- Convert already-parsed <body> children instead of discarding the tree
- Keep body string for backwards compatibility
- Refresh README examples for @tv2media/inews Promise API
- Document INewsStory fields including body vs bodyNodes

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR extends the parsed story output to expose the already-parsed NSML <body> children as a JSON-serializable node tree (bodyNodes), allowing downstream consumers to traverse <pi>, <cc>, anchors, etc. without re-parsing the legacy body HTML string.

Changes:

  • Add NsmlNode types and a new optional INewsStory.bodyNodes?: NsmlNode[] field.
  • Populate bodyNodes during NSML parsing (while keeping the legacy body string unchanged).
  • Add tests for bodyNodes parsing and update the README to document the new shape.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
src/types/inews.ts Introduces NsmlNode types and adds bodyNodes to INewsStory.
src/inewsStoryParser.ts Builds and assigns bodyNodes from the existing htmlparser DOM during parsing.
src/tests/iNewsStoryParser.spec.ts Adds coverage for bodyNodes parsing (including entity unescaping and empty body).
README.md Updates usage/docs and documents the new bodyNodes field and structure.
Comments suppressed due to low confidence (2)

README.md:52

  • This snippet also uses top-level await alongside require(...), which won’t run in a standard CommonJS script. Wrap in an async IIFE so users can copy/paste the example without additional setup.
const inewsQueue = 'YOUR.QUEUE.HERE'
const dirList = await conn.list(inewsQueue)
for (const storyFile of dirList) {
	const story = await conn.story(inewsQueue, storyFile.file)
	console.log(story)
}

README.md:63

  • This example uses top-level await while the README uses require(...) earlier (CommonJS). Wrap in an async IIFE (or use .then) to keep the example executable.
const inewsQueue = 'YOUR.QUEUE.HERE'
const dirList = await conn.list(inewsQueue)
for (const storyFile of dirList) {
	const storyNsml = await conn.storyNsml(inewsQueue, storyFile.file)
	console.log(storyNsml)
}

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread README.md
Comment on lines +36 to +39
const dirList = await conn.list('YOUR.QUEUE.HERE')
for (const story of dirList) {
console.log(story.file)
}
- Explain why CDATA markers are stripped and the semantic cost
- Contrast whole-string body unescape with leaf-only bodyNodes
@rjmunro
rjmunro requested review from Julusian and nytamin July 28, 2026 15:57
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.

2 participants