mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 13:10:43 +00:00
refactor: dedupe shared helpers
This commit is contained in:
@@ -3,6 +3,10 @@
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { compile } from "@mdx-js/mdx";
|
||||
import {
|
||||
checkMintlifyAccordionIndentation,
|
||||
MINTLIFY_ACCORDION_INDENT_MESSAGE,
|
||||
} from "./lib/mintlify-accordion.mjs";
|
||||
|
||||
const MINTLIFY_LANGUAGE_CODES = new Set([
|
||||
"en",
|
||||
@@ -120,59 +124,13 @@ function formatMdxError(filePath, error) {
|
||||
}
|
||||
|
||||
function checkMintlifyMdxStructure(filePath, raw) {
|
||||
const errors = [];
|
||||
const lines = stripFrontmatter(raw).split(/\r?\n/u);
|
||||
const accordionStack = [];
|
||||
let inCodeFence = false;
|
||||
|
||||
for (let index = 0; index < lines.length; index += 1) {
|
||||
const line = lines[index];
|
||||
if (/^\s*(```|~~~)/u.test(line)) {
|
||||
inCodeFence = !inCodeFence;
|
||||
continue;
|
||||
}
|
||||
if (inCodeFence) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const openAccordion = line.match(/^(\s*)<Accordion\b/u);
|
||||
if (openAccordion) {
|
||||
accordionStack.push({
|
||||
indent: openAccordion[1].length,
|
||||
line: index + 1,
|
||||
hasOutdentedListItem: false,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
const listItem = line.match(/^(\s*)[-*+]\s+/u);
|
||||
if (listItem) {
|
||||
for (const accordion of accordionStack) {
|
||||
if (listItem[1].length < accordion.indent) {
|
||||
accordion.hasOutdentedListItem = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const closeAccordion = line.match(/^(\s*)<\/Accordion>/u);
|
||||
if (!closeAccordion) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const opening = accordionStack.pop();
|
||||
if (opening && opening.hasOutdentedListItem && closeAccordion[1].length > opening.indent) {
|
||||
errors.push({
|
||||
type: "mintlify-mdx",
|
||||
file: filePath,
|
||||
line: index + 1,
|
||||
column: closeAccordion[1].length + 1,
|
||||
message:
|
||||
"Accordion closing tag is indented deeper than its opening tag; Mintlify can parse following markdown as nested content.",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return errors;
|
||||
return checkMintlifyAccordionIndentation(stripFrontmatter(raw)).map((error) => ({
|
||||
type: "mintlify-mdx",
|
||||
file: filePath,
|
||||
line: error.line,
|
||||
column: error.column,
|
||||
message: MINTLIFY_ACCORDION_INDENT_MESSAGE,
|
||||
}));
|
||||
}
|
||||
|
||||
async function checkMdxFile(filePath) {
|
||||
|
||||
@@ -4,6 +4,7 @@ import { execFileSync } from "node:child_process";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { repairMintlifyAccordionIndentation } from "./lib/mintlify-accordion.mjs";
|
||||
|
||||
const HERE = path.dirname(fileURLToPath(import.meta.url));
|
||||
const ROOT = path.resolve(HERE, "..");
|
||||
@@ -14,6 +15,10 @@ const SYNC_SUPPORT_FILES = [
|
||||
source: path.join(ROOT, "scripts", "check-docs-mdx.mjs"),
|
||||
target: path.join(".openclaw-sync", "check-docs-mdx.mjs"),
|
||||
},
|
||||
{
|
||||
source: path.join(ROOT, "scripts", "lib", "mintlify-accordion.mjs"),
|
||||
target: path.join(".openclaw-sync", "lib", "mintlify-accordion.mjs"),
|
||||
},
|
||||
{
|
||||
source: path.join(ROOT, ".github", "codex", "prompts", "docs-mdx-repair.md"),
|
||||
target: path.join(".openclaw-sync", "docs-mdx-repair.md"),
|
||||
@@ -284,55 +289,6 @@ function composeDocsConfig() {
|
||||
};
|
||||
}
|
||||
|
||||
function repairMintlifyAccordionIndentation(raw) {
|
||||
const lines = raw.split(/\r?\n/u);
|
||||
const accordionStack = [];
|
||||
let inCodeFence = false;
|
||||
let changed = false;
|
||||
|
||||
for (let index = 0; index < lines.length; index += 1) {
|
||||
const line = lines[index];
|
||||
if (/^\s*(```|~~~)/u.test(line)) {
|
||||
inCodeFence = !inCodeFence;
|
||||
continue;
|
||||
}
|
||||
if (inCodeFence) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const openAccordion = line.match(/^(\s*)<Accordion\b/u);
|
||||
if (openAccordion) {
|
||||
accordionStack.push({
|
||||
indent: openAccordion[1].length,
|
||||
hasOutdentedListItem: false,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
const listItem = line.match(/^(\s*)[-*+]\s+/u);
|
||||
if (listItem) {
|
||||
for (const accordion of accordionStack) {
|
||||
if (listItem[1].length < accordion.indent) {
|
||||
accordion.hasOutdentedListItem = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const closeAccordion = line.match(/^(\s*)<\/Accordion>/u);
|
||||
if (!closeAccordion) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const opening = accordionStack.pop();
|
||||
if (opening && opening.hasOutdentedListItem && closeAccordion[1].length > opening.indent) {
|
||||
lines[index] = `${" ".repeat(opening.indent)}${line.slice(closeAccordion[1].length)}`;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return changed ? lines.join("\n") : raw;
|
||||
}
|
||||
|
||||
function repairGeneratedLocaleDocs(targetDocsDir) {
|
||||
let repaired = 0;
|
||||
for (const locale of GENERATED_LOCALES) {
|
||||
|
||||
73
scripts/lib/mintlify-accordion.mjs
Normal file
73
scripts/lib/mintlify-accordion.mjs
Normal file
@@ -0,0 +1,73 @@
|
||||
export const MINTLIFY_ACCORDION_INDENT_MESSAGE =
|
||||
"Accordion closing tag is indented deeper than its opening tag; Mintlify can parse following markdown as nested content.";
|
||||
|
||||
function visitAccordionIndentation(raw, onMisindentedClose) {
|
||||
const lines = raw.split(/\r?\n/u);
|
||||
const accordionStack = [];
|
||||
let inCodeFence = false;
|
||||
|
||||
for (let index = 0; index < lines.length; index += 1) {
|
||||
const line = lines[index];
|
||||
if (/^\s*(```|~~~)/u.test(line)) {
|
||||
inCodeFence = !inCodeFence;
|
||||
continue;
|
||||
}
|
||||
if (inCodeFence) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const openAccordion = line.match(/^(\s*)<Accordion\b/u);
|
||||
if (openAccordion) {
|
||||
accordionStack.push({
|
||||
indent: openAccordion[1].length,
|
||||
hasOutdentedListItem: false,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
const listItem = line.match(/^(\s*)[-*+]\s+/u);
|
||||
if (listItem) {
|
||||
for (const accordion of accordionStack) {
|
||||
if (listItem[1].length < accordion.indent) {
|
||||
accordion.hasOutdentedListItem = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const closeAccordion = line.match(/^(\s*)<\/Accordion>/u);
|
||||
if (!closeAccordion) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const opening = accordionStack.pop();
|
||||
if (opening && opening.hasOutdentedListItem && closeAccordion[1].length > opening.indent) {
|
||||
onMisindentedClose({ closeAccordion, index, line, lines, opening });
|
||||
}
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
export function checkMintlifyAccordionIndentation(raw) {
|
||||
const errors = [];
|
||||
visitAccordionIndentation(raw, ({ closeAccordion, index }) => {
|
||||
errors.push({
|
||||
line: index + 1,
|
||||
column: closeAccordion[1].length + 1,
|
||||
message: MINTLIFY_ACCORDION_INDENT_MESSAGE,
|
||||
});
|
||||
});
|
||||
return errors;
|
||||
}
|
||||
|
||||
export function repairMintlifyAccordionIndentation(raw) {
|
||||
let changed = false;
|
||||
const lines = visitAccordionIndentation(
|
||||
raw,
|
||||
({ closeAccordion, index, line, lines, opening }) => {
|
||||
lines[index] = `${" ".repeat(opening.indent)}${line.slice(closeAccordion[1].length)}`;
|
||||
changed = true;
|
||||
},
|
||||
);
|
||||
return changed ? lines.join("\n") : raw;
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
rmSync,
|
||||
} from "node:fs";
|
||||
import { builtinModules } from "node:module";
|
||||
import { createRequire } from "node:module";
|
||||
import { tmpdir } from "node:os";
|
||||
import { isAbsolute, join, relative } from "node:path";
|
||||
import { pathToFileURL } from "node:url";
|
||||
@@ -25,7 +26,6 @@ import {
|
||||
} from "./lib/bundled-plugin-root-runtime-mirrors.mjs";
|
||||
import { runInstalledWorkspaceBootstrapSmoke } from "./lib/workspace-bootstrap-smoke.mjs";
|
||||
import { parseReleaseVersion, resolveNpmCommandInvocation } from "./openclaw-npm-release-check.ts";
|
||||
import { createRequire } from "node:module";
|
||||
|
||||
type InstalledPackageJson = {
|
||||
version?: string;
|
||||
@@ -123,7 +123,10 @@ export function normalizeInstalledBinaryVersion(output: string): string {
|
||||
return versionMatch?.[0] ?? trimmed;
|
||||
}
|
||||
|
||||
function listDistJavaScriptFiles(packageRoot: string): string[] {
|
||||
function listDistJavaScriptFiles(
|
||||
packageRoot: string,
|
||||
opts: { skipRelativePath?: (relativePath: string) => boolean } = {},
|
||||
): string[] {
|
||||
const distDir = join(packageRoot, "dist");
|
||||
if (!existsSync(distDir)) {
|
||||
return [];
|
||||
@@ -138,6 +141,10 @@ function listDistJavaScriptFiles(packageRoot: string): string[] {
|
||||
}
|
||||
for (const entry of readdirSync(currentDir, { withFileTypes: true })) {
|
||||
const entryPath = join(currentDir, entry.name);
|
||||
const relativePath = relative(distDir, entryPath).replaceAll("\\", "/");
|
||||
if (opts.skipRelativePath?.(relativePath)) {
|
||||
continue;
|
||||
}
|
||||
if (entry.isDirectory()) {
|
||||
pending.push(entryPath);
|
||||
continue;
|
||||
@@ -166,35 +173,9 @@ export function collectInstalledContextEngineRuntimeErrors(packageRoot: string):
|
||||
}
|
||||
|
||||
function listInstalledRootDistJavaScriptFiles(packageRoot: string): string[] {
|
||||
const distDir = join(packageRoot, "dist");
|
||||
if (!existsSync(distDir)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const pending = [distDir];
|
||||
const files: string[] = [];
|
||||
while (pending.length > 0) {
|
||||
const currentDir = pending.pop();
|
||||
if (!currentDir) {
|
||||
continue;
|
||||
}
|
||||
for (const entry of readdirSync(currentDir, { withFileTypes: true })) {
|
||||
const entryPath = join(currentDir, entry.name);
|
||||
const relativePath = relative(distDir, entryPath).replaceAll("\\", "/");
|
||||
if (relativePath.startsWith("extensions/")) {
|
||||
continue;
|
||||
}
|
||||
if (entry.isDirectory()) {
|
||||
pending.push(entryPath);
|
||||
continue;
|
||||
}
|
||||
if (entry.isFile() && ROOT_DIST_JAVASCRIPT_MODULE_FILE_RE.test(entry.name)) {
|
||||
files.push(entryPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return files;
|
||||
return listDistJavaScriptFiles(packageRoot, {
|
||||
skipRelativePath: (relativePath) => relativePath.startsWith("extensions/"),
|
||||
});
|
||||
}
|
||||
|
||||
type ParsedImportSpecifiersResult =
|
||||
|
||||
Reference in New Issue
Block a user