@diplodoc/transform 4.77.15 → 4.78.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/lib/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type Token from 'markdown-it/lib/token';
2
2
  import type { OptionsType, OutputType } from './typings';
3
+ import type { ContentAudience as VisibilityContentAudience, VisibilityMode as VisibilityContentMode } from './plugins/visibility';
3
4
  type TokensOptionsType = OptionsType & {
4
5
  tokens: true;
5
6
  };
@@ -9,4 +10,6 @@ export = transform;
9
10
  declare namespace transform {
10
11
  type Options = OptionsType;
11
12
  type Output = OutputType;
13
+ type ContentAudience = VisibilityContentAudience;
14
+ type VisibilityMode = VisibilityContentMode;
12
15
  }
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/transform/index.ts"],"names":[],"mappings":";;;;AAGA,iCAA2B;AAE3B,+BAA0B;AAC1B,sDAAsC;AACtC,8CAAkC;AAElC,SAAS,WAAW,CAAC,KAAa,EAAE,OAAoB;IACpD,MAAM,EACF,IAAI,GAAG,EAAE,EACT,IAAI,EACJ,gBAAgB,GAAG,KAAK,EACxB,aAAa,GAAG,KAAK,EACrB,UAAU,GAAG,KAAK,GACrB,GAAG,OAAO,CAAC;IAEZ,OAAO,aAAa,IAAI,UAAU;QAC9B,CAAC,CAAC,KAAK;QACP,CAAC,CAAC,IAAA,gBAAc,EAAC,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,EAAC,gBAAgB,EAAC,CAAC,CAAC;AAChE,CAAC;AAED,SAAS,WAAW,CAAC,KAAc,EAAE,IAAa;IAC9C,SAAG,CAAC,KAAK,CAAC,iBAAiB,IAAI,CAAC,CAAC,CAAC,OAAO,IAAA,YAAI,EAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAE9D,MAAM,KAAK,CAAC;AAChB,CAAC;AAED,SAAS,UAAU,CAAC,IAAY,EAAE,GAAY;IAC1C,OAAO;QACH,MAAM,EAAE,EAAC,GAAG,GAAG,EAAE,IAAI,EAAC;QACtB,IAAI,EAAE,SAAG,CAAC,GAAG,EAAE;KAClB,CAAC;AACN,CAAC;AAMD,SAAS,SAAS,CAAC,WAAmB,EAAE,UAAuB,EAAE;IAC7D,MAAM,KAAK,GAAG,WAAW,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAChD,MAAM,EAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAC,GAAG,IAAA,YAAc,EAAC,OAAO,CAAC,CAAC;IAEtD,IAAI,CAAC;QACD,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;QAC5B,IAAI,OAAO,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;YAC1B,OAAO,MAAM,CAAC;QAClB,CAAC;QACD,OAAO,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,CAAC;IAC5C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC;AACL,CAAC;AAED,iBAAS,SAAS,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/transform/index.ts"],"names":[],"mappings":";;;;AAOA,iCAA2B;AAE3B,+BAA0B;AAC1B,sDAAsC;AACtC,8CAAkC;AAElC,SAAS,WAAW,CAAC,KAAa,EAAE,OAAoB;IACpD,MAAM,EACF,IAAI,GAAG,EAAE,EACT,IAAI,EACJ,gBAAgB,GAAG,KAAK,EACxB,aAAa,GAAG,KAAK,EACrB,UAAU,GAAG,KAAK,GACrB,GAAG,OAAO,CAAC;IAEZ,OAAO,aAAa,IAAI,UAAU;QAC9B,CAAC,CAAC,KAAK;QACP,CAAC,CAAC,IAAA,gBAAc,EAAC,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,EAAC,gBAAgB,EAAC,CAAC,CAAC;AAChE,CAAC;AAED,SAAS,WAAW,CAAC,KAAc,EAAE,IAAa;IAC9C,SAAG,CAAC,KAAK,CAAC,iBAAiB,IAAI,CAAC,CAAC,CAAC,OAAO,IAAA,YAAI,EAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAE9D,MAAM,KAAK,CAAC;AAChB,CAAC;AAED,SAAS,UAAU,CAAC,IAAY,EAAE,GAAY;IAC1C,OAAO;QACH,MAAM,EAAE,EAAC,GAAG,GAAG,EAAE,IAAI,EAAC;QACtB,IAAI,EAAE,SAAG,CAAC,GAAG,EAAE;KAClB,CAAC;AACN,CAAC;AAMD,SAAS,SAAS,CAAC,WAAmB,EAAE,UAAuB,EAAE;IAC7D,MAAM,KAAK,GAAG,WAAW,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAChD,MAAM,EAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAC,GAAG,IAAA,YAAc,EAAC,OAAO,CAAC,CAAC;IAEtD,IAAI,CAAC;QACD,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;QAC5B,IAAI,OAAO,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;YAC1B,OAAO,MAAM,CAAC;QAClB,CAAC;QACD,OAAO,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,CAAC;IAC5C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC;AACL,CAAC;AAED,iBAAS,SAAS,CAAC"}
@@ -0,0 +1,42 @@
1
+ import type MarkdownIt from 'markdown-it';
2
+ import type { MarkdownItPluginCb } from './typings';
3
+ export type ContentAudience = 'human' | 'agent';
4
+ export type VisibilityMode = ContentAudience | 'preserve';
5
+ export interface VisibilityError {
6
+ line: number;
7
+ value: string;
8
+ message: string;
9
+ }
10
+ export interface VisibilityOptions {
11
+ audience?: VisibilityMode;
12
+ lint?: boolean;
13
+ onError?: (error: VisibilityError) => void;
14
+ }
15
+ export interface AudienceFilterResult {
16
+ content: string;
17
+ audienceSpecificContent: ContentAudience[];
18
+ originalCharacters: number;
19
+ filteredCharacters: number;
20
+ removedCharacters: number;
21
+ errors: VisibilityError[];
22
+ }
23
+ /**
24
+ * Creates the audience visibility directive plugin.
25
+ *
26
+ * The `preserve` mode tokenizes both audiences without rendering the directive wrapper. It is
27
+ * intended for source-aware consumers such as the translation pipeline, which retain untouched
28
+ * source ranges around the emitted content tokens.
29
+ *
30
+ * @returns Markdown-it plugin for audience visibility blocks.
31
+ */
32
+ export declare function visibility({ audience, lint, onError, }?: VisibilityOptions): MarkdownIt.PluginSimple;
33
+ /**
34
+ * Filters Markdown source for one content audience while preserving all unrelated source text.
35
+ *
36
+ * @param markdown Markdown source to filter.
37
+ * @param audience Audience whose content should be retained.
38
+ * @returns Filtered source, detected audiences, diagnostics, and character counts.
39
+ */
40
+ export declare function filterAudienceContent(markdown: string, audience: ContentAudience): AudienceFilterResult;
41
+ declare const visibilityPlugin: MarkdownItPluginCb;
42
+ export default visibilityPlugin;
@@ -0,0 +1,194 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.visibility = visibility;
7
+ exports.filterAudienceContent = filterAudienceContent;
8
+ const markdown_it_1 = __importDefault(require("markdown-it"));
9
+ const directive_1 = require("@diplodoc/directive");
10
+ const AUDIENCE_ORDER = ['human', 'agent'];
11
+ const VISIBILITY_DIRECTIVE_REGEXP = /:{3,}[ \t]*visibility/i;
12
+ function parseAudience(value = '') {
13
+ return value === 'human' || value === 'agent' ? value : undefined;
14
+ }
15
+ function createVisibilityError(value, line) {
16
+ const printableValue = value || '<empty>';
17
+ return {
18
+ line,
19
+ value,
20
+ message: `Invalid visibility audience "${printableValue}" at line ${line}; expected "human" or "agent"`,
21
+ };
22
+ }
23
+ function addAudience(target, audience) {
24
+ target.add(audience);
25
+ }
26
+ function orderedAudiences(audiences) {
27
+ const values = new Set(audiences);
28
+ return AUDIENCE_ORDER.filter((audience) => values.has(audience));
29
+ }
30
+ function markAudience(state, audience) {
31
+ var _a;
32
+ if (!state.env.meta || typeof state.env.meta !== 'object' || Array.isArray(state.env.meta)) {
33
+ state.env.meta = {};
34
+ }
35
+ const meta = state.env.meta;
36
+ meta.visibilityAudiences = orderedAudiences([...((_a = meta.visibilityAudiences) !== null && _a !== void 0 ? _a : []), audience]);
37
+ }
38
+ function emitLintToken(state, params, audience) {
39
+ var _a, _b;
40
+ const token = state.push('__yfm_lint', '', 0);
41
+ token.hidden = true;
42
+ token.map = [params.startLine, params.startLine + 1];
43
+ token.attrSet('visibility-directive', 'true');
44
+ token.attrSet('visibility-audience', (_b = (_a = params.contentTitle) === null || _a === void 0 ? void 0 : _a.raw) !== null && _b !== void 0 ? _b : '');
45
+ token.attrSet('YFM023', audience ? 'valid' : 'invalid');
46
+ }
47
+ /**
48
+ * Creates the audience visibility directive plugin.
49
+ *
50
+ * The `preserve` mode tokenizes both audiences without rendering the directive wrapper. It is
51
+ * intended for source-aware consumers such as the translation pipeline, which retain untouched
52
+ * source ranges around the emitted content tokens.
53
+ *
54
+ * @returns Markdown-it plugin for audience visibility blocks.
55
+ */
56
+ function visibility({ audience = 'human', lint = false, onError, } = {}) {
57
+ return (md) => {
58
+ md.use((0, directive_1.directiveParser)());
59
+ if (lint) {
60
+ md.core.ruler.before('block', 'visibility-lint-mode', (state) => {
61
+ const token = new state.Token('__yfm_lint', '', 0);
62
+ token.hidden = true;
63
+ token.attrSet('visibility-parser', 'true');
64
+ state.tokens.push(token);
65
+ });
66
+ }
67
+ (0, directive_1.registerContainerDirective)(md, 'visibility', (state, params) => {
68
+ var _a, _b;
69
+ const rawAudience = (_b = (_a = params.contentTitle) === null || _a === void 0 ? void 0 : _a.raw) !== null && _b !== void 0 ? _b : '';
70
+ const blockAudience = parseAudience(rawAudience);
71
+ if (lint) {
72
+ emitLintToken(state, params, blockAudience);
73
+ }
74
+ if (!blockAudience) {
75
+ onError === null || onError === void 0 ? void 0 : onError(createVisibilityError(rawAudience, params.startLine + 1));
76
+ if (audience === 'preserve') {
77
+ (0, directive_1.tokenizeBlockContent)(state, params.content, 'visibility-directive');
78
+ }
79
+ return true;
80
+ }
81
+ markAudience(state, blockAudience);
82
+ if (audience === 'preserve' || audience === blockAudience) {
83
+ (0, directive_1.tokenizeBlockContent)(state, params.content, 'visibility-directive');
84
+ }
85
+ return true;
86
+ });
87
+ };
88
+ }
89
+ function splitLines(content) {
90
+ var _a;
91
+ return (_a = content.match(/[^\r\n]*(?:\r\n|\n|\r)|[^\r\n]+$/g)) !== null && _a !== void 0 ? _a : [];
92
+ }
93
+ function nestBlocks(blocks) {
94
+ const roots = [];
95
+ const stack = [];
96
+ for (const block of blocks.sort((left, right) => {
97
+ const startDiff = left.params.startLine - right.params.startLine;
98
+ return startDiff || right.params.endLine - left.params.endLine;
99
+ })) {
100
+ while (stack.length &&
101
+ block.params.startLine >= stack[stack.length - 1].params.content.endLine) {
102
+ stack.pop();
103
+ }
104
+ const parent = stack[stack.length - 1];
105
+ if (parent && block.params.endLine <= parent.params.content.endLine) {
106
+ parent.children.push(block);
107
+ }
108
+ else {
109
+ roots.push(block);
110
+ }
111
+ stack.push(block);
112
+ }
113
+ return roots;
114
+ }
115
+ function filterRange(lines, startLine, endLine, blocks, selectedAudience) {
116
+ const parts = [];
117
+ let cursorLine = startLine;
118
+ for (const block of blocks) {
119
+ const { params, audience } = block;
120
+ parts.push(lines.slice(cursorLine, params.startLine).join(''));
121
+ const filteredBody = filterRange(lines, params.content.startLine, params.content.endLine, block.children, selectedAudience);
122
+ if (audience === selectedAudience) {
123
+ parts.push(filteredBody);
124
+ }
125
+ cursorLine = params.endLine;
126
+ }
127
+ parts.push(lines.slice(cursorLine, endLine).join(''));
128
+ return parts.join('');
129
+ }
130
+ /**
131
+ * Filters Markdown source for one content audience while preserving all unrelated source text.
132
+ *
133
+ * @param markdown Markdown source to filter.
134
+ * @param audience Audience whose content should be retained.
135
+ * @returns Filtered source, detected audiences, diagnostics, and character counts.
136
+ */
137
+ function filterAudienceContent(markdown, audience) {
138
+ const originalCharacters = Array.from(markdown).length;
139
+ if (!VISIBILITY_DIRECTIVE_REGEXP.test(markdown)) {
140
+ return {
141
+ content: markdown,
142
+ audienceSpecificContent: [],
143
+ originalCharacters,
144
+ filteredCharacters: originalCharacters,
145
+ removedCharacters: 0,
146
+ errors: [],
147
+ };
148
+ }
149
+ const detectedAudiences = new Set();
150
+ const errors = [];
151
+ const blocks = [];
152
+ const md = new markdown_it_1.default({ html: true }).use((0, directive_1.directiveParser)());
153
+ (0, directive_1.registerContainerDirective)(md, 'visibility', (state, params) => {
154
+ var _a, _b;
155
+ const rawAudience = (_b = (_a = params.contentTitle) === null || _a === void 0 ? void 0 : _a.raw) !== null && _b !== void 0 ? _b : '';
156
+ const blockAudience = parseAudience(rawAudience);
157
+ blocks.push({ audience: blockAudience, params, children: [] });
158
+ if (blockAudience) {
159
+ addAudience(detectedAudiences, blockAudience);
160
+ }
161
+ else {
162
+ errors.push(createVisibilityError(rawAudience, params.startLine + 1));
163
+ }
164
+ // Parse nested directives in the original block state. Their line maps remain relative to
165
+ // the complete source, so reconstruction below can preserve list indentation exactly.
166
+ (0, directive_1.tokenizeBlockContent)(state, params.content, 'visibility-directive');
167
+ return true;
168
+ });
169
+ md.parse(markdown, {});
170
+ const lines = splitLines(markdown);
171
+ const content = filterRange(lines, 0, lines.length, nestBlocks(blocks), audience);
172
+ const filteredCharacters = Array.from(content).length;
173
+ return {
174
+ content,
175
+ audienceSpecificContent: orderedAudiences(detectedAudiences),
176
+ originalCharacters,
177
+ filteredCharacters,
178
+ removedCharacters: originalCharacters - filteredCharacters,
179
+ errors,
180
+ };
181
+ }
182
+ const visibilityPlugin = (md, options) => {
183
+ var _a;
184
+ const lint = options.isLintRun;
185
+ md.use(visibility({
186
+ audience: lint ? 'preserve' : ((_a = options.contentAudience) !== null && _a !== void 0 ? _a : 'human'),
187
+ lint,
188
+ onError: lint
189
+ ? undefined
190
+ : (error) => options.log.error(`${error.message}${options.path ? ` in ${options.path}` : ''}`),
191
+ }));
192
+ };
193
+ exports.default = visibilityPlugin;
194
+ //# sourceMappingURL=visibility.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visibility.js","sourceRoot":"","sources":["../../src/transform/plugins/visibility.ts"],"names":[],"mappings":";;;;;AAqGA,gCAwCC;AAsED,sDAmDC;AAjQD,8DAAyC;AACzC,mDAI6B;AAoC7B,MAAM,cAAc,GAAsB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AAC7D,MAAM,2BAA2B,GAAG,wBAAwB,CAAC;AAE7D,SAAS,aAAa,CAAC,KAAK,GAAG,EAAE;IAC7B,OAAO,KAAK,KAAK,OAAO,IAAI,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACtE,CAAC;AAED,SAAS,qBAAqB,CAAC,KAAa,EAAE,IAAY;IACtD,MAAM,cAAc,GAAG,KAAK,IAAI,SAAS,CAAC;IAC1C,OAAO;QACH,IAAI;QACJ,KAAK;QACL,OAAO,EAAE,gCAAgC,cAAc,aAAa,IAAI,+BAA+B;KAC1G,CAAC;AACN,CAAC;AAED,SAAS,WAAW,CAAC,MAA4B,EAAE,QAAyB;IACxE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AACzB,CAAC;AAED,SAAS,gBAAgB,CAAC,SAAoC;IAC1D,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC;IAClC,OAAO,cAAc,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;AACrE,CAAC;AAED,SAAS,YAAY,CAAC,KAAiB,EAAE,QAAyB;;IAC9D,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,IAAI,OAAO,KAAK,CAAC,GAAG,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;QACzF,KAAK,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC;IACxB,CAAC;IACD,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,IAAsB,CAAC;IAC9C,IAAI,CAAC,mBAAmB,GAAG,gBAAgB,CAAC,CAAC,GAAG,CAAC,MAAA,IAAI,CAAC,mBAAmB,mCAAI,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC;AACjG,CAAC;AAED,SAAS,aAAa,CAClB,KAAiB,EACjB,MAAgC,EAChC,QAAqC;;IAErC,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;IAC9C,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC;IACpB,KAAK,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC;IACrD,KAAK,CAAC,OAAO,CAAC,sBAAsB,EAAE,MAAM,CAAC,CAAC;IAC9C,KAAK,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAA,MAAA,MAAM,CAAC,YAAY,0CAAE,GAAG,mCAAI,EAAE,CAAC,CAAC;IACrE,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;AAC5D,CAAC;AAED;;;;;;;;GAQG;AACH,SAAgB,UAAU,CAAC,EACvB,QAAQ,GAAG,OAAO,EAClB,IAAI,GAAG,KAAK,EACZ,OAAO,MACY,EAAE;IACrB,OAAO,CAAC,EAAE,EAAE,EAAE;QACV,EAAE,CAAC,GAAG,CAAC,IAAA,2BAAe,GAAE,CAAC,CAAC;QAC1B,IAAI,IAAI,EAAE,CAAC;YACP,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,sBAAsB,EAAE,CAAC,KAAK,EAAE,EAAE;gBAC5D,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,KAAK,CAAC,YAAY,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;gBACnD,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC;gBACpB,KAAK,CAAC,OAAO,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAC;gBAC3C,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC7B,CAAC,CAAC,CAAC;QACP,CAAC;QACD,IAAA,sCAA0B,EAAC,EAAE,EAAE,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;;YAC3D,MAAM,WAAW,GAAG,MAAA,MAAA,MAAM,CAAC,YAAY,0CAAE,GAAG,mCAAI,EAAE,CAAC;YACnD,MAAM,aAAa,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC;YAEjD,IAAI,IAAI,EAAE,CAAC;gBACP,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC;YAChD,CAAC;YAED,IAAI,CAAC,aAAa,EAAE,CAAC;gBACjB,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAG,qBAAqB,CAAC,WAAW,EAAE,MAAM,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC;gBACpE,IAAI,QAAQ,KAAK,UAAU,EAAE,CAAC;oBAC1B,IAAA,gCAAoB,EAAC,KAAK,EAAE,MAAM,CAAC,OAAO,EAAE,sBAAsB,CAAC,CAAC;gBACxE,CAAC;gBACD,OAAO,IAAI,CAAC;YAChB,CAAC;YAED,YAAY,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;YAEnC,IAAI,QAAQ,KAAK,UAAU,IAAI,QAAQ,KAAK,aAAa,EAAE,CAAC;gBACxD,IAAA,gCAAoB,EAAC,KAAK,EAAE,MAAM,CAAC,OAAO,EAAE,sBAAsB,CAAC,CAAC;YACxE,CAAC;YAED,OAAO,IAAI,CAAC;QAChB,CAAC,CAAC,CAAC;IACP,CAAC,CAAC;AACN,CAAC;AAED,SAAS,UAAU,CAAC,OAAe;;IAC/B,OAAO,MAAA,OAAO,CAAC,KAAK,CAAC,mCAAmC,CAAC,mCAAI,EAAE,CAAC;AACpE,CAAC;AAED,SAAS,UAAU,CAAC,MAAyB;IACzC,MAAM,KAAK,GAAsB,EAAE,CAAC;IACpC,MAAM,KAAK,GAAsB,EAAE,CAAC;IAEpC,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QAC5C,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC;QACjE,OAAO,SAAS,IAAI,KAAK,CAAC,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC;IACnE,CAAC,CAAC,EAAE,CAAC;QACD,OACI,KAAK,CAAC,MAAM;YACZ,KAAK,CAAC,MAAM,CAAC,SAAS,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,EAC1E,CAAC;YACC,KAAK,CAAC,GAAG,EAAE,CAAC;QAChB,CAAC;QAED,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACvC,IAAI,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;YAClE,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChC,CAAC;aAAM,CAAC;YACJ,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACtB,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;IAED,OAAO,KAAK,CAAC;AACjB,CAAC;AAED,SAAS,WAAW,CAChB,KAAe,EACf,SAAiB,EACjB,OAAe,EACf,MAAyB,EACzB,gBAAiC;IAEjC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,UAAU,GAAG,SAAS,CAAC;IAE3B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QACzB,MAAM,EAAC,MAAM,EAAE,QAAQ,EAAC,GAAG,KAAK,CAAC;QACjC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;QAC/D,MAAM,YAAY,GAAG,WAAW,CAC5B,KAAK,EACL,MAAM,CAAC,OAAO,CAAC,SAAS,EACxB,MAAM,CAAC,OAAO,CAAC,OAAO,EACtB,KAAK,CAAC,QAAQ,EACd,gBAAgB,CACnB,CAAC;QACF,IAAI,QAAQ,KAAK,gBAAgB,EAAE,CAAC;YAChC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC7B,CAAC;QACD,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC;IAChC,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IACtD,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAC1B,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,qBAAqB,CACjC,QAAgB,EAChB,QAAyB;IAEzB,MAAM,kBAAkB,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC;IACvD,IAAI,CAAC,2BAA2B,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC9C,OAAO;YACH,OAAO,EAAE,QAAQ;YACjB,uBAAuB,EAAE,EAAE;YAC3B,kBAAkB;YAClB,kBAAkB,EAAE,kBAAkB;YACtC,iBAAiB,EAAE,CAAC;YACpB,MAAM,EAAE,EAAE;SACb,CAAC;IACN,CAAC;IAED,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAAmB,CAAC;IACrD,MAAM,MAAM,GAAsB,EAAE,CAAC;IACrC,MAAM,MAAM,GAAsB,EAAE,CAAC;IACrC,MAAM,EAAE,GAAG,IAAI,qBAAc,CAAC,EAAC,IAAI,EAAE,IAAI,EAAC,CAAC,CAAC,GAAG,CAAC,IAAA,2BAAe,GAAE,CAAC,CAAC;IAEnE,IAAA,sCAA0B,EAAC,EAAE,EAAE,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;;QAC3D,MAAM,WAAW,GAAG,MAAA,MAAA,MAAM,CAAC,YAAY,0CAAE,GAAG,mCAAI,EAAE,CAAC;QACnD,MAAM,aAAa,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC;QACjD,MAAM,CAAC,IAAI,CAAC,EAAC,QAAQ,EAAE,aAAa,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,EAAC,CAAC,CAAC;QAE7D,IAAI,aAAa,EAAE,CAAC;YAChB,WAAW,CAAC,iBAAiB,EAAE,aAAa,CAAC,CAAC;QAClD,CAAC;aAAM,CAAC;YACJ,MAAM,CAAC,IAAI,CAAC,qBAAqB,CAAC,WAAW,EAAE,MAAM,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC;QAC1E,CAAC;QAED,0FAA0F;QAC1F,sFAAsF;QACtF,IAAA,gCAAoB,EAAC,KAAK,EAAE,MAAM,CAAC,OAAO,EAAE,sBAAsB,CAAC,CAAC;QACpE,OAAO,IAAI,CAAC;IAChB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IACvB,MAAM,KAAK,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;IACnC,MAAM,OAAO,GAAG,WAAW,CAAC,KAAK,EAAE,CAAC,EAAE,KAAK,CAAC,MAAM,EAAE,UAAU,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,CAAC;IAClF,MAAM,kBAAkB,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;IAEtD,OAAO;QACH,OAAO;QACP,uBAAuB,EAAE,gBAAgB,CAAC,iBAAiB,CAAC;QAC5D,kBAAkB;QAClB,kBAAkB;QAClB,iBAAiB,EAAE,kBAAkB,GAAG,kBAAkB;QAC1D,MAAM;KACT,CAAC;AACN,CAAC;AAED,MAAM,gBAAgB,GAAuB,CAAC,EAAE,EAAE,OAAO,EAAE,EAAE;;IACzD,MAAM,IAAI,GAAG,OAAO,CAAC,SAAS,CAAC;IAC/B,EAAE,CAAC,GAAG,CACF,UAAU,CAAC;QACP,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,MAAA,OAAO,CAAC,eAAe,mCAAI,OAAO,CAAC;QAClE,IAAI;QACJ,OAAO,EAAE,IAAI;YACT,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,CACN,OAAO,CAAC,GAAG,CAAC,KAAK,CACb,GAAG,KAAK,CAAC,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CACjE;KACd,CAAC,CACL,CAAC;AACN,CAAC,CAAC;AAEF,kBAAe,gBAAgB,CAAC"}
package/lib/plugins.js CHANGED
@@ -18,6 +18,7 @@ const imsize_1 = __importDefault(require("./plugins/imsize"));
18
18
  const term_1 = __importDefault(require("./plugins/term"));
