confluence-md-sync 0.1.1

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.
Files changed (47) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +247 -0
  3. package/dist/attachments/attachment.d.ts +39 -0
  4. package/dist/attachments/attachment.js +83 -0
  5. package/dist/attachments/hash.d.ts +2 -0
  6. package/dist/attachments/hash.js +6 -0
  7. package/dist/cli.d.ts +13 -0
  8. package/dist/cli.js +85 -0
  9. package/dist/client/client.d.ts +128 -0
  10. package/dist/client/client.js +311 -0
  11. package/dist/client/config.d.ts +42 -0
  12. package/dist/client/config.js +54 -0
  13. package/dist/csv.d.ts +18 -0
  14. package/dist/csv.js +86 -0
  15. package/dist/index.d.ts +13 -0
  16. package/dist/index.js +20 -0
  17. package/dist/macros/builder.d.ts +30 -0
  18. package/dist/macros/builder.js +58 -0
  19. package/dist/macros/index.d.ts +44 -0
  20. package/dist/macros/index.js +50 -0
  21. package/dist/macros/plugins/core.d.ts +49 -0
  22. package/dist/macros/plugins/core.js +214 -0
  23. package/dist/macros/plugins/table-filter.d.ts +35 -0
  24. package/dist/macros/plugins/table-filter.js +155 -0
  25. package/dist/macros/registry.d.ts +29 -0
  26. package/dist/macros/registry.js +111 -0
  27. package/dist/macros/types.d.ts +38 -0
  28. package/dist/macros/types.js +15 -0
  29. package/dist/macros/xml.d.ts +28 -0
  30. package/dist/macros/xml.js +52 -0
  31. package/dist/markdown/markdown.d.ts +36 -0
  32. package/dist/markdown/markdown.js +78 -0
  33. package/dist/markdown/render.d.ts +35 -0
  34. package/dist/markdown/render.js +80 -0
  35. package/dist/markdown/validate.d.ts +11 -0
  36. package/dist/markdown/validate.js +60 -0
  37. package/dist/pages/page.d.ts +104 -0
  38. package/dist/pages/page.js +234 -0
  39. package/dist/pages/tables.d.ts +72 -0
  40. package/dist/pages/tables.js +163 -0
  41. package/dist/publish/publish.d.ts +67 -0
  42. package/dist/publish/publish.js +164 -0
  43. package/dist/publish/runner.d.ts +36 -0
  44. package/dist/publish/runner.js +41 -0
  45. package/dist/wrapper.d.ts +21 -0
  46. package/dist/wrapper.js +36 -0
  47. package/package.json +69 -0
