diff --git a/.changeset/tidy-buses-switch.md b/.changeset/tidy-buses-switch.md new file mode 100644 index 00000000..23e1eb9e --- /dev/null +++ b/.changeset/tidy-buses-switch.md @@ -0,0 +1,6 @@ +--- +'@doc-kit/core': patch +'@doc-kit/generator-react': patch +--- + +chore: replace `semver` with `verkit` (smaller, faster, zero-dependency SemVer toolkit) diff --git a/docs/creating-generators.md b/docs/creating-generators.md index e8158558..cded6604 100644 --- a/docs/creating-generators.md +++ b/docs/creating-generators.md @@ -138,7 +138,7 @@ export async function generate(input, worker) { /** * Transform metadata entries to MyFormat * @param {Array} entries - * @param {import('semver').SemVer} version + * @param {import('verkit').SemVer} version * @returns {string} */ function transformToMyFormat(entries, version) { diff --git a/package.json b/package.json index c789c16f..38400b72 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,6 @@ "@reporters/github": "~2.1.4", "@types/mdast": "~4.0.4", "@types/node": "~24.10.1", - "@types/semver": "~7.8.0", "c8": "~12.0.0", "eslint-plugin-jsdoc": "64.5.4", "eslint-plugin-react-x": "5.20.8", diff --git a/packages/core/package.json b/packages/core/package.json index 2f203560..e8b11b76 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -70,7 +70,6 @@ "remark-parse": "^11.0.0", "remark-rehype": "^11.1.2", "remark-stringify": "^11.0.0", - "semver": "^7.8.5", "shiki": "^4.4.3", "tinyglobby": "^0.2.17", "unified": "^11.0.5", @@ -80,6 +79,7 @@ "unist-util-remove": "^4.0.0", "unist-util-select": "^5.1.0", "unist-util-visit": "^5.1.0", + "verkit": "^0.5.0", "yaml": "^2.9.1" }, "devDependencies": { diff --git a/packages/core/src/parsers/__tests__/markdown.test.mjs b/packages/core/src/parsers/__tests__/markdown.test.mjs index 71c0d681..1b17030d 100644 --- a/packages/core/src/parsers/__tests__/markdown.test.mjs +++ b/packages/core/src/parsers/__tests__/markdown.test.mjs @@ -4,7 +4,7 @@ import assert from 'node:assert/strict'; import { describe, it, mock } from 'node:test'; import dedent from 'dedent'; -import { SemVer } from 'semver'; +import { parse } from 'verkit'; let content; mock.module('../../utils/loaders.mjs', { @@ -25,8 +25,8 @@ describe('parseChangelog', () => { const results = await parseChangelog('...'); assert.deepStrictEqual(results, [ - { version: new SemVer('24.0.0'), isLts: false }, - { version: new SemVer('22.0.0'), isLts: true }, + { version: parse('24.0.0'), isLts: false }, + { version: parse('22.0.0'), isLts: true }, ]); }); }); diff --git a/packages/core/src/parsers/markdown.mjs b/packages/core/src/parsers/markdown.mjs index 05286013..2466b61f 100644 --- a/packages/core/src/parsers/markdown.mjs +++ b/packages/core/src/parsers/markdown.mjs @@ -1,6 +1,6 @@ 'use strict'; -import { coerce } from 'semver'; +import { coerce } from 'verkit'; import { loadFromURL } from '#utils/loaders.mjs'; diff --git a/packages/core/src/parsers/types.d.ts b/packages/core/src/parsers/types.d.ts index 5e1f3e20..279c7730 100644 --- a/packages/core/src/parsers/types.d.ts +++ b/packages/core/src/parsers/types.d.ts @@ -1,4 +1,4 @@ -import type { SemVer } from 'semver'; +import type { SemVer } from 'verkit'; export interface ReleaseEntry { version: SemVer; diff --git a/packages/core/src/utils/__tests__/generators.test.mjs b/packages/core/src/utils/__tests__/generators.test.mjs index 6fe290db..cb8f2bbe 100644 --- a/packages/core/src/utils/__tests__/generators.test.mjs +++ b/packages/core/src/utils/__tests__/generators.test.mjs @@ -1,6 +1,8 @@ import assert from 'node:assert/strict'; import { describe, it } from 'node:test'; +import { normalize } from 'verkit'; + import { getEntryDescription, groupNodesByModule, @@ -103,17 +105,17 @@ describe('getVersionFromSemVer', () => { describe('coerceSemVer', () => { it('returns valid semver unchanged', () => { const result = coerceSemVer('1.2.3'); - assert.equal(result.version, '1.2.3'); + assert.equal(normalize(result), '1.2.3'); }); it('coerces invalid version to fallback', () => { const result = coerceSemVer('invalid'); - assert.equal(result.version, '0.0.0'); + assert.equal(normalize(result), '0.0.0'); }); it('handles null input', () => { const result = coerceSemVer(null); - assert.equal(result.version, '0.0.0'); + assert.equal(normalize(result), '0.0.0'); }); }); diff --git a/packages/core/src/utils/configuration/__tests__/index.test.mjs b/packages/core/src/utils/configuration/__tests__/index.test.mjs index 140c0f35..c6ded965 100644 --- a/packages/core/src/utils/configuration/__tests__/index.test.mjs +++ b/packages/core/src/utils/configuration/__tests__/index.test.mjs @@ -5,6 +5,8 @@ import { join } from 'node:path'; import { describe, it, mock, beforeEach } from 'node:test'; import { pathToFileURL } from 'node:url'; +import { normalize } from 'verkit'; + import logger from '../../../logger/index.mjs'; // Mock dependencies @@ -291,7 +293,7 @@ describe('config.mjs', () => { assert.strictEqual(config.global.input, 'custom-src/'); assert.strictEqual(config.global.output, 'custom-dist/'); - assert.strictEqual(config.global.version.version, '20.0.0'); + assert.strictEqual(normalize(config.global.version), '20.0.0'); assert.deepStrictEqual(config.target, ['html', 'orama-db']); assert.strictEqual(config.threads, 2); assert.strictEqual(config.web.showSearchBox, true); diff --git a/packages/core/src/utils/configuration/index.mjs b/packages/core/src/utils/configuration/index.mjs index 5ab50803..ab8c4806 100644 --- a/packages/core/src/utils/configuration/index.mjs +++ b/packages/core/src/utils/configuration/index.mjs @@ -4,7 +4,7 @@ import { fileURLToPath } from 'node:url'; import { isMainThread } from 'node:worker_threads'; import { cosmiconfig } from 'cosmiconfig'; -import { coerce } from 'semver'; +import { coerce } from 'verkit'; import { loadGenerators, diff --git a/packages/core/src/utils/configuration/types.d.ts b/packages/core/src/utils/configuration/types.d.ts index 2437302b..be29341f 100644 --- a/packages/core/src/utils/configuration/types.d.ts +++ b/packages/core/src/utils/configuration/types.d.ts @@ -1,4 +1,4 @@ -import type { SemVer } from 'semver'; +import type { SemVer } from 'verkit'; import type { ReleaseEntry } from '#parsers/types'; diff --git a/packages/core/src/utils/generators.mjs b/packages/core/src/utils/generators.mjs index 516113bc..7a14a191 100644 --- a/packages/core/src/utils/generators.mjs +++ b/packages/core/src/utils/generators.mjs @@ -1,6 +1,6 @@ 'use strict'; -import { coerce, major } from 'semver'; +import { coerce, getMajor } from 'verkit'; import { transformNodeToString } from './unist.mjs'; @@ -45,7 +45,7 @@ export const groupNodesByModule = nodes => { /** * Parses the SemVer string into a Node.js-alike version * - * @param {import('semver').SemVer} version The version to be parsed + * @param {import('verkit').SemVer} version The version to be parsed */ export const getVersionFromSemVer = version => version.minor === 0 @@ -59,8 +59,8 @@ export const getVersionFromSemVer = version => * This is a safe fallback to ensure that we always have a SemVer compatible version * even if the input is not a valid SemVer string * - * @param {string|import('semver').SemVer} version SemVer compatible version (maybe) - * @returns {import('semver').SemVer} SemVer compatible version + * @param {string|import('verkit').SemVer} version SemVer compatible version (maybe) + * @returns {import('verkit').SemVer} SemVer compatible version */ export const coerceSemVer = version => { const coercedVersion = coerce(version); @@ -76,12 +76,12 @@ export const coerceSemVer = version => { /** * Gets compatible versions for an entry * - * @param {string | import('semver').SemVer} introduced + * @param {string | import('verkit').SemVer} introduced * @param {Array} releases * @returns {Array} */ export const getCompatibleVersions = (introduced, releases) => { - const coercedMajor = major(coerceSemVer(introduced)); + const coercedMajor = getMajor(coerceSemVer(introduced)); // All Node.js versions that support the current API; If there's no "introduced_at" field, // we simply show all versions, as we cannot pinpoint the exact version return releases.filter(release => release.version.major >= coercedMajor); diff --git a/packages/node-legacy/package.json b/packages/node-legacy/package.json index 9984b535..529c21ce 100644 --- a/packages/node-legacy/package.json +++ b/packages/node-legacy/package.json @@ -31,6 +31,7 @@ "remark-parse": "^11.0.0", "remark-rehype": "^11.1.2", "unist-builder": "^4.0.0", - "unist-util-visit": "^5.1.0" + "unist-util-visit": "^5.1.0", + "verkit": "^0.5.0" } } diff --git a/packages/node-legacy/src/legacy-html-all/generate.mjs b/packages/node-legacy/src/legacy-html-all/generate.mjs index 307c7a02..cb3e5be3 100644 --- a/packages/node-legacy/src/legacy-html-all/generate.mjs +++ b/packages/node-legacy/src/legacy-html-all/generate.mjs @@ -6,6 +6,7 @@ import { join } from 'node:path'; import getConfig from '@doc-kit/core/utils/configuration/index.mjs'; import { minifyHTML } from '@doc-kit/core/utils/html-minifier.mjs'; import { getProcessor } from '@doc-kit/core/utils/markdown/processor.mjs'; +import { normalize } from 'verkit'; import { replaceTemplateValues } from '../legacy-html/utils/replaceTemplateValues.mjs'; import tableOfContents from '../legacy-html/utils/tableOfContents.mjs'; @@ -50,7 +51,7 @@ export async function generate(input) { path: 'all', added: '', section: 'All', - version: `v${config.version.version}`, + version: `v${normalize(config.version)}`, toc: aggregatedToC, nav: String(parsedSideNav), content: aggregatedContent, diff --git a/packages/node-legacy/src/legacy-html/utils/replaceTemplateValues.mjs b/packages/node-legacy/src/legacy-html/utils/replaceTemplateValues.mjs index 4d434ea7..05d6a65e 100644 --- a/packages/node-legacy/src/legacy-html/utils/replaceTemplateValues.mjs +++ b/packages/node-legacy/src/legacy-html/utils/replaceTemplateValues.mjs @@ -1,6 +1,7 @@ 'use strict'; import { populate } from '@doc-kit/core/utils/configuration/templates.mjs'; +import { normalize } from 'verkit'; import { buildToC, @@ -28,7 +29,7 @@ export const replaceTemplateValues = ( .replace('__ID__', api) .replace(/__FILENAME__/g, api) .replace('__SECTION__', section) - .replace(/__VERSION__/g, `v${config.version.version}`) + .replace(/__VERSION__/g, `v${normalize(config.version)}`) .replace(/__TOC__/g, tableOfContents.wrapToC(toc)) .replace(/__GTOC__/g, nav) .replace('__CONTENT__', content) diff --git a/packages/react/package.json b/packages/react/package.json index e9199f72..5ea296e7 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -55,10 +55,10 @@ "remark-parse": "^11.0.0", "remark-rehype": "^11.1.2", "remark-stringify": "^11.0.0", - "semver": "^7.8.5", "unified": "^11.0.5", "unist-builder": "^4.0.0", "unist-util-visit": "^5.1.0", + "verkit": "^0.5.0", "vite": "~8.3.1" }, "devDependencies": { diff --git a/packages/react/src/html/ui/components/SideBar/index.jsx b/packages/react/src/html/ui/components/SideBar/index.jsx index 143e3302..d4afb405 100644 --- a/packages/react/src/html/ui/components/SideBar/index.jsx +++ b/packages/react/src/html/ui/components/SideBar/index.jsx @@ -1,5 +1,6 @@ import Select from '@node-core/ui-components/Common/Select'; import SideBar from '@node-core/ui-components/Containers/Sidebar'; +import { normalize } from 'verkit'; import { project, @@ -114,7 +115,7 @@ const Sidebar = ({ metadata }) => { const remote = useRemoteConfig(); const availableVersions = remote?.versions ?? versions; - const currentVersion = `v${version.version}`; + const currentVersion = `v${normalize(version)}`; // Filter versions by compatibility and resolve per-page URL const compatibleVersions = availableVersions diff --git a/packages/react/src/html/ui/types.d.ts b/packages/react/src/html/ui/types.d.ts index a0756d6d..e2dc2f1f 100644 --- a/packages/react/src/html/ui/types.d.ts +++ b/packages/react/src/html/ui/types.d.ts @@ -1,6 +1,6 @@ import { MetadataEntry } from '@doc-kit/core/generators/metadata/types'; import { GlobalConfiguration } from '@doc-kit/core/utils/configuration/types'; -import { SemVer } from 'semver'; +import { SemVer } from 'verkit'; import { Configuration } from '../types'; diff --git a/packages/react/src/html/utils/__tests__/config.test.mjs b/packages/react/src/html/utils/__tests__/config.test.mjs index 94e2e0c3..9a22109b 100644 --- a/packages/react/src/html/utils/__tests__/config.test.mjs +++ b/packages/react/src/html/utils/__tests__/config.test.mjs @@ -3,7 +3,7 @@ import { describe, it, mock } from 'node:test'; import { setConfig } from '@doc-kit/core/utils/configuration/index.mjs'; import { loadMarkdownPlugins } from '@doc-kit/core/utils/markdown/plugins.mjs'; -import { SemVer } from 'semver'; +import { parse } from 'verkit'; mock.module('@node-core/rehype-shiki', { exports: { @@ -38,8 +38,8 @@ const { const config = await setConfig({ version: 'v22.0.0', changelog: [ - { version: new SemVer('20.0.0'), isLts: true, isCurrent: false }, - { version: new SemVer('22.0.0'), isLts: false, isCurrent: true }, + { version: parse('20.0.0'), isLts: true, isCurrent: false }, + { version: parse('22.0.0'), isLts: false, isCurrent: true }, ], }); @@ -72,8 +72,8 @@ describe('buildVersionEntries', () => { it('creates version entries with labels and URL templates', () => { const result = buildVersionEntries( [ - { version: new SemVer('20.0.0'), isLts: true, isCurrent: false }, - { version: new SemVer('22.0.0'), isLts: false, isCurrent: true }, + { version: parse('20.0.0'), isLts: true, isCurrent: false }, + { version: parse('22.0.0'), isLts: false, isCurrent: true }, ], 'https://nodejs.org/docs/latest-{version}/api{path}.html' ); @@ -93,7 +93,7 @@ describe('buildVersionEntries', () => { it('does not append a label suffix for versions that are neither LTS nor Current', () => { const result = buildVersionEntries( - [{ version: new SemVer('18.0.0'), isLts: false, isCurrent: false }], + [{ version: parse('18.0.0'), isLts: false, isCurrent: false }], '{version}' ); @@ -102,7 +102,7 @@ describe('buildVersionEntries', () => { it('formats minor versions when minor is non-zero', () => { const result = buildVersionEntries( - [{ version: new SemVer('21.7.0'), isLts: false, isCurrent: false }], + [{ version: parse('21.7.0'), isLts: false, isCurrent: false }], '{version}' ); diff --git a/packages/react/src/html/utils/config.mjs b/packages/react/src/html/utils/config.mjs index 512cbdbf..bfb556c1 100644 --- a/packages/react/src/html/utils/config.mjs +++ b/packages/react/src/html/utils/config.mjs @@ -9,6 +9,7 @@ import { } from '@doc-kit/core/utils/generators.mjs'; import { parseInline, renderAsHTML } from '@doc-kit/core/utils/inline.mjs'; import { omitKeys } from '@doc-kit/core/utils/misc.mjs'; +import { normalize } from 'verkit'; import { getSortedHeadNodes } from '../../jsx-ast/utils/getSortedHeadNodes.mjs'; @@ -181,7 +182,7 @@ export default function createConfigSource(input, server = false) { config.editURL && populate(config.editURL, { ...config, - version: `v${configVersion.version}`, + version: `v${normalize(configVersion)}`, }); const pageURL = populate(config.pageURL, config); diff --git a/packages/react/src/html/utils/processing.mjs b/packages/react/src/html/utils/processing.mjs index b18a1d61..6c041d89 100644 --- a/packages/react/src/html/utils/processing.mjs +++ b/packages/react/src/html/utils/processing.mjs @@ -1,5 +1,6 @@ import getConfig from '@doc-kit/core/utils/configuration/index.mjs'; import { populate } from '@doc-kit/core/utils/configuration/templates.mjs'; +import { normalize } from 'verkit'; import { ROUTER_DATA_ATTRIBUTE } from '../ui/constants.mjs'; import { THEME_SCRIPT } from '../ui/theme-script.mjs'; @@ -224,7 +225,7 @@ export const populatePage = ({ template, data, dehydrated, assets }) => { const titleSuffix = populate(config.title, { ...config, - version: config.version.version, + version: normalize(config.version), }); const root = resolvePageRoot(data); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e4274c3d..7a2101dc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -29,9 +29,6 @@ importers: '@types/node': specifier: ~24.10.1 version: 24.10.15 - '@types/semver': - specifier: ~7.8.0 - version: 7.8.0 c8: specifier: ~12.0.0 version: 12.0.0 @@ -134,9 +131,6 @@ importers: remark-stringify: specifier: ^11.0.0 version: 11.0.0 - semver: - specifier: ^7.8.5 - version: 7.8.5 shiki: specifier: ^4.4.3 version: 4.4.3 @@ -164,6 +158,9 @@ importers: unist-util-visit: specifier: ^5.1.0 version: 5.1.0 + verkit: + specifier: ^0.5.0 + version: 0.5.0 yaml: specifier: ^2.9.1 version: 2.9.1 @@ -223,6 +220,9 @@ importers: unist-util-visit: specifier: ^5.1.0 version: 5.1.0 + verkit: + specifier: ^0.5.0 + version: 0.5.0 packages/react: dependencies: @@ -301,9 +301,6 @@ importers: remark-stringify: specifier: ^11.0.0 version: 11.0.0 - semver: - specifier: ^7.8.5 - version: 7.8.5 unified: specifier: ^11.0.5 version: 11.0.5 @@ -313,6 +310,9 @@ importers: unist-util-visit: specifier: ^5.1.0 version: 5.1.0 + verkit: + specifier: ^0.5.0 + version: 0.5.0 vite: specifier: ~8.3.1 version: 8.3.1(@types/node@24.10.15)(esbuild@0.28.1)(yaml@2.9.1) @@ -2005,9 +2005,6 @@ packages: '@types/react@19.2.18': resolution: {integrity: sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w==} - '@types/semver@7.8.0': - resolution: {integrity: sha512-1mAINjtQCXXeLkJ9ehXkwOcBpqtLxiVtKhpUf83DdRNdQKV0iXZpaHYqRr7nj+wvxuJzoAmAwXI+sCNMv1CzLQ==} - '@types/unist@2.0.11': resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} @@ -3446,6 +3443,10 @@ packages: resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} engines: {node: '>=10.12.0'} + verkit@0.5.0: + resolution: {integrity: sha512-u4J1hr6Y+C/hit34GwL3eIcUf3wngT8TlYUjK7tk0jxydKLAq3sYvifjdTDA6U3KCKRcQCQDGf/srjxfZF3l7g==} + engines: {node: '>=18.12.0'} + vfile-location@5.0.3: resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} @@ -4994,8 +4995,6 @@ snapshots: dependencies: csstype: 3.2.3 - '@types/semver@7.8.0': {} - '@types/unist@2.0.11': {} '@types/unist@3.0.3': {} @@ -6901,6 +6900,8 @@ snapshots: '@types/istanbul-lib-coverage': 2.0.6 convert-source-map: 2.0.0 + verkit@0.5.0: {} + vfile-location@5.0.3: dependencies: '@types/unist': 3.0.3