AstRange - bhsd-harry/wikiparser-node GitHub Wiki

目录

Other Languages

简介

仿照 Range 类设计,属性和方法也和 Range 类非常相似。主要的区别在于 AstRange 的起点和终点间必须为同一节点的连续子节点。

以下所有属性和方法在 MiniBrowser 版本中均不可用。

Properties

startContainer

展开

type: AstNode
起点容器,只读。

// startContainer (main)
var root = Parser.parse("[[a]]bc"),
	{lastChild} = root,
	range = root.createRange();
assert.equal(lastChild, "bc");
range.setStart(root, 1);
assert.strictEqual(range.startContainer, root);
range.setStart(lastChild, 0);
assert.strictEqual(range.startContainer, lastChild);

startOffset

展开

type: number
起点位置,只读。

// startOffset (main)
var root = Parser.parse("[[a]]bc"),
	{lastChild} = root,
	range = root.createRange();
assert.equal(lastChild, "bc");
range.setStart(root, 1);
assert.strictEqual(range.startOffset, 1);
range.setStart(lastChild, 1);
assert.strictEqual(range.startOffset, 1);

startIndex

展开

type: number
起点绝对位置,只读。

// startIndex (main)
var root = Parser.parse("[[a]]bc"),
	{lastChild} = root,
	range = root.createRange();
assert.equal(lastChild, "bc");
range.setStart(root, 1);
assert.strictEqual(range.startIndex, 5);
range.setStart(lastChild, 1);
assert.strictEqual(range.startIndex, 6);

startPos

展开

type: {top: number, left: number}
起点行列位置,只读。

// startPos (main)
var root = Parser.parse("[[a]]\nb"),
	{lastChild} = root,
	range = root.createRange();
assert.equal(lastChild, "\nb");
range.setStart(root, 1);
assert.deepStrictEqual(range.startPos, {top: 0, left: 5});
range.setStart(lastChild, 1);
assert.deepStrictEqual(range.startPos, {top: 1, left: 0});

endContainer

展开

type: AstNode
终点容器,只读。

// endContainer (main)
var root = Parser.parse("[[a]]bc"),
	{lastChild} = root,
	range = root.createRange();
assert.equal(lastChild, "bc");
range.setEnd(root, 1);
assert.strictEqual(range.endContainer, root);
range.setEnd(lastChild, 0);
assert.strictEqual(range.endContainer, lastChild);

endOffset

展开

type: number
终点位置,只读。

// endOffset (main)
var root = Parser.parse("[[a]]bc"),
	{lastChild} = root,
	range = root.createRange();
assert.equal(lastChild, "bc");
range.setEnd(root, 1);
assert.strictEqual(range.endOffset, 1);
range.setEnd(lastChild, 1);
assert.strictEqual(range.endOffset, 1);

endIndex

展开

type: number
终点绝对位置,只读。

// endIndex (main)
var root = Parser.parse("[[a]]bc"),
	{firstChild, lastChild} = root,
	range = root.createRange();
assert.equal(firstChild, "[[a]]");
assert.equal(lastChild, "bc");
range.setEnd(root, 1);
assert.strictEqual(range.endIndex, 5);
range.setEnd(lastChild, 1);
assert.strictEqual(range.endIndex, 6);
range.setEnd(firstChild, 1);
assert.strictEqual(range.endIndex, 3);
range.setStart(firstChild, 0);
assert.strictEqual(range.endIndex, 3);

endPos

展开

type: {top: number, left: number}
终点行列位置,只读。

// endPos (main)
var root = Parser.parse("[[a]]\nb"),
	{lastChild} = root,
	range = root.createRange();
assert.equal(lastChild, "\nb");
range.setEnd(root, 1);
assert.deepStrictEqual(range.endPos, {top: 0, left: 5});
range.setEnd(lastChild, 1);
assert.deepStrictEqual(range.endPos, {top: 1, left: 0});

collapsed

展开

type: boolean
起始和终止位置是否重合,只读。

// collapsed (main)
var root = Parser.parse("[[a]]b"),
	{lastChild} = root,
	range = root.createRange();
assert.equal(lastChild, "b");
range.setStart(root, 1);
range.setEnd(root, 1);
assert.ok(range.collapsed);
range.setEnd(lastChild, 0);
assert.ok(!range.collapsed);