19
19
  const block_anchor_1 = __importDefault(require("./plugins/block-anchor"));
20
20
  const inline_code_1 = __importDefault(require("./plugins/inline-code"));
21
+ const visibility_1 = __importDefault(require("./plugins/visibility"));
21
22
  const defaultPlugins = [
22
23
  meta_1.default,
23
24
  deflist_1.default,
@@ -35,6 +36,7 @@ const defaultPlugins = [
35
36
  term_1.default,
36
37
  block_anchor_1.default,
37
38
  inline_code_1.default,
39
+ visibility_1.default,
38
40
  ];
39
41
  module.exports = defaultPlugins;
40
42
  //# sourceMappingURL=plugins.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"plugins.js","sourceRoot":"","sources":["../src/transform/plugins.ts"],"names":[],"mappings":";;;;AAEA,0DAAkC;AAClC,gEAAwC;AACxC,wDAAgC;AAChC,4DAAoC;AACpC,gEAAwC;AACxC,0DAAkC;AAClC,0DAAkC;AAClC,wDAAgC;AAChC,4DAAoC;AACpC,oEAA4C;AAC5C,4DAAuC;AACvC,0DAAkC;AAClC,8DAAsC;AACtC,0DAAkC;AAClC,0EAAiD;AACjD,wEAA+C;AAE/C,MAAM,cAAc,GAAG;IACnB,cAAI;IACJ,iBAAO;IACP,aAAG;IACH,eAAK;IACL,iBAAO;IACP,cAAI;IACJ,cAAI;IACJ,aAAG;IACH,eAAK;IACL,mBAAS;IACT,eAAQ;IACR,cAAI;IACJ,gBAAM;IACN,cAAI;IACJ,sBAAW;IACX,qBAAU;CACW,CAAC;AAE1B,iBAAS,cAAc,CAAC"}
1
+ {"version":3,"file":"plugins.js","sourceRoot":"","sources":["../src/transform/plugins.ts"],"names":[],"mappings":";;;;AAEA,0DAAkC;AAClC,gEAAwC;AACxC,wDAAgC;AAChC,4DAAoC;AACpC,gEAAwC;AACxC,0DAAkC;AAClC,0DAAkC;AAClC,wDAAgC;AAChC,4DAAoC;AACpC,oEAA4C;AAC5C,4DAAuC;AACvC,0DAAkC;AAClC,8DAAsC;AACtC,0DAAkC;AAClC,0EAAiD;AACjD,wEAA+C;AAC/C,sEAA8C;AAE9C,MAAM,cAAc,GAAG;IACnB,cAAI;IACJ,iBAAO;IACP,aAAG;IACH,eAAK;IACL,iBAAO;IACP,cAAI;IACJ,cAAI;IACJ,aAAG;IACH,eAAK;IACL,mBAAS;IACT,eAAQ;IACR,cAAI;IACJ,gBAAM;IACN,cAAI;IACJ,sBAAW;IACX,qBAAU;IACV,oBAAU;CACW,CAAC;AAE1B,iBAAS,cAAc,CAAC"}
package/lib/typings.d.ts CHANGED
@@ -6,6 +6,7 @@ import type { SanitizeFunction, SanitizeOptions } from './sanitize';
6
6
  import type { LogLevels, Logger } from './log';
7
7
  import type { ChangelogItem } from './plugins/changelog/types';
8
8
  import type { IDGenerator } from './plugins/utils';
9
+ import type { VisibilityMode } from './plugins/visibility';
9
10
  export interface MarkdownIt extends DefaultMarkdownIt {
10
11
  assets?: string[];
11
12
  meta?: string[];
@@ -79,6 +80,10 @@ export interface OptionsType {
79
80
  * @default false
80
81
  */
81
82
  codeLineWrapping?: boolean;
83
+ /**
84
+ * Selects audience-specific content. Defaults to `human`.
85
+ */
86
+ contentAudience?: VisibilityMode;
82
87
  /**
83
88
  * Custom ID generator factory to use for this transform call.
84
89
  * If provided, it will be called once per file to create a per-file isolated generator.
@@ -130,6 +135,7 @@ export interface MarkdownItPluginOpts {
130
135
  * the next non-blank line is an `{% include %}` directive.
131
136
  */
132
137
  multilineTermDefinitions?: boolean;
138
+ contentAudience?: VisibilityMode;
133
139
  }
134
140
  export type MarkdownItPluginCb<T extends {} = {}> = {
135
141
  (md: MarkdownIt, opts: T & MarkdownItPluginOpts): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diplodoc/transform",
3
- "version": "4.77.15",
3
+ "version": "4.78.0",
4
4
  "description": "A simple transformer of text in YFM (Yandex Flavored Markdown) to HTML",
5
5
  "keywords": [
6
6
  "markdown",
@@ -54,8 +54,9 @@
54
54
  },
55
55
  "dependencies": {
56
56
  "@diplodoc/cut-extension": "^1.1.6",
57
+ "@diplodoc/directive": "^0.4.0",
57
58
  "@diplodoc/file-extension": "^0.2.5",
58
- "@diplodoc/tabs-extension": "^3.10.5",
59
+ "@diplodoc/tabs-extension": "^3.10.7",
59
60
  "@diplodoc/utils": "^2.3.5",
60
61
  "chalk": "^4.1.2",
61
62
  "cheerio": "^1.0.0",
@@ -1,5 +1,9 @@
1
1
  import type Token from 'markdown-it/lib/token';
2
2
  import type {EnvType, OptionsType, OutputType} from './typings';
3
+ import type {
4
+ ContentAudience as VisibilityContentAudience,
5
+ VisibilityMode as VisibilityContentMode,
6
+ } from './plugins/visibility';
3
7
 
4
8
  import {bold} from 'chalk';
5
9
 
@@ -59,4 +63,6 @@ export = transform;
59
63
  namespace transform {
60
64
  export type Options = OptionsType;
61
65
  export type Output = OutputType;
66
+ export type ContentAudience = VisibilityContentAudience;
67
+ export type VisibilityMode = VisibilityContentMode;
62
68
  }
@@ -0,0 +1,281 @@
1
+ import type MarkdownIt from 'markdown-it';
2
+ import type StateBlock from 'markdown-it/lib/rules_block/state_block';
3
+ import type {ContainerDirectiveParams} from '@diplodoc/directive';
4
+ import type {MarkdownItPluginCb} from './typings';
5
+
6
+ import MarkdownItImpl from 'markdown-it';
7
+ import {
8
+ directiveParser,
9
+ registerContainerDirective,
10
+ tokenizeBlockContent,
11
+ } from '@diplodoc/directive';
12
+
13
+ export type ContentAudience = 'human' | 'agent';
14
+ export type VisibilityMode = ContentAudience | 'preserve';
15
+
16
+ export interface VisibilityError {
17
+ line: number;
18
+ value: string;
19
+ message: string;
20
+ }
21
+
22
+ export interface VisibilityOptions {
23
+ audience?: VisibilityMode;
24
+ lint?: boolean;
25
+ onError?: (error: VisibilityError) => void;
26
+ }
27
+
28
+ export interface AudienceFilterResult {
29
+ content: string;
30
+ audienceSpecificContent: ContentAudience[];
31
+ originalCharacters: number;
32
+ filteredCharacters: number;
33
+ removedCharacters: number;
34
+ errors: VisibilityError[];
35
+ }
36
+
37
+ type VisibilityMeta = Record<string, unknown> & {
38
+ visibilityAudiences?: ContentAudience[];
39
+ };
40
+
41
+ type VisibilityBlock = {
42
+ audience?: ContentAudience;
43
+ params: ContainerDirectiveParams;
44
+ children: VisibilityBlock[];
45
+ };
46
+
47
+ const AUDIENCE_ORDER: ContentAudience[] = ['human', 'agent'];
48
+ const VISIBILITY_DIRECTIVE_REGEXP = /:{3,}[ \t]*visibility/i;
49
+
50
+ function parseAudience(value = ''): ContentAudience | undefined {
51
+ return value === 'human' || value === 'agent' ? value : undefined;
52
+ }
53
+
54
+ function createVisibilityError(value: string, line: number): VisibilityError {
55
+ const printableValue = value || '<empty>';
56
+ return {
57
+ line,
58
+ value,
59
+ message: `Invalid visibility audience "${printableValue}" at line ${line}; expected "human" or "agent"`,
60
+ };
61
+ }
62
+
63
+ function addAudience(target: Set<ContentAudience>, audience: ContentAudience): void {
64
+ target.add(audience);
65
+ }
66
+
67
+ function orderedAudiences(audiences: Iterable<ContentAudience>): ContentAudience[] {
68
+ const values = new Set(audiences);
69
+ return AUDIENCE_ORDER.filter((audience) => values.has(audience));
70
+ }
71
+
72
+ function markAudience(state: StateBlock, audience: ContentAudience): void {
73
+ if (!state.env.meta || typeof state.env.meta !== 'object' || Array.isArray(state.env.meta)) {
74
+ state.env.meta = {};
75
+ }
76
+ const meta = state.env.meta as VisibilityMeta;
77
+ meta.visibilityAudiences = orderedAudiences([...(meta.visibilityAudiences ?? []), audience]);
78
+ }
79
+
80
+ function emitLintToken(
81
+ state: StateBlock,
82
+ params: ContainerDirectiveParams,
83
+ audience: ContentAudience | undefined,
84
+ ): void {
85
+ const token = state.push('__yfm_lint', '', 0);
86
+ token.hidden = true;
87
+ token.map = [params.startLine, params.startLine + 1];
88
+ token.attrSet('visibility-directive', 'true');
89
+ token.attrSet('visibility-audience', params.contentTitle?.raw ?? '');
90
+ token.attrSet('YFM023', audience ? 'valid' : 'invalid');
91
+ }
92
+
93
+ /**
94
+ * Creates the audience visibility directive plugin.
95
+ *
96
+ * The `preserve` mode tokenizes both audiences without rendering the directive wrapper. It is
97
+ * intended for source-aware consumers such as the translation pipeline, which retain untouched
98
+ * source ranges around the emitted content tokens.
99
+ *
100
+ * @returns Markdown-it plugin for audience visibility blocks.
101
+ */
102
+ export function visibility({
103
+ audience = 'human',
104
+ lint = false,
105
+ onError,
106
+ }: VisibilityOptions = {}): MarkdownIt.PluginSimple {
107
+ return (md) => {
108
+ md.use(directiveParser());
109
+ if (lint) {
110
+ md.core.ruler.before('block', 'visibility-lint-mode', (state) => {
111
+ const token = new state.Token('__yfm_lint', '', 0);
112
+ token.hidden = true;
113
+ token.attrSet('visibility-parser', 'true');
114
+ state.tokens.push(token);
115
+ });
116
+ }
117
+ registerContainerDirective(md, 'visibility', (state, params) => {
118
+ const rawAudience = params.contentTitle?.raw ?? '';
119
+ const blockAudience = parseAudience(rawAudience);
120
+
121
+ if (lint) {
122
+ emitLintToken(state, params, blockAudience);
123
+ }
124
+
125
+ if (!blockAudience) {
126
+ onError?.(createVisibilityError(rawAudience, params.startLine + 1));
127
+ if (audience === 'preserve') {
128
+ tokenizeBlockContent(state, params.content, 'visibility-directive');
129
+ }
130
+ return true;
131
+ }
132
+
133
+ markAudience(state, blockAudience);
134
+
135
+ if (audience === 'preserve' || audience === blockAudience) {
136
+ tokenizeBlockContent(state, params.content, 'visibility-directive');
137
+ }
138
+
139
+ return true;
140
+ });
141
+ };
142
+ }
143
+
144
+ function splitLines(content: string): string[] {
145
+ return content.match(/[^\r\n]*(?:\r\n|\n|\r)|[^\r\n]+$/g) ?? [];
146
+ }
147
+
148
+ function nestBlocks(blocks: VisibilityBlock[]): VisibilityBlock[] {
149
+ const roots: VisibilityBlock[] = [];
150
+ const stack: VisibilityBlock[] = [];
151
+
152
+ for (const block of blocks.sort((left, right) => {
153
+ const startDiff = left.params.startLine - right.params.startLine;
154
+ return startDiff || right.params.endLine - left.params.endLine;
155
+ })) {
156
+ while (
157
+ stack.length &&
158
+ block.params.startLine >= stack[stack.length - 1].params.content.endLine
159
+ ) {
160
+ stack.pop();
161
+ }
162
+
163
+ const parent = stack[stack.length - 1];
164
+ if (parent && block.params.endLine <= parent.params.content.endLine) {
165
+ parent.children.push(block);
166
+ } else {
167
+ roots.push(block);
168
+ }
169
+ stack.push(block);
170
+ }
171
+
172
+ return roots;
173
+ }
174
+
175
+ function filterRange(
176
+ lines: string[],
177
+ startLine: number,
178
+ endLine: number,
179
+ blocks: VisibilityBlock[],
180
+ selectedAudience: ContentAudience,
181
+ ): string {
182
+ const parts: string[] = [];
183
+ let cursorLine = startLine;
184
+
185
+ for (const block of blocks) {
186
+ const {params, audience} = block;
187
+ parts.push(lines.slice(cursorLine, params.startLine).join(''));
188
+ const filteredBody = filterRange(
189
+ lines,
190
+ params.content.startLine,
191
+ params.content.endLine,
192
+ block.children,
193
+ selectedAudience,
194
+ );
195
+ if (audience === selectedAudience) {
196
+ parts.push(filteredBody);
197
+ }
198
+ cursorLine = params.endLine;
199
+ }
200
+
201
+ parts.push(lines.slice(cursorLine, endLine).join(''));
202
+ return parts.join('');
203
+ }
204
+
205
+ /**
206
+ * Filters Markdown source for one content audience while preserving all unrelated source text.
207
+ *
208
+ * @param markdown Markdown source to filter.
209
+ * @param audience Audience whose content should be retained.
210
+ * @returns Filtered source, detected audiences, diagnostics, and character counts.
211
+ */
212
+ export function filterAudienceContent(
213
+ markdown: string,
214
+ audience: ContentAudience,
215
+ ): AudienceFilterResult {
216
+ const originalCharacters = Array.from(markdown).length;
217
+ if (!VISIBILITY_DIRECTIVE_REGEXP.test(markdown)) {
218
+ return {
219
+ content: markdown,
220
+ audienceSpecificContent: [],
221
+ originalCharacters,
222
+ filteredCharacters: originalCharacters,
223
+ removedCharacters: 0,
224
+ errors: [],
225
+ };
226
+ }
227
+
228
+ const detectedAudiences = new Set<ContentAudience>();
229
+ const errors: VisibilityError[] = [];
230
+ const blocks: VisibilityBlock[] = [];
231
+ const md = new MarkdownItImpl({html: true}).use(directiveParser());
232
+
233
+ registerContainerDirective(md, 'visibility', (state, params) => {
234
+ const rawAudience = params.contentTitle?.raw ?? '';
235
+ const blockAudience = parseAudience(rawAudience);
236
+ blocks.push({audience: blockAudience, params, children: []});
237
+
238
+ if (blockAudience) {
239
+ addAudience(detectedAudiences, blockAudience);
240
+ } else {
241
+ errors.push(createVisibilityError(rawAudience, params.startLine + 1));
242
+ }
243
+
244
+ // Parse nested directives in the original block state. Their line maps remain relative to
245
+ // the complete source, so reconstruction below can preserve list indentation exactly.
246
+ tokenizeBlockContent(state, params.content, 'visibility-directive');
247
+ return true;
248
+ });
249
+
250
+ md.parse(markdown, {});
251
+ const lines = splitLines(markdown);
252
+ const content = filterRange(lines, 0, lines.length, nestBlocks(blocks), audience);
253
+ const filteredCharacters = Array.from(content).length;
254
+
255
+ return {
256
+ content,
257
+ audienceSpecificContent: orderedAudiences(detectedAudiences),
258
+ originalCharacters,
259
+ filteredCharacters,
260
+ removedCharacters: originalCharacters - filteredCharacters,
261
+ errors,
262
+ };
263
+ }
264
+
265
+ const visibilityPlugin: MarkdownItPluginCb = (md, options) => {
266
+ const lint = options.isLintRun;
267
+ md.use(
268
+ visibility({
269
+ audience: lint ? 'preserve' : (options.contentAudience ?? 'human'),
270
+ lint,
271
+ onError: lint
272
+ ? undefined
273
+ : (error) =>
274
+ options.log.error(
275
+ `${error.message}${options.path ? ` in ${options.path}` : ''}`,
276
+ ),
277
+ }),
278
+ );
279
+ };
280
+
281
+ export default visibilityPlugin;
@@ -16,6 +16,7 @@ import imsize from './plugins/imsize';
16
16
  import term from './plugins/term';
17
17
  import blockAnchor from './plugins/block-anchor';
18
18
  import inlineCode from './plugins/inline-code';
19
+ import visibility from './plugins/visibility';
19
20
 
20
21
  const defaultPlugins = [
21
22
  meta,
@@ -34,6 +35,7 @@ const defaultPlugins = [
34
35
  term,
35
36
  blockAnchor,
36
37
  inlineCode,
38
+ visibility,
37
39
  ] as MarkdownItPluginCb[];
38
40
 
39
41
  export = defaultPlugins;