2023-12-20 11:34:39 +05:30
|
|
|
import fs from "node:fs/promises";
|
|
|
|
|
import path from "node:path";
|
|
|
|
|
import childProcess from "node:child_process";
|
|
|
|
|
|
2023-12-24 20:19:58 +05:30
|
|
|
export const IMG_RX = /(\.png|\.jpg|\.svg|\.gif)$/gim;
|
|
|
|
|
export const SLUG_RX = /(?<=\nslug: ).*?$/gm;
|
2023-12-20 11:34:39 +05:30
|
|
|
|
|
|
|
|
export async function* walkSync(dir) {
|
|
|
|
|
const files = await fs.readdir(dir, { withFileTypes: true });
|
|
|
|
|
for (const file of files) {
|
|
|
|
|
if (file.isDirectory()) {
|
|
|
|
|
yield* walkSync(path.join(dir, file.name));
|
|
|
|
|
} else {
|
|
|
|
|
yield path.join(dir, file.name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function execGit(args, opts = {}, root = null) {
|
|
|
|
|
const gitRoot = root || getRootDir();
|
|
|
|
|
const { status, error, stdout, stderr } = childProcess.spawnSync(
|
|
|
|
|
"git",
|
|
|
|
|
args,
|
|
|
|
|
{
|
|
|
|
|
cwd: gitRoot,
|
|
|
|
|
// Default is 1MB
|
|
|
|
|
maxBuffer: 1024 * 1024 * 100, // 100MB
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
if (error || status !== 0) {
|
|
|
|
|
if (stderr) {
|
|
|
|
|
console.log(args);
|
|
|
|
|
console.log(`Error running git ${args}`);
|
|
|
|
|
console.error(stderr);
|
|
|
|
|
}
|
|
|
|
|
if (error) {
|
|
|
|
|
throw error;
|
|
|
|
|
}
|
|
|
|
|
throw new Error(
|
|
|
|
|
`git command failed: ${stderr.toString() || stdout.toString()}`,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
return stdout.toString().trim();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function getRootDir() {
|
|
|
|
|
return execGit(["rev-parse", "--show-toplevel"], {}, process.cwd());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function isImagePath(path) {
|
|
|
|
|
return IMG_RX.test(path);
|
|
|
|
|
}
|
2024-02-13 13:10:09 +05:30
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Returns locations (line and column numbers) of 'searchValue' in the given 'content'.
|
|
|
|
|
*/
|
|
|
|
|
export function getLocations(content, searchValue) {
|
|
|
|
|
const lineLengths = content.split("\n").map((line) => line.length);
|
|
|
|
|
const searchRx =
|
|
|
|
|
searchValue instanceof RegExp
|
|
|
|
|
? searchValue
|
|
|
|
|
: new RegExp(searchValue, "mig");
|
|
|
|
|
const matches = [...content.matchAll(searchRx)].map((match) => match.index);
|
|
|
|
|
const positions = [];
|
|
|
|
|
|
|
|
|
|
let currentPosition = 0;
|
|
|
|
|
lineLengths.forEach((lineLength, index) => {
|
|
|
|
|
lineLength += 1; // add '\n'
|
|
|
|
|
for (const match of matches) {
|
|
|
|
|
if (currentPosition < match && currentPosition + lineLength > match) {
|
|
|
|
|
positions.push({
|
|
|
|
|
line: index + 1,
|
|
|
|
|
column: match - currentPosition + 1,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
currentPosition += lineLength;
|
|
|
|
|
});
|
|
|
|
|
return positions;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Convert Markdown header into URL slug.
|
|
|
|
|
*/
|
|
|
|
|
export function stringToFragment(text) {
|
2024-08-26 22:19:24 +05:30
|
|
|
if (!text) return text;
|
2024-02-13 13:10:09 +05:30
|
|
|
return text
|
|
|
|
|
.trim()
|
|
|
|
|
.replace(/["#$%&+,/:;=?@[\]^`{|}~')(\\]/g, "")
|
|
|
|
|
.replace(/\s+/g, "_");
|
|
|
|
|
}
|