Skip to content

Commit c9e9f77

Browse files
committed
ci: fix sync-docs workflow
Signed-off-by: Emilien Escalle <emilien.escalle@escemi.com>
1 parent 2def582 commit c9e9f77

6 files changed

Lines changed: 269 additions & 206 deletions

File tree

.github/actions/prepare-docs/lib/artifact/artifact-processor.js

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
"use strict";
22

33
const path = require("path");
4-
const { MARKDOWN_EXTENSIONS, STATIC_DIRECTORY } = require("../constants");
4+
const {
5+
MARKDOWN_EXTENSIONS,
6+
STATIC_DIRECTORY,
7+
STATIC_ASSET_PREFIX,
8+
} = require("../constants");
59
const { iterateFiles } = require("../utils/file-iterator");
610
const {
711
normalizeToPosix,
@@ -11,7 +15,6 @@ const {
1115
toSystemPath,
1216
deriveTitleFromReadmePath,
1317
} = require("../utils/path-utils");
14-
const { registerAssetPath } = require("../utils/asset-registry");
1518
const { MarkdownProcessor } = require("../markdown/markdown-processor");
1619

1720
class ArtifactProcessor {
@@ -62,11 +65,11 @@ class ArtifactProcessor {
6265
const normalizedSourcePath = normalizeToPosix(relativePath);
6366
const sanitizedRelativePathRaw = sanitizeRelativePath(relativePath);
6467
const sanitizedRelativePath = rewriteReadmeToIndex(
65-
sanitizedRelativePathRaw,
68+
sanitizedRelativePathRaw
6669
);
6770
const renamedFromReadme = didRewriteReadme(
6871
sanitizedRelativePathRaw,
69-
sanitizedRelativePath,
72+
sanitizedRelativePath
7073
);
7174
const derivedTitle = renamedFromReadme
7275
? deriveTitleFromReadmePath({
@@ -80,7 +83,7 @@ class ArtifactProcessor {
8083
}
8184

8285
const isMarkdown = MARKDOWN_EXTENSIONS.has(
83-
path.extname(sanitizedRelativePath).toLowerCase(),
86+
path.extname(sanitizedRelativePath).toLowerCase()
8487
);
8588

8689
let targetRelativePath;
@@ -93,11 +96,11 @@ class ArtifactProcessor {
9396
} else {
9497
assetRegistration = registerAssetPath(
9598
this.assetMap,
96-
sanitizedRelativePath,
99+
sanitizedRelativePath
97100
);
98101
targetRelativePath = path.posix.join(
99102
STATIC_DIRECTORY,
100-
assetRegistration.storageRelativePath,
103+
assetRegistration.storageRelativePath
101104
);
102105
destination = toSystemPath(this.outputPath, targetRelativePath);
103106
}
@@ -119,7 +122,7 @@ class ArtifactProcessor {
119122
});
120123
} else {
121124
this.core.info(
122-
` Copied asset: ${targetRelativePath} (public ${assetRegistration.publicPath})`,
125+
` Copied asset: ${targetRelativePath} (public ${assetRegistration.publicPath})`
123126
);
124127
}
125128
}
@@ -142,6 +145,27 @@ class ArtifactProcessor {
142145
}
143146
}
144147

148+
function registerAssetPath(assetMap, assetPath) {
149+
const key = normalizeToPosix(assetPath);
150+
const storageRelativePath = path.posix.join(STATIC_ASSET_PREFIX, key);
151+
const publicPath = `/${storageRelativePath}`.replace(/\/+/g, "/");
152+
153+
if (!assetMap.has(key)) {
154+
assetMap.set(key, {
155+
storageRelativePath,
156+
publicPath,
157+
});
158+
}
159+
160+
const registration = assetMap.get(key);
161+
162+
return {
163+
key,
164+
storageRelativePath: registration.storageRelativePath,
165+
publicPath: registration.publicPath,
166+
};
167+
}
168+
145169
module.exports = {
146170
ArtifactProcessor,
147171
};

.github/actions/prepare-docs/lib/documentation-preparer.js

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ const {
55
ensureArtifactDirectory,
66
prepareOutputDirectory,
77
} = require("./utils/fs-utils");
8-
const { parseRepositorySlug } = require("./utils/repository-utils");
98
const { resolveSourceBranch } = require("./services/source-branch-resolver");
109
const { ArtifactProcessor } = require("./artifact/artifact-processor");
1110
const { ensureIndexPage } = require("./artifact/index-page-writer");
@@ -29,7 +28,7 @@ class DocumentationPreparer {
2928
ensureArtifactDirectory(this.artifactPath);
3029

3130
this.core.info(
32-
`Preparing documentation bundle for ${this.sourceRepository}`,
31+
`Preparing documentation bundle for ${this.sourceRepository}`
3332
);
3433

3534
await prepareOutputDirectory(this.outputPath, this.io);
@@ -66,7 +65,7 @@ class DocumentationPreparer {
6665
});
6766

6867
this.core.info(
69-
`Documentation bundle prepared with ${processedFiles.length} files.`,
68+
`Documentation bundle prepared with ${processedFiles.length} files.`
7069
);
7170

7271
return {
@@ -76,6 +75,15 @@ class DocumentationPreparer {
7675
}
7776
}
7877

78+
function parseRepositorySlug(repository) {
79+
const [owner, name] = (repository || "").split("/");
80+
if (!owner || !name) {
81+
throw new Error(`Invalid repository slug "${repository}".`);
82+
}
83+
84+
return { owner, name };
85+
}
86+
7987
module.exports = {
8088
DocumentationPreparer,
8189
};

.github/actions/prepare-docs/lib/markdown/markdown-normalizer.js

Lines changed: 49 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
"use strict";
22

3-
const {
4-
splitLinkPathAndSuffix,
5-
sanitizeLinkPath,
6-
} = require("../utils/path-utils");
7-
const { resolveAssetPublicPath } = require("../utils/asset-registry");
3+
const { AssetRewriter } = require("../services/asset-rewriter");
84

95
function normalizeMarkdownBody(content, options = {}) {
106
if (!content) {
117
return content;
128
}
139

14-
return rewriteLocalLinks(convertAngleBracketLinks(content), options);
10+
const assetRewriter = new AssetRewriter(options);
11+
const convertedLinks = convertAngleBracketLinks(content);
12+
const rewrittenMarkdownLinks = rewriteLocalLinks(
13+
convertedLinks,
14+
assetRewriter
15+
);
16+
return rewriteHtmlAttributes(rewrittenMarkdownLinks, assetRewriter);
1517
}
1618

1719
function convertAngleBracketLinks(text) {
@@ -25,11 +27,11 @@ function convertAngleBracketLinks(text) {
2527
const isEmail = raw.includes("@");
2628
const href = isEmail ? `mailto:${raw}` : raw;
2729
return `[${raw}](${href})`;
28-
},
30+
}
2931
);
3032
}
3133

