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

feat: + gadget-Shiki #579

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open

feat: + gadget-Shiki #579

wants to merge 4 commits into from

Conversation

dragon-fish
Copy link
Contributor

@dragon-fish dragon-fish commented Dec 5, 2024

Summary by Sourcery

添加 Shiki 代码高亮器作为一个小工具。

新特性:

  • 引入 Shiki 代码高亮器作为新的小工具。

测试:

  • 测试 Shiki
Original summary in English

Summary by Sourcery

Add Shiki code highlighter as a gadget.

New Features:

  • Introduce the Shiki code highlighter as a new gadget.

Tests:

  • Test Shiki

Copy link
Member

@gui-ying233 gui-ying233 left a comment

Choose a reason for hiding this comment

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

<code> 被渲染成 <pre> 是预期行为吗(

Comment on lines +16 to +20
const shiki = await import(SHIKI_CDN);
TARGET_ELEMENTS.forEach((el) => {
renderBlock(shiki, el);
});
mw.hook("npm:shiki").fire(shiki);
Copy link
Member

Choose a reason for hiding this comment

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

VM20415:59 Uncaught (in promise) ReferenceError: Cannot access 'getLangFromElement' before initialization

这5行是不是应该放在最后(?

}
return [langInfo.aliases?.[0], langInfo.name, langInfo.id, lang].filter(Boolean).sort((a, b) => a.length - b.length)[0];
})();
console.info("[SHIKI]", "Rendering", el, lang, langInfo);
Copy link
Member

Choose a reason for hiding this comment

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

