Skip to content

Commit

Permalink
Merge pull request #454 from the-draupnir-project/gnuxie/dead-document
Browse files Browse the repository at this point in the history
TypeCheck JSX expressions, children, and attributes ^-^
  • Loading branch information
Gnuxie authored Jun 15, 2024
2 parents c4ac8ad + d0cc9ca commit 54437ee
Show file tree
Hide file tree
Showing 10 changed files with 56 additions and 27 deletions.
2 changes: 1 addition & 1 deletion src/appservice/bot/ListCommand.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ defineMatrixInterfaceAdaptor({
<code>{draupnir.clientUserID}</code>
<code>{draupnir.failType}</code>:
<br />
{draupnir.cause}
{String(draupnir.cause)}
</li>
})}
</ul>
Expand Down
4 changes: 2 additions & 2 deletions src/capabilities/CommonRenderers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,9 @@ export function renderResultForUsersInRoom(results: ResultForUsersInRoom, { summ
return <details>
<summary>{summary}</summary>
<ul>
{[...results.map.entries()].map(([userID, outcome]) => {
{[...results.map.entries()].map(([userID, outcome]) =>
<li>{renderUserOutcome(userID, outcome)}</li>
})}
)}
</ul>
</details>
}
2 changes: 1 addition & 1 deletion src/commands/Help.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ function renderTableHelp(table: CommandTable): DocumentNode {
return <fragment>
<b>Documentation: </b> <a href={DOCUMENTATION_URL}>{DOCUMENTATION_URL}</a><br/>
<details>
<summary><b>{table.name} commands:</b></summary>
<summary><b>{table.name.toString()} commands:</b></summary>
{table.getExportedCommands().map(renderCommandSummary)}
{table.getImportedTables().map(renderTableHelp)}
</details>
Expand Down
4 changes: 2 additions & 2 deletions src/commands/KickCommand.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,14 @@ function renderUsersToKick(usersToKick: UsersToKick): DocumentNode {
<summary>
Kicking {usersToKick.size} unique users from protected rooms.
</summary>
{[...usersToKick.entries()].map(([userID, rooms]) => {
{[...usersToKick.entries()].map(([userID, rooms]) =>
<details>
<summary>Kicking {userID} from {rooms.length} rooms.</summary>
<ul>
{rooms.map(room => <li>{room}</li>)}
</ul>
</details>
})}
)}
</details>
</fragment>
}
Expand Down
2 changes: 1 addition & 1 deletion src/commands/ProtectionsCommands.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ function renderSettingChangeSummary(summary: SettingChangeSummary): DocumentNode
const oldJSON = summary.description.toJSON({ [summary.description.key]: summary.oldValue });
const newJSON = summary.description.toJSON({ [summary.description.key]: summary.newValue });
return <fragment>
Setting {summary.description.key} changed from {oldJSON} to {newJSON}
Setting {summary.description.key} changed from <code>{JSON.stringify(oldJSON)}</code> to <code>{JSON.stringify(newJSON)}</code>
</fragment>
}

Expand Down
4 changes: 2 additions & 2 deletions src/commands/ResolveAlias.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import { resolveRoomReferenceSafe } from "matrix-protection-suite-for-matrix-bot
import { defineInterfaceCommand, findTableCommand } from "./interface-manager/InterfaceCommand";
import { ParsedKeywords, findPresentationType, parameters } from "./interface-manager/ParameterParsing";
import { defineMatrixInterfaceAdaptor } from "./interface-manager/MatrixInterfaceAdaptor";
import { tickCrossRenderer } from "./interface-manager/MatrixHelpRenderer";
import { renderRoomPill, tickCrossRenderer } from "./interface-manager/MatrixHelpRenderer";
import { renderMatrixAndSend } from "./interface-manager/DeadDocumentMatrix";
import { JSXFactory } from "./interface-manager/JSXFactory";

Expand Down Expand Up @@ -62,7 +62,7 @@ defineMatrixInterfaceAdaptor({
return;
}
await renderMatrixAndSend(
<root>{result.ok}</root>,
<root><code>{result.ok.toRoomIDOrAlias()}</code> - {renderRoomPill(result.ok)}</root>,
commandRoomID,
event,
client
Expand Down
50 changes: 39 additions & 11 deletions src/commands/interface-manager/JSXFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import { DocumentNode, LeafNode, makeDocumentNode, makeLeafNode, NodeTag, TextNode } from "./DeadDocument";
import { DeadDocumentPresentationMirror } from "./DeadDocumentPresentation";

type rawJSX = DocumentNode|LeafNode|string|number|Array<rawJSX>;
type JSXChild = DocumentNode|LeafNode|string|number|JSXChild[];

export function JSXFactory(tag: NodeTag, properties: unknown, ...rawChildren: (DocumentNode|LeafNode|string)[]) {
const node = makeDocumentNode(tag);
Expand All @@ -15,7 +15,7 @@ export function JSXFactory(tag: NodeTag, properties: unknown, ...rawChildren: (D
node.attributeMap.set(key, value);
}
}
const ensureChild = (rawChild: rawJSX) => {
const ensureChild = (rawChild: JSXChild) => {
if (typeof rawChild === 'string') {
makeLeafNode<TextNode>(NodeTag.TextNode, node, rawChild);
} else if (typeof rawChild === 'number') {
Expand All @@ -37,23 +37,51 @@ export function JSXFactory(tag: NodeTag, properties: unknown, ...rawChildren: (D
return node;
}


// eslint-disable-next-line no-redeclare
namespace JSXFactory {
export interface IntrinsicElements {
[elemName: string]: any;
}
}
// TODO: For `children?` to work without allowing people to accidentally use
// `{undefined}` then we need to enable:
// https://www.typescriptlang.org/tsconfig/#exactOptionalPropertyTypes
// I do not know why this is not on by default when strict is true and
// this is really annoying AaaAaaaAaaAaaAAaaAaa.
// To enable exactOptionalPropertyTypes, we'll have to start with MPS
// or extract DeadDocument into a library.
type NodeProperties = { children?: JSXChild[]|JSXChild };
type LeafNodeProperties = { children?: never[] };

/**
* Pisses me off that tooling is too dumb to use the above
* Has to be global for some reason or VSCodium explodes.
* https://www.typescriptlang.org/docs/handbook/declaration-merging.html
* https://www.typescriptlang.org/tsconfig#jsxFactory
*/
declare global {
export namespace JSX {
export interface IntrinsicElements {
[elemName: string]: any;
a: NodeProperties & { href?: string, name?: string, target?: string },
b: NodeProperties,
br: LeafNodeProperties,
code: NodeProperties & { class?: string },
details: NodeProperties,
em: NodeProperties,
font: NodeProperties & { color?: string},
fragment: NodeProperties,
h1: NodeProperties,
i: NodeProperties,
li: NodeProperties,
ol: NodeProperties & { 'start'?: number },
p: NodeProperties,
pre: NodeProperties,
root: NodeProperties,
span: NodeProperties & {
'data-mx-bg-color'?: string,
'data-mx-color'?: string,
'data-mx-spoiler'?: string | undefined
}
strong: NodeProperties,
summary: NodeProperties,
ul: NodeProperties,
}
export type Element = DocumentNode
export type ElementChildrenAttribute = {
children?: JSXChild[]|JSXChild|never[]|never
}
}
}
6 changes: 3 additions & 3 deletions src/commands/interface-manager/MatrixHelpRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,13 @@ export function renderCommandSummary(command: InterfaceCommand<BaseFunction>): D
</summary>
{command.description
? <fragment><b>Description:</b><br />{command.description}<br /></fragment>
: []
: <fragment></fragment>
}
{command.argumentListParser.descriptions.length > 0
? <fragment>
<b>Parameters:</b><br/>{...command.argumentListParser.descriptions.map(renderParameterDescription)}
</fragment>
: []
: <fragment></fragment>
}
</details>
}
Expand All @@ -70,7 +70,7 @@ function renderTableHelp(table: CommandTable): DocumentNode {
}
return <root>
<details>
<summary><b>{tableName} commands:</b></summary>
<summary><b>{tableName.toString()} commands:</b></summary>
{table.getExportedCommands().map(renderCommandSummary)}
{table.getImportedTables().map(renderTableHelp)}
</details>
Expand Down
5 changes: 3 additions & 2 deletions src/commands/interface-manager/MatrixPromptForAccept.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { MatrixReactionHandler, ReactionListener } from "./MatrixReactionHandler
import { StaticDecode, Type } from "@sinclair/typebox";
import { ReadItem, readCommand } from "./CommandReader";
import { printReadably } from "./PrintReadably";
import { DeadDocumentPresentationMirror } from "./DeadDocumentPresentation";

const log = new Logger('MatrixPromptForAccept');

Expand Down Expand Up @@ -143,7 +144,7 @@ export async function promptDefault<PresentationType extends ReadItem>(
const events = await renderMatrixAndSend(
<root>
No argument was provided for the parameter {parameter.name}, would you like to accept the default?<br/>
{defaultPrompt}
{DeadDocumentPresentationMirror.present(defaultPrompt)}
</root>,
this.roomID, this.event, this.client,
this.reactionHandler.createAnnotation(
Expand Down Expand Up @@ -181,7 +182,7 @@ export async function promptSuggestions(
<ol>
{suggestions.map((suggestion) => {
return <li>
{suggestion}
{DeadDocumentPresentationMirror.present(suggestion)}
</li>
})}
</ol>
Expand Down
4 changes: 2 additions & 2 deletions src/protections/BanPropagation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import { renderMatrixAndSend } from "../commands/interface-manager/DeadDocumentM
import { renderMentionPill, renderRoomPill } from "../commands/interface-manager/MatrixHelpRenderer";
import { ListMatches, renderListRules } from "../commands/Rules";
import { printActionResult } from "../models/RoomUpdateError";
import { AbstractProtection, ActionResult, Logger, MatrixRoomID, MatrixRoomReference, MembershipChange, MembershipChangeType, Ok, PermissionError, PolicyRule, PolicyRuleType, ProtectedRoomsSet, ProtectionDescription, Recommendation, RoomActionError, RoomMembershipRevision, RoomUpdateError, StringRoomID, StringUserID, Task, describeProtection, isError, serverName, UserID, UnknownSettings, UserConsequences, Membership } from "matrix-protection-suite";
import { AbstractProtection, ActionResult, Logger, MatrixRoomID, MatrixRoomReference, MembershipChange, MembershipChangeType, Ok, PermissionError, PolicyRule, PolicyRuleType, ProtectedRoomsSet, ProtectionDescription, Recommendation, RoomActionError, RoomMembershipRevision, RoomUpdateError, StringRoomID, StringUserID, Task, describeProtection, isError, serverName, UnknownSettings, UserConsequences, Membership } from "matrix-protection-suite";
import { Draupnir } from "../Draupnir";
import { resolveRoomReferenceSafe } from "matrix-protection-suite-for-matrix-bot-sdk";
import { DraupnirProtection } from "./Protection";
Expand Down Expand Up @@ -76,7 +76,7 @@ async function promptBanPropagation(
const reactionMap = makePolicyRoomReactionReferenceMap(editablePolicyRoomIDs);
const promptEventId = (await renderMatrixAndSend(
<root>The user {renderMentionPill(change.userID, change.content.displayname ?? change.userID)} was banned
in <a href={`https://matrix.to/#/${change.roomID}`}>{change.roomID}</a> by {new UserID(change.sender)} for <code>{change.content.reason ?? '<no reason supplied>'}</code>.<br/>
in <a href={`https://matrix.to/#/${change.roomID}`}>{change.roomID}</a> by {renderMentionPill(change.sender, change.sender)} for <code>{change.content.reason ?? '<no reason supplied>'}</code>.<br/>
Would you like to add the ban to a policy list?
<ol>
{editablePolicyRoomIDs.map((room) => <li><a href={room.toPermalink()}>{room.toRoomIDOrAlias()}</a></li>)}
Expand Down

0 comments on commit 54437ee

Please sign in to comment.