32-
function rewriteLocalLinks(text, options = {}) {
34+
function rewriteLocalLinks(text, assetRewriter) {
3335
if (!text) {
3436
return text;
3537
}
@@ -109,7 +111,7 @@ function rewriteLocalLinks(text, options = {}) {
109111
}
110112

111113
const target = text.slice(afterBracket + 1, parenEnd);
112-
const rewrittenTarget = rewriteLinkTarget(target, options);
114+
const rewrittenTarget = rewriteLinkTarget(target, assetRewriter);
113115

114116
result += text.slice(bracketIndex, afterBracket + 1);
115117
result += rewrittenTarget;
@@ -118,22 +120,22 @@ function rewriteLocalLinks(text, options = {}) {
118120
index = parenEnd + 1;
119121
}
120122

121-
return rewriteReferenceLinks(result, options);
123+
return rewriteReferenceLinks(result, assetRewriter);
122124
}
123125

124-
function rewriteReferenceLinks(text, options = {}) {
126+
function rewriteReferenceLinks(text, assetRewriter) {
125127
const referencePattern = /^(\s*\[[^\]]+\]:\s*)(.+)$/gm;
126128

127129
return text.replace(referencePattern, (match, prefix, target) => {
128-
const rewritten = rewriteLinkTarget(target, options);
130+
const rewritten = rewriteLinkTarget(target, assetRewriter);
129131
if (rewritten === target) {
130132
return match;
131133
}
132134
return `${prefix}${rewritten}`;
133135
});
134136
}
135137

136-
function rewriteLinkTarget(rawTarget, options = {}) {
138+
function rewriteLinkTarget(rawTarget, assetRewriter) {
137139
if (!rawTarget) {
138140
return rawTarget;
139141
}
@@ -167,48 +169,55 @@ function rewriteLinkTarget(rawTarget, options = {}) {
167169
}
168170
}
169171

170-
if (!urlPart || isExternalLink(urlPart)) {
171-
return rawTarget;
172-
}
172+
const { value, changed } = assetRewriter.rewrite(urlPart);
173173

174-
const { path: targetPath, suffix } = splitLinkPathAndSuffix(urlPart);
175-
if (!targetPath) {
174+
if (!changed) {
176175
return rawTarget;
177176
}
178177

179-
const sanitizedPath = sanitizeLinkPath(targetPath);
180-
const assetPublicPath = resolveAssetPublicPath({
181-
assetMap: options.assetMap,
182-
docRelativePath: options.docRelativePath,
183-
targetPath: sanitizedPath,
184-
docsPath: options.docsPath,
185-
staticPath: options.staticPath,
186-
});
187-
const rewrittenPath = assetPublicPath || sanitizedPath;
188-
const rebuiltTarget = `${rewrittenPath}${suffix}`;
178+
return `${leadingWhitespace}${value}${trailingTitle}`;
179+
}
189180

190-
if (rebuiltTarget === urlPart) {
191-
return rawTarget;
181+
function rewriteHtmlAttributes(text, assetRewriter) {
182+
if (!text) {
183+
return text;
192184
}
193185

194-
return `${leadingWhitespace}${rebuiltTarget}${trailingTitle}`;
186+
const attributePattern = /(<[^>]+?\s)(src|href)(\s*=\s*)(["'])([^"']+?)\4/gi;
187+
188+
return text.replace(
189+
attributePattern,
190+
(match, prefix, attribute, equalsPart, quote, value) => {
191+
const rewrittenValue = rewriteHtmlAttributeValue(value, assetRewriter);
192+
if (rewrittenValue === value) {
193+
return match;
194+
}
195+
196+
return `${prefix}${attribute}${equalsPart}${quote}${rewrittenValue}${quote}`;
197+
}
198+
);
195199
}
196200

197-
function isExternalLink(target) {
198-
const trimmed = target.trim();
199-
if (!trimmed) {
200-
return true;
201+
function rewriteHtmlAttributeValue(rawValue, assetRewriter) {
202+
if (!rawValue) {
203+
return rawValue;
201204
}
202205

203-
if (trimmed.startsWith("#")) {
204-
return true;
206+
const leadingWhitespace = rawValue.match(/^\s+/)?.[0] || "";
207+
const trailingWhitespace = rawValue.match(/\s+$/)?.[0] || "";
208+
const coreValue = rawValue.trim();
209+
210+
if (!coreValue) {
211+
return rawValue;
205212
}
206213

207-
if (trimmed.startsWith("//")) {
208-
return true;
214+
const { value, changed } = assetRewriter.rewrite(coreValue);
215+
216+
if (!changed) {
217+
return rawValue;
209218
}
210219

211-
return /^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(trimmed);
220+
return `${leadingWhitespace}${value}${trailingWhitespace}`;
212221
}
213222

214223
module.exports = {

0 commit comments

Comments
 (0)