Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export interface Class {
parent?: string;
description?: string;
functions?: Array<Function>;
fields?: Array<ClassField>;
}

export interface Panel {
Expand Down Expand Up @@ -80,6 +81,15 @@ export interface Function {
overloads?: Array<FunctionOverload>;
}

export interface ClassField {
name: string;
type: string;
parent: string;
source?: FunctionSource;
description?: string;
realms: Array<Realm>;
}

export interface Type {
name: string;
description?: string;
Expand Down
64 changes: 64 additions & 0 deletions src/wiki-scraper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,70 @@ describe("WikiScraper", () => {
]);
});

it("parses a field page", () => {
const mathPiPageContent =
'<function name="pi" parent="math" type="libraryfield">\r\n' +
"\t<description>\r\n" +
"A variable containing the mathematical constant pi. (`3.1415926535898`)\r\n" +
"\r\n" +
"See also: <page>Trigonometry</page>\r\n" +
"\r\n" +
"<note>It should be noted that due to the nature of floating point numbers, results of calculations with `math.pi` may not be what you expect. See second example below.</note>\r\n" +
"</description>\r\n" +
"\t<realm>Shared and Menu</realm>\r\n" +
"\t<rets>\r\n" +
'\t\t<ret name="" type="number">The mathematical constant, Pi.</ret>\r\n' +
"\t</rets>\r\n" +
"</function>\r\n" +
"\r\n" +
"<example>\r\n" +
"<code>\r\n" +
"print( math.cos( math.pi ) )\r\n" +
"</code>\r\n" +
"<output>\r\n" +
"```\r\n" +
"-1\r\n" +
"```\r\n" +
"</output>\r\n" +
"</example>\r\n" +
"\r\n" +
"<example>\r\n" +
"<description>\r\n" +
"\r\n" +
"`sin(π) = 0`, but because floating point precision is not unlimited it cannot be calculated as exactly `0`.\r\n" +
"</description>\r\n" +
"<code>\r\n" +
"print( math.sin( math.pi ), math.sin( math.pi ) == 0 )\r\n" +
"</code>\r\n" +
"<output>\r\n" +
"```\r\n" +
"1.2246467991474e-16 false\r\n" +
"```\r\n" +
"</output>\r\n" +
"</example>\r\n";

const isField = wikiScraper.isClassFieldPage(mathPiPageContent);
expect(isField).toBeTruthy()

const mathPiField = wikiScraper.parseFieldPage(mathPiPageContent);

expect(mathPiField.name).toBe("pi");
expect(mathPiField.parent).toBe("math");
expect(mathPiField.realms).toEqual(
expect.arrayContaining(["client", "server", "menu"]),
);
expect(mathPiField.type).toBe("number");
const expectedDesc = `
A variable containing the mathematical constant pi. (\`3.1415926535898\`)

See also: <page>Trigonometry</page>

<note>It should be noted that due to the nature of floating point numbers, results of calculations with \`math.pi\` may not be what you expect. See second example below.</note>
`
expect(mathPiField.description).toBe(expectedDesc.trim());
});


it("parses a panel page", () => {
const dbuttonPageContent =
"<panel>\r\n" +
Expand Down
88 changes: 73 additions & 15 deletions src/wiki-scraper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
FunctionArgument,
FunctionReturnValue,
Realm,
ClassField,
Class,
Panel,
WikiPage,
Expand Down Expand Up @@ -269,6 +270,11 @@ export class WikiScraper {
if (type.description) {
_class.description = type.description;
}
} else if (this.isClassFieldPage(wikiPage.content)) {
const field = this.parseFieldPage(wikiPage.content);

_class.fields = _class.fields ?? [];
_class.fields.push(field);
} else if (this.isFunctionPage(wikiPage.content)) {
const _function = this.parseFunctionPage(wikiPage.content);

Expand All @@ -286,6 +292,43 @@ export class WikiScraper {
return Array.from(classes.values());
}

public parseFieldPage(pageContent: string): ClassField {
const $ = this.parseContent(pageContent);
const name = $("function").attr().name;
const parent = $("function").attr().parent;
let rawDescription = $("function > description").html();
const $sourceFile = $("function > file");
const realmsRaw = this.trimMultiLineString($("function > realm").text());
const realms = this.parseRealms(realmsRaw);

const typeEl = $("function > rets")
.children()
.filter((_, el) => el.type == "tag")
.first();

const type = typeEl.attr("type") ?? "nil"

// Currently all the fields define both a normal description and a
// return description, but since the return description seems to mostly
// be useless, only pick it if there is no real description
if (!this.isValidDescription(rawDescription)) {
rawDescription = $(typeEl).html();
}
let description: string | undefined = undefined
if (this.isValidDescription(rawDescription)) {
description = this.trimMultiLineString(rawDescription);
}

return {
name,
type,
description,
parent,
realms,
source: this.parseSourceFile($sourceFile)
};
}

public parseFunctionPage(pageContent: string): Function {
const $ = this.parseContent(pageContent);
const name = $("function").attr().name;
Expand Down Expand Up @@ -339,6 +382,7 @@ export class WikiScraper {
name: name,
parent: parent,
realms: realms,
source: this.parseSourceFile($sourceFile)
};

if (description && description !== "") {
Expand All @@ -362,27 +406,31 @@ export class WikiScraper {
});
}

if ($sourceFile.length > 0) {
const file = $sourceFile.text();
return _function;
}

private parseSourceFile($sourceFile: cheerio.Cheerio): FunctionSource | undefined {
if ($sourceFile.length == 0) {
return undefined
}

const line = $sourceFile.attr().line.replace("L", "");
const lines = line.split("-");
const lineStart = lines[0];
const lineEnd = lines[1];
const file = $sourceFile.text();

const source: FunctionSource = {
file: file,
lineStart: Number(lineStart),
};
const line = $sourceFile.attr().line.replace("L", "");
const lines = line.split("-");
const lineStart = lines[0];
const lineEnd = lines[1];

if (lineEnd) {
source.lineEnd = Number(lineEnd);
}
const source: FunctionSource = {
file: file,
lineStart: Number(lineStart),
};

_function.source = source;
if (lineEnd) {
source.lineEnd = Number(lineEnd);
}

return _function;
return source;
}

public parsePanelPage(pageContent: string): Panel {
Expand Down Expand Up @@ -535,6 +583,12 @@ export class WikiScraper {
return $("panel").length > 0;
}

public isClassFieldPage(pageContent: string): boolean {
const $ = this.parseContent(pageContent);

return $("function[type$=field]").length > 0;
}

public isFunctionPage(pageContent: string): boolean {
const $ = this.parseContent(pageContent);

Expand Down Expand Up @@ -591,6 +645,10 @@ export class WikiScraper {
return cheerio.load(content, { decodeEntities: false });
}

private isValidDescription(str: string | null): str is string {
return str != null && str != ""
}

private trimMultiLineString(str: string) {
return str
.split("\n")
Expand Down