mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-05-21 12:15:21 +00:00
Updated Wiki content
39
.github/workflows/validate_internal_link.yml
vendored
39
.github/workflows/validate_internal_link.yml
vendored
@@ -104,6 +104,11 @@ jobs:
|
|||||||
failures.push(formatFailure(reference, 'sameDocEmptyAnchor', reference.target));
|
failures.push(formatFailure(reference, 'sameDocEmptyAnchor', reference.target));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
const decodedAnchor = decodeLinkComponent(classification.anchorRaw);
|
||||||
|
if (!isKebabCase(decodedAnchor)) {
|
||||||
|
failures.push(formatFailure(reference, 'anchorNotKebabCase', `#${classification.anchorRaw}`));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
const anchors = getAnchors(reference.filePath);
|
const anchors = getAnchors(reference.filePath);
|
||||||
if (!anchors.has(classification.anchorSlug)) {
|
if (!anchors.has(classification.anchorSlug)) {
|
||||||
failures.push(formatFailure(reference, 'missingSameDocAnchor', `#${classification.anchorRaw}`));
|
failures.push(formatFailure(reference, 'missingSameDocAnchor', `#${classification.anchorRaw}`));
|
||||||
@@ -132,6 +137,12 @@ jobs:
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const decodedAnchor = decodeLinkComponent(classification.anchorRaw);
|
||||||
|
if (!isKebabCase(decodedAnchor)) {
|
||||||
|
failures.push(formatFailure(reference, 'anchorNotKebabCase', `${docResult.linkPath}#${classification.anchorRaw}`));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const anchors = getAnchors(docResult.relativePath);
|
const anchors = getAnchors(docResult.relativePath);
|
||||||
if (!anchors.has(classification.anchorSlug)) {
|
if (!anchors.has(classification.anchorSlug)) {
|
||||||
failures.push(formatFailure(reference, 'missingCrossDocAnchor', `${docResult.linkPath}#${classification.anchorRaw}`));
|
failures.push(formatFailure(reference, 'missingCrossDocAnchor', `${docResult.linkPath}#${classification.anchorRaw}`));
|
||||||
@@ -238,6 +249,12 @@ jobs:
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isSnakeCase(sanitized)) {
|
||||||
|
result.error = 'docNotSnakeCase';
|
||||||
|
result.detail = rawPath;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
ensureMarkdownIndex();
|
ensureMarkdownIndex();
|
||||||
const matches = findMarkdownDocuments(sanitized);
|
const matches = findMarkdownDocuments(sanitized);
|
||||||
if (!matches.length) {
|
if (!matches.length) {
|
||||||
@@ -311,6 +328,24 @@ jobs:
|
|||||||
return markdownNameIndex.get(baseName) || [];
|
return markdownNameIndex.get(baseName) || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isSnakeCase(value) {
|
||||||
|
return /^[a-z0-9]+(?:_[a-z0-9]+)*$/.test(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isKebabCase(value) {
|
||||||
|
return /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function decodeLinkComponent(value) {
|
||||||
|
let decoded = value.trim();
|
||||||
|
try {
|
||||||
|
decoded = decodeURIComponent(decoded);
|
||||||
|
} catch (_) {
|
||||||
|
// Ignore decode failure.
|
||||||
|
}
|
||||||
|
return decoded;
|
||||||
|
}
|
||||||
|
|
||||||
function getAnchors(relativePath) {
|
function getAnchors(relativePath) {
|
||||||
if (headingCache.has(relativePath)) {
|
if (headingCache.has(relativePath)) {
|
||||||
return headingCache.get(relativePath);
|
return headingCache.get(relativePath);
|
||||||
@@ -417,6 +452,8 @@ jobs:
|
|||||||
return `${reference.filePath} line ${reference.line}: document links must not include directories; use just the filename (got "${details}").`;
|
return `${reference.filePath} line ${reference.line}: document links must not include directories; use just the filename (got "${details}").`;
|
||||||
case 'extensionNotAllowed':
|
case 'extensionNotAllowed':
|
||||||
return `${reference.filePath} line ${reference.line}: link target "${details}" must omit the .md suffix.`;
|
return `${reference.filePath} line ${reference.line}: link target "${details}" must omit the .md suffix.`;
|
||||||
|
case 'docNotSnakeCase':
|
||||||
|
return `${reference.filePath} line ${reference.line}: document name "${details}" must be snake_case.`;
|
||||||
case 'missingDocName':
|
case 'missingDocName':
|
||||||
return `${reference.filePath} line ${reference.line}: document link "${details}" must include a file name (without .md).`;
|
return `${reference.filePath} line ${reference.line}: document link "${details}" must include a file name (without .md).`;
|
||||||
case 'missingDocument':
|
case 'missingDocument':
|
||||||
@@ -425,6 +462,8 @@ jobs:
|
|||||||
return `${reference.filePath} line ${reference.line}: document link matches multiple files (${details}).`;
|
return `${reference.filePath} line ${reference.line}: document link matches multiple files (${details}).`;
|
||||||
case 'crossDocEmptyAnchor':
|
case 'crossDocEmptyAnchor':
|
||||||
return `${reference.filePath} line ${reference.line}: link to ${details} must include a heading name after '#'.`;
|
return `${reference.filePath} line ${reference.line}: link to ${details} must include a heading name after '#'.`;
|
||||||
|
case 'anchorNotKebabCase':
|
||||||
|
return `${reference.filePath} line ${reference.line}: heading reference ${details} must be kebab-case.`;
|
||||||
case 'missingCrossDocAnchor':
|
case 'missingCrossDocAnchor':
|
||||||
return `${reference.filePath} line ${reference.line}: heading ${details} was not found.`;
|
return `${reference.filePath} line ${reference.line}: heading ${details} was not found.`;
|
||||||
case 'invalidHashCount':
|
case 'invalidHashCount':
|
||||||
|
|||||||
53
.github/workflows/validate_tab_links.yml
vendored
53
.github/workflows/validate_tab_links.yml
vendored
@@ -76,13 +76,19 @@ jobs:
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const matches = findMarkdownDocuments(docName);
|
const decodedDocName = decodeLinkComponent(docName);
|
||||||
|
if (!isSnakeCase(decodedDocName)) {
|
||||||
|
failures.push(formatFailure(reference, 'docNotSnakeCase', docName));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const matches = findMarkdownDocuments(decodedDocName);
|
||||||
if (!matches.length) {
|
if (!matches.length) {
|
||||||
failures.push(formatFailure(reference, 'missingDocument', `${docName}.md`));
|
failures.push(formatFailure(reference, 'missingDocument', `${decodedDocName}.md`));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (matches.length > 1) {
|
if (matches.length > 1) {
|
||||||
failures.push(formatFailure(reference, 'ambiguousDocument', `${docName} -> ${matches.slice(0, 5).join(', ')}`));
|
failures.push(formatFailure(reference, 'ambiguousDocument', `${decodedDocName} -> ${matches.slice(0, 5).join(', ')}`));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,6 +108,12 @@ jobs:
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const decodedAnchor = decodeLinkComponent(anchorRaw);
|
||||||
|
if (!isKebabCase(decodedAnchor)) {
|
||||||
|
failures.push(formatFailure(reference, 'anchorNotKebabCase', `${decodedDocName}#${anchorRaw}`));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const anchors = getAnchors(relativePath);
|
const anchors = getAnchors(relativePath);
|
||||||
const anchorSlug = normalizeAnchor(anchorRaw);
|
const anchorSlug = normalizeAnchor(anchorRaw);
|
||||||
if (!anchorSlug) {
|
if (!anchorSlug) {
|
||||||
@@ -109,7 +121,7 @@ jobs:
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!anchors.has(anchorSlug)) {
|
if (!anchors.has(anchorSlug)) {
|
||||||
failures.push(formatFailure(reference, 'missingCrossDocAnchor', `${docName}#${anchorRaw}`));
|
failures.push(formatFailure(reference, 'missingCrossDocAnchor', `${decodedDocName}#${anchorRaw}`));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -281,6 +293,24 @@ jobs:
|
|||||||
return markdownNameIndex.get(baseName) || [];
|
return markdownNameIndex.get(baseName) || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isSnakeCase(value) {
|
||||||
|
return /^[a-z0-9]+(?:_[a-z0-9]+)*$/.test(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isKebabCase(value) {
|
||||||
|
return /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function decodeLinkComponent(value) {
|
||||||
|
let decoded = value.trim();
|
||||||
|
try {
|
||||||
|
decoded = decodeURIComponent(decoded);
|
||||||
|
} catch (_) {
|
||||||
|
// ignore decode failures
|
||||||
|
}
|
||||||
|
return decoded;
|
||||||
|
}
|
||||||
|
|
||||||
function getAnchors(relativePath) {
|
function getAnchors(relativePath) {
|
||||||
if (headingCache.has(relativePath)) {
|
if (headingCache.has(relativePath)) {
|
||||||
return headingCache.get(relativePath);
|
return headingCache.get(relativePath);
|
||||||
@@ -348,13 +378,8 @@ jobs:
|
|||||||
if (!raw) {
|
if (!raw) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
let decoded = raw.trim();
|
const decoded = decodeLinkComponent(raw);
|
||||||
try {
|
return slugify(decoded);
|
||||||
decoded = decodeURIComponent(decoded);
|
|
||||||
} catch (_) {
|
|
||||||
// ignore decode failures
|
|
||||||
}
|
|
||||||
return slugify(decoded, { preserveCase: true });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildLineOffsets(text) {
|
function buildLineOffsets(text) {
|
||||||
@@ -401,12 +426,18 @@ jobs:
|
|||||||
case 'extensionNotAllowed':
|
case 'extensionNotAllowed':
|
||||||
failure.message = `${lineInfo}: link "${details}" must omit the .md suffix.`;
|
failure.message = `${lineInfo}: link "${details}" must omit the .md suffix.`;
|
||||||
break;
|
break;
|
||||||
|
case 'docNotSnakeCase':
|
||||||
|
failure.message = `${lineInfo}: document name "${details}" must be snake_case.`;
|
||||||
|
break;
|
||||||
case 'missingDocument':
|
case 'missingDocument':
|
||||||
failure.message = `${lineInfo}: document ${details} does not exist in the wiki.`;
|
failure.message = `${lineInfo}: document ${details} does not exist in the wiki.`;
|
||||||
break;
|
break;
|
||||||
case 'ambiguousDocument':
|
case 'ambiguousDocument':
|
||||||
failure.message = `${lineInfo}: document reference is ambiguous (${details}).`;
|
failure.message = `${lineInfo}: document reference is ambiguous (${details}).`;
|
||||||
break;
|
break;
|
||||||
|
case 'anchorNotKebabCase':
|
||||||
|
failure.message = `${lineInfo}: heading reference ${details} must be kebab-case.`;
|
||||||
|
break;
|
||||||
case 'missingCrossDocAnchor':
|
case 'missingCrossDocAnchor':
|
||||||
failure.message = `${lineInfo}: heading ${details} was not found.`;
|
failure.message = `${lineInfo}: heading ${details} was not found.`;
|
||||||
break;
|
break;
|
||||||
|
|||||||
Reference in New Issue
Block a user