mirror of
https://bitbucket.org/siakitem/my-pi.git
synced 2026-08-28 08:35:57 +00:00
chore: initialize my-pi extension bundle
This commit is contained in:
@@ -0,0 +1,317 @@
|
||||
export type Language =
|
||||
| "typescript"
|
||||
| "javascript"
|
||||
| "python"
|
||||
| "rust"
|
||||
| "go"
|
||||
| "java"
|
||||
| "c"
|
||||
| "cpp"
|
||||
| "unknown";
|
||||
|
||||
const LANGUAGE_EXTENSIONS: Record<string, Language> = {
|
||||
".ts": "typescript",
|
||||
".tsx": "typescript",
|
||||
".js": "javascript",
|
||||
".jsx": "javascript",
|
||||
".mjs": "javascript",
|
||||
".py": "python",
|
||||
".pyw": "python",
|
||||
".rs": "rust",
|
||||
".go": "go",
|
||||
".java": "java",
|
||||
".c": "c",
|
||||
".h": "c",
|
||||
".cpp": "cpp",
|
||||
".hpp": "cpp",
|
||||
".cc": "cpp",
|
||||
};
|
||||
|
||||
interface CommentPatterns {
|
||||
line?: string;
|
||||
blockStart?: string;
|
||||
blockEnd?: string;
|
||||
docLine?: string;
|
||||
docBlockStart?: string;
|
||||
}
|
||||
|
||||
const COMMENT_PATTERNS: Record<Language, CommentPatterns> = {
|
||||
typescript: { line: "//", blockStart: "/*", blockEnd: "*/", docBlockStart: "/**" },
|
||||
javascript: { line: "//", blockStart: "/*", blockEnd: "*/", docBlockStart: "/**" },
|
||||
python: { line: "#", blockStart: '"""', blockEnd: '"""', docBlockStart: '"""' },
|
||||
rust: { line: "//", blockStart: "/*", blockEnd: "*/", docLine: "///", docBlockStart: "/**" },
|
||||
go: { line: "//", blockStart: "/*", blockEnd: "*/", docBlockStart: "/**" },
|
||||
java: { line: "//", blockStart: "/*", blockEnd: "*/", docBlockStart: "/**" },
|
||||
c: { line: "//", blockStart: "/*", blockEnd: "*/", docBlockStart: "/**" },
|
||||
cpp: { line: "//", blockStart: "/*", blockEnd: "*/", docBlockStart: "/**" },
|
||||
unknown: { line: "//", blockStart: "/*", blockEnd: "*/" },
|
||||
};
|
||||
|
||||
const IMPORT_PATTERN = /^(use\s+|import\s+|from\s+|require\(|#include)/;
|
||||
const SIGNATURE_PATTERN = /^(pub\s+)?(async\s+)?(fn|def|function|func|class|struct|enum|trait|interface|type)\s+\w+/;
|
||||
const CONST_PATTERN = /^(const|static|let|pub\s+const|pub\s+static)\s+/;
|
||||
|
||||
function getCodePortion(line: string, language: Language): string {
|
||||
const patterns = COMMENT_PATTERNS[language];
|
||||
let quote: '"' | "'" | "`" | null = null;
|
||||
let escaped = false;
|
||||
let code = "";
|
||||
|
||||
for (let index = 0; index < line.length; index += 1) {
|
||||
const character = line[index] ?? "";
|
||||
|
||||
if (escaped) {
|
||||
escaped = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (quote !== null) {
|
||||
if (character === "\\") {
|
||||
escaped = true;
|
||||
continue;
|
||||
}
|
||||
if (character === quote) {
|
||||
quote = null;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (patterns.line && line.startsWith(patterns.line, index)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (patterns.blockStart && patterns.blockEnd && line.startsWith(patterns.blockStart, index)) {
|
||||
const blockEndIndex = line.indexOf(patterns.blockEnd, index + patterns.blockStart.length);
|
||||
if (blockEndIndex === -1) {
|
||||
break;
|
||||
}
|
||||
index = blockEndIndex + patterns.blockEnd.length - 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (character === '"' || character === "'" || character === "`") {
|
||||
quote = character;
|
||||
continue;
|
||||
}
|
||||
|
||||
code += character;
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
function countCodeBraces(line: string, language: Language): { open: number; close: number } {
|
||||
let open = 0;
|
||||
let close = 0;
|
||||
|
||||
for (const character of getCodePortion(line, language)) {
|
||||
if (character === "{") {
|
||||
open += 1;
|
||||
} else if (character === "}") {
|
||||
close += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return { open, close };
|
||||
}
|
||||
|
||||
export function detectLanguage(filePath: string): Language {
|
||||
const lastDot = filePath.lastIndexOf(".");
|
||||
if (lastDot === -1) {
|
||||
return "unknown";
|
||||
}
|
||||
const extension = filePath.slice(lastDot).toLowerCase();
|
||||
return LANGUAGE_EXTENSIONS[extension] ?? "unknown";
|
||||
}
|
||||
|
||||
export function filterMinimal(content: string, language: Language): string {
|
||||
const patterns = COMMENT_PATTERNS[language];
|
||||
const lines = content.split("\n");
|
||||
const result: string[] = [];
|
||||
let inBlockComment = false;
|
||||
let inDocstring = false;
|
||||
let inUserscriptMetadataBlock = false;
|
||||
const userscriptMetadataStartPattern = /^\/\/\s*==\s*userscript\s*==$/i;
|
||||
const userscriptMetadataContentPattern = /^\/\/\s*@\w+/;
|
||||
const userscriptMetadataEndPattern = /^\/\/\s*==\s*\/userscript\s*==$/i;
|
||||
|
||||
for (const line of lines) {
|
||||
const trimmed = line.trim();
|
||||
const isUserscriptMetadataStart = userscriptMetadataStartPattern.test(trimmed);
|
||||
const isUserscriptMetadataContent = userscriptMetadataContentPattern.test(trimmed);
|
||||
const isUserscriptMetadataEnd = userscriptMetadataEndPattern.test(trimmed);
|
||||
|
||||
if (isUserscriptMetadataStart) {
|
||||
inUserscriptMetadataBlock = true;
|
||||
result.push(line);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (inUserscriptMetadataBlock) {
|
||||
result.push(line);
|
||||
if (isUserscriptMetadataEnd) {
|
||||
inUserscriptMetadataBlock = false;
|
||||
} else if (isUserscriptMetadataContent) {
|
||||
// Preserve metadata key/value lines (e.g. // @name) within the userscript block.
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (patterns.blockStart && patterns.blockEnd) {
|
||||
if (
|
||||
!inDocstring &&
|
||||
trimmed.includes(patterns.blockStart) &&
|
||||
!(patterns.docBlockStart && trimmed.startsWith(patterns.docBlockStart))
|
||||
) {
|
||||
inBlockComment = true;
|
||||
}
|
||||
|
||||
if (inBlockComment) {
|
||||
if (trimmed.includes(patterns.blockEnd)) {
|
||||
inBlockComment = false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (language === "python" && trimmed.startsWith('"""')) {
|
||||
inDocstring = !inDocstring;
|
||||
result.push(line);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (inDocstring) {
|
||||
result.push(line);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (patterns.line && trimmed.startsWith(patterns.line)) {
|
||||
if (patterns.docLine && trimmed.startsWith(patterns.docLine)) {
|
||||
result.push(line);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (trimmed.length === 0) {
|
||||
result.push("");
|
||||
continue;
|
||||
}
|
||||
|
||||
result.push(line);
|
||||
}
|
||||
|
||||
return result
|
||||
.join("\n")
|
||||
.replace(/\n{3,}/g, "\n\n")
|
||||
.trim();
|
||||
}
|
||||
|
||||
export function filterAggressive(content: string, language: Language): string {
|
||||
const minimal = filterMinimal(content, language);
|
||||
const lines = minimal.split("\n");
|
||||
const result: string[] = [];
|
||||
let braceDepth = 0;
|
||||
let inImplementation = false;
|
||||
|
||||
for (const line of lines) {
|
||||
const trimmed = line.trim();
|
||||
|
||||
if (IMPORT_PATTERN.test(trimmed)) {
|
||||
result.push(line);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (SIGNATURE_PATTERN.test(trimmed)) {
|
||||
result.push(line);
|
||||
inImplementation = true;
|
||||
braceDepth = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
const braces = countCodeBraces(line, language);
|
||||
const codeTrimmed = getCodePortion(line, language).trim();
|
||||
|
||||
if (inImplementation) {
|
||||
braceDepth += braces.open;
|
||||
braceDepth -= braces.close;
|
||||
|
||||
if (braceDepth <= 1 && (codeTrimmed === "{" || codeTrimmed === "}" || codeTrimmed.endsWith("{"))) {
|
||||
result.push(line);
|
||||
}
|
||||
|
||||
if (braceDepth <= 0) {
|
||||
inImplementation = false;
|
||||
if (trimmed.length > 0 && trimmed !== "}") {
|
||||
result.push(" // ... implementation");
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (CONST_PATTERN.test(trimmed)) {
|
||||
result.push(line);
|
||||
}
|
||||
}
|
||||
|
||||
return result.join("\n").trim();
|
||||
}
|
||||
|
||||
export function smartTruncate(content: string, maxLines: number, _language: Language): string {
|
||||
const lines = content.split("\n");
|
||||
if (lines.length <= maxLines) {
|
||||
return content;
|
||||
}
|
||||
|
||||
const result: string[] = [];
|
||||
let keptLines = 0;
|
||||
let skippedSection = false;
|
||||
|
||||
for (const line of lines) {
|
||||
const trimmed = line.trim();
|
||||
const isImportant =
|
||||
SIGNATURE_PATTERN.test(trimmed) ||
|
||||
IMPORT_PATTERN.test(trimmed) ||
|
||||
trimmed.startsWith("pub ") ||
|
||||
trimmed.startsWith("export ") ||
|
||||
trimmed === "}" ||
|
||||
trimmed === "{";
|
||||
|
||||
if (isImportant || keptLines < maxLines / 2) {
|
||||
if (skippedSection) {
|
||||
result.push(` // ... ${lines.length - keptLines} lines omitted`);
|
||||
skippedSection = false;
|
||||
}
|
||||
result.push(line);
|
||||
keptLines += 1;
|
||||
} else {
|
||||
skippedSection = true;
|
||||
}
|
||||
|
||||
if (keptLines >= maxLines - 1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (skippedSection || keptLines < lines.length) {
|
||||
result.push(`// ... ${lines.length - keptLines} more lines (total: ${lines.length})`);
|
||||
}
|
||||
|
||||
return result.join("\n");
|
||||
}
|
||||
|
||||
export function filterSourceCode(
|
||||
content: string,
|
||||
language: Language,
|
||||
level: "none" | "minimal" | "aggressive",
|
||||
): string {
|
||||
switch (level) {
|
||||
case "none":
|
||||
return content;
|
||||
case "minimal":
|
||||
return filterMinimal(content, language);
|
||||
case "aggressive":
|
||||
return filterAggressive(content, language);
|
||||
default:
|
||||
return content;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user