commonAncestorContainer

展开

type: AstNode
最近的公共祖先,只读。

// commonAncestorContainer (main)
var root = Parser.parse("[[a]]b"),
	{firstChild, lastChild} = root,
	range = root.createRange();
assert.equal(firstChild, "[[a]]");
range.setStart(lastChild, 0);
range.setEnd(lastChild, 1);
assert.strictEqual(range.commonAncestorContainer, lastChild);
range.setStart(root, 0);
assert.strictEqual(range.commonAncestorContainer, root);

childNodes

展开

加入的版本:1.23.0

type: AstNode[]
Range 内包含的节点,只读。

firstChild

展开

加入的版本:1.23.0

type: AstNode | undefined
Range 内包含的第一个节点,只读。

// firstChild (main)
var root = Parser.parse("[[a]]b"),
	range = root.createRange();
range.selectNodeContents(root);
assert.strictEqual(range.firstChild, root.firstChild);

lastChild

展开

加入的版本:1.23.0

type: AstNode | undefined
Range 内包含的最后一个节点,只读。

// lastChild (main)
var root = Parser.parse("[[a]]b"),
	range = root.createRange();
range.selectNodeContents(root);
assert.strictEqual(range.lastChild, root.lastChild);

children

展开

加入的版本:1.23.0

type: Token[]
Range 内包含的非文本节点,只读。

// children (main)
var root = Parser.parse("[[a]]b"),
	range = root.createRange();
range.selectNodeContents(root);
assert.deepStrictEqual(range.children, root.children);

firstElementChild

展开

加入的版本:1.23.0

type: Token | undefined
Range 内的第一个非文本节点,只读。

// firstElementChild (main)
var root = Parser.parse("a[[b]]"),
	range = root.createRange();
range.selectNodeContents(root);
assert.strictEqual(range.firstElementChild, root.lastChild);

lastElementChild

展开

加入的版本:1.23.0

type: Token | undefined
Range 内的最后一个非文本节点,只读。

// lastElementChild (main)
var root = Parser.parse("[[a]]b"),
	range = root.createRange();
range.selectNodeContents(root);
assert.strictEqual(range.lastElementChild, root.firstChild);

childElementCount

展开

加入的版本:1.23.0

type: number
Range 内包含的非文本节点数量,只读。

// childElementCount (main)
var root = Parser.parse("[[a]]b"),
	range = root.createRange();
range.selectNodeContents(root);
assert.strictEqual(range.childElementCount, 1);

offsetHeight

展开

加入的版本:1.23.0

type: number
Range 的行数,只读。

// offsetHeight (main)
var root = Parser.parse("[[a]]\nb"),
	range = root.createRange();
range.selectNodeContents(root);
assert.strictEqual(range.offsetHeight, 2);

offsetWidth

展开

加入的版本:1.23.0

type: number
Range 内最后一行的列数,只读。

// offsetWidth (main)
var root = Parser.parse("[[a]]\nb"),
	range = root.createRange();
range.selectNodeContents(root);
assert.strictEqual(range.offsetWidth, 1);

Methods

setStart

展开

param: AstNode 起点容器
param: number 起点位置
设置起点。

setEnd

展开

param: AstNode 终点容器
param: number 终点位置
设置终点。

setStartAfter

展开

param: AstNode 节点
在节点后设置起点。

// setStartAfter (main)
var root = Parser.parse("a"),
	{firstChild} = root,
	range = root.createRange();
range.setStartAfter(firstChild);
assert.strictEqual(range.startContainer, root);
assert.strictEqual(range.startOffset, 1);

setEndAfter

展开

param: AstNode 节点
在节点后设置终点。

// setEndAfter (main)
var root = Parser.parse("a"),
	{firstChild} = root,
	range = root.createRange();
range.setEndAfter(firstChild);
assert.strictEqual(range.endContainer, root);
assert.strictEqual(range.endOffset, 1);

setStartBefore

展开

param: AstNode 节点
在节点前设置起点。

// setStartBefore (main)
var root = Parser.parse("a"),
	{firstChild} = root,
	range = root.createRange();
range.setStartBefore(firstChild);
assert.strictEqual(range.startContainer, root);
assert.strictEqual(range.startOffset, 0);

setEndBefore

展开

param: AstNode 节点
在节点前设置终点。

