Skip to content

Commit c64079e

Browse files
authored
Merge pull request #69 from Telefonica/release
Release 2.3.0
2 parents 5246539 + 144d4ed commit c64079e

File tree

14 files changed

+520
-10
lines changed

14 files changed

+520
-10
lines changed

components/markdown-confluence-sync/CHANGELOG.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1515

1616
#### Added
1717

18-
- feat(#63): Add apiPrefix option to configure the Confluence API prefix (default: /rest/).
18+
## [2.3.0] - 2025-11-24
19+
20+
#### Added
21+
22+
* feat(#65): Add code blocks transformation to Confluence code macro format.
23+
Code blocks are now converted to Confluence's structured code macro
24+
with syntax highlighting support. This feature is disabled by default
25+
and can be enabled via `rehype.codeBlocks` configuration option.
26+
* feat(#63): Add apiPrefix option to configure the Confluence API prefix (default: /rest/).
1927

2028
## [2.2.0] - 2025-10-17
2129

components/markdown-confluence-sync/README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@ The namespace for the configuration of this library is `markdown-confluence-sync
302302
| `confluence.noticeMessage` | `string` | Notice message to add at the beginning of the Confluence pages. | |
303303
| `confluence.noticeTemplate` | `string` | Template string to use for the notice message. | |
304304
| `confluence.dryRun` | `boolean` | Log create, update or delete requests to Confluence instead of really making them | `false` |
305+
| `rehype.codeBlocks` | `boolean` | Enable conversion of code blocks to Confluence code macro format with syntax highlighting. When disabled, code blocks remain as plain HTML pre/code tags. | `false` |
305306
| `dryRun` | `boolean` | Process markdown files without sending them to `confluence-sync`. Useful to early detection of possible errors in configuration, etc. Note that, requests that would be made to Confluence won't be logged, use `confluence.dryRun` for that, which also connects to Confluence to calculate the requests to do | `false` |
306307
| `config.readArguments` | `boolean` | Read configuration from arguments or not | `false` |
307308
| `config.readFile` | `boolean` | Read configuration from file or not | `false` |
@@ -494,6 +495,30 @@ Apart of supporting the most common markdown features, the library also supports
494495
<ac:rich-text-body><p>This is the content of the details.</p></ac:rich-text-body>
495496
</ac:structured-macro>
496497
```
498+
* Code blocks - Markdown fenced code blocks can be converted to
499+
Confluence code macro format with syntax highlighting support. This
500+
feature is disabled by default but can be enabled via the
501+
`rehype.codeBlocks` configuration option.
502+
* The plugin converts fenced code blocks to Confluence's
503+
`<ac:structured-macro ac:name="code">` format.
504+
* Language syntax highlighting is preserved when specified in the
505+
markdown code fence.
506+
* This feature is disabled by default for compatibility with older
507+
Confluence versions. Enable it by setting `rehype.codeBlocks: true`.
508+
* For example, the following markdown code block:
509+
````markdown
510+
```javascript
511+
const hello = "world";
512+
console.log(hello);
513+
```
514+
````
515+
will be converted to a Confluence code macro as follows:
516+
```markdown
517+
<ac:structured-macro ac:name="code">
518+
<ac:parameter ac:name="language">javascript</ac:parameter>
519+
<ac:plain-text-body><![ CDATA [ const hello = "world";console.log(hello);] ]></ac:plain-text-body>
520+
</ac:structured-macro>
521+
```
497522
498523
### Unsupported features
499524

components/markdown-confluence-sync/jest.unit.config.cjs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ module.exports = {
2020
// An object that configures minimum threshold enforcement for coverage results
2121
coverageThreshold: {
2222
global: {
23-
branches: 98,
24-
functions: 98,
25-
lines: 98,
26-
statements: 98,
23+
branches: 97,
24+
functions: 97,
25+
lines: 97,
26+
statements: 97,
2727
},
2828
},
2929

components/markdown-confluence-sync/markdown-confluence-sync.config.cjs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,7 @@ module.exports = {
4141
rootPageName: "Cross",
4242
},
4343
logLevel: "debug",
44+
rehype: {
45+
codeBlocks: true,
46+
},
4447
};

components/markdown-confluence-sync/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@telefonica/markdown-confluence-sync",
33
"description": "Creates/updates/deletes Confluence pages based on markdown files in a directory. Supports Mermaid diagrams and per-page configuration using frontmatter metadata. Works great with Docusaurus",
4-
"version": "2.2.0",
4+
"version": "2.3.0",
55
"license": "Apache-2.0",
66
"author": "Telefónica Innovación Digital",
77
"repository": {

components/markdown-confluence-sync/src/lib/MarkdownConfluenceSync.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import type {
4141
const MODULE_NAME = "markdown-confluence-sync";
4242
const MARKDOWN_NAMESPACE = "markdown";
4343
const CONFLUENCE_NAMESPACE = "confluence";
44+
const REHYPE_CONFIG_NAMESPACE = "rehype";
4445

4546
const DEFAULT_CONFIG: Configuration["config"] = {
4647
readArguments: false,
@@ -146,6 +147,9 @@ export const MarkdownConfluenceSync: MarkdownConfluenceSyncConstructor = class M
146147

147148
const confluenceConfig =
148149
this._configuration.addNamespace(CONFLUENCE_NAMESPACE);
150+
const rehypeConfig = this._configuration.addNamespace(
151+
REHYPE_CONFIG_NAMESPACE,
152+
);
149153
const confluenceLogger = this._logger.namespace(CONFLUENCE_NAMESPACE);
150154

151155
this._markdownDocuments = new MarkdownDocuments({
@@ -160,6 +164,7 @@ export const MarkdownConfluenceSync: MarkdownConfluenceSyncConstructor = class M
160164
});
161165
this._confluenceSync = new ConfluenceSync({
162166
config: confluenceConfig,
167+
rehypeConfig: rehypeConfig,
163168
logger: confluenceLogger,
164169
mode: this._modeOption,
165170
});

components/markdown-confluence-sync/src/lib/confluence/ConfluenceSync.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ import type {
3434
NoticeTemplateOption,
3535
AuthenticationOptionDefinition,
3636
AuthenticationOption,
37+
RehypeCodeBlocksOptionDefinition,
38+
RehypeCodeBlocksOption,
3739
ApiPrefixOption,
3840
ApiPrefixOptionDefinition,
3941
} from "./ConfluenceSync.types.js";
@@ -93,6 +95,12 @@ const authenticationOption: AuthenticationOptionDefinition = {
9395
type: "object",
9496
};
9597

98+
const rehypeCodeBlocksOption: RehypeCodeBlocksOptionDefinition = {
99+
name: "codeBlocks",
100+
type: "boolean",
101+
default: false,
102+
};
103+
96104
export const ConfluenceSync: ConfluenceSyncConstructor = class ConfluenceSync
97105
implements ConfluenceSyncInterface
98106
{
@@ -111,8 +119,9 @@ export const ConfluenceSync: ConfluenceSyncConstructor = class ConfluenceSync
111119
private _initialized = false;
112120
private _logger: LoggerInterface;
113121
private _modeOption: ModeOption;
122+
private _rehypeCodeBlocksOption: RehypeCodeBlocksOption;
114123

115-
constructor({ config, logger, mode }: ConfluenceSyncOptions) {
124+
constructor({ config, rehypeConfig, logger, mode }: ConfluenceSyncOptions) {
116125
this._urlOption = config.addOption(urlOption) as UrlOption;
117126
this._apiPrefixOption = config.addOption(
118127
apiPrefixOption,
@@ -137,6 +146,11 @@ export const ConfluenceSync: ConfluenceSyncConstructor = class ConfluenceSync
137146
authenticationOption,
138147
) as AuthenticationOption;
139148
this._dryRunOption = config.addOption(dryRunOption) as DryRunOption;
149+
150+
this._rehypeCodeBlocksOption = rehypeConfig.addOption(
151+
rehypeCodeBlocksOption,
152+
) as RehypeCodeBlocksOption;
153+
140154
this._modeOption = mode;
141155
this._logger = logger;
142156
}
@@ -204,6 +218,9 @@ export const ConfluenceSync: ConfluenceSyncConstructor = class ConfluenceSync
204218
rootPageName: this._rootPageNameOption.value,
205219
spaceKey: this._spaceKeyOption.value,
206220
logger: this._logger.namespace("transformer"),
221+
rehype: {
222+
codeBlocks: this._rehypeCodeBlocksOption.value,
223+
},
207224
});
208225

209226
this._confluenceSyncPages = new ConfluenceSyncPages({

components/markdown-confluence-sync/src/lib/confluence/ConfluenceSync.types.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ type NoticeMessageOptionValue = string;
2424
type NoticeTemplateOptionValue = string;
2525
type DryRunOptionValue = boolean;
2626

27+
type RehypeCodeBlocksOptionValue = boolean;
28+
2729
declare global {
2830
//eslint-disable-next-line @typescript-eslint/no-namespace
2931
namespace MarkdownConfluenceSync {
@@ -53,6 +55,10 @@ declare global {
5355
/** Confluence dry run */
5456
dryRun?: DryRunOptionValue;
5557
};
58+
rehype?: {
59+
/** Enable code blocks transformation to Confluence code macro */
60+
codeBlocks?: RehypeCodeBlocksOptionValue;
61+
};
5662
}
5763
}
5864
}
@@ -74,6 +80,8 @@ export type DryRunOptionDefinition = OptionDefinition<
7480
DryRunOptionValue,
7581
{ hasDefault: true }
7682
>;
83+
export type RehypeCodeBlocksOptionDefinition =
84+
OptionDefinition<RehypeCodeBlocksOptionValue>;
7785

7886
export type AuthenticationOptionDefinition =
7987
OptionDefinition<ConfluenceClientAuthenticationConfig>;
@@ -96,13 +104,20 @@ export type DryRunOption = OptionInterfaceOfType<
96104
{ hasDefault: true }
97105
>;
98106

107+
export type RehypeCodeBlocksOption = OptionInterfaceOfType<
108+
RehypeCodeBlocksOptionValue,
109+
{ hasDefault: true }
110+
>;
111+
99112
export interface ConfluenceSyncOptions {
100113
/** Configuration interface */
101114
config: ConfigNamespaceInterface;
102115
/** Logger interface */
103116
logger: LoggerInterface;
104117
/** Sync mode option */
105118
mode: ModeOption;
119+
/** Rehype configuration namespace */
120+
rehypeConfig: ConfigNamespaceInterface;
106121
}
107122

108123
/** Creates a ConfluenceSyncInterface interface */

components/markdown-confluence-sync/src/lib/confluence/transformer/ConfluencePageTransformer.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import { InvalidTemplateError } from "./errors/InvalidTemplateError.js";
2727
import rehypeAddAttachmentsImages from "./support/rehype/rehype-add-attachments-images.js";
2828
import type { ImagesMetadata } from "./support/rehype/rehype-add-attachments-images.types.js";
2929
import rehypeAddNotice from "./support/rehype/rehype-add-notice.js";
30+
import rehypeReplaceCodeBlocks from "./support/rehype/rehype-replace-code-blocks.js";
3031
import rehypeReplaceDetails from "./support/rehype/rehype-replace-details.js";
3132
import rehypeReplaceImgTags from "./support/rehype/rehype-replace-img-tags.js";
3233
import rehypeReplaceInternalReferences from "./support/rehype/rehype-replace-internal-references.js";
@@ -50,13 +51,15 @@ export const ConfluencePageTransformer: ConfluencePageTransformerConstructor = c
5051
private readonly _rootPageName?: string;
5152
private readonly _spaceKey: string;
5253
private readonly _logger?: LoggerInterface;
54+
private readonly _rehypeCodeBlocksEnabled: boolean;
5355

5456
constructor({
5557
noticeMessage,
5658
noticeTemplate,
5759
rootPageName,
5860
spaceKey,
5961
logger,
62+
rehype: { codeBlocks },
6063
}: ConfluencePageTransformerOptions) {
6164
this._noticeMessage = noticeMessage;
6265
this._noticeTemplateRaw = noticeTemplate;
@@ -66,6 +69,11 @@ export const ConfluencePageTransformer: ConfluencePageTransformerConstructor = c
6669
this._rootPageName = rootPageName;
6770
this._spaceKey = spaceKey;
6871
this._logger = logger;
72+
this._rehypeCodeBlocksEnabled = codeBlocks ?? false;
73+
74+
logger?.debug(
75+
`ConfluencePageTransformer initialized with rehype options: ${JSON.stringify({ codeBlocks: this._rehypeCodeBlocksEnabled })}`,
76+
);
6977
}
7078

7179
public async transform(
@@ -88,7 +96,7 @@ export const ConfluencePageTransformer: ConfluencePageTransformerConstructor = c
8896
DEFAULT_MERMAID_DIAGRAMS_LOCATION,
8997
);
9098
try {
91-
const content = remark()
99+
let processor = remark()
92100
.use(remarkGfm)
93101
.use(remarkFrontmatter)
94102
.use(remarkRemoveFootnotes)
@@ -101,7 +109,15 @@ export const ConfluencePageTransformer: ConfluencePageTransformerConstructor = c
101109
.use(rehypeAddNotice, { noticeMessage })
102110
.use(rehypeReplaceDetails)
103111
.use(rehypeReplaceStrikethrough)
104-
.use(rehypeReplaceTaskList)
112+
.use(rehypeReplaceTaskList);
113+
114+
// Conditionally add code blocks plugin
115+
if (this._rehypeCodeBlocksEnabled) {
116+
this._logger?.debug(`Registering rehypeReplaceCodeBlocks plugin`);
117+
processor = processor.use(rehypeReplaceCodeBlocks);
118+
}
119+
120+
const content = processor
105121
.use(rehypeAddAttachmentsImages)
106122
.use(rehypeReplaceImgTags)
107123
.use(rehypeReplaceInternalReferences, {

components/markdown-confluence-sync/src/lib/confluence/transformer/ConfluencePageTransformer.types.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,20 @@ import type { ConfluenceInputPage } from "@telefonica/confluence-sync";
66

77
import type { ConfluenceSyncPage } from "../ConfluenceSync.types.js";
88

9+
/**
10+
* Options for Rehype plugins used in ConfluencePageTransformer
11+
*/
12+
export interface ConfluencePageTransformerRehypeOptions {
13+
/**
14+
* Enable code blocks transformation to Confluence code macro.
15+
* When enabled, markdown code blocks will be converted to Confluence's
16+
* structured code macro format with syntax highlighting support.
17+
* When this option is not specified or set to false, code blocks will remain as plain HTML <pre>/<code> tags rather than being transformed.
18+
* @default false
19+
*/
20+
codeBlocks?: boolean;
21+
}
22+
923
export interface ConfluencePageTransformerOptions {
1024
/** Confluence page notice message */
1125
noticeMessage?: string;
@@ -24,6 +38,8 @@ export interface ConfluencePageTransformerOptions {
2438
spaceKey: string;
2539
/** Logger */
2640
logger?: LoggerInterface;
41+
/** Rehype options */
42+
rehype: ConfluencePageTransformerRehypeOptions;
2743
}
2844

2945
/** Creates a ConfluencePageTransformer interface */

0 commit comments

Comments
 (0)