From 5f84338225da7a8946b78e238717ca9055255ece Mon Sep 17 00:00:00 2001 From: Felix Schneider <99918022+trueberryless@users.noreply.github.com> Date: Mon, 1 Jun 2026 15:59:42 +0200 Subject: [PATCH 1/9] fix(i18n): localize size increase/decrease percentage (#2828) Co-authored-by: CodeRabbit <132028505+coderabbitai@users.noreply.github.com> Co-authored-by: Willow (GHOST) <47755378+ghostdevv@users.noreply.github.com> --- app/components/Package/SizeDecrease.vue | 5 +++-- app/components/Package/SizeIncrease.vue | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/components/Package/SizeDecrease.vue b/app/components/Package/SizeDecrease.vue index 7872286046..fa730b6cd5 100644 --- a/app/components/Package/SizeDecrease.vue +++ b/app/components/Package/SizeDecrease.vue @@ -7,8 +7,9 @@ const props = defineProps<{ const bytesFormatter = useBytesFormatter() const numberFormatter = useNumberFormatter() +const percentFormatter = useNumberFormatter({ style: 'percent' }) -const sizePercent = computed(() => Math.round(Math.abs(props.diff.sizeRatio) * 100)) +const sizePercent = computed(() => percentFormatter.value.format(Math.abs(props.diff.sizeRatio))) const sizeDecreaseAbs = computed(() => Math.abs(props.diff.sizeIncrease)) const depDecreaseAbs = computed(() => Math.abs(props.diff.depDiff)) @@ -33,7 +34,7 @@ const depDecreaseAbs = computed(() => Math.abs(props.diff.depDiff))

{{ sizePercent }} Math.round(props.diff.sizeRatio * 100)) +const sizePercent = computed(() => percentFormatter.value.format(Math.abs(props.diff.sizeRatio))) Date: Mon, 1 Jun 2026 15:01:24 +0100 Subject: [PATCH 2/9] chore: minor ui improvements (#2834) --- app/components/AppHeader.vue | 2 +- app/components/Noodle/Pride1/Logo.vue | 2 +- app/pages/package-timeline/[[org]]/[packageName].vue | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/components/AppHeader.vue b/app/components/AppHeader.vue index e90464ca5b..32fc2fb91d 100644 --- a/app/components/AppHeader.vue +++ b/app/components/AppHeader.vue @@ -258,7 +258,7 @@ useShortcuts({

+
Date: Tue, 2 Jun 2026 10:14:07 +0200 Subject: [PATCH 3/9] fix: update colors when prefers-color-scheme changes (#2839) --- app/composables/useColors.ts | 21 ++++- test/unit/app/composables/use-colors.spec.ts | 83 +++++++++++++++++++- 2 files changed, 101 insertions(+), 3 deletions(-) diff --git a/app/composables/useColors.ts b/app/composables/useColors.ts index 7a5248627f..87bbb64c5d 100644 --- a/app/composables/useColors.ts +++ b/app/composables/useColors.ts @@ -1,5 +1,18 @@ -import { computed, shallowRef, type ComputedRef, type Ref, type ShallowRef, unref } from 'vue' -import { useMutationObserver, useResizeObserver, useSupported } from '@vueuse/core' +import { + computed, + shallowRef, + type ComputedRef, + type Ref, + type ShallowRef, + unref, + watch, +} from 'vue' +import { + useMutationObserver, + useResizeObserver, + useSupported, + usePreferredDark, +} from '@vueuse/core' type CssVariableSource = HTMLElement | null | undefined | Ref @@ -36,6 +49,8 @@ export function useColors( options: { watchHtmlAttributes?: boolean; watchResize?: boolean } = {}, ): { colors: ComputedRef> } { const recomputeToken = shallowRef(0) + const isPreferredDark = usePreferredDark() + const invalidateColors = () => { recomputeToken.value += 1 } @@ -44,6 +59,8 @@ export function useColors( () => typeof window !== 'undefined' && typeof document !== 'undefined', ) + watch(isPreferredDark, invalidateColors) + const colors = computed>(() => { void recomputeToken.value const resolvedElement = resolveElement(element) diff --git a/test/unit/app/composables/use-colors.spec.ts b/test/unit/app/composables/use-colors.spec.ts index 6d8369a6c1..4ad3594446 100644 --- a/test/unit/app/composables/use-colors.spec.ts +++ b/test/unit/app/composables/use-colors.spec.ts @@ -1,12 +1,18 @@ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest' -import { computed, shallowRef } from 'vue' +import { computed, nextTick, shallowRef, ref, type Ref } from 'vue' import { useColors } from '~/composables/useColors' const useSupportedMock = vi.hoisted(() => vi.fn()) const useMutationObserverMock = vi.hoisted(() => vi.fn()) const useResizeObserverMock = vi.hoisted(() => vi.fn()) +const vueUseMockState = vi.hoisted(() => ({ + preferredDark: undefined as unknown as Ref, +})) + vi.mock('@vueuse/core', () => { + vueUseMockState.preferredDark = ref(false) + return { useSupported: (callback: () => boolean) => { useSupportedMock(callback) @@ -14,12 +20,14 @@ vi.mock('@vueuse/core', () => { }, useMutationObserver: useMutationObserverMock, useResizeObserver: useResizeObserverMock, + usePreferredDark: () => vueUseMockState.preferredDark, } }) describe('useColors', () => { beforeEach(() => { vi.clearAllMocks() + vueUseMockState.preferredDark.value = false }) afterEach(() => { @@ -57,4 +65,77 @@ describe('useColors', () => { const { colors } = useColors(elementReference) expect(colors.value).toEqual({}) }) + + it('recomputes colors when preferred dark mode changes', async () => { + const styleValues = { + accent: '#FF0000', + } + + vi.stubGlobal('window', {}) + vi.stubGlobal('document', { + documentElement: {}, + }) + + vi.stubGlobal('getComputedStyle', () => ({ + getPropertyValue: (variableName: string) => { + if (variableName === '--accent') { + return styleValues.accent + } + + return '' + }, + })) + + const elementReference = shallowRef({} as HTMLElement) + const { colors } = useColors(elementReference) + expect(colors.value.accent).toBe('#FF0000') + styleValues.accent = '#00FF00' + vueUseMockState.preferredDark.value = true + await nextTick() + + expect(colors.value.accent).toBe('#00FF00') + }) + + it('attaches an html mutation observer when enabled', () => { + vi.stubGlobal('window', {}) + vi.stubGlobal('document', { + documentElement: {}, + }) + const elementReference = shallowRef(null) + useColors(elementReference, { + watchHtmlAttributes: true, + }) + expect(useMutationObserverMock).toHaveBeenCalledTimes(1) + expect(useMutationObserverMock).toHaveBeenCalledWith( + document.documentElement, + expect.any(Function), + { + attributes: true, + attributeFilter: ['class', 'style', 'data-theme', 'data-bg-theme'], + }, + ) + }) + + it('falls back to document element when no element is provided', () => { + vi.stubGlobal('window', {}) + vi.stubGlobal('document', { + documentElement: {}, + }) + vi.stubGlobal('getComputedStyle', (element: HTMLElement) => { + expect(element).toBe(document.documentElement) + + return { + getPropertyValue: (variableName: string) => { + if (variableName === '--accent') { + return 'red' + } + + return '' + }, + } + }) + const elementReference = shallowRef(null) + const { colors } = useColors(elementReference) + expect(colors.value.accent).toBe('red') + }) }) From 4aed48bbedf27958a0c383cf9229e9c08934ddc7 Mon Sep 17 00:00:00 2001 From: Roman Date: Tue, 2 Jun 2026 16:21:39 +0100 Subject: [PATCH 4/9] chore(deps): update module-replacements (#2838) --- package.json | 2 +- pnpm-lock.yaml | 23 ++++++++++++++--------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 8216391118..21e41ec52c 100644 --- a/package.json +++ b/package.json @@ -90,7 +90,7 @@ "gray-matter": "4.0.3", "ipaddr.js": "2.3.0", "marked": "18.0.0", - "module-replacements": "3.0.0-beta.7", + "module-replacements": "3.0.0-beta.8", "nuxt": "4.4.5", "nuxt-og-image": "^6.4.3", "ofetch": "1.5.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3e926aaa14..1d666694a6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -190,8 +190,8 @@ importers: specifier: 18.0.0 version: 18.0.0 module-replacements: - specifier: 3.0.0-beta.7 - version: 3.0.0-beta.7 + specifier: 3.0.0-beta.8 + version: 3.0.0-beta.8 nuxt: specifier: 4.4.5 version: 4.4.5(@babel/core@7.29.0)(@babel/plugin-syntax-jsx@7.28.6)(@parcel/watcher@2.5.6)(@types/node@24.12.0)(@upstash/redis@1.37.0)(@vue/compiler-sfc@3.5.34)(better-sqlite3@12.8.0)(cac@6.7.14)(db0@0.3.4)(esbuild@0.27.3)(eslint@9.39.2)(ioredis@5.10.1)(magicast@0.5.2)(optionator@0.9.4)(oxlint@1.61.0)(rolldown@1.0.0-rc.16)(rollup-plugin-visualizer@7.0.1)(rollup@4.60.3)(terser@5.46.0)(typescript@6.0.2)(vite@8.0.0)(vue-tsc@3.2.6)(yaml@2.9.0) @@ -415,7 +415,7 @@ importers: version: 12.8.0 docus: specifier: 5.9.0 - version: 5.9.0(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@nuxt/schema@4.4.5)(@takumi-rs/wasm@1.0.9)(@tiptap/extensions@3.24.0)(@tiptap/y-tiptap@3.0.2)(@unhead/vue@2.1.13)(@upstash/redis@1.37.0)(@vue/compiler-dom@3.5.34)(better-sqlite3@12.8.0)(db0@0.3.4)(embla-carousel@8.6.0)(eslint@9.39.2)(focus-trap@8.0.0)(fontless@0.2.1)(h3@2.0.1-rc.20)(ioredis@5.10.1)(magicast@0.5.2)(nuxt@4.4.5)(playwright-core@1.60.0)(react-dom@19.2.4)(react@19.2.4)(rollup@4.60.3)(sharp@0.34.5)(typescript@6.0.2)(unifont@0.7.4)(unstorage@1.17.5)(valibot@1.3.1)(vite@8.0.0)(vue-router@5.0.4)(vue@3.5.34)(yjs@13.6.29) + version: 5.9.0(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@nuxt/schema@4.4.5)(@takumi-rs/wasm@1.0.9)(@tiptap/extensions@3.24.0)(@tiptap/y-tiptap@3.0.2)(@unhead/vue@2.1.13)(@upstash/redis@1.37.0)(@vue/compiler-dom@3.5.34)(better-sqlite3@12.8.0)(db0@0.3.4)(embla-carousel@8.6.0)(eslint@9.39.2)(focus-trap@8.0.0)(fontless@0.2.1)(h3@1.15.11)(ioredis@5.10.1)(magicast@0.5.2)(nuxt@4.4.5)(playwright-core@1.60.0)(react-dom@19.2.4)(react@19.2.4)(rollup@4.60.3)(sharp@0.34.5)(typescript@6.0.2)(unifont@0.7.4)(unstorage@1.17.5)(valibot@1.3.1)(vite@8.0.0)(vue-router@5.0.4)(vue@3.5.34)(yjs@13.6.29) nuxt: specifier: 4.4.5 version: 4.4.5(@babel/core@7.29.0)(@babel/plugin-syntax-jsx@7.28.6)(@parcel/watcher@2.5.6)(@types/node@24.12.0)(@upstash/redis@1.37.0)(@vue/compiler-sfc@3.5.34)(better-sqlite3@12.8.0)(cac@6.7.14)(db0@0.3.4)(esbuild@0.27.3)(eslint@9.39.2)(ioredis@5.10.1)(magicast@0.5.2)(optionator@0.9.4)(oxlint@1.61.0)(rolldown@1.0.0-rc.16)(rollup-plugin-visualizer@7.0.1)(rollup@4.60.3)(terser@5.46.0)(typescript@6.0.2)(vite@8.0.0)(vue-tsc@3.2.6)(yaml@2.9.0) @@ -2269,7 +2269,7 @@ packages: resolution: {integrity: sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==} '@lunariajs/core@https://pkg.pr.new/lunariajs/lunaria/@lunariajs/core@904b935': - resolution: {tarball: https://pkg.pr.new/lunariajs/lunaria/@lunariajs/core@904b935} + resolution: {integrity: sha512-N0PDFIitA/Vzh5V6BtTacWU9jgSDJJtPLHamRLMU85mohmyuVW/pggHX8dzdV5ieqZeHEz8pDZSzH4I0hOYxOg==, tarball: https://pkg.pr.new/lunariajs/lunaria/@lunariajs/core@904b935} version: 0.1.1 engines: {node: '>=18.17.0'} @@ -4941,7 +4941,7 @@ packages: resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} '@storybook-vue/nuxt@https://pkg.pr.new/@storybook-vue/nuxt@1021': - resolution: {tarball: https://pkg.pr.new/@storybook-vue/nuxt@1021} + resolution: {integrity: sha512-OmpGHtbapfpljOkFY8/g+9EkNa+SPcVAcqOiOPyP6upXMSpwNHHfEXFMBiFWqF7xru82zHg2kkfmWArVpVG7tg==, tarball: https://pkg.pr.new/@storybook-vue/nuxt@1021} version: 9.0.1 engines: {node: '>=20.19.0'} peerDependencies: @@ -8845,6 +8845,9 @@ packages: module-replacements@3.0.0-beta.7: resolution: {integrity: sha512-n1F9l3gF1wNh13xmnXS2JU7P9c3DlzCgVEyLKrVN0U37RwrXyYoePMMvYvs/6aUONAxbnscphzESZTCorXFh7Q==} + module-replacements@3.0.0-beta.8: + resolution: {integrity: sha512-sc8TepP9elxoOBXEpxmhPzKKjTjbswHVcmsKGbgvm3k6jZlLu/WMV/Lfmga6IGMgHU/V3WtY2s6VEgM4nTElUQ==} + motion-dom@12.40.0: resolution: {integrity: sha512-HxU3ZaBwNPVQUBQf1xxgq+7JrPNZvjLVxgbpEZL7RrWJnsxOf0/OM+yrHG9ogLQ31Do/r57Oz2gQWPK+6q62mg==} @@ -14511,11 +14514,11 @@ snapshots: - uploadthing - vue - '@nuxtjs/mcp-toolkit@0.13.4(h3@2.0.1-rc.20)(magicast@0.5.2)(zod@4.3.6)': + '@nuxtjs/mcp-toolkit@0.13.4(h3@1.15.11)(magicast@0.5.2)(zod@4.3.6)': dependencies: '@modelcontextprotocol/sdk': 1.29.0(zod@4.3.6) '@nuxt/kit': 4.4.6(magicast@0.5.2) - h3: 2.0.1-rc.20 + h3: 1.15.11 tinyglobby: 0.2.16 zod: 4.3.6 transitivePeerDependencies: @@ -18198,7 +18201,7 @@ snapshots: doctypes@1.1.0: {} - docus@5.9.0(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@nuxt/schema@4.4.5)(@takumi-rs/wasm@1.0.9)(@tiptap/extensions@3.24.0)(@tiptap/y-tiptap@3.0.2)(@unhead/vue@2.1.13)(@upstash/redis@1.37.0)(@vue/compiler-dom@3.5.34)(better-sqlite3@12.8.0)(db0@0.3.4)(embla-carousel@8.6.0)(eslint@9.39.2)(focus-trap@8.0.0)(fontless@0.2.1)(h3@2.0.1-rc.20)(ioredis@5.10.1)(magicast@0.5.2)(nuxt@4.4.5)(playwright-core@1.60.0)(react-dom@19.2.4)(react@19.2.4)(rollup@4.60.3)(sharp@0.34.5)(typescript@6.0.2)(unifont@0.7.4)(unstorage@1.17.5)(valibot@1.3.1)(vite@8.0.0)(vue-router@5.0.4)(vue@3.5.34)(yjs@13.6.29): + docus@5.9.0(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@nuxt/schema@4.4.5)(@takumi-rs/wasm@1.0.9)(@tiptap/extensions@3.24.0)(@tiptap/y-tiptap@3.0.2)(@unhead/vue@2.1.13)(@upstash/redis@1.37.0)(@vue/compiler-dom@3.5.34)(better-sqlite3@12.8.0)(db0@0.3.4)(embla-carousel@8.6.0)(eslint@9.39.2)(focus-trap@8.0.0)(fontless@0.2.1)(h3@1.15.11)(ioredis@5.10.1)(magicast@0.5.2)(nuxt@4.4.5)(playwright-core@1.60.0)(react-dom@19.2.4)(react@19.2.4)(rollup@4.60.3)(sharp@0.34.5)(typescript@6.0.2)(unifont@0.7.4)(unstorage@1.17.5)(valibot@1.3.1)(vite@8.0.0)(vue-router@5.0.4)(vue@3.5.34)(yjs@13.6.29): dependencies: '@ai-sdk/gateway': 3.0.101(zod@4.3.6) '@ai-sdk/mcp': 1.0.36(zod@4.3.6) @@ -18211,7 +18214,7 @@ snapshots: '@nuxt/kit': 4.4.6(magicast@0.5.2) '@nuxt/ui': 4.6.1(@nuxt/content@3.12.0)(@tiptap/extensions@3.24.0)(@tiptap/y-tiptap@3.0.2)(@upstash/redis@1.37.0)(db0@0.3.4)(embla-carousel@8.6.0)(focus-trap@8.0.0)(ioredis@5.10.1)(magicast@0.5.2)(react-dom@19.2.4)(react@19.2.4)(tailwindcss@4.2.2)(typescript@6.0.2)(valibot@1.3.1)(vite@8.0.0)(vue-router@5.0.4)(vue@3.5.34)(yjs@13.6.29)(zod@4.3.6) '@nuxtjs/i18n': 10.2.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@upstash/redis@1.37.0)(@vue/compiler-dom@3.5.34)(db0@0.3.4)(eslint@9.39.2)(ioredis@5.10.1)(magicast@0.5.2)(rollup@4.60.3)(typescript@6.0.2)(vue@3.5.34) - '@nuxtjs/mcp-toolkit': 0.13.4(h3@2.0.1-rc.20)(magicast@0.5.2)(zod@4.3.6) + '@nuxtjs/mcp-toolkit': 0.13.4(h3@1.15.11)(magicast@0.5.2)(zod@4.3.6) '@nuxtjs/mdc': 0.21.1(magicast@0.5.2) '@nuxtjs/robots': 6.0.9(@nuxt/schema@4.4.5)(magicast@0.5.2)(nuxt@4.4.5)(vite@8.0.0)(vue@3.5.34)(zod@4.3.6) '@shikijs/core': 4.1.0 @@ -20531,6 +20534,8 @@ snapshots: module-replacements@3.0.0-beta.7: {} + module-replacements@3.0.0-beta.8: {} + motion-dom@12.40.0: dependencies: motion-utils: 12.39.0 From ebdbf0cbcb4b51ce1ce46ba407e996fb88e6c967 Mon Sep 17 00:00:00 2001 From: Alex Savelyev <91429106+alexdln@users.noreply.github.com> Date: Wed, 3 Jun 2026 17:19:33 +0100 Subject: [PATCH 5/9] feat: versions page improvements (#2844) --- app/pages/package/[[org]]/[name]/versions.vue | 160 ++++++++++-------- 1 file changed, 89 insertions(+), 71 deletions(-) diff --git a/app/pages/package/[[org]]/[name]/versions.vue b/app/pages/package/[[org]]/[name]/versions.vue index 37d01135f8..afd1d7e7cd 100644 --- a/app/pages/package/[[org]]/[name]/versions.vue +++ b/app/pages/package/[[org]]/[name]/versions.vue @@ -269,7 +269,7 @@ const flatItems = computed(() => {
-
+
(() => { /

{{ $t('package.versions.page_title') }}

-
- - - - - - -
@@ -324,32 +290,36 @@ const flatItems = computed(() => {
-

+

{{ $t('package.versions.current_tags') }}

- latest + latest {{ tag }} deprecated + + deprecated +
(() => {
-
+
(() => {
-
+
{{ tag }}
-
+
@@ -443,16 +413,20 @@ const flatItems = computed(() => { /> deprecated + + deprecated +
(() => { {{ numberFormatter.format(getVersionDownloads(row.version)!) }} - +
@@ -479,12 +453,47 @@ const flatItems = computed(() => {
-

- {{ $t('package.versions.page_title') }} - - ({{ versionStrings.length }}) - -

+
+

+ {{ $t('package.versions.page_title') }} + ({{ versionStrings.length }}) +

+ +
+ + + + + + +
+
(() => { {{ item.label }} deprecated + + deprecated + ({{ item.versions.length }}) - v{{ item.versions[0] }} (() => { }} - + (() => { @@ -627,17 +641,21 @@ const flatItems = computed(() => {
- deprecated + + deprecated
(() => { }}
- +
@@ -690,7 +708,7 @@ const flatItems = computed(() => { > (() => { {{ numberFormatter.format(groupDownloadsMap.get(item.groupKey)!) }} - + Date: Thu, 4 Jun 2026 03:40:53 +0800 Subject: [PATCH 6/9] fix: parse hyphenated language names for code examples on package docs (#2734) Co-authored-by: Willow (GHOST) --- server/utils/docs/render.ts | 4 ++-- test/unit/server/utils/docs/render.spec.ts | 26 +++++++++++++++++++++- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/server/utils/docs/render.ts b/server/utils/docs/render.ts index eb3393b173..a70f856551 100644 --- a/server/utils/docs/render.ts +++ b/server/utils/docs/render.ts @@ -191,9 +191,9 @@ async function renderJsDocTags(tags: JsDocTag[], symbolLookup: SymbolLookup): Pr : null const examplePromises = examples.map(async example => { if (!example.doc) return '' - const langMatch = example.doc.match(/```(\w+)?/) + const langMatch = example.doc.match(/```[ \t]*([-\w]+)?/) const lang = langMatch?.[1] || 'typescript' - const code = example.doc.replace(/```\w*\n?/g, '').trim() + const code = example.doc.replace(/```[ \t]*[-\w]*[ \t]*(?:\r\n|\r|\n)?/g, '').trim() return highlightCodeBlock(code, lang) }) diff --git a/test/unit/server/utils/docs/render.spec.ts b/test/unit/server/utils/docs/render.spec.ts index 1d7d5286ef..2d595425a7 100644 --- a/test/unit/server/utils/docs/render.spec.ts +++ b/test/unit/server/utils/docs/render.spec.ts @@ -21,10 +21,11 @@ function createClassSymbol(classDef: DenoDocNode['classDef']): MergedSymbol { } } -function createFunctionSymbol(name: string): MergedSymbol { +function createFunctionSymbol(name: string, jsDoc?: DenoDocNode['jsDoc']): MergedSymbol { const node: DenoDocNode = { name, kind: 'function', + jsDoc, functionDef: { params: [], returnType: { repr: 'void', kind: 'keyword', keyword: 'void' }, @@ -34,6 +35,7 @@ function createFunctionSymbol(name: string): MergedSymbol { return { name, kind: 'function', + jsDoc, nodes: [node], } } @@ -192,3 +194,25 @@ describe('renderDocNodes ordering', () => { expect(alphaIndex).toBeLessThan(betaIndex) }) }) + +describe('renderDocNodes examples', () => { + it('handles hyphenated fenced code languages in @example tags', async () => { + const symbol = createFunctionSymbol('renderTemplate', { + tags: [ + { + kind: 'example', + doc: '```glimmer-ts\nconst greeting = \n```', + }, + ], + }) + + const html = await renderDocNodes([symbol], new Map()) + + expect(html).toContain('

Example

') + expect(html).toContain('shiki') + expect(html).toContain('greeting') + expect(html).not.toMatch(/(^|[>\s])-ts([<\s]|$)/) + expect(html).not.toContain('-ts') + expect(html).not.toContain('```') + }) +}) From 030a0ce3d0b40ea8083d9b106f36620985060925 Mon Sep 17 00:00:00 2001 From: Felix Schneider <99918022+trueberryless@users.noreply.github.com> Date: Thu, 4 Jun 2026 08:14:09 +0200 Subject: [PATCH 7/9] fix: stale workflow (#2846) --- .github/workflows/stale.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 8367d2614f..2237b2e664 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -28,7 +28,7 @@ jobs: remove-stale-when-updated: true only-issue-types: 'bug' stale-issue-label: 'stale' - close-issue-label: 'stale' + close-issue-label: 'stale-to-close' operations-per-run: 500 stale-prs: @@ -45,5 +45,5 @@ jobs: days-before-pr-close: 7 remove-stale-when-updated: true stale-pr-label: 'stale' - close-pr-label: 'stale' + close-pr-label: 'stale-to-close' operations-per-run: 500 From 01c510088489b3988586342af3c6df0ad48d7cdb Mon Sep 17 00:00:00 2001 From: Alex Savelyev <91429106+alexdln@users.noreply.github.com> Date: Thu, 4 Jun 2026 12:18:50 +0100 Subject: [PATCH 8/9] feat: support description elements in readmes (#2849) --- app/components/Readme.vue | 8 ++++++++ server/utils/readme.ts | 3 +++ 2 files changed, 11 insertions(+) diff --git a/app/components/Readme.vue b/app/components/Readme.vue index c4e903cce0..91b5248579 100644 --- a/app/components/Readme.vue +++ b/app/components/Readme.vue @@ -283,6 +283,14 @@ function handleClick(event: MouseEvent) { font-style: italic; } +.readme :deep(dt) { + margin-block-start: 0.5rem; +} + +.readme :deep(dd) { + padding-inline-start: 1.5rem; +} + /* GitHub-style callouts/alerts */ .readme :deep(blockquote[data-callout]) { border-inline-start-width: 3px; diff --git a/server/utils/readme.ts b/server/utils/readme.ts index f49e83465a..6e220f7827 100644 --- a/server/utils/readme.ts +++ b/server/utils/readme.ts @@ -180,6 +180,9 @@ export const ALLOWED_TAGS = [ 'kbd', 'mark', 'button', + 'dl', + 'dt', + 'dd', ] export const ALLOWED_ATTR: Record = { From 94edd111dbbc315591da3cc91953266395bc78b0 Mon Sep 17 00:00:00 2001 From: Felix Schneider <99918022+trueberryless@users.noreply.github.com> Date: Thu, 4 Jun 2026 23:40:25 +0200 Subject: [PATCH 9/9] feat(i18n): update German translation (#2847) --- i18n/locales/de.json | 152 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 127 insertions(+), 25 deletions(-) diff --git a/i18n/locales/de.json b/i18n/locales/de.json index e315922ac8..40d3b9499a 100644 --- a/i18n/locales/de.json +++ b/i18n/locales/de.json @@ -20,7 +20,10 @@ "chat": "chat", "builders_chat": "builders chat", "keyboard_shortcuts": "tastaturkürzel", - "brand": "marke" + "brand": "marke", + "resources": "Ressourcen", + "features": "Funktionen", + "other": "Sonstiges" }, "shortcuts": { "section": { @@ -28,7 +31,7 @@ "search": "Suche", "package": "Paket" }, - "ctrl_key": "Ctrl", + "ctrl_key": "Strg", "command_palette": "Befehlspalette öffnen", "command_palette_description": "Benutze die Befehlspalette, um zwischen Seiten, Paketansichten, Einstellungen und externen Links zu wechseln, ohne die Tastatur zu verlassen. Drücke ⌘K unter macOS. Drücke {ctrlKey}+K unter Windows und Linux.", "focus_search": "Suche fokussieren", @@ -42,7 +45,8 @@ "open_docs": "Dokumentation öffnen", "disable_shortcuts": "Tastaturkürzel deaktivieren", "open_main": "Hauptansicht öffnen", - "open_diff": "Diff-Ansicht öffnen" + "open_diff": "Diff-Ansicht öffnen", + "open_timeline": "Zeitleiste öffnen" }, "search": { "label": "npm-Pakete durchsuchen", @@ -50,7 +54,7 @@ "button": "Suchen", "searching": "Suche läuft...", "found_packages": "Keine Pakete gefunden | 1 Paket gefunden | {count} Pakete gefunden", - "found_packages_sorted": "Keine Ergebnisse gefunden | Sortiere bestes Resultat | Sortiere beste {count} Resultate", + "found_packages_sorted": "Keine Ergebnisse gefunden | Nach bestem Resultat sortiert | Die besten {count} Resultate werden sortiert", "updating": "(wird aktualisiert...)", "no_results": "Keine Pakete gefunden für „{query}“", "rate_limited": "npm-Ratenbegrenzung erreicht, bitte versuche es gleich noch einmal", @@ -149,7 +153,8 @@ "code": "Code", "diff": "Diff", "compare": "Dieses Paket vergleichen", - "download": "Tarball herunterladen" + "download": "Tarball herunterladen", + "changelog": "Änderungsprotokoll" }, "package_actions": { "copy_run": "Befehl zum Ausführen kopieren" @@ -280,7 +285,10 @@ "black": "Schwarz" }, "keyboard_shortcuts_enabled": "Tastenkombinationen aktivieren", - "keyboard_shortcuts_enabled_description": "Tastenkombinationen können deaktiviert werden, wenn sie mit anderen Browser- oder Systemkürzeln in Konflikt stehen" + "keyboard_shortcuts_enabled_description": "Tastenkombinationen können deaktiviert werden, wenn sie mit anderen Browser- oder Systemkürzeln in Konflikt stehen", + "enable_code_ligatures": "Ligaturen im Code aktivieren", + "enable_changelog_autoscroll": "Automatisch zur gewünschten Version scrollen", + "enable_changelog_autoscroll_description": "Automatischer Sprung zur gewünschten Version oder in deren Nähe im Änderungsprotokoll des Pakets" }, "i18n": { "missing_keys": "{count} fehlende Übersetzung | {count} fehlende Übersetzungen", @@ -312,6 +320,7 @@ "warnings": "Warnungen:", "go_back_home": "Zur Startseite", "per_week": "/ Woche", + "per_week_short": "/W", "vanity_downloads_hint": "Vanity-Zahl: keine Pakete angezeigt | Vanity-Zahl: für das angezeigte Paket | Vanity-Zahl: Summe von {count} angezeigten Paketen", "sort": { "name": "Name", @@ -379,9 +388,18 @@ "size": "Installationsgröße um {percent} gestiegen ({size} größer)", "deps": "{count} zusätzliche Abhängigkeiten" }, + "size_decrease": { + "title_size": "Die Paketgröße hat sich seit Version {version} verringert!", + "title_deps": "Die Anzahl der Abhängigkeiten ist seit Version {version} gesunken!", + "title_both": "Die Paketgröße und die Anzahl der Abhängigkeiten sind seit Version {version} gesunken!", + "size": "Installationsgröße um {percent} reduziert (um {size} kleiner)", + "deps": "{count} Abhängigkeit weniger | {count} Abhängigkeiten weniger" + }, "replacement": { "title": "Du brauchst diese Abhängigkeit vielleicht nicht.", - "native": "Dies kann durch {replacement} ersetzt werden, verfügbar seit Node {nodeVersion}.", + "example": "Beispiel:", + "native": "Dies kann seit Node {nodeVersion} durch {replacement} ersetzt werden.", + "native_no_version": "Dieses Paket kann durch {replacement} ersetzt werden.", "simple": "Die {community} hat dieses Paket als überflüssig markiert und empfiehlt: {replacement}.", "documented": "Die {community} hat leistungsstärkere Alternativen für dieses Paket aufgezeigt.", "none": "Dieses Paket wurde als nicht mehr nötig markiert, und seine Funktionalität ist wahrscheinlich in allen Engines nativ verfügbar.", @@ -401,7 +419,7 @@ "inspect_dependency_tree": "Abhängigkeitsbaum untersuchen", "size_tooltip": { "unpacked": "{size} Größe nach dem Entpacken (dieses Paket)", - "total": "{size} Gesamtgröße nach dem Entpacken (inklusive {count} Abhängigkeit für linux-x64) | {size} Gesamtgröße nach dem Entpacken (inklusive aller {count} Abhängigkeiten für linux-x64)" + "total": "{size} Gesamtgröße nach dem Entpacken (inklusive {count} Abhängigkeit für Linux-x64) | {size} Gesamtgröße nach dem Entpacken (inklusive aller {count} Abhängigkeiten für Linux-x64)" } }, "skills": { @@ -432,11 +450,16 @@ "docs": "Dokumentation", "fund": "Spenden", "compare": "Vergleichen", - "compare_this_package": "Dieses Paket vergleichen" + "timeline": "Zeitleiste", + "compare_this_package": "Dieses Paket vergleichen", + "changelog": "Änderungsprotokoll" }, "likes": { "like": "Dieses Paket liken", - "unlike": "Like entfernen" + "unlike": "Like entfernen", + "top_rank_tooltip": "Das gehört zu den Top 10 der beliebtesten Pakete auf npmx! (#{rank})", + "top_rank_label": "#{rank}", + "top_rank_link_label": "Rangliste der Likes anzeigen. Dieses Paket steht auf Platz #{rank}." }, "docs": { "contents": "inhalt", @@ -477,7 +500,8 @@ "warning": "Warnung", "caution": "Vorsicht" }, - "copy_as_markdown": "README als Markdown kopieren" + "copy_as_markdown": "README als Markdown kopieren", + "error_loading": "Die README-Details konnten nicht geladen werden" }, "provenance_section": { "title": "Herkunftsnachweis", @@ -508,6 +532,7 @@ "weekly_downloads": "Wöchentliche Downloads", "keywords": "Schlüsselwörter", "license": "Lizenz", + "version": "Version", "select": "Paket auswählen", "select_maximum": "Maximal {count} Pakete können ausgewählt werden" }, @@ -547,6 +572,9 @@ "filter_help": "Hilfe zum SemVer-Filter", "filter_tooltip": "Filtere Versionen mit einem {link}. Zum Beispiel zeigt ^3.0.0 alle 3.x-Versionen.", "filter_tooltip_link": "SemVer-Bereich", + "license_change_help": "Details zur Lizenzänderung", + "license_change_warning": "Die Lizenz hat sich seit der letzten Version geändert.", + "license_change_record": "Die Lizenz dieses Pakets hat sich von \"{from}\" zu \"{to}\" geändert.", "no_matches": "Keine Versionen entsprechen diesem Bereich", "copy_alt": { "per_version_analysis": "Die Version {version} wurde {downloads} mal heruntergeladen", @@ -556,6 +584,35 @@ "current_tags": "Aktuelle Tags", "no_match_filter": "Keine Versionen entsprechen {filter}" }, + "timeline": { + "load_more": "Mehr laden", + "load_error": "Die Zeitleiste konnte nicht geladen werden. Bitte versuche es später erneut.", + "size_increase": "Die Installationsgröße hat sich um {percent} % ({size}) erhöht", + "size_decrease": "Die Installationsgröße wurde um {percent} % ({size}) reduziert", + "dep_increase": "{count} Abhängigkeit hinzugefügt | {count} Abhängigkeiten hinzugefügt", + "dep_decrease": "{count} Abhängigkeit entfernt | {count} Abhängigkeiten entfernt", + "license_change": "Die Lizenz wurde von {from} auf {to} geändert", + "esm_added": "Modultyp wurde auf ESM geändert", + "esm_removed": "Der Modultyp wurde von ESM auf CJS geändert", + "types_added": "TypeScript-Typen hinzugefügt", + "types_removed": "TypeScript-Typen entfernt", + "trusted_publisher_added": "Vertrauenswürdige Veröffentlichung aktiviert", + "trusted_publisher_removed": "Vertrauenswürdige Veröffentlichung entfernt", + "provenance_added": "Herkunftsnachweis aktiviert", + "provenance_removed": "Herkunftsnachweis entfernt", + "chart": { + "tab_aria_label": "Auswahl der Maßeinheit", + "base_scale": "Die y-Achse bei Null beginnen", + "zoom": "Zoom", + "reset_minimap": "Minikarte zurücksetzen", + "ordered_versions": "nur stabil", + "copy_alt": { + "key_changes": "Wichtigste Änderungen: {version_events}.", + "version_events": "Version {version}: {events}", + "general_description": "Liniendiagramm, das die {metric} des Pakets {package} von Version {first} bis {last} zeigt. Die {metric} beträgt in Version {first} {first_value} und in Version {last} {last_value} ({overall_progress_percentage} % insgesamt). {key_changes} {watermark}." + } + } + }, "dependencies": { "title": "Abhängigkeit ({count}) | Abhängigkeiten ({count})", "list_label": "Paketabhängigkeiten", @@ -583,12 +640,12 @@ "list_label": "Paket-Maintainer", "you": "(du)", "via": "via {teams}", - "remove_owner": "{name} als Owner entfernen", - "username_to_add": "Benutzername zum Hinzufügen als Owner", + "remove_owner": "{name} als Besitzer entfernen", + "username_to_add": "Benutzername zum Hinzufügen als Besitzer", "username_placeholder": "Benutzername...", "add_button": "Hinzufügen", - "cancel_add": "Owner-Hinzufügung abbrechen", - "add_owner": "+ Owner hinzufügen", + "cancel_add": "Hinzufügen des Besitzers abbrechen", + "add_owner": "+ Besitzer hinzufügen", "show_more": "({count} weitere anzeigen)", "show_less": "(weniger anzeigen)", "maintainer_template": "{avatar} {char126}{name}" @@ -660,6 +717,7 @@ }, "downloads": { "title": "Wöchentliche Downloads", + "version_distribution_title": "Wöchentliche Downloads für Version {version}", "community_distribution": "Community-Adoptionsverteilung ansehen", "subtitle": "Über alle Versionen", "sparkline_nav_hint": "Verwende ← →" @@ -712,7 +770,7 @@ "title": "Team-Zugriff", "refresh": "Team-Zugriff aktualisieren", "list_label": "Team-Zugriffsliste", - "owner": "Owner", + "owner": "Besitzer", "rw": "rw", "ro": "ro", "revoke_access": "Zugriff von {name} entziehen", @@ -758,6 +816,16 @@ "tarball": "Tarball als .tar.gz herunterladen" } }, + "leaderboard": { + "likes": { + "title": "Likes Leaderboard", + "description": "Die 10 derzeit beliebtesten Pakete auf npmx.", + "rank": "Rang", + "likes": "Likes", + "unavailable_title": "Es gibt noch keine Rangliste der Likes", + "unavailable_description": "Wir können derzeit keine Rangliste der Likes anzeigen." + } + }, "connector": { "modal": { "title": "Lokaler Connector", @@ -824,7 +892,7 @@ "username_to_add": "Benutzername zum Hinzufügen zu {team}", "username_placeholder": "Benutzername...", "add_button": "Hinzufügen", - "cancel_add_user": "Benutzer-Hinzufügung abbrechen", + "cancel_add_user": "Hinzufügen des Benutzers abbrechen", "add_member": "+ Mitglied hinzufügen", "team_name_label": "Teamname", "team_name_placeholder": "Teamname...", @@ -856,12 +924,12 @@ "all": "Alle", "developer": "Entwickler", "admin": "Admin", - "owner": "Owner" + "owner": "Besitzer" }, "team_label": "Team", "no_team": "Kein Team", "add_button": "Hinzufügen", - "cancel_add": "Mitglied-Hinzufügung abbrechen", + "cancel_add": "Hinzufügen des Mitglieds abbrechen", "add_member": "+ Mitglied hinzufügen" }, "public_packages": "{count} öffentliches Paket | {count} öffentliche Pakete", @@ -1104,10 +1172,10 @@ "already": "Es gibt", "people": "bereits", "building": "Leute,", - "really": "die", - "cool": "wirklich", - "package": "coole", - "managers": "Paketmanager bauen" + "really": "die wirklich", + "cool": "coole", + "package": "Paketmanager", + "managers": "bauen" } }, "sponsors": { @@ -1118,6 +1186,9 @@ }, "team": { "title": "Team", + "core": "Core", + "maintainers": "Maintainers", + "role_core": "Core", "role_steward": "Verwalter", "role_maintainer": "Maintainer", "sponsor": "Sponsor", @@ -1235,7 +1306,15 @@ "add_hint": "Füge mindestens 2 Pakete zum Vergleichen hinzu." }, "scatter_chart": { - "copy_alt": {} + "title": "Vergleiche {x} mit {y}", + "freshness_score": "Frischebewertung", + "copy_alt": { + "analysis": "{package} : {x_name} ({x_value}) und {y_name} ({y_value})", + "description": "Streudiagramm, das {x_name} gegen {y_name} für die Pakete aus {packages} darstellt. {analysis}. {watermark}" + }, + "filename": "{x}-vs-{y}-Punktdiagramm", + "x_axis": "X-Achse ↦", + "y_axis": "Y-Achse ↥" }, "no_dependency": { "label": "(Keine Abhängigkeit)", @@ -1315,6 +1394,18 @@ "vulnerabilities": { "label": "Sicherheitslücken", "description": "Bekannte Sicherheitsrisiken" + }, + "githubStars": { + "label": "GitHub-Sterne", + "description": "Anzahl der Sterne im GitHub-Repository" + }, + "githubIssues": { + "label": "GitHub-Issues", + "description": "Anzahl der Issues im GitHub-Repository" + }, + "createdAt": { + "label": "Erstellt am", + "description": "Wann das Paket erstellt wurde" } }, "values": { @@ -1637,5 +1728,16 @@ "discord_link_text": "chat.npmx.dev" } }, - "alt_logo_kawaii": "Eine süße, abgerundete und bunte Version des npmx-Logos." + "alt_logo_kawaii": "Eine süße, abgerundete und bunte Version des npmx-Logos.", + "changelog": { + "pre_release": "Vorabversion", + "draft": "Entwurf", + "no_logs": "Leider veröffentlicht dieses Paket keine Änderungsprotokolle oder das Format der Änderungsprotokolle wird nicht unterstützt.", + "error": { + "p1": "Leider konnte das Änderungsprotokoll für {package} nicht geladen werden", + "p2": "Bitte versuche es später noch einmal oder {viewon}" + }, + "rate_limit_ungh": "Entschuldigung, die Zugriffsbeschränkung von GitHub wurde erreicht. Bitte versuche es in einem Moment erneut.", + "version_unavailable": "Die gewünschte Version ist nicht verfügbar." + } }