// setEndBefore (main)
var root = Parser.parse("a"),
	{firstChild} = root,
	range = root.createRange();
range.setEndBefore(firstChild);
assert.strictEqual(range.endContainer, root);
assert.strictEqual(range.endOffset, 0);

selectNodeContents

展开

param: AstNode 节点
设置 Range 包含整个节点的内容。

// selectNodeContents (main)
var root = Parser.parse("[[a]]b"),
	range = root.createRange();
range.selectNodeContents(root);
assert.strictEqual(range.startContainer, root);
assert.strictEqual(range.startOffset, 0);
assert.strictEqual(range.endContainer, root);
assert.strictEqual(range.endOffset, 2);

selectNode

展开

param: AstNode 节点
设置 Range 包含整个节点。

// selectNode (main)
var root = Parser.parse("[[a]]b"),
	{firstChild} = root,
	range = root.createRange();
assert.equal(firstChild, "[[a]]");
range.selectNode(firstChild);
assert.strictEqual(range.startContainer, root);
assert.strictEqual(range.startOffset, 0);
assert.strictEqual(range.endContainer, root);
assert.strictEqual(range.endOffset, 1);

collapse

展开

param: boolean 重合至起始位置,默认行为是重合至终止位置
使起始和终止位置重合。

// collapse (main)
var root = Parser.parse("a"),
	range = root.createRange();
range.setEnd(root, 1);
range.collapse();
assert.strictEqual(range.startContainer, root);
assert.strictEqual(range.startOffset, 1);
range.setStart(root, 0);
range.collapse(true);
assert.strictEqual(range.endContainer, root);
assert.strictEqual(range.endOffset, 0);

comparePoint

展开

param: AstNode 端点容器
param: number 端点位置
returns: -1 | 0 | 1
比较端点和 Range 的位置。

// comparePoint (main)
var root = Parser.parse("abcd"),
	{firstChild} = root,
	range = root.createRange();
range.setStart(firstChild, 1);
range.setEnd(firstChild, 3);
assert.equal(range, "bc");
assert.strictEqual(range.comparePoint(firstChild, 0), -1);
assert.strictEqual(range.comparePoint(firstChild, 2), 0);
assert.strictEqual(range.comparePoint(firstChild, 4), 1);
range.selectNodeContents(firstChild);
assert.strictEqual(range.comparePoint(root, 0), -1);
assert.strictEqual(range.comparePoint(root, 1), 1);

isPointInRange

展开

param: AstNode 端点容器
param: number 端点位置
returns: boolean
端点是否在Range中。

// isPointInRange (main)
var root = Parser.parse("abcd"),
	{firstChild} = root,
	range = root.createRange();
range.setStart(firstChild, 1);
range.setEnd(firstChild, 3);
assert.equal(range, "bc");
assert.ok(!range.isPointInRange(firstChild, 0));
assert.ok(range.isPointInRange(firstChild, 2));
assert.ok(!range.isPointInRange(firstChild, 4));
range.selectNodeContents(firstChild);
assert.ok(!range.isPointInRange(root, 0));
assert.ok(!range.isPointInRange(root, 1));

cloneRange

展开

returns: AstRange
复制 AstRange 对象。

// cloneRange (main)
var root = Parser.parse("a"),
	range = root.createRange();
range.setStart(root, 0);
range.setEnd(root, 1);
assert.deepStrictEqual(range.cloneRange(), range);

detach

展开

清空 Range 对象。

// detach (main)
var root = Parser.parse("a"),
	range = root.createRange();
range.setStart(root, 0);
range.setEnd(root, 1);
range.detach();

deleteContents

展开

删除 Range 中的内容。

// deleteContents (main)
var root = Parser.parse("ab[[c]]{{d}}e"),
	{firstChild, lastChild} = root,
	range = root.createRange();
