@kaciras-blog/markdown
Advanced tools
Comparing version 3.1.0 to 3.2.0
@@ -1,2 +0,2 @@ | ||
import { a as f } from "./fence-30cfdf9c.js"; | ||
import { a as f } from "./fence-78fb79d9.js"; | ||
import { silencePromise as u, identity as d } from "@kaciras/utilities/browser"; | ||
@@ -3,0 +3,0 @@ function g(n, o) { |
@@ -5,10 +5,10 @@ import "./web/markdown.css"; | ||
export * from "./miscellaneous.js"; | ||
export * from "./activate.ts"; | ||
export * from "./activate.js"; | ||
export { default as MarkdownIt } from "markdown-it"; | ||
export { default as TOC } from "markdown-it-toc-done-right"; | ||
export { default as Collect } from "./collect.js"; | ||
export { default as Directive } from "./directive.js"; | ||
export { default as Collapsible } from "./collapsible.js"; | ||
export { default as Fence } from "./web/fence.js"; | ||
export { default as Media } from "./web/media.js"; | ||
export { default as toc } from "markdown-it-toc-done-right"; | ||
export { default as collect } from "./collect.js"; | ||
export { default as directive } from "./directive.js"; | ||
export { default as collapsible } from "./collapsible.js"; | ||
export { default as fence } from "./web/fence.js"; | ||
export { default as media } from "./web/media.js"; | ||
export { default as highlight } from "./web/highlight.js"; |
382
lib/index.js
@@ -1,62 +0,358 @@ | ||
import { A as C, a as g, C as b, D as p, F as v, M as A, U as w, c as M, d as D, h as F } from "./highlight-b436cd80.js"; | ||
import { f as I } from "./fence-30cfdf9c.js"; | ||
import { default as x } from "markdown-it"; | ||
import { default as B } from "markdown-it-toc-done-right"; | ||
var u = /* @__PURE__ */ ((e) => (e[e.None = 0] = "None", e[e.Italic = 1] = "Italic", e[e.Bold = 2] = "Bold", e[e.Code = 4] = "Code", e[e.StrikeThrough = 8] = "StrikeThrough", e))(u || {}); | ||
function k(e) { | ||
let n = 0, t = 0, o = e.length - 1, r = 0, c = e.charCodeAt(0); | ||
if (o < 1) | ||
import v, { unescapeMd as p } from "markdown-it/lib/common/utils.js"; | ||
import y from "markdown-it-toc-done-right"; | ||
import { default as Oe } from "markdown-it-toc-done-right"; | ||
import m from "markdown-it-anchor"; | ||
import L from "markdown-it-footnote"; | ||
import { f as $ } from "./fence-78fb79d9.js"; | ||
import a from "highlight.js/lib/core"; | ||
import x from "highlight.js/lib/languages/c"; | ||
import w from "highlight.js/lib/languages/cpp"; | ||
import M from "highlight.js/lib/languages/xml"; | ||
import _ from "highlight.js/lib/languages/csharp"; | ||
import j from "highlight.js/lib/languages/css"; | ||
import C from "highlight.js/lib/languages/dockerfile"; | ||
import S from "highlight.js/lib/languages/go"; | ||
import B from "highlight.js/lib/languages/http"; | ||
import A from "highlight.js/lib/languages/ini"; | ||
import z from "highlight.js/lib/languages/java"; | ||
import T from "highlight.js/lib/languages/javascript"; | ||
import E from "highlight.js/lib/languages/json"; | ||
import P from "highlight.js/lib/languages/kotlin"; | ||
import F from "highlight.js/lib/languages/less"; | ||
import H from "highlight.js/lib/languages/lua"; | ||
import G from "highlight.js/lib/languages/protobuf"; | ||
import N from "highlight.js/lib/languages/python"; | ||
import R from "highlight.js/lib/languages/rust"; | ||
import q from "highlight.js/lib/languages/scss"; | ||
import D from "highlight.js/lib/languages/shell"; | ||
import O from "highlight.js/lib/languages/sql"; | ||
import U from "highlight.js/lib/languages/yaml"; | ||
import W from "highlight.js/lib/languages/typescript"; | ||
import { default as We } from "markdown-it"; | ||
function J(e, r, s, t) { | ||
const n = e.tShift[r] + e.bMarks[r], i = e.src.slice(n, e.eMarks[r]); | ||
let o; | ||
try { | ||
o = V(i); | ||
} catch { | ||
return !1; | ||
} | ||
if (!t) { | ||
const { type: l, label: c, href: u, attrs: b } = o, f = e.push("directive", l, 0); | ||
f.attrs = [["href", u]], f.meta = b, f.content = c, f.map = [r, e.line]; | ||
} | ||
return e.line = r + 1, !0; | ||
} | ||
function V(e) { | ||
const r = /^@([a-z][a-z0-9\-_]*)/i.exec(e); | ||
if (!r) | ||
throw new Error("Not a directive syntax."); | ||
const [s, t] = r, n = d(e, s.length, 91, 93), i = d(e, n + 1, 40, 41), o = p(e.slice(s.length + 1, n)), l = p(e.slice(n + 2, i)), c = i + 1; | ||
let u = {}; | ||
if (e.charCodeAt(c) === 123) | ||
u = JSON.parse(e.slice(c)); | ||
else if (c !== e.length) | ||
throw new Error("Extra strings after the directive."); | ||
return { type: t, label: o, href: l, attrs: u }; | ||
} | ||
function d(e, r, s, t) { | ||
if (e.charCodeAt(r) !== s) { | ||
const i = String.fromCharCode(s), o = e.charAt(r); | ||
throw new Error(`Expect ${i}, but found ${o}`); | ||
} | ||
let n = 1; | ||
for (; ++r < e.length; ) { | ||
switch (e.charCodeAt(r)) { | ||
case 92: | ||
++r; | ||
break; | ||
case s: | ||
n++; | ||
break; | ||
case t: | ||
n--; | ||
break; | ||
} | ||
if (n === 0) | ||
return r; | ||
} | ||
throw new Error(`Bracket count does not match, level=${n}`); | ||
} | ||
function K(e, r) { | ||
return r = e.normalizeLink(r), e.validateLink(r) ? r : ""; | ||
} | ||
const Q = { | ||
audio(e) { | ||
return `<audio src="${e}" controls></audio>`; | ||
}, | ||
video(e, r, s) { | ||
let t = `src="${e}"`; | ||
return r = s.normalizeLink(r), r && s.validateLink(r) && (t += ` poster="${r}"`), `<video ${t} controls></video>`; | ||
}, | ||
// 仍然加上 controls 避免无法播放 | ||
gif(e) { | ||
return `<video src="${e}" loop muted controls></video>`; | ||
} | ||
}; | ||
function h(e, r = Q) { | ||
e.renderer.rules.directive = (s, t) => { | ||
const n = s[t], { tag: i, content: o } = n, l = n.attrGet("href"), c = r[i]; | ||
return c ? c(K(e, l), o, e) : `[Unknown directive: ${i}]`; | ||
}, e.block.ruler.before("html_block", "directive", J); | ||
} | ||
var X = /* @__PURE__ */ ((e) => (e[e.None = 0] = "None", e[e.Italic = 1] = "Italic", e[e.Bold = 2] = "Bold", e[e.Code = 4] = "Code", e[e.StrikeThrough = 8] = "StrikeThrough", e))(X || {}); | ||
function Ge(e) { | ||
let r = 0, s = 0, t = e.length - 1, n = 0, i = e.charCodeAt(0); | ||
if (t < 1) | ||
return [0, 0]; | ||
function i() { | ||
return r === 0 ? 0 : c === 126 && r === 2 ? 8 : c === 96 ? 4 : c !== 42 && c !== 95 ? 0 : r === 1 ? 1 : r === 2 ? 2 : 3; | ||
function o() { | ||
return n === 0 ? 0 : i === 126 && n === 2 ? 8 : i === 96 ? 4 : i !== 42 && i !== 95 ? 0 : n === 1 ? 1 : n === 2 ? 2 : 3; | ||
} | ||
for (; t < o; t++, o--, r++) { | ||
const a = e.charCodeAt(t); | ||
if (a !== e.charCodeAt(o)) | ||
for (; s < t; s++, t--, n++) { | ||
const c = e.charCodeAt(s); | ||
if (c !== e.charCodeAt(t)) | ||
break; | ||
if (a !== c) { | ||
const f = i(); | ||
if (f === 0) | ||
if (c !== i) { | ||
const u = o(); | ||
if (u === 0) | ||
break; | ||
r = 0, c = a, n |= f; | ||
n = 0, i = c, r |= u; | ||
} | ||
} | ||
const l = i(); | ||
return [n | l, l === 0 ? t - r : t]; | ||
const l = o(); | ||
return [r | l, l === 0 ? s - n : s]; | ||
} | ||
function s(e, n) { | ||
function t(o) { | ||
for (const r of o) | ||
switch (r.type) { | ||
function Y(e) { | ||
return { | ||
subLanguage: "xml", | ||
contains: [ | ||
e.COMMENT("<!--", "-->", { | ||
relevance: 10 | ||
}), | ||
{ | ||
begin: /^\s*<script\s.*?lang=(["'])ts\1.*?>/gm, | ||
end: /^\s*<\/script>/gm, | ||
excludeBegin: !0, | ||
excludeEnd: !0, | ||
subLanguage: "typescript" | ||
}, | ||
{ | ||
begin: /^\s*<script.*?>/gm, | ||
end: /^\s*<\/script>/gm, | ||
excludeBegin: !0, | ||
excludeEnd: !0, | ||
subLanguage: "javascript" | ||
}, | ||
{ | ||
begin: /^\s*<style\s.*?lang=(["'])s[ca]ss\1.*?>/gm, | ||
end: /^\s*<\/style>/gm, | ||
excludeBegin: !0, | ||
excludeEnd: !0, | ||
subLanguage: "scss" | ||
}, | ||
{ | ||
begin: /^\s*<style\s.*?lang=(["'])less\1.*?>/gm, | ||
end: /^\s*<\/style>/gm, | ||
excludeBegin: !0, | ||
excludeEnd: !0, | ||
subLanguage: "less" | ||
}, | ||
{ | ||
begin: /^\s*<style\s.*?lang=(["'])stylus\1.*?>/gm, | ||
end: /^\s*<\/style>/gm, | ||
excludeBegin: !0, | ||
excludeEnd: !0, | ||
subLanguage: "stylus" | ||
}, | ||
{ | ||
begin: /^\s*<style.*?>/gm, | ||
end: /^\s*<\/style>/gm, | ||
excludeBegin: !0, | ||
excludeEnd: !0, | ||
subLanguage: "css" | ||
} | ||
] | ||
}; | ||
} | ||
a.registerLanguage("c", x); | ||
a.registerLanguage("cpp", w); | ||
a.registerLanguage("xml", M); | ||
a.registerLanguage("cs", _); | ||
a.registerLanguage("css", j); | ||
a.registerLanguage("dockerfile", C); | ||
a.registerLanguage("go", S); | ||
a.registerLanguage("http", B); | ||
a.registerLanguage("ini", A); | ||
a.registerLanguage("java", z); | ||
a.registerLanguage("javascript", T); | ||
a.registerLanguage("json", E); | ||
a.registerLanguage("kotlin", P); | ||
a.registerLanguage("less", F); | ||
a.registerLanguage("lua", H); | ||
a.registerLanguage("protobuf", G); | ||
a.registerLanguage("python", N); | ||
a.registerLanguage("rust", R); | ||
a.registerLanguage("scss", q); | ||
a.registerLanguage("shell", D); | ||
a.registerLanguage("sql", O); | ||
a.registerLanguage("yaml", U); | ||
a.registerLanguage("typescript", W); | ||
a.registerLanguage("vue", Y); | ||
function Z(e, r, s) { | ||
if (!a.getLanguage(r)) | ||
return v.escapeHtml(e); | ||
if (s !== "diff") | ||
return a.highlight(e, { language: r }).value; | ||
let t = e.split(` | ||
`); | ||
const n = /* @__PURE__ */ new Map(); | ||
for (let o = 0; o < t.length; o++) { | ||
switch (t[o].charCodeAt(0)) { | ||
case 43: | ||
n.set(o, !0); | ||
break; | ||
case 45: | ||
n.set(o, !1); | ||
break; | ||
default: | ||
continue; | ||
} | ||
t[o] = t[o].slice(1); | ||
} | ||
e = t.join(` | ||
`), e = a.highlight(e, { language: r }).value, t = e.split(` | ||
`); | ||
const i = []; | ||
for (let o = 0; o < t.length; o++) { | ||
switch (n.has(o - 1) && i.push("</span>"), n.get(o)) { | ||
case !0: | ||
i.push("<span class='hljs-insert'>"); | ||
break; | ||
case !1: | ||
i.push("<span class='hljs-delete'>"); | ||
break; | ||
} | ||
i.push(t[o], ` | ||
`); | ||
} | ||
return i.pop(), i.join(""); | ||
} | ||
function k(e) { | ||
const r = new URLSearchParams(e.split("?")[1]), s = parseFloat(r.get("vw")), t = parseFloat(r.get("vh")); | ||
return s && t ? `style='--width:${s}px;--aspect:${s}/${t}'` : ""; | ||
} | ||
function I(e, r) { | ||
const s = e[r], t = s.attrGet("src") ?? "", n = this.utils.escapeHtml(s.content); | ||
return `<span class="center-wrapper"><a ${k(t)} href="${t}" target="_blank" rel="noopener,nofollow"><img data-src="${t}" alt="${n}" class="md-img" crossorigin></a>${n ? `<span class="md-alt">${n}</span>` : ""}</span>`; | ||
} | ||
const ee = { | ||
// 大部分浏览器只允许无声视频自动播放,不过 GIF 视频本来就是无声的。 | ||
gif(e, r, s) { | ||
return r = s.utils.escapeHtml(r), `<p class="center-wrapper" ${k(e)}><video class="gif" crossorigin loop muted data-src="${e}"></video>${r ? `<span class="md-alt">${r}</span>` : ""}</p>`; | ||
}, | ||
video(e, r, s) { | ||
return r = s.normalizeLink(r), s.validateLink(r) || (r = ""), `<p class="center-wrapper"><video class="md-video" controls crossorigin poster="${r}" data-src="${e}"></video></p>`; | ||
}, | ||
audio(e, r, s) { | ||
return r = s.utils.escapeHtml(r), `<p class="center-wrapper"><audio controls data-src="${e}" crossorigin></audio>${r ? `<span class="md-alt">${r}</span>` : ""}</p>`; | ||
} | ||
}; | ||
function re(e) { | ||
e.use(h, ee), e.renderer.rules.image = I.bind(e); | ||
} | ||
function g(e, r, s) { | ||
const { src: t, bMarks: n, tShift: i, eMarks: o } = e, l = n[r] + i[r], c = o[r]; | ||
return l + s.length === c && t.startsWith(s, l); | ||
} | ||
function te(e, r, s) { | ||
if (!g(e, r, "<details>")) | ||
return !1; | ||
let t = r + 1, n = 1; | ||
for (; t < s && n > 0; t++) | ||
g(e, t, "<details>") ? n += 1 : g(e, t, "</details>") && (n -= 1); | ||
if (n !== 0) | ||
return !1; | ||
const i = e.parentType, o = e.lineMax; | ||
e.parentType = "collapsible", e.lineMax = t - 1; | ||
let l = e.push("collapsible_open", "details", 1); | ||
return l.block = !0, l.markup = "<details>", l.map = [r, r + 1], e.md.block.tokenize(e, r + 1, t - 1), l = e.push("collapsible_close", "details", -1), l.block = !0, l.markup = "</details>", e.parentType = i, e.lineMax = o, e.line = t, !0; | ||
} | ||
function ne(e, r, s) { | ||
const { src: t, bMarks: n, eMarks: i } = e; | ||
if (!g(e, r, "<summary>") || e.tokens.at(-1)?.type !== "collapsible_open") | ||
return !1; | ||
let o = r += 1; | ||
for (; o < s && !g(e, o, "</summary>"); o++) | ||
; | ||
e.push("summary_open", "summary", 1); | ||
const l = e.push("inline", "", 0); | ||
return l.children = [], l.content = t.slice(n[r], i[o - 1]), e.push("summary_close", "summary", -1), e.line = o + 1, !0; | ||
} | ||
function se(e) { | ||
e.block.ruler.before("fence", "collapsible", te), e.block.ruler.before("fence", "summary", ne); | ||
} | ||
function oe(e) { | ||
const { renderer: r } = e, s = r.renderToken; | ||
r.renderToken = function(t, n, i) { | ||
const o = t[n]; | ||
return o.type === "link_open" && o.attrPush(["rel", "ugc,nofollow"]), s.call(this, t, n, i); | ||
}; | ||
} | ||
function ie(e) { | ||
e.use(m, { | ||
permalink: m.permalink.linkInsideHeader({ | ||
placement: "after", | ||
class: "anchor-link" | ||
}), | ||
slugify: (r) => r.trim().toLowerCase().replace(/\s+/g, "-") | ||
}); | ||
} | ||
function ae(e) { | ||
e.use(L); | ||
const { rules: r } = e.renderer; | ||
r.footnote_block_open = () => "<h2 class='footnotes'></h2><ol class='footnotes-list'>", r.footnote_block_close = () => "</ol>"; | ||
} | ||
function le(e) { | ||
const { rules: r } = e.renderer, s = r.code_inline; | ||
r.code_inline = (t, n, i, o, l) => (t[n].attrPush(["class", "inline-code"]), s(t, n, i, o, l)); | ||
} | ||
function Ne(e, r = {}) { | ||
return r.plain ? e.use(h) : (r.guest || e.use(ie), e.options.highlight ??= Z, e.use($), e.use(re), e.use(le)), r.guest ? e.use(oe) : e.use(y), e.use(ae).use(se); | ||
} | ||
function Re(e, r) { | ||
function s(t) { | ||
for (const n of t) | ||
switch (n.type) { | ||
case "inline": | ||
t(r.children); | ||
s(n.children); | ||
break; | ||
case "link_open": | ||
case "directive": | ||
n(r.attrGet("href")); | ||
r(n.attrGet("href")); | ||
break; | ||
case "image": | ||
n(r.attrGet("src")); | ||
r(n.attrGet("src")); | ||
break; | ||
} | ||
} | ||
e.core.ruler.push("collect-links", (o) => t(o.tokens)); | ||
e.core.ruler.push("collect-links", (t) => s(t.tokens)); | ||
} | ||
export { | ||
C as Anchor, | ||
g as Classify, | ||
b as Collapsible, | ||
s as Collect, | ||
p as Directive, | ||
u as Emphasis, | ||
I as Fence, | ||
v as Footnote, | ||
x as MarkdownIt, | ||
A as Media, | ||
B as TOC, | ||
w as UGC, | ||
M as checkLink, | ||
D as defaultDirectiveMap, | ||
k as getEmphasis, | ||
F as highlight | ||
X as Emphasis, | ||
We as MarkdownIt, | ||
ie as anchor, | ||
K as checkLink, | ||
le as classify, | ||
se as collapsible, | ||
Re as collect, | ||
Q as defaultDirectiveMap, | ||
h as directive, | ||
$ as fence, | ||
ae as footnote, | ||
Ge as getEmphasis, | ||
Z as highlight, | ||
Ne as kfmPreset, | ||
re as media, | ||
Oe as toc, | ||
oe as ugc | ||
}; |
@@ -7,7 +7,7 @@ import MarkdownIt from "markdown-it"; | ||
*/ | ||
export declare function UGC(markdownIt: MarkdownIt): void; | ||
export declare function ugc(markdownIt: MarkdownIt): void; | ||
/** | ||
* 给标题加上锚点,是对 markdown-it-anchor 的简单封装。 | ||
*/ | ||
export declare function Anchor(markdownIt: MarkdownIt): void; | ||
export declare function anchor(markdownIt: MarkdownIt): void; | ||
/** | ||
@@ -26,6 +26,24 @@ * 在文章的末尾添加一段显示所有脚注。因为可能用于评论,所以修改渲染函数去掉横线, | ||
*/ | ||
export declare function Footnote(markdownIt: MarkdownIt): void; | ||
export declare function footnote(markdownIt: MarkdownIt): void; | ||
/** | ||
* 给行内代码加个 inline-code 类以便跟代码块区分。 | ||
*/ | ||
export declare function Classify(markdownIt: MarkdownIt): void; | ||
export declare function classify(markdownIt: MarkdownIt): void; | ||
export interface PresetOptions { | ||
/** | ||
* 如果为 true 则仅添加语法类插件,渲染的结果只有必要的标签, | ||
* 用于给第三方阅读器使用(RSS,阅读模式……)。 | ||
* | ||
* 反之则渲染出更丰富且有交互能力的 HTML,需要搭配样式表和激活。 | ||
*/ | ||
plain?: boolean; | ||
/** | ||
* 如果为 true 则移除一些用于长文的插件,并加入 UGC 防刷外链, | ||
* 适用于用户评论等第三方输入。 | ||
*/ | ||
guest?: boolean; | ||
} | ||
/** | ||
* 一次性添加其他所有 KFM 插件的插件,用于一些常见情况。 | ||
*/ | ||
export declare function kfmPreset(markdownIt: MarkdownIt, options?: PresetOptions): MarkdownIt; |
import type MarkdownIt from "markdown-it"; | ||
/** | ||
* 高亮代码的函数,返回带有高亮标签的 HTML,language 为空或不支持则返回 falsy 值。 | ||
*/ | ||
type HighLighter = (code: string, language: string, diff: boolean) => string | undefined; | ||
/** | ||
* 自定义代码块的插件,因为 MarkdownIt 自带的渲染函数要求最外层是 pre,限制了扩展性, | ||
* 所以本项目整个替换它而不是使用 highlight 选项。 | ||
* 自定义代码块的插件,因为 MarkdownIt 默认最外层是 pre,限制了扩展性,所以本项目替换了它。 | ||
* https://github.com/markdown-it/markdown-it/blob/13.0.2/lib/renderer.js#L58 | ||
@@ -21,3 +16,3 @@ * | ||
*/ | ||
export default function fencePlugin(md: MarkdownIt, highlight: HighLighter): void; | ||
export default function (md: MarkdownIt): void; | ||
/** | ||
@@ -29,2 +24,1 @@ * 实现点击按钮复制代码。考虑到代码一行可能很长,以及手机端框选困难,这个功能还是要有的。 | ||
export declare function activateCopyButtons(root: HTMLElement): void; | ||
export {}; |
@@ -1,1 +0,1 @@ | ||
export default function (code: string, language: string, diff: boolean): string | undefined; | ||
export default function (code: string, language: string, attrs?: string): string; |
import { HLJSApi, Language } from "highlight.js"; | ||
/** | ||
* highlight.js 的 Vue SFC 插件,支持解析顶层的语言块(language blocks)。 | ||
* | ||
* 块支持那些语言由构建工具决定,这里只包含了常用的几种。 | ||
* https://vuejs.org/api/sfc-spec.html#pre-processors | ||
* | ||
* highlight.js 的类型里有个 vuePlugin 属性,但却是 undefined。 | ||
*/ | ||
export default function hljsDefineVue(hljs: HLJSApi): Language; |
@@ -5,3 +5,5 @@ import type MarkdownIt from "markdown-it"; | ||
* 在这里,媒体将被渲染成具有更复杂的布局的元素,同时还启用了延迟加载。 | ||
* | ||
* 添加该插件会同时添加 Directive 插件。 | ||
*/ | ||
export default function (markdownIt: MarkdownIt): void; |
{ | ||
"name": "@kaciras-blog/markdown", | ||
"version": "3.1.0", | ||
"version": "3.2.0", | ||
"license": "MIT", | ||
@@ -14,3 +14,2 @@ "description": "Kaciras Flavored Markdown", | ||
"./activate": "./lib/activate.js", | ||
"./presets": "./lib/presets.js", | ||
"./style.css": "./lib/style.css" | ||
@@ -23,3 +22,3 @@ }, | ||
"dependencies": { | ||
"@kaciras/utilities": "^0.10.1", | ||
"@kaciras/utilities": "^0.10.2", | ||
"bootstrap-icons": "^1.11.1", | ||
@@ -33,4 +32,4 @@ "highlight.js": "^11.9.0", | ||
"devDependencies": { | ||
"@types/html-minifier-terser": "^7.0.0", | ||
"@types/markdown-it": "^13.0.2", | ||
"@types/html-minifier-terser": "^7.0.1", | ||
"@types/markdown-it": "^13.0.5", | ||
"@vitest/coverage-v8": "^0.34.6", | ||
@@ -41,3 +40,3 @@ "html-minifier-terser": "^7.2.0", | ||
"postcss-simple-vars": "^7.0.1", | ||
"vite": "^4.4.11", | ||
"vite": "^4.5.0", | ||
"vitest": "^0.34.6" | ||
@@ -44,0 +43,0 @@ }, |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
28302
18
616
1
Updated@kaciras/utilities@^0.10.2