Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 31 additions & 7 deletions src/resources/editor/tools/vs-code.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -24724,6 +24724,10 @@ var require_yaml_intelligence_resources = __commonJS({
short: "Visual style for theorem environments in Typst output.",
long: "Controls how theorems, lemmas, definitions, etc. are rendered: -\n<code>simple</code>: Plain text with bold title and italic body\n(default) - <code>fancy</code>: Colored boxes using brand colors -\n<code>clouds</code>: Rounded colored background boxes -\n<code>rainbow</code>: Colored left border with colored title"
},
{
short: "Email format version",
long: "Specifies which email format version to use."
},
"Project configuration.",
"Project type (<code>default</code>, <code>website</code>,\n<code>book</code>, or <code>manuscript</code>)",
"Files to render (defaults to all files)",
Expand Down Expand Up @@ -25305,12 +25309,12 @@ var require_yaml_intelligence_resources = __commonJS({
mermaid: "%%"
},
"handlers/mermaid/schema.yml": {
_internalId: 221789,
_internalId: 222034,
type: "object",
description: "be an object",
properties: {
"mermaid-format": {
_internalId: 221781,
_internalId: 222026,
type: "enum",
enum: [
"png",
Expand All @@ -25326,7 +25330,7 @@ var require_yaml_intelligence_resources = __commonJS({
exhaustiveCompletions: true
},
theme: {
_internalId: 221788,
_internalId: 222033,
type: "anyOf",
anyOf: [
{
Expand Down Expand Up @@ -25463,6 +25467,26 @@ var require_yaml_intelligence_resources = __commonJS({
long: "Controls how theorems, lemmas, definitions, etc. are rendered:\n- `simple`: Plain text with bold title and italic body (default)\n- `fancy`: Colored boxes using brand colors\n- `clouds`: Rounded colored background boxes\n- `rainbow`: Colored left border with colored title\n"
}
}
],
"schema/document-email.yml": [
{
name: "email-version",
tags: {
formats: [
"email"
]
},
schema: {
enum: [
1,
2
]
},
description: {
short: "Email format version",
long: "Specifies which email format version to use.\n\n- `1`: Legacy email format with document-level metadata (compatible with older Connect versions)\n- `2`: New email format with multiple individual emails and v2 markers (requires Posit Connect 2026.03 or later)\n"
}
}
]
};
}
Expand Down Expand Up @@ -25623,7 +25647,7 @@ function locationString(loc) {

// ../text.ts
function lines(text) {
return text.split(/\r?\n/);
return text.split(/\r\n?|\n/);
}
function* matchAll(text, regexp) {
if (!regexp.global) {
Expand All @@ -25636,7 +25660,7 @@ function* matchAll(text, regexp) {
}
function* lineOffsets(text) {
yield 0;
for (const match of matchAll(text, /\r?\n/g)) {
for (const match of matchAll(text, /\r\n?|\n/g)) {
yield match.index + match[0].length;
}
}
Expand Down Expand Up @@ -25822,7 +25846,7 @@ function matchAll2(str2, regex) {
return result;
}
function rangedLines(text, includeNewLines = false) {
const regex = /\r?\n/g;
const regex = /\r\n?|\n/g;
const result = [];
let startOffset = 0;
if (!includeNewLines) {
Expand Down Expand Up @@ -34695,7 +34719,7 @@ async function breakQuartoMd(src, validate2 = false, lenient = false, startCodeC
};
const yamlRegEx = /^---\s*$/;
const startCodeCellRegEx = startCodeCellRegex || new RegExp(
"^\\s*(```+)\\s*\\{([=A-Za-z]+)( *[ ,].*)?\\}\\s*$"
"^\\s*(```+)\\s*\\{([=A-Za-z][=A-Za-z0-9._]*)( *[ ,].*)?\\}\\s*$"
);
const startCodeRegEx = /^```/;
const endCodeRegEx = /^\s*(```+)\s*$/;
Expand Down

Large diffs are not rendered by default.

38 changes: 31 additions & 7 deletions src/resources/editor/tools/yaml/web-worker.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 27 additions & 3 deletions src/resources/editor/tools/yaml/yaml-intelligence-resources.json
Original file line number Diff line number Diff line change
Expand Up @@ -17696,6 +17696,10 @@
"short": "Visual style for theorem environments in Typst output.",
"long": "Controls how theorems, lemmas, definitions, etc. are rendered: -\n<code>simple</code>: Plain text with bold title and italic body\n(default) - <code>fancy</code>: Colored boxes using brand colors -\n<code>clouds</code>: Rounded colored background boxes -\n<code>rainbow</code>: Colored left border with colored title"
},
{
"short": "Email format version",
"long": "Specifies which email format version to use."
},
"Project configuration.",
"Project type (<code>default</code>, <code>website</code>,\n<code>book</code>, or <code>manuscript</code>)",
"Files to render (defaults to all files)",
Expand Down Expand Up @@ -18277,12 +18281,12 @@
"mermaid": "%%"
},
"handlers/mermaid/schema.yml": {
"_internalId": 221789,
"_internalId": 222034,
"type": "object",
"description": "be an object",
"properties": {
"mermaid-format": {
"_internalId": 221781,
"_internalId": 222026,
"type": "enum",
"enum": [
"png",
Expand All @@ -18298,7 +18302,7 @@
"exhaustiveCompletions": true
},
"theme": {
"_internalId": 221788,
"_internalId": 222033,
"type": "anyOf",
"anyOf": [
{
Expand Down Expand Up @@ -18435,5 +18439,25 @@
"long": "Controls how theorems, lemmas, definitions, etc. are rendered:\n- `simple`: Plain text with bold title and italic body (default)\n- `fancy`: Colored boxes using brand colors\n- `clouds`: Rounded colored background boxes\n- `rainbow`: Colored left border with colored title\n"
}
}
],
"schema/document-email.yml": [
{
"name": "email-version",
"tags": {
"formats": [
"email"
]
},
"schema": {
"enum": [
1,
2
]
},
"description": {
"short": "Email format version",
"long": "Specifies which email format version to use.\n\n- `1`: Legacy email format with document-level metadata (compatible with older Connect versions)\n- `2`: New email format with multiple individual emails and v2 markers (requires Posit Connect 2026.03 or later)\n"
}
}
]
}
17 changes: 16 additions & 1 deletion src/resources/filters/modules/connectversion.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,20 @@ Connect version sniffing utilities for email extension
Functions to detect and compare Posit Connect versions from environment variables
]]

-- Get email format version override from metadata
-- Can be set in YAML as:
-- format:
-- email:
-- email-version: 2
-- Returns: version string (e.g., "2") if override is set, nil otherwise
function get_email_format_override(meta)
if meta and meta["email-version"] then
return pandoc.utils.stringify(meta["email-version"])
end

return nil
end

-- Parse Connect version from SPARK_CONNECT_USER_AGENT
-- Format: posit-connect/2024.09.0
-- posit-connect/2024.09.0-dev+26-dirty-g51b853f70e
Expand Down Expand Up @@ -70,5 +84,6 @@ end

-- Export functions for module usage
return {
is_connect_version_at_least = is_connect_version_at_least
is_connect_version_at_least = is_connect_version_at_least,
get_email_format_override = get_email_format_override
}
20 changes: 16 additions & 4 deletions src/resources/filters/quarto-post/email.lua
Original file line number Diff line number Diff line change
Expand Up @@ -347,10 +347,22 @@ function process_document(doc)
return doc
end

-- Detect format upfront: Check Connect version and look for document-level metadata
-- This must be determined before processing to avoid confusion about which format to use
if connectversion.is_connect_version_at_least(constants.kConnectEmailMetadataChangeVersion) then
connect_supports_v2 = true
-- Check for explicit email format override first
local format_override = connectversion.get_email_format_override(doc.meta)
if format_override then
-- If override is set, interpret the value as a string
if format_override == "2" then
connect_supports_v2 = true
io.stderr:write("WARNING: Email format v2 is being forced via 'format.email.version: " .. format_override .. "' in YAML. This overrides the Connect version detection.\n")
else
connect_supports_v2 = false
io.stderr:write("WARNING: Email format v1 is being forced via 'format.email.version: " .. format_override .. "' in YAML. This overrides the Connect version detection.\n")
end
else
-- Fall back to version sniffing if no explicit override
if connectversion.is_connect_version_at_least(constants.kConnectEmailMetadataChangeVersion) then
connect_supports_v2 = true
end
end

-- Scan for document-level metadata at the TOP LEVEL of the document
Expand Down
12 changes: 12 additions & 0 deletions src/resources/schema/document-email.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
- name: email-version
tags:
formats: [email]
schema:
enum: [1, 2]
description:
short: "Email format version"
long: |
Specifies which email format version to use.
- `1`: Legacy email format with document-level metadata (compatible with older Connect versions)
- `2`: New email format with multiple individual emails and v2 markers (requires Posit Connect 2026.03 or later)
28 changes: 28 additions & 0 deletions tests/docs/email/email-force-v2.qmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
title: Email Test Document
author: Charles Teague
format:
email:
email-version: 2
---

The report content. Anything that is here is not part of the email message.

::: {.email}

::: {.subject}
The subject line.
:::

::: {.email-text}
An optional text-only version of the email message..
:::

The HTML email content. Here you can add code cells, produce images, and write accompanying text.
This content is not seen when viewing the rendered document on Connect (it's only
seen when sending an email from the Connect document page). Emails from Connect
can be sent manually, and they can also be scheduled.

:::

Any additional report content not part of the email message.
17 changes: 17 additions & 0 deletions tests/smoke/render/render-email.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,23 @@ testRender(docs("email/email-multi-v2.qmd"), "email", false, [
}
});

// Test v2 format override with old Connect version
// Uses email-format: v2 in YAML to force v2 despite old Connect version
testRender(docs("email/email-force-v2.qmd"), "email", false, [fileExists(previewFileV2_1), validJsonWithMultipleEmails(jsonFile, 1, {
"0": {
"email_id": 1,
"subject": "The subject line.",
"attachments": [],
"suppress_scheduled": false,
"send_report_as_attachment": false
}
})], {
...cleanupCtx,
env: {
"SPARK_CONNECT_USER_AGENT": "posit-connect/2024.09.0"
}
});

// Test mixed metadata - some emails have metadata, others don't
testRender(docs("email/email-mixed-metadata-v2.qmd"), "email", false, [
fileExists(previewFileV2_1),
Expand Down
Loading