Files
outline/shared/editor/rules/links.ts
T
dependabot[bot] fc01deeefd chore(deps-dev): bump oxlint-tsgolint from 0.14.2 to 0.22.1 (#12320)
* chore(deps-dev): bump oxlint-tsgolint from 0.14.2 to 0.22.1

Bumps [oxlint-tsgolint](https://github.com/oxc-project/tsgolint) from 0.14.2 to 0.22.1.
- [Release notes](https://github.com/oxc-project/tsgolint/releases)
- [Commits](https://github.com/oxc-project/tsgolint/compare/v0.14.2...v0.22.1)

---
updated-dependencies:
- dependency-name: oxlint-tsgolint
  dependency-version: 0.22.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* chore: Switch tsconfig to bundler resolution for tsgolint 0.22.1

oxlint-tsgolint 0.22.1 removed support for moduleResolution=node10
(the alias for "node"). Switch to "bundler" with resolvePackageJsonExports
disabled so packages whose exports field omits a types condition still
resolve. Update markdown-it type imports to sub-paths since the package's
.d.mts entry only re-exports a subset of named types.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix: Resolve type-aware lint errors caught by tsgolint 0.22.1

oxlint-tsgolint 0.22.1 catches several await-thenable, no-floating-promises,
and no-meaningless-void-operator cases the prior 0.14.2 missed:

- Drop redundant inner `await` from Promise.all([await x, await y]) call sites
  so the array entries are real Promises rather than already-resolved values.
- Replace Promise.all wrappers around synchronous presenters (presentEvent,
  presentTemplate, presentPublicTeam) with plain map / direct calls.
- Wrap non-promise branches of ternaries inside Promise.all with
  Promise.resolve so the array remains thenable across both arms.
- Add `void` to the unawaited provider.connect() in the auth-failed retry
  chain, and remove `void` from the disconnect() call which returns void.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Tom Moor <tom@getoutline.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-12 07:59:13 -04:00

102 lines
3.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type MarkdownIt from "markdown-it";
import type Token from "markdown-it/lib/token.mjs";
import env from "../../env";
function isParagraph(token: Token) {
return token.type === "paragraph_open";
}
function isInline(token: Token) {
return token.type === "inline";
}
function isLinkOpen(token: Token) {
return token.type === "link_open";
}
function isLinkClose(token: Token) {
return token.type === "link_close";
}
function isAttachment(token: Token) {
const href = token.attrGet("href");
if (href?.includes("display=link")) {
return false;
}
return (
// internal
// external (public share are pre-signed and this is a reasonable way of detecting them)
href?.startsWith("/api/attachments.redirect") ||
href?.startsWith("/api/files.get") ||
href?.startsWith(`${env.URL}/api/files.get`) ||
((href?.startsWith(env.AWS_S3_UPLOAD_BUCKET_URL) ||
href?.startsWith(env.AWS_S3_ACCELERATE_URL)) &&
href?.includes("X-Amz-Signature"))
);
}
export default function linksToNodes(md: MarkdownIt) {
md.core.ruler.after("breaks", "attachments", (state) => {
const tokens = state.tokens;
let insideLink;
for (let i = 0; i < tokens.length - 1; i++) {
// once we find an inline token look through it's children for links
if (isInline(tokens[i]) && isParagraph(tokens[i - 1])) {
const tokenChildren = tokens[i].children || [];
for (let j = 0; j < tokenChildren.length - 1; j++) {
const current = tokenChildren[j];
if (!current) {
continue;
}
if (isLinkOpen(current)) {
insideLink = current;
continue;
}
if (isLinkClose(current)) {
insideLink = null;
continue;
}
// of hey, we found a link lets check to see if it should be
// converted to a file attachment
if (insideLink && isAttachment(insideLink)) {
const { content } = current;
const parts = content.split(" ");
const size = parts.pop();
const title = parts.join(" ");
if (size?.includes("x")) {
// convert to video
const token = new state.Token("video", "video", 0);
token.attrSet("src", insideLink.attrGet("href") || "");
token.attrSet("width", size.split("x")[0] || "0");
token.attrSet("height", size.split("x")[1] || "0");
token.attrSet("title", title);
tokens.splice(i - 1, 3, token);
} else {
// convert to attachment token
const token = new state.Token("attachment", "a", 0);
token.attrSet("href", insideLink.attrGet("href") || "");
token.attrSet("size", size || "0");
token.attrSet("title", title);
tokens.splice(i - 1, 3, token);
}
// delete the inline link this makes the assumption that the
// attachment is the only thing in the para.
insideLink = null;
break;
}
}
}
}
return false;
});
}