assert.equal(firstChild, "ab");
assert.equal(lastChild, "e");
range.setStart(firstChild, 1);
range.setEnd(firstChild, 2);
assert.equal(range, "b");
range.deleteContents();
assert.equal(root, "a[[c]]{{d}}e");
assert.strictEqual(range.startContainer, firstChild);
assert.strictEqual(range.startOffset, 1);
assert.strictEqual(range.endContainer, firstChild);
assert.strictEqual(range.endOffset, 1);
range.detach();
range.setStart(root, 2);
range.setEnd(lastChild, 1);
assert.equal(range, "{{d}}e");
range.deleteContents();
assert.equal(root, "a[[c]]");
assert.strictEqual(range.startContainer, root);
assert.strictEqual(range.startOffset, 2);
assert.strictEqual(range.endContainer, root);
assert.strictEqual(range.endOffset, 2);
range.setStart(firstChild, 0);
assert.equal(range, "a[[c]]");
range.deleteContents();
assert.equal(root, "");
assert.strictEqual(range.startContainer, root);
assert.strictEqual(range.startOffset, 1);
assert.strictEqual(range.endContainer, root);
assert.strictEqual(range.endOffset, 1);

remove

展开

加入的版本:1.23.0

deleteContents 方法的别名。

getBoundingClientRect

展开

returns: {top: number, left: number, height: number, left: number}
获取行列位置和大小。

// getBoundingClientRect (main)
var root = Parser.parse("ab\n[[c]]"),
	{firstChild} = root,
	range = root.createRange();
assert.equal(firstChild, "ab\n");
range.setStart(firstChild, 1);
range.setEnd(firstChild, 2);
assert.equal(range, "b");
assert.deepStrictEqual(range.getBoundingClientRect(), {
	top: 0,
	left: 1,
	height: 1,
	width: 1,
});
range.setEnd(root, 2);
assert.equal(range, "b\n[[c]]");
assert.deepStrictEqual(range.getBoundingClientRect(), {
	top: 0,
	left: 1,
	height: 2,
	width: 5,
});

getClientRects

展开

加入的版本:1.23.0

returns: {top: number, left: number, height: number, left: number}[]
获取 Range 内节点的行列位置和大小。

// getClientRects (main)
var root = Parser.parse("ab\n[[c]]"),
	range = root.createRange();
range.selectNodeContents(root);
assert.deepStrictEqual(range.getClientRects(), [
	{
		top: 0,
		left: 0,
		height: 2,
		width: 0,
	},
	{
		top: 1,
		left: 0,
		height: 1,
		width: 5,
	},
]);

insertNode

展开

param: AstNode | string 插入的节点
param: boolean 是否在 Range 后插入,默认行为是插入到 Range 前
在 Range 前或后插入节点。

// insertNode (main)
var root = Parser.parse("abcd"),
	{firstChild} = root,
	range = root.createRange();
range.setStart(firstChild, 1);
range.setEnd(firstChild, 3);
assert.equal(range, "bc");
range.insertNode("e");
assert.equal(root, "aebcd");
assert.equal(range, "bc");
range.insertNode("f", true);
assert.equal(root, "aebcfd");
assert.equal(range, "bc");

before

展开

加入的版本:1.23.0

param: AstNode | string 插入的节点
在 Range 前插入节点。

// before (main)
var root = Parser.parse("ab[[c]]"),
	{firstChild} = root,
	range = root.createRange();
range.setStart(firstChild, 1);
range.setEnd(root, 2);
assert.equal(range, "b[[c]]");
range.before("d", "e");
assert.equal(root, "adeb[[c]]");
assert.equal(range, "b[[c]]");

after

展开

加入的版本:1.23.0

param: AstNode | string 插入的节点
在 Range 后插入节点。

// after (main)
var root = Parser.parse("abc"),
	{firstChild} = root,
	range = root.createRange();
range.setStart(firstChild, 1);
range.setEnd(firstChild, 2);
assert.equal(range, "b");
range.after("d", "e");
assert.equal(root, "abdec");
assert.equal(range, "b");

replaceWith

展开

加入的版本:1.23.0

param: AstNode | string 新节点
使用新节点或文本替换当前 Range。

// replaceWith (main)
var root = Parser.parse("abc"),
	{firstChild} = root,
	range = root.createRange();
range.setStart(firstChild, 1);
range.setEnd(firstChild, 2);
assert.equal(range, "b");
range.replaceWith("d", "e");
assert.equal(root, "adec");
assert.equal(range, "de");

append

展开

加入的版本:1.23.0

param: AstNode | string 插入的节点
在 Range 末尾追加节点或文本。

// append (main)
var root = Parser.parse("abc"),
	{firstChild} = root,
	range = root.createRange();