能不能不要拉屎(至少改成console.debug吧(

Suggested change
console.info("[SHIKI]", "Rendering", el, lang, langInfo);
console.debug("[SHIKI]", "Rendering", el, lang, langInfo);

Comment on lines +27 to +28
counter-reset: step;
counter-increment: step calc(var(--start, 1) - 1);
Copy link
Member

Choose a reason for hiding this comment

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

为啥不直接

Suggested change
counter-reset: step;
counter-increment: step calc(var(--start, 1) - 1);
counter-reset: step calc(var(--start, 1) - 1);

Comment on lines +106 to +111
el.style.display = "none";
el.dataset.shikiRendered = "1";
const wrapper = document.createElement("div");
wrapper.innerHTML = html;
const pre = wrapper.querySelector("pre");
el.insertAdjacentElement("afterend", pre);
Copy link
Member

Choose a reason for hiding this comment

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

希望能把 el 的属性继承到 pre,例如 style

{
pre: (node) => {
node.properties.class += ` lang-${langLabel}`;
node.properties.style += ";";
Copy link
Member

Choose a reason for hiding this comment

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

妈妈生的

@dragon-fish
Copy link
Contributor Author

@sourcery-ai review

Copy link

sourcery-ai bot commented Dec 31, 2024

审阅者指南 by Sourcery

这个拉取请求引入了一个名为"Shiki"的新小工具,用于代码高亮。它添加了对 Shiki 高亮器的支持,作为现有 Prism 高亮器的替代方案。实现涉及添加新的小工具定义、JavaScript 文件、CSS 文件,并更新现有的 code-prettify 小工具以检查"gadget-Shiki"用户选项。

Shiki 代码高亮过程的序列图

sequenceDiagram
    participant User
    participant Page
    participant ShikiGadget
    participant ShikiCDN

    User->>Page: 查看包含代码块的页面
    activate Page
    Page->>ShikiGadget: 初始化
    activate ShikiGadget
    ShikiGadget->>ShikiCDN: 从 CDN 导入 Shiki
    ShikiCDN-->>ShikiGadget: 返回 Shiki 库
    ShikiGadget->>ShikiGadget: 查找目标元素
    loop 对每个代码块
        ShikiGadget->>ShikiGadget: 获取元素的语言
        ShikiGadget->>ShikiGadget: 渲染代码块
        ShikiGadget->>Page: 插入高亮代码
    end
    ShikiGadget-->>Page: 触发 'npm:shiki' 钩子
    deactivate ShikiGadget
    Page-->>User: 显示高亮代码
    deactivate Page
Loading

Shiki 小工具结构的类图

classDiagram
    class ShikiGadget {
        +SHIKI_CDN: string
        +TARGET_ELEMENTS: NodeList
        +getLangFromContentModel()
        +getLangFromElement(el)
        +renderBlock(shiki, el)
    }

    class ShikiStyles {
        +pre.shiki
        +shiki-lang-badge
        +line-number
    }

    class GadgetDefinition {
        +ResourceLoader: boolean
        +hidden: boolean
        +default: boolean
        +type: string
        +dependencies: array
    }

    ShikiGadget --> ShikiStyles: 使用
    GadgetDefinition --> ShikiGadget: 定义
Loading

代码块渲染过程的状态图

stateDiagram-v2
    [*] --> CheckGadget
    CheckGadget --> Exit: 如果启用了 Prism 或 Shiki
    CheckGadget --> FindElements: 否则
    FindElements --> GetLanguage
    GetLanguage --> FromElement: 检查元素属性
    GetLanguage --> FromContentModel: 检查页面属性
    FromElement --> RenderBlock
    FromContentModel --> RenderBlock
    RenderBlock --> ApplyStyles
    ApplyStyles --> DisplayResult
    DisplayResult --> [*]
Loading

文件级变更

变更 详情 文件
添加 Shiki 小工具文件。
  • 创建 Shiki JavaScript 文件,使用 Shiki 库处理代码高亮。
  • 创建 Shiki CSS 文件,为高亮代码块设置样式。
  • 创建 Shiki 定义文件,注册小工具及其依赖项。
src/gadgets/Shiki/MediaWiki:Gadget-Shiki.js
src/gadgets/Shiki/MediaWiki:Gadget-Shiki.css
src/gadgets/Shiki/definition.yaml
更新 code-prettify 小工具。
  • 修改 code-prettify 小工具,检查"gadget-Shiki"用户选项,并在启用时阻止执行。
src/gadgets/code-prettify/MediaWiki:Gadget-code-prettify.js
将 Shiki 添加到小工具定义列表。
  • 在 Gadgets-definition-list.yaml 文件中将"Shiki"添加到可用小工具列表。
src/gadgets/Gadgets-definition-list.yaml
更新 VS Code 设置。
  • 更新 VS Code 设置,包含新 Shiki 小工具文件的配置。此更改可能与开发工具相关,不会直接影响最终用户的小工具功能。
.vscode/settings.json

提示和命令

与 Sourcery 交互

  • 触发新审阅: 在拉取请求中评论 @sourcery-ai review
  • 继续讨论: 直接回复 Sourcery 的审阅评论。
  • 从审阅评论生成 GitHub 问题: 通过回复评论,要求 Sourcery 创建一个问题。
  • 生成拉取请求标题: 在拉取请求标题的任何位置写 @sourcery-ai 以随时生成标题。
  • 生成拉取请求摘要: 在拉取请求正文的任何位置写 @sourcery-ai summary 以随时生成 PR 摘要。您还可以使用此命令指定摘要的插入位置。

自定义您的体验

访问您的仪表板以:

  • 启用或禁用审阅功能,如 Sourcery 生成的拉取请求摘要、审阅者指南等。
  • 更改审阅语言。
  • 添加、删除或编辑自定义审阅说明。
  • 调整其他审阅设置。

获取帮助

Original review guide in English

Reviewer's Guide by Sourcery

This pull request introduces a new gadget named "Shiki" for code highlighting. It adds support for the Shiki highlighter as an alternative to the existing Prism highlighter. The implementation involves adding a new gadget definition, JavaScript file, CSS file, and updating the existing code-prettify gadget to check for the "gadget-Shiki" user option.

Sequence diagram for Shiki code highlighting process

sequenceDiagram
    participant User
    participant Page
    participant ShikiGadget
    participant ShikiCDN

    User->>Page: Views page with code blocks
    activate Page
    Page->>ShikiGadget: Initialize
    activate ShikiGadget
    ShikiGadget->>ShikiCDN: Import Shiki from CDN
    ShikiCDN-->>ShikiGadget: Return Shiki library
    ShikiGadget->>ShikiGadget: Find target elements
    loop For each code block
        ShikiGadget->>ShikiGadget: Get language from element
        ShikiGadget->>ShikiGadget: Render code block
        ShikiGadget->>Page: Insert highlighted code
    end
    ShikiGadget-->>Page: Fire 'npm:shiki' hook
    deactivate ShikiGadget
    Page-->>User: Display highlighted code
    deactivate Page
Loading

Class diagram for Shiki gadget structure

classDiagram
    class ShikiGadget {
        +SHIKI_CDN: string
        +TARGET_ELEMENTS: NodeList
        +getLangFromContentModel()
        +getLangFromElement(el)
        +renderBlock(shiki, el)
    }

    class ShikiStyles {
        +pre.shiki
        +shiki-lang-badge
        +line-number
    }

    class GadgetDefinition {
        +ResourceLoader: boolean
        +hidden: boolean
        +default: boolean
        +type: string
        +dependencies: array
    }

    ShikiGadget --> ShikiStyles: uses
    GadgetDefinition --> ShikiGadget: defines
Loading

State diagram for code block rendering process

stateDiagram-v2
    [*] --> CheckGadget
    CheckGadget --> Exit: if Prism or Shiki enabled
    CheckGadget --> FindElements: else
    FindElements --> GetLanguage
    GetLanguage --> FromElement: Check element attributes
    GetLanguage --> FromContentModel: Check page properties
    FromElement --> RenderBlock
    FromContentModel --> RenderBlock
    RenderBlock --> ApplyStyles
    ApplyStyles --> DisplayResult
    DisplayResult --> [*]
Loading

File-Level Changes

Change Details Files
Added Shiki gadget files.
  • Created the Shiki JavaScript file to handle code highlighting using the Shiki library.
  • Created the Shiki CSS file to style the highlighted code blocks.
  • Created the Shiki definition file to register the gadget and its dependencies.
src/gadgets/Shiki/MediaWiki:Gadget-Shiki.js
src/gadgets/Shiki/MediaWiki:Gadget-Shiki.css
src/gadgets/Shiki/definition.yaml
Updated code-prettify gadget.
  • Modified the code-prettify gadget to check for the "gadget-Shiki" user option and prevent execution if it is enabled.
src/gadgets/code-prettify/MediaWiki:Gadget-code-prettify.js
Added Shiki to gadget definition list.
  • Added "Shiki" to the list of available gadgets in the Gadgets-definition-list.yaml file.
src/gadgets/Gadgets-definition-list.yaml
Updated VS Code settings.
  • Updated VS Code settings to include configurations for the new Shiki gadget files. This change is likely related to development tooling and does not directly affect the gadget's functionality for end-users.
.vscode/settings.json

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time. You can also use
    this command to specify where the summary should be inserted.

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

@dragon-fish - 我已经审查了你的更改 - 这里有一些反馈:

总体评论

  • 考虑将 Shiki 本地打包,而不是从 esm.sh CDN 加载,以提高安全性和可靠性
这是我在审查期间查看的内容
  • 🟡 一般问题:发现 2 个问题
  • 🟢 安全性:一切看起来都很好
  • 🟢 测试:一切看起来都很好
  • 🟡 复杂性:发现 1 个问题
  • 🟢 文档:一切看起来都很好

Sourcery 对开源项目免费 - 如果你喜欢我们的评论,请考虑分享它们 ✨
帮助我变得更有用!请点击每条评论上的 👍 或 👎,我将使用反馈来改进你的评论。
Original comment in English

Hey @dragon-fish - I've reviewed your changes - here's some feedback:

Overall Comments:

  • Consider bundling Shiki locally instead of loading from esm.sh CDN to improve security and reliability
Here's what I looked at during the review
  • 🟡 General issues: 2 issues found
  • 🟢 Security: all looks good
  • 🟢 Testing: all looks good
  • 🟡 Complexity: 1 issue found
  • 🟢 Documentation: all looks good

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

"use strict";

(async () => {
const SHIKI_CDN = "https://esm.sh/shiki@1.24.0";
Copy link

Choose a reason for hiding this comment

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

建议: 考虑为 Shiki 导入添加备用 CDN 和超时处理

外部 CDN 依赖可能会失败。考虑实现备用 CDN 并添加超时处理,以在 CDN 不可用时优雅降级。

Original comment in English

suggestion: Consider adding fallback CDN and timeout handling for the Shiki import

External CDN dependencies can fail. Consider implementing a fallback CDN and adding timeout handling to gracefully degrade when the CDN is unavailable.

TARGET_ELEMENTS.forEach((el) => {
renderBlock(shiki, el);
});
mw.hook("npm:shiki").fire(shiki);
Copy link

Choose a reason for hiding this comment

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

问题 (bug_risk): 钩子在所有块渲染之前触发,这可能导致竞争条件

考虑在所有块渲染后触发钩子,方法是等待所有 renderBlock 承诺解决。

Original comment in English

issue (bug_risk): Hook is fired before all blocks are rendered, which could cause race conditions

Consider firing the hook after all blocks have been rendered by waiting for all renderBlock promises to resolve.


"use strict";

(async () => {
Copy link

Choose a reason for hiding this comment

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

问题 (复杂性): 考虑通过使用 async/await 并将转换器配置提取到单独的变量中来简化 renderBlock 函数。

renderBlock 函数可以在保持功能的同时简化:

  1. 使用 async/await 而不是 promise 链
  2. 提取转换器配置以减少嵌套

这是一个建议的重构:

Original comment in English

issue (complexity): Consider simplifying the renderBlock function by using async/await and extracting the transformer configuration into a separate variable.

The renderBlock function could be simplified while maintaining functionality:

  1. Use async/await instead of promise chains
  2. Extract transformer config to reduce nesting

Here's a suggested refactor:

const shikiTransformer = {
  pre: (node) => {
    node.properties.class += ` lang-${langLabel}`;
    node.properties.style += ";";
    node.properties.style += `padding-right: ${(10 * langLabel.length + 12).toFixed()}px;`;
    if (lineFrom) {
      node.properties.class += " line-number";
    }
  },
  code: (node) => {
    node.properties.class += " shiki-code";
    node.tagName = "div";
    node.properties.style += `;--start: ${+lineFrom};`;
  },
  line: (node, line) => {
    node.properties["data-line-number-raw"] = line;
  },
  postprocess: (html) => {
    if (langLabel) {
      return html.replace("</pre>", `<span class="shiki-lang-badge">${langLabel}</span></pre>`);
    }
  },
};

async function renderBlock(shiki, el) {
  if (el.classList.contains("shiki") || !!el.dataset.shikiRendered) {
    return null;
  }

  const lang = getLangFromElement(el) || getLangFromContentModel();
  if (!lang) {
    return null;
  }

  try {
    const html = await shiki.codeToHtml(el.innerText.trimEnd(), {
      lang,
      theme: "one-dark-pro",
      transformers: [shikiTransformer],
    });

    el.style.display = "none";
    el.dataset.shikiRendered = "1";
    const wrapper = document.createElement("div");
    wrapper.innerHTML = html;
    const pre = wrapper.querySelector("pre");
    el.insertAdjacentElement("afterend", pre);
    return pre;
  } catch (e) {
    console.error("[SHIKI] Render failed", el, e);
    return null;
  }
}

</details>

Comment on lines +55 to +119
async function renderBlock(shiki, el) {
if (el.classList.contains("shiki") || !!el.dataset.shikiRendered) {
return Promise.resolve(null);
}
const lang = getLangFromElement(el) || getLangFromContentModel();
if (!lang) {
return Promise.resolve(null);
}

const langInfo = shiki.bundledLanguagesInfo.find((i) => i.aliases?.includes(lang) || i.id === lang || i.name === lang);
const langLabel = (() => {
if (!langInfo) {
return lang;
}
return [langInfo.aliases?.[0], langInfo.name, langInfo.id, lang].filter(Boolean).sort((a, b) => a.length - b.length)[0];
})();
console.info("[SHIKI]", "Rendering", el, lang, langInfo);

const lineFrom = el.dataset.lineFrom || el.dataset.from || "1";

const renderedEl = await shiki
.codeToHtml(el.innerText.trimEnd(), {
lang,
theme: "one-dark-pro",
transformers: [
{
pre: (node) => {
node.properties.class += ` lang-${langLabel}`;
node.properties.style += ";";
node.properties.style += `padding-right: ${(10 * langLabel.length + 12).toFixed()}px;`;
if (lineFrom) {
node.properties.class += " line-number";
}
},
code: (node) => {
node.properties.class += " shiki-code";
node.tagName = "div";
node.properties.style += `;--start: ${+lineFrom};`;
},
line: (node, line) => {
node.properties["data-line-number-raw"] = line;
},
postprocess: (html) => {
if (langLabel) {
return html.replace("</pre>", `<span class="shiki-lang-badge">${langLabel}</span></pre>`);
}
},
},
],
})
.then((html) => {
el.style.display = "none";
el.dataset.shikiRendered = "1";
const wrapper = document.createElement("div");
wrapper.innerHTML = html;
const pre = wrapper.querySelector("pre");
el.insertAdjacentElement("afterend", pre);
return pre;
})
.catch((e) => {
console.error("[SHIKI] Render failed", el, e);
return null;
});
return renderedEl;
};
Copy link

Choose a reason for hiding this comment

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

问题 (代码质量): 避免在块内声明函数,倾向于使用函数赋值表达式。 (avoid-function-declarations-in-blocks)

解释函数声明可能在 Javascript 中被提升,但不同浏览器之间的行为不一致。 提升通常令人困惑,应避免。在块内使用函数声明时, 应使用函数表达式,这会在作用域内创建函数。
Original comment in English

issue (code-quality): Avoid function declarations, favouring function assignment expressions, inside blocks. (avoid-function-declarations-in-blocks)

ExplanationFunction declarations may be hoisted in Javascript, but the behaviour is inconsistent between browsers. Hoisting is generally confusing and should be avoided. Rather than using function declarations inside blocks, you should use function expressions, which create functions in-scope.

Comment on lines +75 to +118
const renderedEl = await shiki
.codeToHtml(el.innerText.trimEnd(), {
lang,
theme: "one-dark-pro",
transformers: [
{
pre: (node) => {
node.properties.class += ` lang-${langLabel}`;
node.properties.style += ";";
node.properties.style += `padding-right: ${(10 * langLabel.length + 12).toFixed()}px;`;
if (lineFrom) {
node.properties.class += " line-number";
}
},
code: (node) => {
node.properties.class += " shiki-code";
node.tagName = "div";
node.properties.style += `;--start: ${+lineFrom};`;
},
line: (node, line) => {
node.properties["data-line-number-raw"] = line;
},
postprocess: (html) => {
if (langLabel) {
return html.replace("</pre>", `<span class="shiki-lang-badge">${langLabel}</span></pre>`);
}
},
},
],
})
.then((html) => {
el.style.display = "none";
el.dataset.shikiRendered = "1";
const wrapper = document.createElement("div");
wrapper.innerHTML = html;
const pre = wrapper.querySelector("pre");
el.insertAdjacentElement("afterend", pre);
return pre;
})
.catch((e) => {
console.error("[SHIKI] Render failed", el, e);
return null;
});
return renderedEl;
Copy link

Choose a reason for hiding this comment

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

建议 (代码质量): 内联立即返回的变量 (inline-immediately-returned-variable)

Suggested change
const renderedEl = await shiki
.codeToHtml(el.innerText.trimEnd(), {
lang,
theme: "one-dark-pro",
transformers: [
{
pre: (node) => {
node.properties.class += ` lang-${langLabel}`;
node.properties.style += ";";
node.properties.style += `padding-right: ${(10 * langLabel.length + 12).toFixed()}px;`;
if (lineFrom) {
node.properties.class += " line-number";
}
},
code: (node) => {
node.properties.class += " shiki-code";
node.tagName = "div";
node.properties.style += `;--start: ${+lineFrom};`;
},
line: (node, line) => {
node.properties["data-line-number-raw"] = line;
},
postprocess: (html) => {
if (langLabel) {
return html.replace("</pre>", `<span class="shiki-lang-badge">${langLabel}</span></pre>`);
}
},
},
],
})
.then((html) => {
el.style.display = "none";
el.dataset.shikiRendered = "1";
const wrapper = document.createElement("div");
wrapper.innerHTML = html;
const pre = wrapper.querySelector("pre");
el.insertAdjacentElement("afterend", pre);
return pre;
})
.catch((e) => {
console.error("[SHIKI] Render failed", el, e);
return null;
});
return renderedEl;
return await shiki
.codeToHtml(el.innerText.trimEnd(), {
lang,
theme: "one-dark-pro",
transformers: [
{
pre: (node) => {
node.properties.class += ` lang-${langLabel}`;
node.properties.style += ";";
node.properties.style += `padding-right: ${(10 * langLabel.length + 12).toFixed()}px;`;
if (lineFrom) {
node.properties.class += " line-number";
}
},
code: (node) => {
node.properties.class += " shiki-code";
node.tagName = "div";
node.properties.style += `;--start: ${+lineFrom};`;
},
line: (node, line) => {
node.properties["data-line-number-raw"] = line;
},
postprocess: (html) => {
if (langLabel) {
return html.replace("</pre>", `<span class="shiki-lang-badge">${langLabel}</span></pre>`);
}
},
},
],
})
.then((html) => {
el.style.display = "none";
el.dataset.shikiRendered = "1";
const wrapper = document.createElement("div");
wrapper.innerHTML = html;
const pre = wrapper.querySelector("pre");
el.insertAdjacentElement("afterend", pre);
return pre;
})
.catch((e) => {
console.error("[SHIKI] Render failed", el, e);
return null;
});


解释我们经常在代码中看到的是将结果赋值给一个变量
然后立即返回它。

直接返回结果可以缩短代码并删除不必要的
变量,减少阅读函数的心理负担。

中间变量可能有用的地方是如果它们随后被用作
参数或条件,并且名称可以作为变量代表的注释。在你从函数返回它的情况下,
函数名称用于告诉你结果是什么,因此变量名称
是不必要的。

Original comment in English

suggestion (code-quality): Inline variable that is immediately returned (inline-immediately-returned-variable)

Suggested change
const renderedEl = await shiki
.codeToHtml(el.innerText.trimEnd(), {
lang,
theme: "one-dark-pro",
transformers: [
{
pre: (node) => {
node.properties.class += ` lang-${langLabel}`;
node.properties.style += ";";
node.properties.style += `padding-right: ${(10 * langLabel.length + 12).toFixed()}px;`;
if (lineFrom) {
node.properties.class += " line-number";
}
},
code: (node) => {
node.properties.class += " shiki-code";
node.tagName = "div";
node.properties.style += `;--start: ${+lineFrom};`;
},
line: (node, line) => {
node.properties["data-line-number-raw"] = line;
},
postprocess: (html) => {
if (langLabel) {
return html.replace("</pre>", `<span class="shiki-lang-badge">${langLabel}</span></pre>`);
}
},
},
],
})
.then((html) => {
el.style.display = "none";
el.dataset.shikiRendered = "1";
const wrapper = document.createElement("div");
wrapper.innerHTML = html;
const pre = wrapper.querySelector("pre");
el.insertAdjacentElement("afterend", pre);
return pre;
})
.catch((e) => {
console.error("[SHIKI] Render failed", el, e);
return null;
});
return renderedEl;
return await shiki
.codeToHtml(el.innerText.trimEnd(), {
lang,
theme: "one-dark-pro",
transformers: [
{
pre: (node) => {
node.properties.class += ` lang-${langLabel}`;
node.properties.style += ";";
node.properties.style += `padding-right: ${(10 * langLabel.length + 12).toFixed()}px;`;
if (lineFrom) {
node.properties.class += " line-number";
}
},
code: (node) => {
node.properties.class += " shiki-code";
node.tagName = "div";
node.properties.style += `;--start: ${+lineFrom};`;
},
line: (node, line) => {
node.properties["data-line-number-raw"] = line;
},
postprocess: (html) => {
if (langLabel) {
return html.replace("</pre>", `<span class="shiki-lang-badge">${langLabel}</span></pre>`);
}
},
},
],
})
.then((html) => {
el.style.display = "none";
el.dataset.shikiRendered = "1";
const wrapper = document.createElement("div");
wrapper.innerHTML = html;
const pre = wrapper.querySelector("pre");
el.insertAdjacentElement("afterend", pre);
return pre;
})
.catch((e) => {
console.error("[SHIKI] Render failed", el, e);
return null;
});


ExplanationSomething that we often see in people's code is assigning to a result variable
and then immediately returning it.

Returning the result directly shortens the code and removes an unnecessary
variable, reducing the mental load of reading the function.

Where intermediate variables can be useful is if they then get used as a
parameter or a condition, and the name can act like a comment on what the
variable represents. In the case where you're returning it from a function, the
function name is there to tell you what the result is, so the variable name
is unnecessary.

Copy link
Member

Choose a reason for hiding this comment

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

✖ ./src/gadgets/Shiki/definition.yaml is invalid

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: 🏗 处理中
Development

Successfully merging this pull request may close these issues.

4 participants