mirror of
https://github.com/outline/outline.git
synced 2026-06-13 03:14:59 +03:00
chore: clear mechanical lint warnings (Phase 1) (#12198)
* chore: clear mechanical lint warnings Drops 44 oxlint warnings (559 → 515) by fixing easy mechanical rules across the codebase: no-useless-escape, no-duplicate-type-constituents, no-redundant-type-constituents, no-unused-expressions, no-meaningless-void-operator, require-array-sort-compare, await-thenable. * chore: drop callback parameter from useCallback deps The `open` argument is a parameter of the callback, not a closed-over variable, so it doesn't belong in the deps array. * chore: promote cleared lint rules to errors Promotes the rules cleared in this PR from warn to error so future violations fail the lint: - no-unused-expressions - typescript/await-thenable - typescript/no-duplicate-type-constituents - typescript/no-meaningless-void-operator - typescript/require-array-sort-compare Removes the override that suppressed no-useless-escape on source files (the global rule is already error) and fixes the 21 escape violations that this exposed in regex character classes and template literals. * chore: address PR review feedback - usePinnedDocuments: simplify UrlId to plain string instead of the intersection trick. - PlantUML embed: move - to end of character class so it's a literal hyphen rather than a range operator. - checkboxes: type token params as Token | undefined to match the actual call sites that pass tokens[index - 2] etc.
This commit is contained in:
+5
-1
@@ -73,9 +73,13 @@
|
||||
"eqeqeq": "error",
|
||||
"curly": "error",
|
||||
"no-console": "error",
|
||||
"no-unused-expressions": "error",
|
||||
"arrow-body-style": ["error", "as-needed"],
|
||||
"no-useless-escape": "off",
|
||||
"react/react-in-jsx-scope": "off",
|
||||
"typescript/await-thenable": "error",
|
||||
"typescript/no-duplicate-type-constituents": "error",
|
||||
"typescript/no-meaningless-void-operator": "error",
|
||||
"typescript/require-array-sort-compare": "error",
|
||||
"react/self-closing-comp": [
|
||||
"error",
|
||||
{
|
||||
|
||||
@@ -47,7 +47,7 @@ export const ContextMenu = observer(
|
||||
onClose?.();
|
||||
}
|
||||
},
|
||||
[open, onOpen, onClose]
|
||||
[onOpen, onClose]
|
||||
);
|
||||
|
||||
const enablePointerEvents = React.useCallback(() => {
|
||||
|
||||
@@ -143,7 +143,7 @@ export const Suggestions = observer(
|
||||
);
|
||||
|
||||
React.useEffect(() => {
|
||||
void fetchUsersByQuery(query);
|
||||
fetchUsersByQuery(query);
|
||||
}, [query, fetchUsersByQuery]);
|
||||
|
||||
function getListItemProps(suggestion: User | Group) {
|
||||
|
||||
@@ -72,8 +72,7 @@ type ContentProps = React.ComponentPropsWithoutRef<
|
||||
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Content>;
|
||||
|
||||
const MenuContent = React.forwardRef<
|
||||
| React.ElementRef<typeof DropdownMenuPrimitive.Content>
|
||||
| React.ElementRef<typeof ContextMenuPrimitive.Content>,
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Content>,
|
||||
ContentProps
|
||||
>((props, ref) => {
|
||||
const { variant } = useMenuContext();
|
||||
@@ -120,8 +119,7 @@ type SubMenuTriggerProps = BaseItemProps &
|
||||
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubTrigger>;
|
||||
|
||||
const SubMenuTrigger = React.forwardRef<
|
||||
| React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>
|
||||
| React.ElementRef<typeof ContextMenuPrimitive.SubTrigger>,
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
|
||||
SubMenuTriggerProps
|
||||
>((props, ref) => {
|
||||
const { variant } = useMenuContext();
|
||||
@@ -150,8 +148,7 @@ type SubMenuContentProps = React.ComponentPropsWithoutRef<
|
||||
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubContent>;
|
||||
|
||||
const SubMenuContent = React.forwardRef<
|
||||
| React.ElementRef<typeof DropdownMenuPrimitive.SubContent>
|
||||
| React.ElementRef<typeof ContextMenuPrimitive.SubContent>,
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
|
||||
SubMenuContentProps
|
||||
>((props, ref) => {
|
||||
const { variant } = useMenuContext();
|
||||
@@ -203,8 +200,7 @@ type MenuGroupProps = {
|
||||
>;
|
||||
|
||||
const MenuGroup = React.forwardRef<
|
||||
| React.ElementRef<typeof DropdownMenuPrimitive.Group>
|
||||
| React.ElementRef<typeof ContextMenuPrimitive.Group>,
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Group>,
|
||||
MenuGroupProps
|
||||
>((props, ref) => {
|
||||
const { variant } = useMenuContext();
|
||||
@@ -275,8 +271,7 @@ type MenuButtonProps = BaseItemProps & {
|
||||
>;
|
||||
|
||||
const MenuButton = React.forwardRef<
|
||||
| React.ElementRef<typeof DropdownMenuPrimitive.Item>
|
||||
| React.ElementRef<typeof ContextMenuPrimitive.Item>,
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Item>,
|
||||
MenuButtonProps
|
||||
>((props, ref) => {
|
||||
const { variant } = useMenuContext();
|
||||
@@ -338,8 +333,7 @@ type MenuInternalLinkProps = BaseItemProps & {
|
||||
>;
|
||||
|
||||
const MenuInternalLink = React.forwardRef<
|
||||
| React.ElementRef<typeof DropdownMenuPrimitive.Item>
|
||||
| React.ElementRef<typeof ContextMenuPrimitive.Item>,
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Item>,
|
||||
MenuInternalLinkProps
|
||||
>((props, ref) => {
|
||||
const { variant } = useMenuContext();
|
||||
@@ -375,8 +369,7 @@ type MenuExternalLinkProps = BaseItemProps & {
|
||||
>;
|
||||
|
||||
const MenuExternalLink = React.forwardRef<
|
||||
| React.ElementRef<typeof DropdownMenuPrimitive.Item>
|
||||
| React.ElementRef<typeof ContextMenuPrimitive.Item>,
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Item>,
|
||||
MenuExternalLinkProps
|
||||
>((props, ref) => {
|
||||
const { variant } = useMenuContext();
|
||||
@@ -409,8 +402,7 @@ type MenuSeparatorProps = React.ComponentPropsWithoutRef<
|
||||
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Separator>;
|
||||
|
||||
const MenuSeparator = React.forwardRef<
|
||||
| React.ElementRef<typeof DropdownMenuPrimitive.Separator>
|
||||
| React.ElementRef<typeof ContextMenuPrimitive.Separator>,
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
|
||||
MenuSeparatorProps
|
||||
>((props, ref) => {
|
||||
const { variant } = useMenuContext();
|
||||
@@ -434,8 +426,7 @@ type MenuLabelProps = React.ComponentPropsWithoutRef<
|
||||
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Label>;
|
||||
|
||||
const MenuLabel = React.forwardRef<
|
||||
| React.ElementRef<typeof DropdownMenuPrimitive.Label>
|
||||
| React.ElementRef<typeof ContextMenuPrimitive.Label>,
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Label>,
|
||||
MenuLabelProps
|
||||
>((props, ref) => {
|
||||
const { variant } = useMenuContext();
|
||||
|
||||
@@ -144,7 +144,11 @@ const LinkEditor: React.FC<Props> = ({
|
||||
|
||||
if (selectedIndex >= 0 && results[selectedIndex]) {
|
||||
const selectedDoc = results[selectedIndex];
|
||||
!mark ? addLink(selectedDoc.url) : updateLink(selectedDoc.url);
|
||||
if (!mark) {
|
||||
addLink(selectedDoc.url);
|
||||
} else {
|
||||
updateLink(selectedDoc.url);
|
||||
}
|
||||
} else if (!trimmedQuery) {
|
||||
removeLink();
|
||||
} else if (!mark) {
|
||||
@@ -238,7 +242,11 @@ const LinkEditor: React.FC<Props> = ({
|
||||
{results.map((doc, index) => (
|
||||
<SuggestionsMenuItem
|
||||
onClick={() => {
|
||||
!mark ? addLink(doc.path) : updateLink(doc.path);
|
||||
if (!mark) {
|
||||
addLink(doc.path);
|
||||
} else {
|
||||
updateLink(doc.path);
|
||||
}
|
||||
}}
|
||||
onPointerMove={() => setSelectedIndex(index)}
|
||||
selected={index === selectedIndex}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { InputRule } from "@shared/editor/lib/InputRule";
|
||||
|
||||
const rightArrow = new InputRule(/->$/, "→");
|
||||
// Note that the suppression of pipe here prevents conflict with table creation rule.
|
||||
const emdash = new InputRule(/(?:^|[^\|])(--\s)$/, "— ");
|
||||
const emdash = new InputRule(/(?:^|[^|])(--\s)$/, "— ");
|
||||
const oneHalf = new InputRule(/(?:^|\s)(1\/2)$/, "½");
|
||||
const threeQuarters = new InputRule(/(?:^|\s)(3\/4)$/, "¾");
|
||||
const copyright = new InputRule(/\(c\)$/, "©️");
|
||||
@@ -12,17 +12,11 @@ const trademarked = new InputRule(/\(tm\)$/, "™️");
|
||||
const ellipsis = new InputRule(/\.\.\.$/, "…");
|
||||
|
||||
// Double quotes
|
||||
const openDoubleQuote = new InputRule(
|
||||
/(?:^|[\s\{\[\(\<'"\u2018\u201C])(")$/,
|
||||
"“"
|
||||
);
|
||||
const openDoubleQuote = new InputRule(/(?:^|[\s{[(<'"\u2018\u201C])(")$/, "“");
|
||||
const closeDoubleQuote = new InputRule(/^(?!.*`)[\s\S]*(")$/, "”");
|
||||
|
||||
// Single quotes
|
||||
const openSingleQuote = new InputRule(
|
||||
/(?:^|[\s\{\[\(\<'"\u2018\u201C])(')$/,
|
||||
"‘"
|
||||
);
|
||||
const openSingleQuote = new InputRule(/(?:^|[\s{[(<'"\u2018\u201C])(')$/, "‘");
|
||||
const closeSingleQuote = new InputRule(/^(?!.*`)[\s\S]*(')$/, "’");
|
||||
|
||||
export default class SmartText extends Extension {
|
||||
|
||||
@@ -27,7 +27,7 @@ export default class Suggestion extends Extension {
|
||||
: `(?:${triggers.map(escapeRegExp).join("|")})`;
|
||||
|
||||
this.openRegex = new RegExp(
|
||||
`(?:^|\\s|\\(|[\\p{Script=Han}\\p{Script=Hiragana}\\p{Script=Katakana}\\p{Script=Hangul}])${triggerPattern}(${`[\\p{L}\/\\p{M}\\d${
|
||||
`(?:^|\\s|\\(|[\\p{Script=Han}\\p{Script=Hiragana}\\p{Script=Katakana}\\p{Script=Hangul}])${triggerPattern}(${`[\\p{L}/\\p{M}\\d${
|
||||
this.options.allowSpaces ? "\\s{1}" : ""
|
||||
}\\.\\-–_]+`})${this.options.requireSearchTerm ? "" : "?"}$`,
|
||||
"u"
|
||||
|
||||
@@ -31,7 +31,7 @@ const DEFAULT_LIMIT = 10;
|
||||
* @returns
|
||||
*/
|
||||
export default function usePaginatedRequest<T = unknown>(
|
||||
requestFn: (params?: PaginationParams | undefined) => Promise<T[]>,
|
||||
requestFn: (params?: PaginationParams) => Promise<T[]>,
|
||||
params: PaginationParams = {}
|
||||
): RequestResponse<T> {
|
||||
const [data, setData] = useState<T[]>();
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useEffect } from "react";
|
||||
import usePersistedState from "~/hooks/usePersistedState";
|
||||
import useStores from "./useStores";
|
||||
|
||||
type UrlId = "home" | string;
|
||||
type UrlId = string;
|
||||
|
||||
export const pinsCacheKey = (urlId: UrlId) => `pins-${urlId}`;
|
||||
|
||||
|
||||
@@ -282,7 +282,7 @@ export function useDocumentSave({
|
||||
titleRef.current = value;
|
||||
document.title = value;
|
||||
updateIsDirtyRef.current();
|
||||
void autosave();
|
||||
autosave();
|
||||
},
|
||||
[document, autosave]
|
||||
);
|
||||
|
||||
@@ -42,7 +42,7 @@ export class OAuthScopeHelper {
|
||||
return t("Write all data");
|
||||
}
|
||||
|
||||
const [namespace, method] = scope.replace("/api/", "").split(/[:\.]/g);
|
||||
const [namespace, method] = scope.replace("/api/", "").split(/[:.]/g);
|
||||
const readableMethod =
|
||||
methodToReadable[method as keyof typeof methodToReadable] ?? method;
|
||||
if (!readableMethod) {
|
||||
|
||||
@@ -43,7 +43,9 @@ const LoadingState = observer(function LoadingState() {
|
||||
ui.addActiveModel(template);
|
||||
}
|
||||
return () => {
|
||||
template && ui.removeActiveModel(template);
|
||||
if (template) {
|
||||
ui.removeActiveModel(template);
|
||||
}
|
||||
};
|
||||
}, [template, ui]);
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ export default class PinsStore extends Store<Pin> {
|
||||
}
|
||||
|
||||
@action
|
||||
fetchPage = async (params?: FetchParams | undefined): Promise<Pin[]> => {
|
||||
fetchPage = async (params?: FetchParams): Promise<Pin[]> => {
|
||||
this.isFetching = true;
|
||||
|
||||
try {
|
||||
|
||||
@@ -12,9 +12,7 @@ export default class StarsStore extends Store<Star> {
|
||||
}
|
||||
|
||||
@action
|
||||
fetchPage = async (
|
||||
params?: PaginationParams | undefined
|
||||
): Promise<Star[]> => {
|
||||
fetchPage = async (params?: PaginationParams): Promise<Star[]> => {
|
||||
this.isFetching = true;
|
||||
|
||||
try {
|
||||
|
||||
@@ -19,9 +19,7 @@ export default class UserMembershipsStore extends Store<UserMembership> {
|
||||
}
|
||||
|
||||
@action
|
||||
fetchPage = async (
|
||||
params?: PaginationParams | undefined
|
||||
): Promise<UserMembership[]> => {
|
||||
fetchPage = async (params?: PaginationParams): Promise<UserMembership[]> => {
|
||||
this.isFetching = true;
|
||||
|
||||
try {
|
||||
|
||||
@@ -401,7 +401,7 @@ export default abstract class Store<T extends Model> {
|
||||
|
||||
@action
|
||||
fetchPage = async (
|
||||
params?: FetchPageParams | undefined
|
||||
params?: FetchPageParams
|
||||
): Promise<PaginatedResponse<T>> => {
|
||||
if (!this.actions.includes(RPCAction.List)) {
|
||||
throw new Error(`Cannot list ${this.modelName}`);
|
||||
|
||||
@@ -285,7 +285,7 @@ class ApiClient {
|
||||
|
||||
post = <T = any>(
|
||||
path: string,
|
||||
data?: JSONObject | FormData | undefined,
|
||||
data?: JSONObject | FormData,
|
||||
options?: FetchOptions
|
||||
): Promise<T> => {
|
||||
if (data instanceof FormData) {
|
||||
|
||||
@@ -54,7 +54,7 @@ class ApiKey extends ParanoidModel<
|
||||
name: string;
|
||||
|
||||
/** A list of scopes that this API key has access to */
|
||||
@Matches(/[\/\.\w\s]*/, {
|
||||
@Matches(/[/.\w\s]*/, {
|
||||
each: true,
|
||||
})
|
||||
@Column(DataType.ARRAY(DataType.STRING))
|
||||
|
||||
@@ -83,7 +83,7 @@ class OAuthAuthentication extends ParanoidModel<
|
||||
grantId: string | null;
|
||||
|
||||
/** A list of scopes that this authentication has access to */
|
||||
@Matches(/[\/\.\w\s]*/, {
|
||||
@Matches(/[/.\w\s]*/, {
|
||||
each: true,
|
||||
})
|
||||
@Column(DataType.ARRAY(DataType.STRING))
|
||||
|
||||
@@ -57,7 +57,7 @@ class OAuthAuthorizationCode extends IdModel<
|
||||
grantId: string | null;
|
||||
|
||||
/** A list of scopes that this authorization code has access to */
|
||||
@Matches(/[\/\.\w\s]*/, {
|
||||
@Matches(/[/.\w\s]*/, {
|
||||
each: true,
|
||||
})
|
||||
@Column(DataType.ARRAY(DataType.STRING))
|
||||
|
||||
@@ -155,7 +155,7 @@ export default class ImportJSONTask extends ImportTask {
|
||||
}
|
||||
|
||||
if (Object.values(item.attachments).length) {
|
||||
await mapAttachments(item.attachments);
|
||||
mapAttachments(item.attachments);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -228,11 +228,11 @@ export default class ImportMarkdownZipTask extends ImportTask {
|
||||
document.text = document.text
|
||||
.replace(new RegExp(escapeRegExp(encodedPath), "g"), reference)
|
||||
.replace(
|
||||
new RegExp(`\\\.?/?${escapeRegExp(normalizedAttachmentPath)}`, "g"),
|
||||
new RegExp(`\\.?/?${escapeRegExp(normalizedAttachmentPath)}`, "g"),
|
||||
reference
|
||||
)
|
||||
.replace(
|
||||
new RegExp(`\\\.?/?${escapeRegExp(genericNormalizedPath)}`, "g"),
|
||||
new RegExp(`\\.?/?${escapeRegExp(genericNormalizedPath)}`, "g"),
|
||||
reference
|
||||
);
|
||||
}
|
||||
|
||||
@@ -397,9 +397,9 @@ describe("#comments.list", () => {
|
||||
|
||||
expect(res.status).toEqual(200);
|
||||
expect(body.data.length).toEqual(2);
|
||||
expect([body.data[0].id, body.data[1].id].sort()).toEqual(
|
||||
[comment1.id, comment2.id].sort()
|
||||
);
|
||||
expect(
|
||||
[body.data[0].id, body.data[1].id].sort((a, b) => a.localeCompare(b))
|
||||
).toEqual([comment1.id, comment2.id].sort((a, b) => a.localeCompare(b)));
|
||||
expect(body.policies.length).toEqual(2);
|
||||
expect(body.policies[0].abilities.read).toBeTruthy();
|
||||
expect(body.policies[1].abilities.read).toBeTruthy();
|
||||
|
||||
@@ -48,7 +48,7 @@ describe("#ValidateKey.sanitize", () => {
|
||||
const uuid1 = randomUUID();
|
||||
const uuid2 = randomUUID();
|
||||
expect(
|
||||
ValidateKey.sanitize(`public/${uuid1}/${uuid2}/~\.\u0000\malicious_key`)
|
||||
ValidateKey.sanitize(`public/${uuid1}/${uuid2}/~.\u0000malicious_key`)
|
||||
).toEqual(`public/${uuid1}/${uuid2}/~.malicious_key`);
|
||||
});
|
||||
|
||||
|
||||
@@ -183,9 +183,7 @@ const embeds: EmbedDescriptor[] = [
|
||||
id: "canva",
|
||||
title: "Canva",
|
||||
keywords: "design",
|
||||
regexMatch: [
|
||||
/^https:\/\/(?:www\.)?canva\.com\/design\/([\/a-zA-Z0-9_\-]*)$/,
|
||||
],
|
||||
regexMatch: [/^https:\/\/(?:www\.)?canva\.com\/design\/([/a-zA-Z0-9_-]*)$/],
|
||||
transformMatch: (matches: RegExpMatchArray) => {
|
||||
const input = matches.input ?? matches[0];
|
||||
|
||||
@@ -634,7 +632,7 @@ const embeds: EmbedDescriptor[] = [
|
||||
id: "tella",
|
||||
title: "Tella",
|
||||
keywords: "video",
|
||||
regexMatch: [/^https?:\/\/(?:www\.)?tella\.tv\/video\/([^\/]+)(?:.*)?$/],
|
||||
regexMatch: [/^https?:\/\/(?:www\.)?tella\.tv\/video\/([^/]+)(?:.*)?$/],
|
||||
transformMatch: (matches: RegExpMatchArray) =>
|
||||
`https://www.tella.tv/video/${matches[1]}/embed?b=0&title=1&a=0&loop=0&t=0&muted=0&wt=1`,
|
||||
icon: <Img src="/images/tella.png" alt="Tella" />,
|
||||
@@ -719,7 +717,7 @@ const embeds: EmbedDescriptor[] = [
|
||||
title: "YouTube",
|
||||
keywords: "google video",
|
||||
regexMatch: [
|
||||
/(?:https?:\/\/)?(?:www\.)?youtu\.?be(?:\.com)?\/?.*(?:watch|embed)?(?:.*v=|v\/|\/)([a-zA-Z0-9_-]{11})([\&\?](.*))?$/i,
|
||||
/(?:https?:\/\/)?(?:www\.)?youtu\.?be(?:\.com)?\/?.*(?:watch|embed)?(?:.*v=|v\/|\/)([a-zA-Z0-9_-]{11})([&?](.*))?$/i,
|
||||
],
|
||||
icon: <Img src="/images/youtube.png" alt="YouTube" />,
|
||||
component: YouTube,
|
||||
@@ -729,7 +727,7 @@ const embeds: EmbedDescriptor[] = [
|
||||
title: "Plant UML",
|
||||
keywords: "plant plantuml uml",
|
||||
regexMatch: [
|
||||
/(?:https?:\/\/)?(?:www\.)?editor\.plantuml\.com\/uml\/([a-zA-Z0-9\-_]+)([\&\?].*)?$/i,
|
||||
/(?:https?:\/\/)?(?:www\.)?editor\.plantuml\.com\/uml\/([a-zA-Z0-9_-]+)([&?].*)?$/i,
|
||||
],
|
||||
icon: <Img src="/images/plantuml.png" alt="PlantUml" />,
|
||||
component: PlantUmlDiagrams,
|
||||
|
||||
@@ -14,7 +14,7 @@ function safeSlugify(text: string) {
|
||||
|
||||
const slug = `h-${escape(
|
||||
slugify(text, {
|
||||
remove: /[!"#$%&'\.()*+,\/:;<=>?@\[\]\\^_`{|}~]/g,
|
||||
remove: /[!"#$%&'.()*+,/:;<=>?@[\]\\^_`{|}~]/g,
|
||||
lower: true,
|
||||
})
|
||||
)}`;
|
||||
|
||||
@@ -25,11 +25,11 @@ this is code
|
||||
});
|
||||
|
||||
test("returns true for latex fence", () => {
|
||||
expect(isMarkdown(`\$i\$`)).toBe(true);
|
||||
expect(isMarkdown(`$i$`)).toBe(true);
|
||||
expect(
|
||||
isMarkdown(`\$0.00
|
||||
isMarkdown(`$0.00
|
||||
random content
|
||||
\$1.00`)
|
||||
$1.00`)
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
|
||||
@@ -3,19 +3,19 @@ import type MarkdownIt from "markdown-it";
|
||||
|
||||
const CHECKBOX_REGEX = /\[(X|\s|_|-)\]\s(.*)?/i;
|
||||
|
||||
function matches(token: Token | void) {
|
||||
function matches(token: Token | undefined) {
|
||||
return token && token.content.match(CHECKBOX_REGEX);
|
||||
}
|
||||
|
||||
function isInline(token: Token | void): boolean {
|
||||
function isInline(token: Token | undefined): boolean {
|
||||
return !!token && token.type === "inline";
|
||||
}
|
||||
|
||||
function isParagraph(token: Token | void): boolean {
|
||||
function isParagraph(token: Token | undefined): boolean {
|
||||
return !!token && token.type === "paragraph_open";
|
||||
}
|
||||
|
||||
function isListItem(token: Token | void): boolean {
|
||||
function isListItem(token: Token | undefined): boolean {
|
||||
// Only match list_item_open, not checkbox_item_open - items that are already
|
||||
// checkbox_item_open have been processed (e.g., by the tables rule for
|
||||
// checkboxes in table cells) and should not be processed again.
|
||||
|
||||
@@ -4,7 +4,7 @@ import { full as emojiPlugin } from "markdown-it-emoji";
|
||||
import { isUUID } from "validator";
|
||||
import { nameToEmoji } from "../lib/emoji";
|
||||
|
||||
type Options = MarkdownIt.Options & {
|
||||
type Options = {
|
||||
emoji: boolean;
|
||||
};
|
||||
|
||||
|
||||
@@ -46,8 +46,8 @@ export default class AuthenticationHelper {
|
||||
const [namespace, method] = resource.split(".");
|
||||
|
||||
return scopes.some((scope) => {
|
||||
const [scopeNamespace, scopeMethod] = scope.match(/[:\.]/g)
|
||||
? scope.replace("/api/", "").split(/[:\.]/g)
|
||||
const [scopeNamespace, scopeMethod] = scope.match(/[:.]/g)
|
||||
? scope.replace("/api/", "").split(/[:.]/g)
|
||||
: ["*", scope];
|
||||
const isRouteScope = scope.startsWith("/api/");
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ export function isCurrency(value: string): boolean {
|
||||
}
|
||||
|
||||
// Remove digits, separators, whitespace, and negative indicators
|
||||
remaining = remaining.replace(/[\d.,\s()\-]/g, "");
|
||||
remaining = remaining.replace(/[\d.,\s()-]/g, "");
|
||||
|
||||
// If anything remains, it's not a valid currency
|
||||
return remaining.length === 0;
|
||||
|
||||
Reference in New Issue
Block a user