range.setStart(firstChild, 1);
range.setEnd(firstChild, 2);
assert.equal(range, "b");
range.append("d", "e");
assert.equal(root, "abdec");
assert.equal(range, "bde");

prepend

展开

加入的版本:1.23.0

param: AstNode | string 插入的节点
在 Range 开头追加节点或文本。

// prepend (main)
var root = Parser.parse("abc"),
	{firstChild} = root,
	range = root.createRange();
range.setStart(firstChild, 1);
range.setEnd(firstChild, 2);
assert.equal(range, "b");
range.prepend("d", "e");
assert.equal(root, "adebc");
assert.equal(range, "deb");

removeChild

展开

加入的版本:1.23.0

param: AstNode 移除的子节点
从 Range 中移除子节点。

// removeChild (main)
var root = Parser.parse("a[[b]]c"),
	{firstElementChild} = root,
	range = root.createRange();
assert.equal(firstElementChild, "[[b]]");
range.selectNodeContents(root);
range.removeChild(firstElementChild);
assert.equal(root, "ac");
assert.equal(range, "ac");

extractContents

展开

returns: AstNode[]
获取 Range 内的全部节点。

// extractContents (main)
var root = Parser.parse("abc"),
	{firstChild} = root,
	range = root.createRange();
assert.equal(firstChild, "abc");
range.setStart(firstChild, 0);
range.setEnd(firstChild, 0);
assert.equal(range, "");
assert.deepStrictEqual(range.extractContents(), []);
range.setEnd(firstChild, 3);
assert.equal(range, "abc");
assert.deepStrictEqual(
	range.extractContents(),
	[root.createTextNode("abc")],
);
range.setStart(firstChild, 1);
range.setEnd(firstChild, 2);
assert.equal(range, "b");
assert.deepStrictEqual(
	range.extractContents(),
	[root.createTextNode("b")],
);
range.setEnd(root, 3);
assert.equal(range, "bc");
assert.deepStrictEqual(range.extractContents(), [
	root.createTextNode("b"),
	root.createTextNode("c"),
]);
range.setStart(root, 0);
assert.equal(range, "abc");
assert.deepStrictEqual(range.extractContents(), [
	root.createTextNode("a"),
	root.createTextNode("b"),
	root.createTextNode("c"),
]);

cloneContents

展开

returns: AstNode[]
拷贝 Range 内的全部节点。

// cloneContents (main)
var root = Parser.parse("ab<p>"),
	{firstChild} = root,
	range = root.createRange(),
	cloned;
assert.equal(firstChild, "ab");
range.setStart(firstChild, 1);
range.setEnd(root, 2);
assert.equal(range, "b<p>");
cloned = range.cloneContents();
assert.deepStrictEqual(cloned, [
	root.createTextNode("b"),
	root.createElement("p"),
]);

getRootNode

展开

加入的版本:1.23.0

returns: AstNode
获取 Range 的根节点。

// getRootNode (main)
var root = Parser.parse("abc"),
	{firstChild} = root,
	range = root.createRange();
range.setStart(firstChild, 1);
assert.strictEqual(range.getRootNode(), root);

closest

展开

加入的版本:1.23.0

param: string 选择器
returns: Token | undefined
获取与 Range 最近的符合选择器的祖先节点。这是一个 TypeScript 泛型函数

TypeScript 示例:

import type {LinkToken} from "wikiparser-node";
const {firstChild} = Parser.parse("[[a]]"),
	range = firstChild!.createRange();
range.selectNodeContents(firstChild!);
range.closest<LinkToken>("link") satisfies LinkToken | undefined;

JavaScript 示例:

// closest (main)
var root = Parser.parse("abc"),
	{firstChild} = root,
	range = root.createRange();
range.setStart(firstChild, 1);
range.setEnd(firstChild, 2);
assert.strictEqual(range.closest("root"), root);

querySelector

展开

加入的版本:1.23.0

param: string 选择器
returns: Token | undefined
获取 Range 内第一个符合选择器的节点。这是一个 TypeScript 泛型函数

TypeScript 示例:

import type {LinkToken} from "wikiparser-node";
const root = Parser.parse("[[a]]"),
	range = root.createRange();
range.selectNodeContents(root);
range.querySelector<LinkToken>("link") satisfies LinkToken | undefined;

JavaScript 示例:

// querySelector (main)
var root = Parser.parse("[[a]]{{b}}"),
	{lastChild} = root,
	range = root.createRange();
