confluence-md-sync 0.10.0 → 0.11.0
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.
- package/dist/export/to-markdown.js +18 -0
- package/dist/macros/index.d.ts +2 -0
- package/dist/macros/index.js +4 -0
- package/dist/macros/plugins/structurizr.d.ts +5 -0
- package/dist/macros/plugins/structurizr.js +17 -0
- package/dist/markdown/native.js +5 -1
- package/dist/markdown/structurizr.d.ts +5 -0
- package/dist/markdown/structurizr.js +16 -0
- package/dist/markdown/validate.js +5 -0
- package/package.json +1 -1
|
@@ -140,6 +140,14 @@ class Converter {
|
|
|
140
140
|
if (meaningful.length === 1 && meaningful[0].kind === 'el' && meaningful[0].name === 'ac:structured-macro') {
|
|
141
141
|
return this.macroToMd(meaningful[0]);
|
|
142
142
|
}
|
|
143
|
+
if (meaningful.length > 1 && meaningful.every(n => n.kind === 'el' && n.name === 'ac:structured-macro')) {
|
|
144
|
+
const native = meaningful.map(n => this.tryNativeMd(n, getAttr(n, 'ac:name') ?? ''));
|
|
145
|
+
if (native.every(s => s?.startsWith('{{') && !s.includes('\n'))) {
|
|
146
|
+
this.stats.native += native.length;
|
|
147
|
+
this.stats.normalized++; // A paragraph around block macros is redundant in Confluence.
|
|
148
|
+
return native.join(' ');
|
|
149
|
+
}
|
|
150
|
+
}
|
|
143
151
|
return this.paragraphMd(el.children);
|
|
144
152
|
}
|
|
145
153
|
if (el.name === 'hr')
|
|
@@ -1238,6 +1246,16 @@ class Converter {
|
|
|
1238
1246
|
throw new Unrepresentable();
|
|
1239
1247
|
const ref = kids[0];
|
|
1240
1248
|
const filename = getAttr(ref, 'ri:filename') ?? '';
|
|
1249
|
+
const architecture = /^(.*\.dsl)\.((?:[0-9a-f]{2})+)\.png$/.exec(filename);
|
|
1250
|
+
if (architecture && ref.name === 'ri:attachment' && !/[{}|\n/\\]/.test(architecture[1])) {
|
|
1251
|
+
const view = new TextDecoder('utf-8').decode(Uint8Array.from(architecture[2].match(/../g), b => parseInt(b, 16)));
|
|
1252
|
+
if (view && !/[{}|\n\uFFFD]/.test(view)) {
|
|
1253
|
+
this.files.add(architecture[1]);
|
|
1254
|
+
this.files.add(architecture[1].replace(/\.dsl$/, '.json'));
|
|
1255
|
+
this.images.add(filename);
|
|
1256
|
+
return `{{structurizr:${architecture[1]}|view=${view}}}`;
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1241
1259
|
const stem = filename.replace(/\.png$/i, '');
|
|
1242
1260
|
const drawioName = getAttr(el, 'ac:alt')?.match(/^drawio:(.+)$/)?.[1]
|
|
1243
1261
|
?? (stem !== filename && (this.drawioNames.has(stem) || /\.drawio$/i.test(stem)) ? stem : undefined);
|
package/dist/macros/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export { coreMacrosPlugin, extractPlainText } from './plugins/core.js';
|
|
|
6
6
|
export { tableFilterPlugin, TABLE_FILTER_DEFAULTS } from './plugins/table-filter.js';
|
|
7
7
|
export { csvTablePlugin, CSV_TABLE_DEFAULTS } from './plugins/csv-table.js';
|
|
8
8
|
export { portfolioForJiraPlanPlugin } from './plugins/portfolio-for-jira-plan.js';
|
|
9
|
+
export { structurizrPlugin } from './plugins/structurizr.js';
|
|
9
10
|
export { drawioPlugin } from './plugins/drawio.js';
|
|
10
11
|
export { searchPlugin } from './plugins/search.js';
|
|
11
12
|
import { MacroRegistry } from './registry.js';
|
|
@@ -51,5 +52,6 @@ export declare const macros: {
|
|
|
51
52
|
csvTable: typeof csvTable;
|
|
52
53
|
portfolioForJiraPlan: typeof portfolioForJiraPlan;
|
|
53
54
|
drawio: (name: string, opts?: Record<string, string | undefined>) => import("../index.js").Markdown;
|
|
55
|
+
structurizr: (name: string, view: string) => import("../index.js").Markdown;
|
|
54
56
|
search: (query: string, options?: Record<string, string | undefined>) => import("../index.js").Markdown;
|
|
55
57
|
};
|
package/dist/macros/index.js
CHANGED
|
@@ -6,6 +6,7 @@ export { coreMacrosPlugin, extractPlainText } from './plugins/core.js';
|
|
|
6
6
|
export { tableFilterPlugin, TABLE_FILTER_DEFAULTS } from './plugins/table-filter.js';
|
|
7
7
|
export { csvTablePlugin, CSV_TABLE_DEFAULTS } from './plugins/csv-table.js';
|
|
8
8
|
export { portfolioForJiraPlanPlugin } from './plugins/portfolio-for-jira-plan.js';
|
|
9
|
+
export { structurizrPlugin } from './plugins/structurizr.js';
|
|
9
10
|
export { drawioPlugin } from './plugins/drawio.js';
|
|
10
11
|
export { searchPlugin } from './plugins/search.js';
|
|
11
12
|
import { MacroRegistry } from './registry.js';
|
|
@@ -17,6 +18,7 @@ import { anchor, children, codeBlock, excerpt, excerptInclude, expand, includePa
|
|
|
17
18
|
import { tableExcerpt, tableExcerptInclude, tableFilter, tableJoiner } from './plugins/table-filter.js';
|
|
18
19
|
import { csvTable } from './plugins/csv-table.js';
|
|
19
20
|
import { portfolioForJiraPlan } from './plugins/portfolio-for-jira-plan.js';
|
|
21
|
+
import { structurizr, structurizrPlugin } from './plugins/structurizr.js';
|
|
20
22
|
import { drawio, drawioPlugin } from './plugins/drawio.js';
|
|
21
23
|
import { search, searchPlugin } from './plugins/search.js';
|
|
22
24
|
/** Creates a registry pre-loaded with all built-in plugins. */
|
|
@@ -27,6 +29,7 @@ export function createDefaultRegistry() {
|
|
|
27
29
|
.use(csvTablePlugin)
|
|
28
30
|
.use(portfolioForJiraPlanPlugin)
|
|
29
31
|
.use(drawioPlugin)
|
|
32
|
+
.use(structurizrPlugin)
|
|
30
33
|
.use(searchPlugin);
|
|
31
34
|
}
|
|
32
35
|
/**
|
|
@@ -67,5 +70,6 @@ export const macros = {
|
|
|
67
70
|
csvTable,
|
|
68
71
|
portfolioForJiraPlan,
|
|
69
72
|
drawio,
|
|
73
|
+
structurizr,
|
|
70
74
|
search,
|
|
71
75
|
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type MacroPlugin } from '../types.js';
|
|
2
|
+
export declare function structurizrPreview(name: string, view: string): string;
|
|
3
|
+
/** Confluence needs no third-party plugin: the view is a PNG, sources remain attachments. */
|
|
4
|
+
export declare const structurizrPlugin: MacroPlugin;
|
|
5
|
+
export declare const structurizr: (name: string, view: string) => import("../../index.js").Markdown;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { macro } from '../builder.js';
|
|
2
|
+
import { paramMap } from '../types.js';
|
|
3
|
+
import { escapeXmlAttr } from '../xml.js';
|
|
4
|
+
export function structurizrPreview(name, view) {
|
|
5
|
+
if (typeof name !== 'string' || !/\.dsl$/i.test(name) || /[/\\{}|]/.test(name) || !view || view.length > 120 || /[{}|\n\r]/.test(view))
|
|
6
|
+
throw new Error('structurizr: a .dsl attachment and view key are required');
|
|
7
|
+
return `${name}.${Array.from(new TextEncoder().encode(view), b => b.toString(16).padStart(2, '0')).join('')}.png`;
|
|
8
|
+
}
|
|
9
|
+
/** Confluence needs no third-party plugin: the view is a PNG, sources remain attachments. */
|
|
10
|
+
export const structurizrPlugin = {
|
|
11
|
+
name: 'structurizr',
|
|
12
|
+
macros: [{ name: 'structurizr', render(ctx) {
|
|
13
|
+
const { name, view } = paramMap(ctx.params);
|
|
14
|
+
return `<ac:image ac:alt="${escapeXmlAttr(`Structurizr · ${view}`)}"><ri:attachment ri:filename="${escapeXmlAttr(structurizrPreview(name, view))}" /></ac:image>`;
|
|
15
|
+
} }],
|
|
16
|
+
};
|
|
17
|
+
export const structurizr = (name, view) => macro('structurizr').param('name', name).param('view', view).toMarkdown();
|
package/dist/markdown/native.js
CHANGED
|
@@ -47,6 +47,7 @@ export const NATIVE_DIRECTIVES = {
|
|
|
47
47
|
export const NATIVE_PLACEHOLDERS = {
|
|
48
48
|
search: 'search',
|
|
49
49
|
drawio: 'drawio',
|
|
50
|
+
structurizr: 'structurizr',
|
|
50
51
|
toc: 'toc',
|
|
51
52
|
children: 'children',
|
|
52
53
|
jira: 'jira',
|
|
@@ -59,6 +60,7 @@ export const NATIVE_PLACEHOLDERS = {
|
|
|
59
60
|
export function nativeMacroList() {
|
|
60
61
|
return [
|
|
61
62
|
{ macro: 'search', syntax: '{{search:query=…|spacekey=…|type=page|maxLimit=10}}' },
|
|
63
|
+
{ macro: 'structurizr', syntax: '{{structurizr:workspace.dsl|view=containers}}' },
|
|
62
64
|
{ macro: 'drawio', syntax: '{{drawio:diagram.drawio|format=macro}} | {{drawio:diagram.drawio|format=image}}' },
|
|
63
65
|
{ macro: 'info', syntax: '> [!INFO] Заголовок?' },
|
|
64
66
|
{ macro: 'note', syntax: '> [!NOTE] Заголовок?' },
|
|
@@ -79,7 +81,7 @@ export function nativeMacroList() {
|
|
|
79
81
|
const ADMONITION_FIRST_RE = /^>\s*\[!([A-Za-z]+)\]\s*(.*)$/;
|
|
80
82
|
const DIRECTIVE_OPEN_RE = /^:::\s+([a-z-]+)(?:\s+(.*?))?\s*$/;
|
|
81
83
|
const DIRECTIVE_CLOSE_RE = /^:::\s*$/;
|
|
82
|
-
const PLACEHOLDER_INLINE_RE = /\{\{(search|drawio|toc|children|jira|status|anchor|properties-report|portfolio-for-jira-plan)(?::((?:"(?:\\.|[^"\\])*"|[^{}"]|\{[^{])*?))?\}\}/g;
|
|
84
|
+
const PLACEHOLDER_INLINE_RE = /\{\{(search|drawio|structurizr|toc|children|jira|status|anchor|properties-report|portfolio-for-jira-plan)(?::((?:"(?:\\.|[^"\\])*"|[^{}"]|\{[^{])*?))?\}\}/g;
|
|
83
85
|
const FENCE_RE = /^\s*(`{3,}|~{3,})/;
|
|
84
86
|
/** Компактная пара маркеров без тела — для строчного контекста. */
|
|
85
87
|
function inlineMarker(macroName, params) {
|
|
@@ -122,6 +124,8 @@ function placeholderParams(kind, raw) {
|
|
|
122
124
|
if (raw === undefined || raw.trim() === '')
|
|
123
125
|
return [];
|
|
124
126
|
const { head, attrs } = splitAttrs(raw);
|
|
127
|
+
if (kind === 'structurizr')
|
|
128
|
+
return [{ name: 'name', value: head }, ...attrs];
|
|
125
129
|
if (kind === 'drawio')
|
|
126
130
|
return [{ name: 'diagramName', value: head }, ...attrs];
|
|
127
131
|
const params = [];
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import MarkdownIt from 'markdown-it';
|
|
2
|
+
import { parsePlaceholder } from './render.js';
|
|
3
|
+
import { structurizrPreview } from '../macros/plugins/structurizr.js';
|
|
4
|
+
export function structurizrReferences(markdown) {
|
|
5
|
+
const refs = [];
|
|
6
|
+
for (const token of new MarkdownIt().parse(markdown, {}))
|
|
7
|
+
for (const child of token.children ?? []) {
|
|
8
|
+
if (child.type !== 'text')
|
|
9
|
+
continue;
|
|
10
|
+
for (const match of child.content.matchAll(/\{\{structurizr:([^}]+)\}\}/g)) {
|
|
11
|
+
const { name, attrs } = parsePlaceholder(match[1]);
|
|
12
|
+
refs.push({ name, json: name.replace(/\.dsl$/, '.json'), preview: structurizrPreview(name, Object.fromEntries(attrs).view) });
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return refs;
|
|
16
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { basename } from 'node:path';
|
|
2
2
|
import { extractPlaceholders } from './render.js';
|
|
3
|
+
import { structurizrReferences } from './structurizr.js';
|
|
3
4
|
import { drawioReferences } from './drawio.js';
|
|
4
5
|
export class MarkdownValidationError extends Error {
|
|
5
6
|
constructor(message) {
|
|
@@ -13,6 +14,10 @@ export function validateMarkdown(opts) {
|
|
|
13
14
|
files.push(diagram.name);
|
|
14
15
|
images.push(diagram.preview);
|
|
15
16
|
}
|
|
17
|
+
for (const diagram of structurizrReferences(opts.markdown)) {
|
|
18
|
+
files.push(diagram.name, diagram.json);
|
|
19
|
+
images.push(diagram.preview);
|
|
20
|
+
}
|
|
16
21
|
const tables = extractTablePlaceholders(opts.markdown);
|
|
17
22
|
const providedImages = new Set(opts.imagePaths.map((p) => basename(p)));
|
|
18
23
|
const providedFiles = new Set(opts.filePaths.map((p) => basename(p)));
|
package/package.json
CHANGED