136 lines
4.0 KiB
TypeScript
136 lines
4.0 KiB
TypeScript
import {parse as parseYaml, stringify} from "https://deno.land/std@0.166.0/encoding/yaml.ts";
|
|
|
|
function trimSubstring(str: string, start: number, end: number) {
|
|
while (str[start] === ' ' || str[start] === '\t' || str[start] === '\r' || str[start] === '\n') {
|
|
start++;
|
|
}
|
|
return str.substring(start, end);
|
|
}
|
|
|
|
function splitTwo(str: string, separator: string): [string, string] {
|
|
const index = str.indexOf(separator);
|
|
if (index === -1) {
|
|
return [str, ''];
|
|
}
|
|
return [str.substring(0, index), str.substring(index + separator.length)];
|
|
}
|
|
|
|
export interface Doc {
|
|
from_url?: string;
|
|
name: string;
|
|
author: string;
|
|
star: number;
|
|
fork: number;
|
|
desc: string;
|
|
url: string;
|
|
tags: string[];
|
|
readme: string;
|
|
}
|
|
|
|
export class DocParser {
|
|
constructor() {
|
|
}
|
|
|
|
parse(content: string) {
|
|
if(!content.startsWith('---')){
|
|
throw new Error('Invalid doc format');
|
|
}
|
|
const index = content.indexOf('\n---', 3);
|
|
const meta = content.substring(3, index);
|
|
const readme = trimSubstring(content, index + 4, content.length);
|
|
const doc = parseYaml(meta) as Doc;
|
|
doc.readme = readme;
|
|
return doc;
|
|
}
|
|
|
|
parseAlternative(content: string): Doc {
|
|
if(!content.startsWith('---')){
|
|
throw new Error('Invalid doc format');
|
|
}
|
|
const index = content.indexOf('\n---', 3);
|
|
const meta = content.substring(3, index);
|
|
const readme = trimSubstring(content, index + 4, content.length);
|
|
const doc = {} as Doc;
|
|
const lines = meta.split('\n').map(line => line.trim());
|
|
for(const line of lines){
|
|
if(line.length === 0) continue;
|
|
let [key, value] = splitTwo(line, ':');
|
|
value = value.trimStart();
|
|
if (value.startsWith('"') && value.endsWith('"')) {
|
|
value = value.substring(1, value.length - 1);
|
|
value = value.replace('\\"', '"');
|
|
}
|
|
key = key.trimEnd();
|
|
switch(key){
|
|
case 'name':
|
|
doc.name = value;
|
|
break;
|
|
case 'author':
|
|
doc.author = value;
|
|
break;
|
|
case 'star':
|
|
doc.star = parseInt(value);
|
|
break;
|
|
case 'fork':
|
|
doc.fork = parseInt(value);
|
|
break;
|
|
case 'desc':
|
|
doc.desc = value;
|
|
break;
|
|
case 'url':
|
|
doc.url = value;
|
|
break;
|
|
case 'tags':
|
|
doc.tags = JSON.parse(value.replaceAll("'",'"'));
|
|
break;
|
|
case 'from_url':
|
|
doc.from_url = value;
|
|
break;
|
|
default:
|
|
throw new Error(`Invalid key: ${key}`);
|
|
}
|
|
}
|
|
doc.readme = readme;
|
|
return doc;
|
|
}
|
|
}
|
|
|
|
export async function readDoc(path: string, alternative: boolean = false): Promise<Doc> {
|
|
const doc = await Deno.readTextFile(path);
|
|
const parser = new DocParser();
|
|
if(alternative){
|
|
return parser.parseAlternative(doc);
|
|
}
|
|
return parser.parse(doc);
|
|
}
|
|
|
|
function genDocContent(doc: Doc): string {
|
|
return `---
|
|
${doc.from_url ? `from_url: ${doc.from_url}\n` : ''}name: "${doc.name}"
|
|
author: "${doc.author}"
|
|
star: ${doc.star}
|
|
fork: ${doc.fork}
|
|
desc: "${doc.desc.replaceAll("\"", "\\\"")}"
|
|
url: ${doc.url}
|
|
tags: ${JSON.stringify(doc.tags)}
|
|
---
|
|
${doc.readme}
|
|
`;
|
|
}
|
|
|
|
export async function writeDoc(path: string, doc: Doc, options?: Omit<Deno.WriteFileOptions, "append">) {
|
|
const content = genDocContent(doc);
|
|
await Deno.writeTextFile(path, content, options);
|
|
}
|
|
|
|
async function main() {
|
|
const doc = await readDoc('./mysample.md');
|
|
console.log(stringify(doc as any));
|
|
const doc2 = await readDoc('./mysample.md', true);
|
|
console.log(stringify(doc2 as any));
|
|
console.log(genDocContent(doc2));
|
|
}
|
|
|
|
if (import.meta.main) {
|
|
await main();
|
|
} |