mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-05-26 22:55:57 +00:00
Updated Wiki content
160
.github/workflows/validate_tab_links.yml
vendored
160
.github/workflows/validate_tab_links.yml
vendored
@@ -39,6 +39,7 @@ jobs:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const source = await response.text();
|
const source = await response.text();
|
||||||
|
const lineOffsets = buildLineOffsets(source);
|
||||||
|
|
||||||
const references = collectReferences(source);
|
const references = collectReferences(source);
|
||||||
if (!references.length) {
|
if (!references.length) {
|
||||||
@@ -113,7 +114,8 @@ jobs:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (failures.length) {
|
if (failures.length) {
|
||||||
const block = failures.join('\n');
|
failures.sort((a, b) => a.line - b.line);
|
||||||
|
const block = failures.map(failure => failure.message).join('\n');
|
||||||
core.exportVariable('ERROR_BLOCK', block);
|
core.exportVariable('ERROR_BLOCK', block);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -132,31 +134,113 @@ jobs:
|
|||||||
refs.push({
|
refs.push({
|
||||||
option: match[1],
|
option: match[1],
|
||||||
target: match[2].trim(),
|
target: match[2].trim(),
|
||||||
line: lineFromIndex(text, match.index),
|
line: lineFromIndex(match.index),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const labelPathPattern = /label_path\s*=\s*"([^"]+)"/g;
|
const labelPathPattern = /\bline\s*\.\s*label_path\s*=\s*"([^"]+)"/g;
|
||||||
while ((match = labelPathPattern.exec(text)) !== null) {
|
while ((match = labelPathPattern.exec(text)) !== null) {
|
||||||
refs.push({
|
refs.push({
|
||||||
option: 'label_path',
|
option: 'label_path',
|
||||||
target: match[1].trim(),
|
target: match[1].trim(),
|
||||||
line: lineFromIndex(text, match.index),
|
line: lineFromIndex(match.index),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const appendOptionLinePattern = /append_option_line\s*\(\s*[^,]+,\s*[^,]+,\s*"([^"]+)"/g;
|
for (const reference of collectAppendOptionLineReferences(text)) {
|
||||||
while ((match = appendOptionLinePattern.exec(text)) !== null) {
|
refs.push(reference);
|
||||||
refs.push({
|
|
||||||
option: 'append_option_line',
|
|
||||||
target: match[1].trim(),
|
|
||||||
line: lineFromIndex(text, match.index),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return refs;
|
return refs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function collectAppendOptionLineReferences(text) {
|
||||||
|
const refs = [];
|
||||||
|
const pattern = /append_option_line\s*\(/g;
|
||||||
|
let match;
|
||||||
|
while ((match = pattern.exec(text)) !== null) {
|
||||||
|
const callStart = match.index;
|
||||||
|
const argsResult = parseCallArguments(text, pattern.lastIndex);
|
||||||
|
if (!argsResult.args) {
|
||||||
|
pattern.lastIndex = argsResult.endIndex;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
pattern.lastIndex = argsResult.endIndex;
|
||||||
|
if (argsResult.args.length < 3) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const targetLiteral = extractStringLiteral(argsResult.args[2]);
|
||||||
|
if (!targetLiteral) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
refs.push({
|
||||||
|
option: 'append_option_line',
|
||||||
|
target: targetLiteral.trim(),
|
||||||
|
line: lineFromIndex(callStart),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return refs;
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseCallArguments(text, startIndex) {
|
||||||
|
const args = [];
|
||||||
|
let current = '';
|
||||||
|
let depth = 1;
|
||||||
|
let inString = false;
|
||||||
|
let stringChar = '';
|
||||||
|
let escaped = false;
|
||||||
|
let i = startIndex;
|
||||||
|
for (; i < text.length; i += 1) {
|
||||||
|
const ch = text[i];
|
||||||
|
if (inString) {
|
||||||
|
current += ch;
|
||||||
|
if (escaped) {
|
||||||
|
escaped = false;
|
||||||
|
} else if (ch === '\\') {
|
||||||
|
escaped = true;
|
||||||
|
} else if (ch === stringChar) {
|
||||||
|
inString = false;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ch === '"' || ch === '\'') {
|
||||||
|
inString = true;
|
||||||
|
stringChar = ch;
|
||||||
|
current += ch;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ch === '(') {
|
||||||
|
depth += 1;
|
||||||
|
current += ch;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ch === ')') {
|
||||||
|
depth -= 1;
|
||||||
|
if (depth === 0) {
|
||||||
|
args.push(current.trim());
|
||||||
|
return { args, endIndex: i + 1 };
|
||||||
|
}
|
||||||
|
current += ch;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ch === ',' && depth === 1) {
|
||||||
|
args.push(current.trim());
|
||||||
|
current = '';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
current += ch;
|
||||||
|
}
|
||||||
|
return { args: null, endIndex: text.length };
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractStringLiteral(argumentText) {
|
||||||
|
const trimmed = argumentText.trim();
|
||||||
|
if (!trimmed.startsWith('"') || !trimmed.endsWith('"')) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
return trimmed.slice(1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
function ensureMarkdownIndex() {
|
function ensureMarkdownIndex() {
|
||||||
if (markdownIndexReady) {
|
if (markdownIndexReady) {
|
||||||
return;
|
return;
|
||||||
@@ -273,37 +357,63 @@ jobs:
|
|||||||
return slugify(decoded);
|
return slugify(decoded);
|
||||||
}
|
}
|
||||||
|
|
||||||
function lineFromIndex(text, index) {
|
function buildLineOffsets(text) {
|
||||||
let line = 1;
|
const offsets = [0];
|
||||||
for (let i = 0; i < index; i += 1) {
|
for (let i = 0; i < text.length; i += 1) {
|
||||||
if (text.charCodeAt(i) === 10) {
|
if (text.charCodeAt(i) === 10) {
|
||||||
line += 1;
|
offsets.push(i + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return line;
|
return offsets;
|
||||||
|
}
|
||||||
|
|
||||||
|
function lineFromIndex(position) {
|
||||||
|
let low = 0;
|
||||||
|
let high = lineOffsets.length - 1;
|
||||||
|
while (low <= high) {
|
||||||
|
const mid = (low + high) >> 1;
|
||||||
|
if (lineOffsets[mid] <= position) {
|
||||||
|
low = mid + 1;
|
||||||
|
} else {
|
||||||
|
high = mid - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return high + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatFailure(reference, reason, details) {
|
function formatFailure(reference, reason, details) {
|
||||||
|
const link = `https://github.com/OrcaSlicer/OrcaSlicer/blob/main/src/slic3r/GUI/Tab.cpp#L${reference.line}`;
|
||||||
|
const lineInfo = `[Tab.cpp line ${reference.line}](${link})`;
|
||||||
|
const failure = { line: reference.line, message: '' };
|
||||||
switch (reason) {
|
switch (reason) {
|
||||||
case 'hashCount':
|
case 'hashCount':
|
||||||
return `Tab.cpp line ${reference.line}: link "${details}" cannot contain more than one '#'.`;
|
failure.message = `${lineInfo}: link "${details}" cannot contain more than one '#'.`;
|
||||||
|
break;
|
||||||
case 'missingDocName':
|
case 'missingDocName':
|
||||||
return `Tab.cpp line ${reference.line}: link "${details}" must include a document name.`;
|
failure.message = `${lineInfo}: link "${details}" must include a document name.`;
|
||||||
|
break;
|
||||||
case 'missingAnchor':
|
case 'missingAnchor':
|
||||||
return `Tab.cpp line ${reference.line}: link "${details}" must include a heading name after '#'.`;
|
failure.message = `${lineInfo}: link "${details}" must include a heading name after '#'.`;
|
||||||
|
break;
|
||||||
case 'pathNotAllowed':
|
case 'pathNotAllowed':
|
||||||
return `Tab.cpp line ${reference.line}: link "${details}" must omit any directory segments.`;
|
failure.message = `${lineInfo}: link "${details}" must omit any directory segments.`;
|
||||||
|
break;
|
||||||
case 'extensionNotAllowed':
|
case 'extensionNotAllowed':
|
||||||
return `Tab.cpp line ${reference.line}: link "${details}" must omit the .md suffix.`;
|
failure.message = `${lineInfo}: link "${details}" must omit the .md suffix.`;
|
||||||
|
break;
|
||||||
case 'missingDocument':
|
case 'missingDocument':
|
||||||
return `Tab.cpp line ${reference.line}: document ${details} does not exist in the wiki.`;
|
failure.message = `${lineInfo}: document ${details} does not exist in the wiki.`;
|
||||||
|
break;
|
||||||
case 'ambiguousDocument':
|
case 'ambiguousDocument':
|
||||||
return `Tab.cpp line ${reference.line}: document reference is ambiguous (${details}).`;
|
failure.message = `${lineInfo}: document reference is ambiguous (${details}).`;
|
||||||
|
break;
|
||||||
case 'missingCrossDocAnchor':
|
case 'missingCrossDocAnchor':
|
||||||
return `Tab.cpp line ${reference.line}: heading ${details} was not found.`;
|
failure.message = `${lineInfo}: heading ${details} was not found.`;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return `Tab.cpp line ${reference.line}: invalid link ${details}.`;
|
failure.message = `${lineInfo}: invalid link ${details}.`;
|
||||||
}
|
}
|
||||||
|
return failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
- name: Show invalid Tab links
|
- name: Show invalid Tab links
|
||||||
|
|||||||
Reference in New Issue
Block a user