@@ -0,0 +1,44 @@
1
+ export { paramMap, type MacroDefinition, type MacroParam, type MacroPlugin, type MacroRenderer, type RendererContext, } from './types.js';
2
+ export { MacroBuilder, macro, escapeParamValue, unescapeParamValue } from './builder.js';
3
+ export { MacroRegistry, processMacros } from './registry.js';
4
+ export { escapeXmlAttr, generateMacroId, structuredMacro, pageLinkValue, type StructuredMacroOptions, } from './xml.js';
5
+ export { coreMacrosPlugin, extractPlainText } from './plugins/core.js';
6
+ export { tableFilterPlugin, TABLE_FILTER_DEFAULTS } from './plugins/table-filter.js';
7
+ import { MacroRegistry } from './registry.js';
8
+ import { anchor, children, codeBlock, excerpt, excerptInclude, expand, includePage, jiraIssue, panel, status, toc } from './plugins/core.js';
9
+ import { tableExcerpt, tableExcerptInclude, tableFilter } from './plugins/table-filter.js';
10
+ /** Creates a registry pre-loaded with all built-in plugins. */
11
+ export declare function createDefaultRegistry(): MacroRegistry;
12
+ /**
13
+ * Глобальный реестр по умолчанию (core + table-filter). Используется,
14
+ * если в publishPage/processMacros не передан свой registry.
15
+ */
16
+ export declare const defaultMacroRegistry: MacroRegistry;
17
+ /** Возвращает глобальный реестр макросов. */
18
+ export declare function getMacroRegistry(): MacroRegistry;
19
+ /**
20
+ * Namespace с построителями макросов — генерируют маркеры в Markdown.
21
+ *
22
+ * @example
23
+ * macros.tableFilter(macros.tableExcerpt(tableMd, 'jira_fact'), { totalrow: ',,Sum' })
24
+ */
25
+ export declare const macros: {
26
+ expand: typeof expand;
27
+ note: (body: import("../index.js").Markdown | string, title?: string) => import("../index.js").Markdown;
28
+ info: (body: import("../index.js").Markdown | string, title?: string) => import("../index.js").Markdown;
29
+ warning: (body: import("../index.js").Markdown | string, title?: string) => import("../index.js").Markdown;
30
+ tip: (body: import("../index.js").Markdown | string, title?: string) => import("../index.js").Markdown;
31
+ panel: typeof panel;
32
+ codeBlock: typeof codeBlock;
33
+ status: typeof status;
34
+ toc: typeof toc;
35
+ jiraIssue: typeof jiraIssue;
36
+ anchor: typeof anchor;
37
+ children: typeof children;
38
+ includePage: typeof includePage;
39
+ excerpt: typeof excerpt;
40
+ excerptInclude: typeof excerptInclude;
41
+ tableExcerpt: typeof tableExcerpt;
42
+ tableFilter: typeof tableFilter;
43
+ tableExcerptInclude: typeof tableExcerptInclude;
44
+ };
@@ -0,0 +1,50 @@
1
+ export { paramMap, } from './types.js';
2
+ export { MacroBuilder, macro, escapeParamValue, unescapeParamValue } from './builder.js';
3
+ export { MacroRegistry, processMacros } from './registry.js';
4
+ export { escapeXmlAttr, generateMacroId, structuredMacro, pageLinkValue, } from './xml.js';
5
+ export { coreMacrosPlugin, extractPlainText } from './plugins/core.js';
6
+ export { tableFilterPlugin, TABLE_FILTER_DEFAULTS } from './plugins/table-filter.js';
7
+ import { MacroRegistry } from './registry.js';
8
+ import { coreMacrosPlugin } from './plugins/core.js';
9
+ import { tableFilterPlugin } from './plugins/table-filter.js';
10
+ import { anchor, children, codeBlock, excerpt, excerptInclude, expand, includePage, info, jiraIssue, note, panel, status, tip, toc, warning, } from './plugins/core.js';
11
+ import { tableExcerpt, tableExcerptInclude, tableFilter } from './plugins/table-filter.js';
12
+ /** Creates a registry pre-loaded with all built-in plugins. */
13
+ export function createDefaultRegistry() {
14
+ return new MacroRegistry().use(coreMacrosPlugin).use(tableFilterPlugin);
15
+ }
16
+ /**
17
+ * Глобальный реестр по умолчанию (core + table-filter). Используется,
18
+ * если в publishPage/processMacros не передан свой registry.
19
+ */
20
+ export const defaultMacroRegistry = createDefaultRegistry();
21
+ /** Возвращает глобальный реестр макросов. */
22
+ export function getMacroRegistry() {
23
+ return defaultMacroRegistry;
24
+ }
25
+ /**
26
+ * Namespace с построителями макросов — генерируют маркеры в Markdown.
27
+ *
28
+ * @example
29
+ * macros.tableFilter(macros.tableExcerpt(tableMd, 'jira_fact'), { totalrow: ',,Sum' })
30
+ */
31
+ export const macros = {
32
+ expand,
33
+ note,
34
+ info,
35
+ warning,
36
+ tip,
37
+ panel,
38
+ codeBlock,
39
+ status,
40
+ toc,
41
+ jiraIssue,
42
+ anchor,
43
+ children,
44
+ includePage,
45
+ excerpt,
46
+ excerptInclude,
47
+ tableExcerpt,
48
+ tableFilter,
49
+ tableExcerptInclude,
50
+ };
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Core plugin: built-in Confluence macros available out of the box.
3
+ *
4
+ * Rich-body macros (expand, note, panel, …) wrap already-rendered XHTML.
5
+ * Bodyless macros (toc, status, jira, …) pass their params through.
6
+ */
7
+ import { Markdown } from '../../markdown/markdown.js';
8
+ import { type MacroPlugin } from '../types.js';
9
+ /** Unwraps `<pre><code>…</code></pre>` / `<p>…</p>` and decodes HTML entities. */
10
+ export declare function extractPlainText(body: string): string;
11
+ export declare const coreMacrosPlugin: MacroPlugin;
12
+ /** Обёртывает markdown в макрос "развернуть". */
13
+ export declare function expand(body: Markdown | string, title?: string): Markdown;
14
+ /** Обёртывает markdown в макрос "примечание". */
15
+ export declare const note: (body: Markdown | string, title?: string) => Markdown;
16
+ /** Обёртывает markdown в макрос "информация". */
17
+ export declare const info: (body: Markdown | string, title?: string) => Markdown;
18
+ /** Обёртывает markdown в макрос "предупреждение". */
19
+ export declare const warning: (body: Markdown | string, title?: string) => Markdown;
20
+ /** Обёртывает markdown в макрос "совет". */
21
+ export declare const tip: (body: Markdown | string, title?: string) => Markdown;
22
+ /** Обёртывает markdown в панель с произвольными параметрами (title, borderColor, bgColor, …). */
23
+ export declare function panel(body: Markdown | string, opts?: Record<string, string | undefined>): Markdown;
24
+ /** Блок кода с подсветкой. Тело — сырой текст программы. */
25
+ export declare function codeBlock(source: string, opts?: {
26
+ language?: string;
27
+ title?: string;
28
+ linenumbers?: boolean;
29
+ collapse?: boolean;
30
+ }): Markdown;
31
+ /** Статус-лейбл: status('Green', 'ON TRACK'). */
32
+ export declare function status(colour: string, title: string, subtle?: boolean): Markdown;
33
+ /** Оглавление страницы. Параметры — как у Confluence toc (maxLevel, minLevel, style, …). */
34
+ export declare function toc(opts?: Record<string, string | undefined>): Markdown;
35
+ /** Ссылка-карточка на задачу Jira по ключу. */
36
+ export declare function jiraIssue(key: string, opts?: Record<string, string | undefined>): Markdown;
37
+ /** Якорь для внутристраничных ссылок. */
38
+ export declare function anchor(name: string): Markdown;
39
+ /** Список дочерних страниц. */
40
+ export declare function children(opts?: Record<string, string | undefined>): Markdown;
41
+ /** Включение другой страницы целиком. */
42
+ export declare function includePage(page: string, space?: string): Markdown;
43
+ /** Именованный excerpt (переиспользуемый фрагмент страницы). */
44
+ export declare function excerpt(body: Markdown | string, hidden?: boolean): Markdown;
45
+ /** Включение excerpt с другой страницы. */
46
+ export declare function excerptInclude(page: string, opts?: {
47
+ space?: string;
48
+ nopanel?: boolean;
49
+ }): Markdown;
@@ -0,0 +1,214 @@
1
+ /**
2
+ * Core plugin: built-in Confluence macros available out of the box.
3
+ *
4
+ * Rich-body macros (expand, note, panel, …) wrap already-rendered XHTML.
5
+ * Bodyless macros (toc, status, jira, …) pass their params through.
6
+ */
7
+ import { macro } from '../builder.js';
8
+ import { paramMap } from '../types.js';
9
+ import { pageLinkValue, structuredMacro } from '../xml.js';
10
+ /** Rich-body macro that forwards the listed params (if present). */
11
+ function richBodyMacro(name, allowedParams) {
12
+ return {
13
+ name,
14
+ render: (ctx) => {
15
+ const params = ctx.params
16
+ .filter((p) => !allowedParams || allowedParams.includes(p.name))
17
+ .map((p) => ({ name: p.name, value: p.value }));
18
+ return structuredMacro(name, ctx.macroId, { params, richBody: ctx.body });
19
+ },
20
+ };
21
+ }
22
+ /** Bodyless macro: params pass through, body (if any) is discarded. */
23
+ function bodylessMacro(name) {
24
+ return {
25
+ name,
26
+ render: (ctx) => structuredMacro(name, ctx.macroId, { params: ctx.params }),
27
+ };
28
+ }
29
+ /**
30
+ * `code` macro: the body must be plain text inside CDATA. By the time
31
+ * processMacros runs, markdown-it has already rendered the body — a fenced
32
+ * code block becomes `<pre><code>…</code></pre>` with escaped entities.
33
+ * We unwrap that and decode entities back to raw source text.
34
+ */
35
+ const codeMacro = {
36
+ name: 'code',
37
+ render: (ctx) => {
38
+ const map = paramMap(ctx.params);
39
+ const params = ctx.params.filter((p) => ['language', 'title', 'linenumbers', 'collapse', 'firstline', 'theme'].includes(p.name));
40
+ void map;
41
+ return structuredMacro('code', ctx.macroId, {
42
+ params,
43
+ plainBody: extractPlainText(ctx.body),
44
+ });
45
+ },
46
+ };
47
+ /** Unwraps `<pre><code>…</code></pre>` / `<p>…</p>` and decodes HTML entities. */
48
+ export function extractPlainText(body) {
49
+ let text = body.trim();
50
+ const pre = text.match(/^<pre[^>]*><code[^>]*>([\s\S]*?)<\/code><\/pre>$/);
51
+ if (pre) {
52
+ text = pre[1].replace(/\n$/, '');
53
+ }
54
+ else {
55
+ const p = text.match(/^<p[^>]*>([\s\S]*?)<\/p>$/);
56
+ if (p)
57
+ text = p[1];
58
+ }
59
+ return text
60
+ .replace(/<br\s*\/?>/gi, '\n')
61
+ .replace(/&lt;/g, '<')
62
+ .replace(/&gt;/g, '>')
63
+ .replace(/&quot;/g, '"')
64
+ .replace(/&apos;/g, "'")
65
+ .replace(/&#39;/g, "'")
66
+ .replace(/&amp;/g, '&');
67
+ }
68
+ /** `anchor`: the anchor name goes into the unnamed (`""`) parameter. */
69
+ const anchorMacro = {
70
+ name: 'anchor',
71
+ render: (ctx) => {
72
+ const map = paramMap(ctx.params);
73
+ return structuredMacro('anchor', ctx.macroId, {
74
+ params: [{ name: '', value: map.name ?? '' }],
75
+ });
76
+ },
77
+ };
78
+ /** `include`: includes another page; page reference goes into the unnamed param as ac:link. */
79
+ const includeMacro = {
80
+ name: 'include',
81
+ render: (ctx) => {
82
+ const map = paramMap(ctx.params);
83
+ return structuredMacro('include', ctx.macroId, {
84
+ params: [{ name: '', value: pageLinkValue(map.page ?? '', map.space), raw: true }],
85
+ });
86
+ },
87
+ };
88
+ /** `excerpt-include`: transcludes a named excerpt from another page. */
89
+ const excerptIncludeMacro = {
90
+ name: 'excerpt-include',
91
+ render: (ctx) => {
92
+ const map = paramMap(ctx.params);
93
+ const params = [
94
+ { name: '', value: pageLinkValue(map.page ?? '', map.space), raw: true },
95
+ ];
96
+ if (map.nopanel)
97
+ params.push({ name: 'nopanel', value: map.nopanel });
98
+ return structuredMacro('excerpt-include', ctx.macroId, { params });
99
+ },
100
+ };
101
+ export const coreMacrosPlugin = {
102
+ name: 'core',
103
+ macros: [
104
+ // Rich-body containers
105
+ richBodyMacro('expand', ['title']),
106
+ richBodyMacro('note', ['title', 'icon']),
107
+ richBodyMacro('info', ['title', 'icon']),
108
+ richBodyMacro('warning', ['title', 'icon']),
109
+ richBodyMacro('tip', ['title', 'icon']),
110
+ richBodyMacro('panel'),
111
+ richBodyMacro('excerpt', ['hidden', 'atlassian-macro-output-type']),
112
+ // Plain-text body
113
+ codeMacro,
114
+ // Bodyless
115
+ bodylessMacro('toc'),
116
+ bodylessMacro('status'),
117
+ bodylessMacro('jira'),
118
+ bodylessMacro('children'),
119
+ bodylessMacro('pagetree'),
120
+ bodylessMacro('recently-updated'),
121
+ anchorMacro,
122
+ includeMacro,
123
+ excerptIncludeMacro,
124
+ ],
125
+ };
126
+ // ── Convenience builders (produce macro markers in Markdown) ────────────
127
+ /** Обёртывает markdown в макрос "развернуть". */
128
+ export function expand(body, title) {
129
+ const builder = macro('expand').body(body);
130
+ if (title)
131
+ builder.param('title', title);
132
+ return builder.toMarkdown();
133
+ }
134
+ function admonition(name) {
135
+ return (body, title) => {
136
+ const builder = macro(name).body(body);
137
+ if (title)
138
+ builder.param('title', title);
139
+ return builder.toMarkdown();
140
+ };
141
+ }
142
+ /** Обёртывает markdown в макрос "примечание". */
143
+ export const note = admonition('note');
144
+ /** Обёртывает markdown в макрос "информация". */
145
+ export const info = admonition('info');
146
+ /** Обёртывает markdown в макрос "предупреждение". */
147
+ export const warning = admonition('warning');
148
+ /** Обёртывает markdown в макрос "совет". */
149
+ export const tip = admonition('tip');
150
+ /** Обёртывает markdown в панель с произвольными параметрами (title, borderColor, bgColor, …). */
151
+ export function panel(body, opts = {}) {
152
+ return macro('panel').withParams(opts).body(body).toMarkdown();
153
+ }
154
+ /** Блок кода с подсветкой. Тело — сырой текст программы. */
155
+ export function codeBlock(source, opts = {}) {
156
+ const builder = macro('code');
157
+ if (opts.language)
158
+ builder.param('language', opts.language);
159
+ if (opts.title)
160
+ builder.param('title', opts.title);
161
+ if (opts.linenumbers)
162
+ builder.param('linenumbers', 'true');
163
+ if (opts.collapse)
164
+ builder.param('collapse', 'true');
165
+ // Тело оборачиваем в fenced block, чтобы markdown-it не тронул содержимое
166
+ // и code-renderer смог вытащить plain text из <pre><code>.
167
+ return builder.body('```\n' + source + '\n```').toMarkdown();
168
+ }
169
+ /** Статус-лейбл: status('Green', 'ON TRACK'). */
170
+ export function status(colour, title, subtle = false) {
171
+ const builder = macro('status').param('colour', colour).param('title', title);
172
+ if (subtle)
173
+ builder.param('subtle', 'true');
174
+ return builder.toMarkdown();
175
+ }
176
+ /** Оглавление страницы. Параметры — как у Confluence toc (maxLevel, minLevel, style, …). */
177
+ export function toc(opts = {}) {
178
+ return macro('toc').withParams(opts).toMarkdown();
179
+ }
180
+ /** Ссылка-карточка на задачу Jira по ключу. */
181
+ export function jiraIssue(key, opts = {}) {
182
+ return macro('jira').param('key', key).withParams(opts).toMarkdown();
183
+ }
184
+ /** Якорь для внутристраничных ссылок. */
185
+ export function anchor(name) {
186
+ return macro('anchor').param('name', name).toMarkdown();
187
+ }
188
+ /** Список дочерних страниц. */
189
+ export function children(opts = {}) {
190
+ return macro('children').withParams(opts).toMarkdown();
191
+ }
192
+ /** Включение другой страницы целиком. */
193
+ export function includePage(page, space) {
194
+ const builder = macro('include').param('page', page);
195
+ if (space)
196
+ builder.param('space', space);
197
+ return builder.toMarkdown();
198
+ }
199
+ /** Именованный excerpt (переиспользуемый фрагмент страницы). */
200
+ export function excerpt(body, hidden = false) {
201
+ const builder = macro('excerpt').body(body);
202
+ if (hidden)
203
+ builder.param('hidden', 'true');
204
+ return builder.toMarkdown();
205
+ }
206
+ /** Включение excerpt с другой страницы. */
207
+ export function excerptInclude(page, opts = {}) {
208
+ const builder = macro('excerpt-include').param('page', page);
209
+ if (opts.space)
210
+ builder.param('space', opts.space);
211
+ if (opts.nopanel)
212
+ builder.param('nopanel', 'true');
213
+ return builder.toMarkdown();
214
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Plugin for the "Table Filter and Charts for Confluence" app macros:
3
+ * table-excerpt, table-filter, table-excerpt-include.
4
+ */
5
+ import { Markdown } from '../../markdown/markdown.js';
6
+ import { type MacroPlugin } from '../types.js';
7
+ export declare const TABLE_FILTER_DEFAULTS: Record<string, string>;
8
+ export declare const tableFilterPlugin: MacroPlugin;
9
+ /**
10
+ * Обёртывает markdown в макрос "выборка таблицы".
11
+ *
12
+ * @example
13
+ * tableExcerpt(tableMarkdown, 'jira_fact', true)
14
+ */
15
+ export declare function tableExcerpt(body: Markdown | string, name?: string, hide?: boolean): Markdown;
16
+ /**
17
+ * Обёртывает markdown в макрос "фильтрация таблицы".
18
+ *
19
+ * Применяет полный набор дефолтов, какой Confluence-редактор сохраняет
20
+ * при создании макроса — в том числе пустые-присутствие параметры
21
+ * (`fixedCols`, `column`, etc). Без них макрос рендерит контролы как
22
+ * отдельную панель НАД таблицей; с дефолтом `hidePane=Table header`
23
+ * фильтры встают в шапку колонок. Caller перекрывает что нужно через
24
+ * `opts` (например `totalrow`); пустая строка в opts означает «оставить
25
+ * как пустое-присутствие», не удаление.
26
+ *
27
+ * @example
28
+ * tableFilter(tableExcerptMd, { totalrow: ',,,Sum,Sum,Sum' })
29
+ */
30
+ export declare function tableFilter(body: Markdown | string, opts?: Record<string, string | undefined>): Markdown;
31
+ /** Включение table-excerpt с другой страницы по имени выборки. */
32
+ export declare function tableExcerptInclude(name: string, page: string, opts?: {
33
+ space?: string;
34
+ type?: string;
35
+ }): Markdown;
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Plugin for the "Table Filter and Charts for Confluence" app macros:
3
+ * table-excerpt, table-filter, table-excerpt-include.
4
+ */
5
+ import { macro } from '../builder.js';
6
+ import { paramMap } from '../types.js';
7
+ import { pageLinkValue, structuredMacro } from '../xml.js';
8
+ // Дефолты table-filter из Confluence-редактора (нашли реверсом).
9
+ // Особенно важен hidePane=Table header — без него фильтры рендерятся
10
+ // отдельной панелью НАД таблицей; с ним — встают в шапку колонок.
11
+ // Пустые-присутствие нужны, чтобы редактор не «потерял» эти контролы
12
+ // при следующем открытии и сохранении страницы.
13
+ export const TABLE_FILTER_DEFAULTS = {
14
+ hidelabels: 'false',
15
+ sparkName: 'Sparkline',
16
+ hidePane: 'Table header',
17
+ sparkline: 'false',
18
+ isFirstTimeEnter: 'true',
19
+ hideColumns: 'false',
20
+ customNoTableMsg: 'false',
21
+ disabled: 'false',
22
+ enabledInEditor: 'false',
23
+ globalFilter: 'false',
24
+ hideControls: 'false',
25
+ numbering: 'Dynamic Ascending',
26
+ disableSave: 'false',
27
+ separator: 'Point (.)',
28
+ datepattern: "d M yy 'г'.",
29
+ updateSelectOptions: 'false',
30
+ worklog: '365|5|8|y w d h m|y w d h m',
31
+ isOR: 'AND',
32
+ fixedCols: '',
33
+ ddSeparator: '',
34
+ customNoTableMsgText: '',
35
+ limitHeight: '',
36
+ default: '',
37
+ 'cell-width': '',
38
+ totalRowName: '',
39
+ totalColName: '',
40
+ iconfilter: '',
41
+ order: '',
42
+ inverse: '',
43
+ datefilter: '',
44
+ column: '',
45
+ sort: '',
46
+ totalcol: '',
47
+ rowsPerPage: '',
48
+ labels: '',
49
+ thousandSeparator: '',
50
+ ignoreFirstNrows: '',
51
+ ddOperator: '',
52
+ userfilter: '',
53
+ numberfilter: '',
54
+ heightValue: '',
55
+ hideFilters: '',
56
+ showNRowsifNotFiltered: '',
57
+ };
58
+ export const tableFilterPlugin = {
59
+ name: 'table-filter',
60
+ macros: [
61
+ {
62
+ // Макрос "Выборка таблицы" (table-excerpt).
63
+ // Параметры: name — название выборки; hide — скрывать ли содержимое.
64
+ name: 'table-excerpt',
65
+ render: (ctx) => {
66
+ const map = paramMap(ctx.params);
67
+ const params = [];
68
+ if (map.hide === 'true')
69
+ params.push({ name: 'hide', value: 'true' });
70
+ if (map.name)
71
+ params.push({ name: 'name', value: map.name });
72
+ return structuredMacro('table-excerpt', ctx.macroId, { params, richBody: ctx.body });
73
+ },
74
+ },
75
+ {
76
+ // Макрос "Фильтрация таблицы" (table-filter). Оборачивает контент
77
+ // (обычно table-excerpt с готовой таблицей) в Confluence-фильтр.
78
+ // Все ключи параметров пробрасываются как есть — Confluence для
79
+ // не указанных применяет дефолты. Часто используемые:
80
+ // - totalrow: ",,,Sum,Sum,…" — операции по колонкам (пустое — пропуск).
81
+ // - numbering: "Dynamic Ascending" — нумерация строк.
82
+ // - separator: "Point (.)" / "Comma (,)" — десятичный разделитель.
83
+ // - hideControls / hidelabels / globalFilter: "true" / "false".
84
+ // - totalRowName: подпись строки итогов.
85
+ name: 'table-filter',
86
+ render: (ctx) => structuredMacro('table-filter', ctx.macroId, {
87
+ params: ctx.params,
88
+ richBody: ctx.body,
89
+ }),
90
+ },
91
+ {
92
+ // Включение table-excerpt с другой страницы.
93
+ name: 'table-excerpt-include',
94
+ render: (ctx) => {
95
+ const map = paramMap(ctx.params);
96
+ const params = [
97
+ { name: 'name', value: map.name ?? '' },
98
+ { name: 'page', value: pageLinkValue(map.page ?? '', map.space), raw: true },
99
+ { name: 'type', value: map.type ?? 'page' },
100
+ ];
101
+ return structuredMacro('table-excerpt-include', ctx.macroId, { params });
102
+ },
103
+ },
104
+ ],
105
+ };
106
+ // ── Convenience builders ────────────────────────────────────────────────
107
+ /**
108
+ * Обёртывает markdown в макрос "выборка таблицы".
109
+ *
110
+ * @example
111
+ * tableExcerpt(tableMarkdown, 'jira_fact', true)
112
+ */
113
+ export function tableExcerpt(body, name, hide) {
114
+ const builder = macro('table-excerpt').body(body);
115
+ if (name)
116
+ builder.param('name', name);
117
+ if (hide)
118
+ builder.param('hide', 'true');
119
+ return builder.toMarkdown();
120
+ }
121
+ /**
122
+ * Обёртывает markdown в макрос "фильтрация таблицы".
123
+ *
124
+ * Применяет полный набор дефолтов, какой Confluence-редактор сохраняет
125
+ * при создании макроса — в том числе пустые-присутствие параметры
126
+ * (`fixedCols`, `column`, etc). Без них макрос рендерит контролы как
127
+ * отдельную панель НАД таблицей; с дефолтом `hidePane=Table header`
128
+ * фильтры встают в шапку колонок. Caller перекрывает что нужно через
129
+ * `opts` (например `totalrow`); пустая строка в opts означает «оставить
130
+ * как пустое-присутствие», не удаление.
131
+ *
132
+ * @example
133
+ * tableFilter(tableExcerptMd, { totalrow: ',,,Sum,Sum,Sum' })
134
+ */
135
+ export function tableFilter(body, opts = {}) {
136
+ const merged = { ...TABLE_FILTER_DEFAULTS };
137
+ for (const [k, v] of Object.entries(opts)) {
138
+ if (v !== undefined)
139
+ merged[k] = v;
140
+ }
141
+ const builder = macro('table-filter').body(body);
142
+ for (const [k, v] of Object.entries(merged)) {
143
+ builder.param(k, v);
144
+ }
145
+ return builder.toMarkdown();
146
+ }
147
+ /** Включение table-excerpt с другой страницы по имени выборки. */
148
+ export function tableExcerptInclude(name, page, opts = {}) {
149
+ const builder = macro('table-excerpt-include').param('name', name).param('page', page);
150
+ if (opts.space)
151
+ builder.param('space', opts.space);
152
+ if (opts.type)
153
+ builder.param('type', opts.type);
154
+ return builder.toMarkdown();
155
+ }
@@ -0,0 +1,29 @@
1
+ import { Markdown } from '../markdown/markdown.js';
2
+ import type { MacroPlugin, MacroRenderer } from './types.js';
3
+ /**
4
+ * Реестр макросов. Пустой при создании — наполняется плагинами через
5
+ * {@link use} или точечной регистрацией через {@link register}.
6
+ *
7
+ * @example
8
+ * const registry = new MacroRegistry()
9
+ * .use(coreMacrosPlugin)
10
+ * .use(tableFilterPlugin)
11
+ * .register('my-macro', (ctx) => `<ac:structured-macro ...>`);
12
+ */
13
+ export declare class MacroRegistry {
14
+ private renderers;
15
+ private pluginNames;
16
+ /** Registers all macros of a plugin. Later registrations win on name clash. */
17
+ use(plugin: MacroPlugin): this;
18
+ register(name: string, renderer: MacroRenderer): this;
19
+ has(name: string): boolean;
20
+ getRenderer(name: string): MacroRenderer | undefined;
21
+ getAllRenderers(): Map<string, MacroRenderer>;
22
+ /** Names of plugins registered via {@link use} (for diagnostics). */
23
+ get plugins(): string[];
24
+ }
25
+ /**
26
+ * Преобразует маркеры макросов в XHTML storage format.
27
+ * Обрабатывает вложенные макросы снизу вверх (от inner к outer).
28
+ */
29
+ export declare function processMacros(storage: Markdown | string, registry: MacroRegistry): Markdown;