Skip to content

Commit 749d7a5

Browse files
committed
fix: Merge Includes
1 parent 29d7783 commit 749d7a5

File tree

22 files changed

+369
-188
lines changed

22 files changed

+369
-188
lines changed

src/commands/build/features/output-md/index.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export type OutputMdConfig = {
3232
};
3333

3434
export type PreprocessConfig = {
35-
preprocess: Partial<OutputMdConfig>;
35+
preprocess: OutputMdConfig;
3636
};
3737

3838
export class OutputMd {
@@ -48,7 +48,7 @@ export class OutputMd {
4848
hashIncludes: true,
4949
});
5050
const mergeIncludes = defined('mergeIncludes', args, config.preprocess || {}, {
51-
mergeIncludes: false,
51+
mergeIncludes: true,
5252
});
5353
const mergeAutotitles = defined('mergeAutotitles', args, config.preprocess || {}, {
5454
mergeAutotitles: true,
@@ -89,12 +89,14 @@ export class OutputMd {
8989
return processed.get(entry.path);
9090
}
9191

92-
const deps = await all(entry.deps.map((dep) => dump(dep, true)));
92+
const deps = await all(
93+
entry.deps.map((dep) => dump(dep, !config.mergeIncludes)),
94+
);
9395
let content = entry.content;
9496
const sheduler = new Sheduler();
9597

96-
if (!config.mergeIncludes && config.hashIncludes) {
97-
sheduler.addStep(rehashIncludes(run, deps));
98+
if (config.hashIncludes) {
99+
sheduler.addStep(rehashIncludes(run, deps, config.mergeIncludes));
98100
}
99101

100102
if (config.mergeAutotitles) {
@@ -104,7 +106,10 @@ export class OutputMd {
104106
await sheduler.shedule(entry);
105107
content = await sheduler.process(content);
106108

107-
const hash = config.hashIncludes ? rehashContent(content) : '';
109+
const hash =
110+
config.hashIncludes && !config.mergeIncludes
111+
? rehashContent(content)
112+
: '';
108113
const link = signlink(entry.path, hash);
109114
const hashed = {...entry, content, hash};
110115

src/commands/build/features/output-md/plugins/resolve-deps.ts

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,57 @@ function rehashInclude(include: HashedGraphNode) {
77
return replaceAll(include.match, include.link, signlink(include.link, include.hash));
88
}
99

10-
export function rehashIncludes(_run: Run, deps: HashedGraphNode[]): StepFunction {
10+
function addIndent(content: string, numSpaces: number, skipFirstLine = false): string {
11+
if (!content || numSpaces <= 0) {
12+
return content;
13+
}
14+
15+
const indent = ' '.repeat(numSpaces);
16+
// Разбиваем строку, сохраняя разделители
17+
const parts = content.split(/(\r\n|\r|\n)/);
18+
19+
let isFirstTextLine = true;
20+
const result: string[] = [];
21+
for (let i = 0; i < parts.length; i++) {
22+
const part = parts[i];
23+
24+
// Если это окончание строки, просто добавляем его
25+
if (part === '\r\n' || part === '\n' || part === '\r') {
26+
result.push(part);
27+
continue;
28+
}
29+
// Если это первая текстовая строка и нужно пропустить
30+
if (isFirstTextLine && skipFirstLine) {
31+
isFirstTextLine = false;
32+
result.push(part);
33+
continue;
34+
}
35+
isFirstTextLine = false;
36+
// Добавляем отступ только к непустым строкам
37+
result.push(part ? indent + part : part);
38+
}
39+
return result.join('');
40+
}
41+
42+
export function rehashIncludes(
43+
_run: Run,
44+
deps: HashedGraphNode[],
45+
mergeIncludes: boolean,
46+
): StepFunction {
1147
return async function (sheduler: Sheduler): Promise<void> {
1248
const actor = async (content: string, {dep}: StepContext): Promise<string> => {
1349
let result = content;
14-
const {location} = dep as HashedGraphNode;
50+
const {location, content: depContent, indent} = dep as HashedGraphNode;
1551

16-
const rehashed = rehashInclude(dep as HashedGraphNode);
17-
result = result.slice(0, location[0]) + rehashed + result.slice(location[1]);
52+
if (mergeIncludes) {
53+
result =
54+
result.slice(0, location[0]) +
55+
addIndent(depContent, indent, true) +
56+
result.slice(location[1]);
57+
} else {
58+
const rehashed = rehashInclude(dep as HashedGraphNode);
59+
result = result.slice(0, location[0]) + rehashed + result.slice(location[1]);
60+
}
1861

1962
return result;
2063
};

src/core/markdown/loader.spec.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ describe('Markdown loader', () => {
242242
link: './include.md',
243243
location: [12, 42],
244244
match: '{% include [](./include.md) %}',
245+
indent: 0,
245246
hash: null,
246247
search: null,
247248
},
@@ -269,6 +270,7 @@ describe('Markdown loader', () => {
269270
link: './include1.md',
270271
location: [12, 43],
271272
match: '{% include [](./include1.md) %}',
273+
indent: 0,
272274
hash: null,
273275
search: null,
274276
},
@@ -278,6 +280,7 @@ describe('Markdown loader', () => {
278280
location: [45, 99],
279281
match: '{% include [some text (with) braces](./include2.md) %}',
280282
hash: null,
283+
indent: 0,
281284
search: null,
282285
},
283286
{
@@ -286,6 +289,7 @@ describe('Markdown loader', () => {
286289
location: [105, 140],
287290
match: '{% include [](./deep/include.md) %}',
288291
hash: null,
292+
indent: 4,
289293
search: null,
290294
},
291295
]);
@@ -312,6 +316,7 @@ describe('Markdown loader', () => {
312316
link: './include1.md',
313317
location: [12, 43],
314318
match: '{% include [](./include1.md) %}',
319+
indent: 0,
315320
hash: null,
316321
search: null,
317322
},
@@ -320,6 +325,7 @@ describe('Markdown loader', () => {
320325
link: './include2.md',
321326
location: [45, 99],
322327
match: '{% include [some text (with) braces](./include2.md) %}',
328+
indent: 0,
323329
hash: null,
324330
search: null,
325331
},

src/core/markdown/loader/resolve-deps.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,19 @@ export function resolveDependencies(this: LoaderContext, content: string) {
1010

1111
// Include example: {% include [createfolder](create-folder.md) %}
1212
// Regexp result: [createfolder](create-folder.md)
13-
const INCLUDE_CONTENTS = /{%\s*include\s*.+?%}/g;
13+
const INCLUDE_CONTENTS = /(\r?\n\s+)?({%\s*include\s*.+?%})/g;
1414

1515
let match;
1616
// eslint-disable-next-line no-cond-assign
1717
while ((match = INCLUDE_CONTENTS.exec(content))) {
1818
// Ugly workaround for include examples
1919
// TODO: rewrite all inspect code on markdown-it parsing with minimal set of plugins
20+
match.index = match.index + (match[1]?.length || 0);
2021
if (content[match.index - 1] === '`') {
2122
continue;
2223
}
2324

24-
const link = findLink(match[0]) as string;
25+
const link = findLink(match[2]) as string;
2526
// TODO: warn about non local urls
2627
const include = parseLocalUrl<IncludeInfo>(link);
2728

@@ -30,6 +31,7 @@ export function resolveDependencies(this: LoaderContext, content: string) {
3031
include.link = link;
3132
include.match = content.slice(match.index, INCLUDE_CONTENTS.lastIndex);
3233
include.location = [match.index, INCLUDE_CONTENTS.lastIndex];
34+
include.indent = match[1]?.replace(/\r?\n/g, '').length || 0;
3335

3436
includes.push(include);
3537
}

src/core/markdown/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export type IncludeInfo = Pick<UrlWithStringQuery, 'hash' | 'search'> & {
2424
link: string;
2525
match: string;
2626
location: Location;
27+
indent: number;
2728
};
2829

2930
export type AssetInfo = Pick<UrlWithStringQuery, 'hash' | 'search'> & {

tests/e2e/__snapshots__/include-toc.test.ts.snap

Lines changed: 19 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,34 @@
22

33
exports[`Include toc > Nested toc inclusions with mixed including modes > filelist 1`] = `
44
"[
5-
"product1/_includes/inc-hash.md",
65
"product1/article1.md",
76
"product1/toc.yaml",
8-
"product2/overlay1/_includes/inc-hash.md",
97
"product2/overlay1/article1.md",
10-
"product2/overlay2/_includes/inc-hash.md",
118
"product2/overlay2/article1.md",
12-
"product2/overlay3/_includes/inc-hash.md",
139
"product2/overlay3/article1.md",
1410
"product2/p2.md",
1511
"product2/toc.yaml"
1612
]"
1713
`;
1814

19-
exports[`Include toc > Nested toc inclusions with mixed including modes 1`] = `"This is the core include."`;
20-
21-
exports[`Include toc > Nested toc inclusions with mixed including modes 2`] = `
15+
exports[`Include toc > Nested toc inclusions with mixed including modes 1`] = `
2216
"---
2317
metadata:
2418
- name: generator
2519
content: Diplodoc Platform vDIPLODOC-VERSION
2620
---
2721
This is the core content of Article 1.
2822
29-
{% include [x](_includes/inc-hash.md) %}
23+
This is the core include.
24+
"
25+
`;
26+
27+
exports[`Include toc > Nested toc inclusions with mixed including modes 2`] = `
28+
"title: Product 1 title
29+
items:
30+
- name: Article1
31+
href: article1.md
32+
path: product1/toc.yaml
3033
"
3134
`;
3235

@@ -52,66 +55,45 @@ path: toc.yaml
5255
`;
5356

5457
exports[`Include toc > Nested toc inclusions with mixed including modes 3`] = `
55-
"title: Product 1 title
56-
items:
57-
- name: Article1
58-
href: article1.md
59-
path: product1/toc.yaml
60-
"
61-
`;
62-
63-
exports[`Include toc > Nested toc inclusions with mixed including modes 4`] = `
64-
"This is the core include.
65-
"
66-
`;
67-
68-
exports[`Include toc > Nested toc inclusions with mixed including modes 5`] = `
6958
"---
7059
metadata:
7160
- name: generator
7261
content: Diplodoc Platform vDIPLODOC-VERSION
7362
---
7463
This is the overlay content of Article 1 for product 2.
7564
76-
{% include [x](_includes/inc-hash.md) %}
77-
"
78-
`;
65+
This is the core include.
7966
80-
exports[`Include toc > Nested toc inclusions with mixed including modes 6`] = `
81-
"This is the core include.
8267
"
8368
`;
8469

85-
exports[`Include toc > Nested toc inclusions with mixed including modes 7`] = `
70+
exports[`Include toc > Nested toc inclusions with mixed including modes 4`] = `
8671
"---
8772
metadata:
8873
- name: generator
8974
content: Diplodoc Platform vDIPLODOC-VERSION
9075
---
9176
This is the overlay number #2 of Article 1 content for product 2.
9277
93-
{% include [x](_includes/inc-hash.md) %}
94-
"
95-
`;
78+
This is the core include.
9679
97-
exports[`Include toc > Nested toc inclusions with mixed including modes 8`] = `
98-
"This is the core include.
9980
"
10081
`;
10182

102-
exports[`Include toc > Nested toc inclusions with mixed including modes 9`] = `
83+
exports[`Include toc > Nested toc inclusions with mixed including modes 5`] = `
10384
"---
10485
metadata:
10586
- name: generator
10687
content: Diplodoc Platform vDIPLODOC-VERSION
10788
---
10889
This is the core content of Article 1.
10990
110-
{% include [x](_includes/inc-hash.md) %}
91+
This is the core include.
92+
11193
"
11294
`;
11395

114-
exports[`Include toc > Nested toc inclusions with mixed including modes 10`] = `
96+
exports[`Include toc > Nested toc inclusions with mixed including modes 6`] = `
11597
"---
11698
metadata:
11799
- name: generator
@@ -123,7 +105,7 @@ Check here link to [Article1 overlay 1](overlay1/article1.md)
123105
Check here link to [Article1 overlay 2](overlay2/article1.md)"
124106
`;
125107

126-
exports[`Include toc > Nested toc inclusions with mixed including modes 11`] = `
108+
exports[`Include toc > Nested toc inclusions with mixed including modes 7`] = `
127109
"title: Product 2 title
128110
items:
129111
- name: P2 Article

0 commit comments

Comments
 (0)