UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

137 lines 5.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DocMaker = exports.WikiChangeType = void 0; var WikiChangeType; (function (WikiChangeType) { WikiChangeType[WikiChangeType["Changed"] = 0] = "Changed"; WikiChangeType[WikiChangeType["UnimportantChange"] = 1] = "UnimportantChange"; WikiChangeType[WikiChangeType["Identical"] = 2] = "Identical"; })(WikiChangeType || (exports.WikiChangeType = WikiChangeType = {})); const DefaultReplacementPatterns = [ // eslint-disable-next-line no-irregular-whitespace -- we may produce it in output [/\d+(\.\d+)?( |\s*)?ms/g, ''], [/tmp[%A-Za-z0-9-]+/g, ''], [/"?(timing|searchTimeMs|processTimeMs|id|tsId)"?:\s*\d+(\.\d)?,?/g, ''], [/"format":"compact".+/gmius, ''], [/%%\s*\d*-+/g, ''], [/"[rR]": "\d+\.\d+\.\d+.*?"/g, ''], [/R\s*\d+\.\d+\.\d+/g, ''], [/v\d+\.\d+\.\d+/g, ''], // clean paths [/%2Fhome%2F([a-zA-Z0-9._-]+%2F)*/g, ''], // async wrapper depends on whether the promise got fulfilled already [/async|%20/g, ''], [/\s*Copied mermaid url to clipboard\s*\([^)]+\)/gmi, ''] ]; /** * Abstract base class for generating wiki files. * **Please make sure to register your WikiMaker implementation in the CLI wiki tool to have it executed: * `src/cli/wiki.ts`.** * * If this wiki page produces multiple pages ("sub files"), you can use `writeSubFile` inside the `text` method * to write those additional files. */ class DocMaker { target; filename; purpose; printHeader; currentArgs; writtenSubfiles = new Set(); /** * Creates a new WikiMaker instance. * @param target - The target path where the wiki file will be generated. * @param filename - The name of the file being generated. Probably use `module.filename`. * @param purpose - The purpose of the file, e.g., 'wiki context for types'. * @param printHeader - Whether to print the auto-generation header. Default is `true`. Only mark this `false` if you plan to add it yourself. * @protected */ constructor(target, filename, purpose, printHeader = true) { this.filename = filename; this.purpose = purpose; this.target = target; this.printHeader = printHeader; } /** * Gets the target path where the wiki file will be generated. */ getTarget() { return this.target; } /** * Gets the name of the producer of this wiki file. */ getProducer() { return this.filename; } /** * Gets the set of subfiles written during the last `make` call. */ getWrittenSubfiles() { return this.writtenSubfiles; } /** * Generates or updates the wiki file at the given target location. * @returns `true` if the file was created or updated, `false` if it was identical and not changed. */ async make(args) { this.currentArgs = args; this.writtenSubfiles = new Set(); const newText = (this.printHeader ? (await args.ctx.header(this.filename, this.purpose)) + '\n' : '') + await this.text(args); if (args.force || this.didUpdate(this.target, newText, args.readFileSync(this.target)?.toString()) === WikiChangeType.Changed) { args.writeFileSync(this.target, newText); return true; } return this.writtenSubfiles.size > 0; } /** * Please note that for subfiles you have to always add your own header */ writeSubFile(path, data) { if (!this.currentArgs) { throw new Error('DocMaker: writeSubFile called outside of make()'); } if (this.currentArgs.force || this.didUpdate(path, data, this.currentArgs.readFileSync(path)?.toString()) === WikiChangeType.Changed) { this.currentArgs.writeFileSync(path.toString(), data); this.writtenSubfiles.add(path.toString()); return true; } return false; } /** * Normalizes the given wiki text for comparison. */ normalizeText(text) { // drop first two meta lines let result = text.split('\n').slice(2).join('\n'); for (const [pattern, replacement] of DefaultReplacementPatterns) { result = result.replace(pattern, replacement); } return result.trim(); } /** * Determines the type of change between the old and new text. */ didUpdate(path, newText, oldText) { if (oldText === newText) { return WikiChangeType.Identical; } const normOld = this.normalizeText(oldText ?? ''); const normNew = this.normalizeText(newText); const same = normOld === normNew; if (!same) { // find first diff for (let i = 0; i < Math.min(normOld.length, normNew.length); i++) { if (normOld[i] !== normNew[i]) { const contextOld = normOld.slice(Math.max(0, i - 20), Math.min(normOld.length, i + 20)); const contextNew = normNew.slice(Math.max(0, i - 20), Math.min(normNew.length, i + 20)); console.log(` [${path.toString()}] First diff at pos ${i}:\n - Old: ...${contextOld}...\n + New: ...${contextNew}...`); break; } } } return same ? WikiChangeType.UnimportantChange : WikiChangeType.Changed; } } exports.DocMaker = DocMaker; //# sourceMappingURL=doc-maker.js.map