assert.equal(lastChild, "{{b}}");
range.selectNodeContents(root);
assert.strictEqual(range.querySelector("template"), lastChild);

getElementByTypes

展开

加入的版本:1.23.0

param: string 使用,分隔的节点类型列表
returns: Token | undefined
获取 Range 内第一个符合指定类型的节点。这是一个 TypeScript 泛型函数

TypeScript 示例:

import type {LinkToken, TranscludeToken} from "wikiparser-node";
const root = Parser.parse("[[a]]{{b}}"),
	range = root.createRange();
range.selectNodeContents(root);
range.getElementByTypes<LinkToken | TranscludeToken>(
	"link, template",
) satisfies LinkToken | TranscludeToken | undefined;

JavaScript 示例:

// getElementByTypes (main)
var root = Parser.parse("[[a]]{{b}}"),
	{lastChild} = root,
	range = root.createRange();
assert.equal(lastChild, "{{b}}");
range.selectNodeContents(root);
assert.strictEqual(range.getElementByTypes("template"), lastChild);

getElementById

展开

加入的版本:1.23.0

param: string 标签 id
returns: Token | undefined
获取 Range 内第一个符合 id 的节点。

// getElementById (main)
var root = Parser.parse([[a]]<b id="c">'),
	{lastChild} = root,
	range = root.createRange();
assert.equal(lastChild, '<b id="c">');
range.selectNodeContents(root);
assert.strictEqual(range.getElementById("c"), lastChild);

querySelectorAll

展开

加入的版本:1.23.0

param: string 选择器
returns: Token[]
获取 Range 内所有符合选择器的节点。这是一个 TypeScript 泛型函数

TypeScript 示例:

import type {LinkToken} from "wikiparser-node";
const root = Parser.parse("[[a]][[b]]"),
	range = root.createRange();
range.selectNodeContents(root);
range.querySelectorAll<LinkToken>("link") satisfies LinkToken[];

JavaScript 示例:

// querySelectorAll (main)
var root = Parser.parse("[[a]][[b]]"),
	{firstChild, lastChild} = root,
	range = root.createRange();
assert.equal(firstChild, "[[a]]");
assert.equal(lastChild, "[[b]]");
range.selectNodeContents(root);
assert.deepStrictEqual(
	range.querySelectorAll("link"),
	[firstChild, lastChild],
);

getElementsByClassName

展开

加入的版本:1.23.0

param: string 类名
returns: Token[]
获取 Range 内所有符合类名的节点。

// getElementsByClassName (main)
var root = Parser.parse('<b class="c">[[a]]<p class="c">'),
	{firstChild, lastChild} = root,
	range = root.createRange();
assert.equal(firstChild, '<b class="c">');
assert.equal(lastChild, '<p class="c">');
range.selectNodeContents(root);
assert.deepStrictEqual(
	range.getElementsByClassName("c"),
	[firstChild, firstChild.firstChild, lastChild, lastChild.firstChild],
);

getElementsByTagName

展开

加入的版本:1.23.0

param: string 标签名
returns: Token[]
获取 Range 内所有符合标签名的节点。这是一个 TypeScript 泛型函数

TypeScript 示例:

import type {HtmlToken} from "wikiparser-node";
const root = Parser.parse("<b></b>"),
	range = root.createRange();
range.selectNodeContents(root);
range.getElementsByTagName<HtmlToken>("b") satisfies HtmlToken[];

JavaScript 示例:

// getElementsByTagName (main)
var root = Parser.parse("<b>[[a]]<b>"),
	{firstChild, lastChild} = root,
	range = root.createRange();
assert.equal(firstChild, "<b>");
assert.equal(lastChild, "<b>");
range.selectNodeContents(root);
assert.deepStrictEqual(
	range.getElementsByTagName("b"),
	[firstChild, lastChild],
);

escape

展开

加入的版本:1.23.0

转义 Range 内的节点。

// escape (main)
var root = Parser.parse("=\n{|"),
	{firstChild, lastChild} = root,
	range = root.createRange();
assert.equal(firstChild, "=\n");
assert.equal(lastChild, "{|");
range.selectNodeContents(root);
range.escape();
assert.equal(root, "{{=}}\n{{{!}}");
⚠️ **GitHub.com Fallback** ⚠️