diff --git a/eleventy.config.mjs b/eleventy.config.mjs index 1b618d829..611a9e5c9 100644 --- a/eleventy.config.mjs +++ b/eleventy.config.mjs @@ -216,7 +216,7 @@ function computeMagicMetadata(packages) { }) } -function basePackage(pkg) { +export function basePackage(pkg) { // Create a new array of releases with cleaned platforms const rawReleases = pkg.releases || [] const releases = rawReleases.map(release => ({ @@ -225,12 +225,7 @@ function basePackage(pkg) { platforms: util.prettifyPlatformLabels(release.platforms), })) - const supportsModernSublime = releases.some((release) => { - return util.parseSublimeTextMin(release.sublime_text) >= 3000 - }) - const doesNotSupportNewestSublime = releases.every((release) => { - return util.parseSublimeTextMax(release.sublime_text) < 4000 - }) + const compatibility = util.computeSublimeCompatibility(releases) // For each release, infer a human web URL under key "web" // Rules: @@ -281,9 +276,9 @@ function basePackage(pkg) { if (pkg.failing_since || pkg.fail_reason) { labels.unshift('FAILING') } - if (!supportsModernSublime) { + if (compatibility === 'st2') { labels.unshift('ST2') - } else if (doesNotSupportNewestSublime) { + } else if (compatibility === 'st3') { labels.unshift('ST3') } if (pkg.removed) { @@ -307,8 +302,8 @@ function basePackage(pkg) { platforms: platforms, // Human-readable label shown on cards and package stats/labels. platform_statement: util.computePlatformStatement(platforms), - outdated: !supportsModernSublime, - st3_only: supportsModernSublime && doesNotSupportNewestSublime, + compatibility, + outdated: compatibility === 'st2', } } diff --git a/eleventy.config.test.mjs b/eleventy.config.test.mjs new file mode 100644 index 000000000..01e7b27db --- /dev/null +++ b/eleventy.config.test.mjs @@ -0,0 +1,43 @@ +import { describe, expect, it } from 'vitest' +import { basePackage } from './eleventy.config.mjs' + +describe('basePackage compatibility labels', () => { + it('does not infer ST labels for skeleton tombstones', () => { + const pkg = basePackage({ + name: 'Yollama', + labels: ['auto-complete', 'ai', 'assistant'], + first_seen: '2024-02-19T21:02:58Z', + removed: '2025-11-16T12:38:48Z', + }) + + expect(pkg.labels).toEqual(['RIP', 'auto-complete', 'ai', 'assistant']) + expect(pkg.compatibility).toBeNull() + expect(pkg.outdated).toBe(false) + }) + + it('derives ST2 labels and flags from compatibility', () => { + const pkg = basePackage({ + name: 'Old Package', + releases: [ + { version: '1.0.0', sublime_text: '<3000', platforms: ['*'] }, + ], + }) + + expect(pkg.labels).toEqual(['ST2']) + expect(pkg.compatibility).toBe('st2') + expect(pkg.outdated).toBe(true) + }) + + it('derives ST3 labels and flags from compatibility', () => { + const pkg = basePackage({ + name: 'ST3 Package', + releases: [ + { version: '1.0.0', sublime_text: '3000-3999', platforms: ['*'] }, + ], + }) + + expect(pkg.labels).toEqual(['ST3']) + expect(pkg.compatibility).toBe('st3') + expect(pkg.outdated).toBe(false) + }) +}) diff --git a/eleventy.filters.mjs b/eleventy.filters.mjs index ec8247587..ac04f6547 100644 --- a/eleventy.filters.mjs +++ b/eleventy.filters.mjs @@ -122,10 +122,9 @@ function compactSearchPackage(pkg) { (pkg.labels ?? []).join(','), ] - if (pkg.outdated || pkg.st3_only || pkg.removed || pkg.archived_at) { + if (pkg.outdated || pkg.removed || pkg.archived_at) { row.push( pkg.outdated ? 1 : 0, - pkg.st3_only ? 1 : 0, timestamp(pkg.removed) || 0, timestamp(pkg.archived_at) || 0, ) diff --git a/eleventy.util.mjs b/eleventy.util.mjs index 205d5f984..0f05da2a0 100644 --- a/eleventy.util.mjs +++ b/eleventy.util.mjs @@ -619,6 +619,41 @@ function toLiveFileUrl(url) { ) } +/** + * @typedef {'st2' | 'st3' | 'current'} SublimeCompatibility + */ + +/** + * Infer Sublime Text compatibility from release selectors. + * + * Returns null when release data is unavailable, such as for skeleton + * tombstones. + * + * @param {Array<{sublime_text?: string}>} releases + * @returns {SublimeCompatibility | null} + */ +export function computeSublimeCompatibility(releases) { + if (releases.length === 0) { + return null + } + + const supportsModernSublime = releases.some((release) => { + return parseSublimeTextMin(release.sublime_text) >= 3000 + }) + if (!supportsModernSublime) { + return 'st2' + } + + const doesNotSupportNewestSublime = releases.every((release) => { + return parseSublimeTextMax(release.sublime_text) < 4000 + }) + if (doesNotSupportNewestSublime) { + return 'st3' + } + + return 'current' +} + /** * Convert a Sublime Text build selector into its starting build number. * Rules: @@ -862,6 +897,32 @@ if (import.meta.vitest) { }) }) + describe('computeSublimeCompatibility', () => { + it('returns null when release data is unavailable', () => { + expect(computeSublimeCompatibility([])).toBeNull() + }) + + it('detects ST2-only packages', () => { + expect(computeSublimeCompatibility([ + { sublime_text: '<3000' }, + { sublime_text: '2000' }, + ])).toBe('st2') + }) + + it('detects ST3-only packages', () => { + expect(computeSublimeCompatibility([ + { sublime_text: '3000-3999' }, + { sublime_text: '3000' }, + ])).toBe('st3') + }) + + it('detects packages compatible with current Sublime Text', () => { + expect(computeSublimeCompatibility([ + { sublime_text: '*' }, + ])).toBe('current') + }) + }) + describe('parseSublimeTextMin', () => { it.each([ [null, 0], diff --git a/static/module/minisearch.js b/static/module/minisearch.js index db0c72354..91b0cf953 100644 --- a/static/module/minisearch.js +++ b/static/module/minisearch.js @@ -61,7 +61,6 @@ function createMinisearchInstance(MiniSearch) { 'magic_score', 'magic', 'outdated', - 'st3_only', ], searchOptions: { boost: { author: 2, name: 2 }, diff --git a/static/package-search.js b/static/package-search.js index f5c01a882..f1472efda 100644 --- a/static/package-search.js +++ b/static/package-search.js @@ -68,7 +68,6 @@ function expandSearchPackage(row) { platform_statement, labels, outdated, - st3_only, removed, archived_at, ] = row @@ -87,7 +86,6 @@ function expandSearchPackage(row) { platform_statement, labels, ...(outdated ? { outdated: true } : {}), - ...(st3_only ? { st3_only: true } : {}), ...(removed ? { removed } : {}), ...(archived_at ? { archived_at } : {}), }