search_awesome/doc_load/load.ts
2022-11-29 17:55:06 +09:00

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();
}