Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

style(typescript): enable strict except noImplicitAny and strictNullChecks #7559

Merged
merged 16 commits into from
Nov 24, 2022
Merged
Show file tree
Hide file tree
Changes from 15 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
26 changes: 15 additions & 11 deletions build/flaws/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import path from "path";

import chalk from "chalk";
import { RequestError } from "got";

import { Document } from "../../content";
import { FLAW_LEVELS, VALID_FLAW_CHECKS } from "../../libs/constants";
Expand Down Expand Up @@ -223,17 +223,21 @@ export async function fixFixableFlaws(doc, options, document) {
console.log(`Downloaded ${flaw.src} to ${destination}`);
newSrc = path.basename(destination);
} catch (error) {
const { response } = error;
if (response && response.statusCode === 404) {
console.log(chalk.yellow(`Skipping ${flaw.src} (404)`));
continue;
} else if (error.code === "ETIMEDOUT" || error.code === "ENOTFOUND") {
console.log(chalk.yellow(`Skipping ${flaw.src} (${error.code})`));
continue;
} else {
console.error(error);
throw error;
if (error instanceof RequestError) {
if (error.response.statusCode === 404) {
console.log(chalk.yellow(`Skipping ${flaw.src} (404)`));
continue;
} else if (
error.code === "ETIMEDOUT" ||
error.code === "ENOTFOUND"
) {
console.log(chalk.yellow(`Skipping ${flaw.src} (${error.code})`));
continue;
}
}

console.error(error);
throw error;
}
}
newRawBody = replaceMatchesInText(flaw.src, newRawBody, newSrc, {
Expand Down
6 changes: 5 additions & 1 deletion build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import path from "path";

import chalk from "chalk";
import {
MacroInvocationError,
MacroLiveSampleError,
MacroRedirectedLinkError,
} from "../kumascript/src/errors";
Expand Down Expand Up @@ -333,7 +334,10 @@ export async function buildDocument(
try {
[$, flaws] = await kumascript.render(document.url);
} catch (error) {
if (error.name === "MacroInvocationError") {
if (
error instanceof MacroInvocationError &&
error.name === "MacroInvocationError"
) {
// The source HTML couldn't even be parsed! There's no point allowing
// anything else move on.
// But considering that this might just be one of many documents you're
Expand Down
4 changes: 2 additions & 2 deletions build/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,8 @@ export function splitSections(rawHTML) {

const iterable = [...($("#_body")[0] as cheerio.Element).childNodes];
let c = 0;
iterable.forEach((child: cheerio.Element) => {
if (child.tagName === "h2") {
caugner marked this conversation as resolved.
Show resolved Hide resolved
iterable.forEach((child) => {
if ("tagName" in child && child.tagName === "h2") {
if (c) {
blocks.push(section.clone());
section.empty();
Expand Down
2 changes: 0 additions & 2 deletions client/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@
"compilerOptions": {
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"strict": true,
"module": "esnext",
"isolatedModules": true,
"noImplicitAny": false,
"noEmit": true,
"noFallthroughCasesInSwitch": true,
"jsx": "react-jsx"
Expand Down
4 changes: 2 additions & 2 deletions content/popularities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ export function getPopularities() {
path.join(dirname, "..", "popularities.json")
);
Object.entries(JSON.parse(fs.readFileSync(filePath, "utf-8"))).forEach(
([url, value]: [string, number]) => {
popularities.set(url, value);
([url, value]: [string, unknown]) => {
popularities.set(url, value as number);
}
);
}
Expand Down
2 changes: 1 addition & 1 deletion content/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export function memoize<Args>(
fn: (...args: Args[]) => any
): (...args: (Args | typeof MEMOIZE_INVALIDATE)[]) => any {
if (process.env.NODE_ENV !== "production") {
return fn;
return fn as (...args: (Args | typeof MEMOIZE_INVALIDATE)[]) => any;
}

const cache = new LRU({ max: 2000 });
Expand Down
5 changes: 4 additions & 1 deletion filecheck/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,10 @@ export async function checkFile(filePath, options: CheckerOptions = {}) {
}
const $ = cheerio.load(content);
const disallowedTagNames = new Set(["script", "object", "iframe", "embed"]);
$("*").each((i, element: cheerio.Element) => {
$("*").each((i, element) => {
if (!("tagName" in element)) {
return;
}
const { tagName } = element;
if (disallowedTagNames.has(tagName)) {
throw new Error(`${filePath} contains a <${tagName}> tag`);
Expand Down
8 changes: 5 additions & 3 deletions kumascript/src/api/mdn.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import got from "got";
import { KumaThis } from "../environment";
import * as util from "./util";

// Module level caching for repeat calls to fetchWebExtExamples().
Expand All @@ -23,7 +24,7 @@ const mdn = {
* { "en-US": "Foo", "de": "Bar", "es": "Baz" }
* Return the one which matches the current locale.
*/
localString(strings) {
localString(this: KumaThis, strings) {
let lang = this.env.locale;
if (!(lang in strings)) lang = "en-US";
return strings[lang];
Expand All @@ -35,7 +36,7 @@ const mdn = {
* Return a map which matches the current locale, falling back to en-US
* properties when the localized map contains partial properties.
*/
localStringMap(maps) {
localStringMap(this: KumaThis, maps) {
const lang = this.env.locale;
const defaultMap = maps["en-US"];
if (lang == "en-US" || !(lang in maps)) {
Expand Down Expand Up @@ -66,7 +67,7 @@ const mdn = {
* "hello");
* => "Hallo!" (in case the locale is 'de')
*/
getLocalString(strings, key) {
getLocalString(this: KumaThis, strings, key) {
if (!Object.prototype.hasOwnProperty.call(strings, key)) {
return key;
}
Expand Down Expand Up @@ -122,6 +123,7 @@ const mdn = {
* Throw a deprecation error.
*/
deprecated(
this: KumaThis,
message = "This macro has been deprecated, and should be removed."
) {
this.env.recordNonFatalError("deprecated", message);
Expand Down
14 changes: 9 additions & 5 deletions kumascript/src/api/page.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { KumaThis } from "../environment";

const page = {
// Determines whether or not the page has the specified tag. Returns
// true if it does, otherwise false. This is case-insensitive.
Expand Down Expand Up @@ -38,8 +40,8 @@ const page = {
//
// This is not called by any macros, and is only used here by
// wiki.tree(), so we could move it to be part of that function.
subpages(path, depth, self) {
return this.page.subpagesExpand(path, depth, self);
subpages(this: KumaThis, path, depth, self) {
return (this.page as any).subpagesExpand(path, depth, self);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know why this.page doesn't work, possibly because this.page refers to what this would be without specifying this: KumaThis. 🤷

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the this.page.subpagesExpanded needed vs this.subpagesExpanded

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haven't tried, but it looks like all those methods get called using Function.call() with the environment ("KumaThis") as argThis.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this.page.XXX is needed because this is not the page when this function is called, as per the above statement. TypeScript doesn't like this since we're essentially overwriting the variable with a new value, hence the need to cast to any here.

},

// Optional path, defaults to current page
Expand All @@ -50,11 +52,13 @@ const page = {
// Optional self, defaults to false. Include the path page in
// the results
//
subpagesExpand(path, depth, self) {
subpagesExpand(this: KumaThis, path, depth, self) {
try {
return this.info.getChildren(path || this.env.url, self);
} catch (error) {
this.env.recordNonFatalError("bad-pages", error.message);
if (error instanceof Error) {
this.env.recordNonFatalError("bad-pages", error.message);
}
// We allow ourselves to be forgiving with this function because
// we justify it by the fact that at least we record a flaw!
return [];
Expand Down Expand Up @@ -87,7 +91,7 @@ const page = {
}
},

translations(path) {
translations(this: KumaThis, path) {
return this.info.getTranslations(path || this.env.url);
},
};
Expand Down
94 changes: 45 additions & 49 deletions kumascript/src/api/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,58 +175,54 @@ export class HTMLTool {
// If it's a H1-6 tag, generate (slugify) an ID from its text.
// If all else, generate a unique one.
// And we ensure all IDs that get added are completely lowercase.
$([...INJECT_SECTION_ID_TAGS].join(",")).each(
(i, element: cheerio.Element) => {
const $element = $(element);
const isDt = $element[0].name === "dt";
// Default is the existing one. Let's see if we need to change it.
let id = $element.attr("id");
if ($element.attr("name")) {
// The "name" attribute overrides any current "id".
id = slugify($element.attr("name").toLowerCase());
} else if (id) {
// If there’s already has an ID, use it — and lowercase it as long
// as the value isn’t "Quick_links" (which we need to keep as-is),
// and as long as it’s not a class=bc-data div (the ID for which we
// need to keep as-is).
if (
id !== "Quick_links" &&
$element[0].attribs["class"] !== "bc-data"
) {
id = id.toLowerCase();
}
} else if (H1_TO_H6_TAGS.has($element[0].name) || isDt) {
// For heading elements, we start by getting the text content of
// the entire heading element (including any children it may have).
let text = $element.text();
if (isDt) {
// dt elements can, along with the actual term, contain stuff
// like <span class="badge inline optional">Optional</span>. If
// we include the text from that, we end up with generated IDs
// like id="rtcSessionDescriptionInit_Optional". So, for dt, we
// take just the text from the first element child of the dt.
text = $element.contents().first().text();
}
id = slugify(text).toLowerCase();
if (id) {
// Ensure that the slugified "id" has not already been
// taken. If it has, create a unique version of it.
let version = 2;
const originalID = id;
while (knownIDs.has(id)) {
id = `${originalID}_${version++}`.toLowerCase();
}
}
$([...INJECT_SECTION_ID_TAGS].join(",")).each((i, element) => {
const $element = $(element);
const $first = $element[0] as cheerio.Element;
const isDt = $first.name === "dt";
// Default is the existing one. Let's see if we need to change it.
let id = $element.attr("id");
if ($element.attr("name")) {
// The "name" attribute overrides any current "id".
id = slugify($element.attr("name").toLowerCase());
} else if (id) {
// If there’s already has an ID, use it — and lowercase it as long
// as the value isn’t "Quick_links" (which we need to keep as-is),
// and as long as it’s not a class=bc-data div (the ID for which we
// need to keep as-is).
if (id !== "Quick_links" && $first.attribs["class"] !== "bc-data") {
id = id.toLowerCase();
}
} else if (H1_TO_H6_TAGS.has($first.name) || isDt) {
// For heading elements, we start by getting the text content of
// the entire heading element (including any children it may have).
let text = $element.text();
if (isDt) {
// dt elements can, along with the actual term, contain stuff
// like <span class="badge inline optional">Optional</span>. If
// we include the text from that, we end up with generated IDs
// like id="rtcSessionDescriptionInit_Optional". So, for dt, we
// take just the text from the first element child of the dt.
text = $element.contents().first().text();
}
if (!id) {
// No need to call toLowerCase() here, because generateUniqueID()
// makes all-lowercase IDs in the form sectN, where N is a number.
id = generateUniqueID();
id = slugify(text).toLowerCase();
if (id) {
// Ensure that the slugified "id" has not already been
// taken. If it has, create a unique version of it.
let version = 2;
const originalID = id;
while (knownIDs.has(id)) {
id = `${originalID}_${version++}`.toLowerCase();
}
}
knownIDs.add(id);
$element.attr("id", id);
}
);
if (!id) {
// No need to call toLowerCase() here, because generateUniqueID()
// makes all-lowercase IDs in the form sectN, where N is a number.
id = generateUniqueID();
}
knownIDs.add(id);
$element.attr("id", id);
});
return this;
}

Expand Down
13 changes: 11 additions & 2 deletions kumascript/src/api/web.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import * as util from "./util";
const DUMMY_BASE_URL = "https://example.com";

import { CONTENT_ROOT } from "../../../libs/env";
import { KumaThis } from "../environment";

const _warned = new Map();
// The purpose of this function is to make sure `console.warn` is only called once
Expand Down Expand Up @@ -52,7 +53,15 @@ const web = {
//
// For translated content, if the document doesn't exist
// then hyperlink to corresponding en-US document is returned.
smartLink(href, title, content, subpath, basepath, ignoreFlawMacro = null) {
smartLink(
this: KumaThis,
href,
title,
content,
subpath,
basepath,
ignoreFlawMacro = null
) {
let flaw;
let flawAttribute = "";
const page = this.info.getPageByURL(href);
Expand Down Expand Up @@ -164,7 +173,7 @@ const web = {
flawAttribute = ` data-flaw-src="${util.htmlEscape(flaw.macroSource)}"`;
}
// Let's get a potentially localized title for when the document is missing.
const titleWhenMissing = this.mdn.getLocalString(
const titleWhenMissing = (this.mdn as any).getLocalString(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is similar to the previous issue, except that this.web.getJSONData() works here (although this.web is the self-reference here) whereas this.mdn.getLocalString() doesn't. 😕

this.web.getJSONData("L10n-Common"),
"summary"
);
Expand Down
15 changes: 8 additions & 7 deletions kumascript/src/api/wiki.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { KumaThis } from "../environment";
import * as util from "./util";

const wiki = {
Expand All @@ -12,7 +13,7 @@ const wiki = {
//
// Doesn't support the revision parameter offered by DekiScript
//
async page(path, section, revision, show, heading) {
async page(this: KumaThis, path, section, revision, show, heading) {
// Adjusts the visibility and heading levels of the specified HTML.
//
// The show parameter indicates whether or not the top level
Expand Down Expand Up @@ -57,7 +58,7 @@ const wiki = {
}

let result = await this.renderPrerequisiteFromURL(
this.wiki.ensureExistence(path)
(this.wiki as any).ensureExistence(path)
);
const pathDescription = this.info.getDescription(path);

Expand All @@ -78,17 +79,17 @@ const wiki = {
},

// Returns the page object for the specified page.
getPage(path) {
getPage(this: KumaThis, path) {
return this.info.getPageByURL(path || this.env.url);
},

hasPage(path) {
hasPage(this: KumaThis, path) {
const page = this.info.getPageByURL(path || this.env.url);

return Boolean(page.slug);
},

ensureExistence(path) {
ensureExistence(this: KumaThis, path) {
if (!this.info.hasPage(path)) {
throw new Error(
`${this.env.url.toLowerCase()} references ${this.info.getDescription(
Expand All @@ -115,13 +116,13 @@ const wiki = {
// Special note: If ordered is true, pages whose locale differ from
// the current page's locale are omitted, to work around misplaced
// localizations showing up in navigation.
tree(path, depth, self, reverse, ordered) {
tree(this: KumaThis, path, depth, self, reverse, ordered) {
// If the path ends with a slash, remove it.
if (path.substr(-1, 1) === "/") {
path = path.slice(0, -1);
}

const pages = this.page.subpages(path, depth, self);
const pages = (this.page as any).subpages(path, depth, self);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto


if (reverse == 0) {
pages.sort(alphanumForward);
Expand Down
Loading