diff --git a/e2e/cases/alias/index.test.ts b/e2e/cases/alias/index.test.ts index 90ffa190c..8fce62eb2 100644 --- a/e2e/cases/alias/index.test.ts +++ b/e2e/cases/alias/index.test.ts @@ -1,9 +1,9 @@ import { expect, test } from 'vitest'; -import { buildAndGetJsResults } from '#shared'; +import { buildAndGetResults } from '#shared'; test('source.alias', async () => { const fixturePath = __dirname; - const { entries } = await buildAndGetJsResults(fixturePath); + const { entries } = await buildAndGetResults(fixturePath); expect(entries.esm).toContain('hello world'); expect(entries.cjs).toContain('hello world'); diff --git a/e2e/cases/autoExtension/index.test.ts b/e2e/cases/autoExtension/index.test.ts index 90c79fde8..7698a3dce 100644 --- a/e2e/cases/autoExtension/index.test.ts +++ b/e2e/cases/autoExtension/index.test.ts @@ -1,17 +1,17 @@ import { extname, join } from 'node:path'; import { expect, test } from 'vitest'; -import { buildAndGetJsResults } from '#shared'; +import { buildAndGetResults } from '#shared'; test('autoExtension generate .mjs in build artifacts with esm format when type is commonjs', async () => { const fixturePath = join(__dirname, 'type-commonjs'); - const { entryFiles } = await buildAndGetJsResults(fixturePath); + const { entryFiles } = await buildAndGetResults(fixturePath); expect(extname(entryFiles.esm!)).toEqual('.mjs'); expect(extname(entryFiles.cjs!)).toEqual('.js'); }); test('autoExtension generate .cjs in build artifacts with cjs format when type is module', async () => { const fixturePath = join(__dirname, 'type-module'); - const { entryFiles } = await buildAndGetJsResults(fixturePath); + const { entryFiles } = await buildAndGetResults(fixturePath); expect(extname(entryFiles.esm!)).toEqual('.js'); expect(extname(entryFiles.cjs!)).toEqual('.cjs'); }); diff --git a/e2e/cases/bundle-false/index.test.ts b/e2e/cases/bundle-false/index.test.ts index 7cf3c24ed..556750a8f 100644 --- a/e2e/cases/bundle-false/index.test.ts +++ b/e2e/cases/bundle-false/index.test.ts @@ -1,10 +1,10 @@ import { join } from 'node:path'; import { expect, test } from 'vitest'; -import { buildAndGetJsResults } from '#shared'; +import { buildAndGetResults } from '#shared'; test('bundle: false', async () => { const fixturePath = join(__dirname, 'basic'); - const { files } = await buildAndGetJsResults(fixturePath); + const { files } = await buildAndGetResults(fixturePath); // TODO: record file paths with inline snapshot // need to add path serialization diff --git a/e2e/cases/define/index.test.ts b/e2e/cases/define/index.test.ts index dadd4d52e..6b01111f6 100644 --- a/e2e/cases/define/index.test.ts +++ b/e2e/cases/define/index.test.ts @@ -1,9 +1,9 @@ import { expect, test } from 'vitest'; -import { buildAndGetJsResults } from '#shared'; +import { buildAndGetResults } from '#shared'; test('source.define', async () => { const fixturePath = __dirname; - const { entries } = await buildAndGetJsResults(fixturePath); + const { entries } = await buildAndGetResults(fixturePath); expect(entries.esm).not.toContain('console.info(VERSION)'); expect(entries.esm).toContain('1.0.0'); diff --git a/e2e/cases/dts/bundle-false/rslib.config.ts b/e2e/cases/dts/bundle-false/rslib.config.ts new file mode 100644 index 000000000..42d99d4a0 --- /dev/null +++ b/e2e/cases/dts/bundle-false/rslib.config.ts @@ -0,0 +1,24 @@ +import { defineConfig } from '@rslib/core'; +import { generateBundleCjsConfig, generateBundleEsmConfig } from '#shared'; + +export default defineConfig({ + lib: [ + generateBundleEsmConfig(__dirname, { + bundle: false, + dts: { + bundle: false, + }, + }), + generateBundleCjsConfig(__dirname, { + bundle: false, + dts: { + bundle: false, + }, + }), + ], + source: { + entry: { + main: ['./src/**'], + }, + }, +}); diff --git a/e2e/cases/dts/bundle-false/src/index.ts b/e2e/cases/dts/bundle-false/src/index.ts new file mode 100644 index 000000000..6eb6b6fb1 --- /dev/null +++ b/e2e/cases/dts/bundle-false/src/index.ts @@ -0,0 +1,3 @@ +export * from './utils/numbers'; +export * from './utils/strings'; +export * from './sum'; diff --git a/e2e/cases/dts/bundle-false/src/sum.ts b/e2e/cases/dts/bundle-false/src/sum.ts new file mode 100644 index 000000000..2759c8823 --- /dev/null +++ b/e2e/cases/dts/bundle-false/src/sum.ts @@ -0,0 +1,5 @@ +import { num1, num2, num3 } from './utils/numbers'; +import { str1, str2, str3 } from './utils/strings'; + +export const numSum = num1 + num2 + num3; +export const strSum = str1 + str2 + str3; diff --git a/e2e/cases/dts/bundle-false/src/utils/numbers.ts b/e2e/cases/dts/bundle-false/src/utils/numbers.ts new file mode 100644 index 000000000..c1d2a8cd2 --- /dev/null +++ b/e2e/cases/dts/bundle-false/src/utils/numbers.ts @@ -0,0 +1,3 @@ +export const num1 = 1; +export const num2 = 2; +export const num3 = 3; diff --git a/e2e/cases/dts/bundle-false/src/utils/strings.ts b/e2e/cases/dts/bundle-false/src/utils/strings.ts new file mode 100644 index 000000000..d35b5a606 --- /dev/null +++ b/e2e/cases/dts/bundle-false/src/utils/strings.ts @@ -0,0 +1,3 @@ +export const str1 = 'str1'; +export const str2 = 'str2'; +export const str3 = 'str3'; diff --git a/e2e/cases/dts/bundle-false/tsconfig.json b/e2e/cases/dts/bundle-false/tsconfig.json new file mode 100644 index 000000000..888d3e460 --- /dev/null +++ b/e2e/cases/dts/bundle-false/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "@rslib/tsconfig/base", + "compilerOptions": { + "baseUrl": "./" + }, + "include": ["src"] +} diff --git a/e2e/cases/dts/bundle/package.json b/e2e/cases/dts/bundle/package.json new file mode 100644 index 000000000..77cf18a4e --- /dev/null +++ b/e2e/cases/dts/bundle/package.json @@ -0,0 +1,6 @@ +{ + "name": "dts-bundle-test", + "version": "1.0.0", + "private": true, + "type": "module" +} diff --git a/e2e/cases/dts/bundle/rslib.config.ts b/e2e/cases/dts/bundle/rslib.config.ts new file mode 100644 index 000000000..ae05de122 --- /dev/null +++ b/e2e/cases/dts/bundle/rslib.config.ts @@ -0,0 +1,25 @@ +import { defineConfig } from '@rslib/core'; +import { + generateBundleCjsConfig, + generateBundleEsmConfig, +} from '../../../scripts/shared'; + +export default defineConfig({ + lib: [ + generateBundleEsmConfig(__dirname, { + dts: { + bundle: true, + }, + }), + generateBundleCjsConfig(__dirname, { + dts: { + bundle: true, + }, + }), + ], + source: { + entry: { + main: './src/index.ts', + }, + }, +}); diff --git a/e2e/cases/dts/bundle/src/index.ts b/e2e/cases/dts/bundle/src/index.ts new file mode 100644 index 000000000..6eb6b6fb1 --- /dev/null +++ b/e2e/cases/dts/bundle/src/index.ts @@ -0,0 +1,3 @@ +export * from './utils/numbers'; +export * from './utils/strings'; +export * from './sum'; diff --git a/e2e/cases/dts/bundle/src/sum.ts b/e2e/cases/dts/bundle/src/sum.ts new file mode 100644 index 000000000..2759c8823 --- /dev/null +++ b/e2e/cases/dts/bundle/src/sum.ts @@ -0,0 +1,5 @@ +import { num1, num2, num3 } from './utils/numbers'; +import { str1, str2, str3 } from './utils/strings'; + +export const numSum = num1 + num2 + num3; +export const strSum = str1 + str2 + str3; diff --git a/e2e/cases/dts/bundle/src/utils/numbers.ts b/e2e/cases/dts/bundle/src/utils/numbers.ts new file mode 100644 index 000000000..c1d2a8cd2 --- /dev/null +++ b/e2e/cases/dts/bundle/src/utils/numbers.ts @@ -0,0 +1,3 @@ +export const num1 = 1; +export const num2 = 2; +export const num3 = 3; diff --git a/e2e/cases/dts/bundle/src/utils/strings.ts b/e2e/cases/dts/bundle/src/utils/strings.ts new file mode 100644 index 000000000..d35b5a606 --- /dev/null +++ b/e2e/cases/dts/bundle/src/utils/strings.ts @@ -0,0 +1,3 @@ +export const str1 = 'str1'; +export const str2 = 'str2'; +export const str3 = 'str3'; diff --git a/e2e/cases/dts/bundle/tsconfig.json b/e2e/cases/dts/bundle/tsconfig.json new file mode 100644 index 000000000..888d3e460 --- /dev/null +++ b/e2e/cases/dts/bundle/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "@rslib/tsconfig/base", + "compilerOptions": { + "baseUrl": "./" + }, + "include": ["src"] +} diff --git a/e2e/cases/dts/index.test.ts b/e2e/cases/dts/index.test.ts new file mode 100644 index 000000000..3a7f5c3a2 --- /dev/null +++ b/e2e/cases/dts/index.test.ts @@ -0,0 +1,18 @@ +import { join } from 'node:path'; +import { expect, test } from 'vitest'; +import { buildAndGetResults } from '#shared'; + +test('dts when bundle: false', async () => { + const fixturePath = join(__dirname, 'bundle-false'); + const { files } = await buildAndGetResults(fixturePath, 'dts'); + + expect(files.esm?.length).toBe(4); + expect(files.esm?.[0]!.endsWith('.d.ts')).toEqual(true); +}); + +test('dts when bundle: true', async () => { + const fixturePath = join(__dirname, 'bundle'); + const { entryFiles } = await buildAndGetResults(fixturePath, 'dts'); + + expect(entryFiles.esm!.endsWith('index.d.ts')).toEqual(true); +}); diff --git a/e2e/cases/externals/browser/index.test.ts b/e2e/cases/externals/browser/index.test.ts index b6705851a..c9c747d48 100644 --- a/e2e/cases/externals/browser/index.test.ts +++ b/e2e/cases/externals/browser/index.test.ts @@ -1,9 +1,9 @@ import { join } from 'node:path'; import { expect, test } from 'vitest'; -import { buildAndGetJsResults } from '#shared'; +import { buildAndGetResults } from '#shared'; test('should fail to build when `output.target` is not "node"', async () => { const fixturePath = join(__dirname); - const build = buildAndGetJsResults(fixturePath); + const build = buildAndGetResults(fixturePath); await expect(build).rejects.toThrowError('Rspack build failed!'); }); diff --git a/e2e/cases/externals/node/index.test.ts b/e2e/cases/externals/node/index.test.ts index 423b8c6c7..3aff75de1 100644 --- a/e2e/cases/externals/node/index.test.ts +++ b/e2e/cases/externals/node/index.test.ts @@ -1,10 +1,10 @@ import { join } from 'node:path'; import { expect, test } from 'vitest'; -import { buildAndGetJsResults } from '#shared'; +import { buildAndGetResults } from '#shared'; test('auto externalize Node.js built-in modules when `output.target` is "node"', async () => { const fixturePath = join(__dirname); - const { entries } = await buildAndGetJsResults(fixturePath); + const { entries } = await buildAndGetResults(fixturePath); for (const external of [ 'import * as __WEBPACK_EXTERNAL_MODULE_fs__ from "fs"', diff --git a/e2e/cases/syntax/config/index.test.ts b/e2e/cases/syntax/config/index.test.ts index e3e5f7143..856371f1c 100644 --- a/e2e/cases/syntax/config/index.test.ts +++ b/e2e/cases/syntax/config/index.test.ts @@ -1,9 +1,9 @@ import { expect, test } from 'vitest'; -import { buildAndGetJsResults } from '#shared'; +import { buildAndGetResults } from '#shared'; test('should downgrade class private method by default', async () => { const fixturePath = __dirname; - const { entries } = await buildAndGetJsResults(fixturePath); + const { entries } = await buildAndGetResults(fixturePath); expect(entries.esm).toMatchSnapshot(); expect(entries.esm).not.toContain('#bar'); diff --git a/e2e/cases/syntax/default/index.test.ts b/e2e/cases/syntax/default/index.test.ts index de207958a..7aa5f6612 100644 --- a/e2e/cases/syntax/default/index.test.ts +++ b/e2e/cases/syntax/default/index.test.ts @@ -1,9 +1,9 @@ import { expect, test } from 'vitest'; -import { buildAndGetJsResults } from '#shared'; +import { buildAndGetResults } from '#shared'; test('should downgrade class private method by default', async () => { const fixturePath = __dirname; - const { entries } = await buildAndGetJsResults(fixturePath); + const { entries } = await buildAndGetResults(fixturePath); expect(entries.esm).toMatchSnapshot(); expect(entries.esm).toContain('#bar'); diff --git a/e2e/package.json b/e2e/package.json index d9b8f48f4..4c687e7fd 100644 --- a/e2e/package.json +++ b/e2e/package.json @@ -14,7 +14,7 @@ }, "devDependencies": { "@playwright/test": "1.43.1", - "@rsbuild/core": "1.0.1-beta.6", + "@rsbuild/core": "1.0.1-beta.8", "@rslib/core": "workspace:*", "@rslib/tsconfig": "workspace:*", "@types/fs-extra": "^11.0.4", diff --git a/e2e/scripts/shared.ts b/e2e/scripts/shared.ts index 3e65866c7..be5e72111 100644 --- a/e2e/scripts/shared.ts +++ b/e2e/scripts/shared.ts @@ -37,31 +37,41 @@ export function generateBundleCjsConfig( return mergeConfig(cjsBasicConfig, config)!; } -export async function getJsResults(rslibConfig: RslibConfig) { +export async function getResults(rslibConfig: RslibConfig, type: 'js' | 'dts') { const files: Record = {}; const contents: Record> = {}; const entries: Record = {}; const entryFiles: Record = {}; for (const libConfig of rslibConfig.lib) { - const content = await globContentJSON(libConfig?.output?.distPath?.root!, { + let globFolder = ''; + if (type === 'js') { + globFolder = libConfig?.output?.distPath?.root!; + } else if (type === 'dts' && libConfig.dts !== false) { + globFolder = + libConfig.dts?.distPath! ?? libConfig?.output?.distPath?.root!; + } + + if (!globFolder) continue; + + const regex = type === 'dts' ? /\.d.(ts|cts|mts)$/ : /\.(js|cjs|mjs)$/; + + const content = await globContentJSON(globFolder, { absolute: true, ignore: ['/**/*.map'], }); - const jsFiles = Object.keys(content).filter((file) => - /\.(js|cjs|mjs)$/.test(file), - ); + const fileSet = Object.keys(content).filter((file) => regex.test(file)); - if (jsFiles.length) { - files[libConfig.format!] = jsFiles; + if (fileSet.length) { + files[libConfig.format!] = fileSet; contents[libConfig.format!] = content; } // Only applied in bundle mode, a shortcut to get single entry result - if (libConfig.bundle !== false && jsFiles.length === 1) { + if (libConfig.bundle !== false && fileSet.length === 1) { entries[libConfig.format!] = Object.values(content)[0]!; - entryFiles[libConfig.format!] = jsFiles[0]!; + entryFiles[libConfig.format!] = fileSet[0]!; } } @@ -73,11 +83,14 @@ export async function getJsResults(rslibConfig: RslibConfig) { }; } -export const buildAndGetJsResults = async (fixturePath: string) => { +export const buildAndGetResults = async ( + fixturePath: string, + type: 'js' | 'dts' = 'js', +) => { const rslibConfig = await loadConfig(join(fixturePath, 'rslib.config.ts')); process.chdir(fixturePath); await build(rslibConfig); - const results = await getJsResults(rslibConfig); + const results = await getResults(rslibConfig, type); return { contents: results.contents, files: results.files, diff --git a/packages/core/modern.config.ts b/packages/core/modern.config.ts index d624df4fb..3bc30c426 100644 --- a/packages/core/modern.config.ts +++ b/packages/core/modern.config.ts @@ -1,7 +1,12 @@ import { defineConfig, moduleTools } from '@modern-js/module-tools'; import prebundleConfig from './prebundle.config.mjs'; -const externals = ['@rsbuild/core', /[\\/]compiled[\\/]/, /node:/]; +const externals = [ + '@rsbuild/core', + /[\\/]compiled[\\/]/, + /node:/, + 'typescript', +]; const define = { RSLIB_VERSION: require('./package.json').version, }; diff --git a/packages/core/package.json b/packages/core/package.json index 44465641d..10a0eb7b8 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -26,26 +26,41 @@ "bin": { "rslib": "./bin/rslib.js" }, - "files": ["bin", "dist", "dist-types", "compiled"], + "files": [ + "bin", + "dist", + "dist-types", + "compiled" + ], "scripts": { "build": "modern build", "dev": "modern build --watch", "prebundle": "prebundle" }, "dependencies": { - "@rsbuild/core": "1.0.1-beta.6" + "@rsbuild/core": "1.0.1-beta.8", + "rsbuild-plugin-dts": "workspace:*" }, "devDependencies": { "@rslib/tsconfig": "workspace:*", "@types/fs-extra": "^11.0.4", - "fast-glob": "^3.3.2", "commander": "^12.1.0", + "fast-glob": "^3.3.2", "fs-extra": "^11.2.0", "picocolors": "1.0.1", "prebundle": "1.1.0", "rslog": "^1.2.2", "typescript": "^5.5.3" }, + "peerDependencies": { + "@microsoft/api-extractor": "^7", + "typescript": "^5" + }, + "peerDependenciesMeta": { + "@microsoft/api-extractor": { + "optional": true + } + }, "engines": { "node": ">=16.0.0" }, diff --git a/packages/core/src/config.ts b/packages/core/src/config.ts index 05742f6f1..6b29e5691 100644 --- a/packages/core/src/config.ts +++ b/packages/core/src/config.ts @@ -1,5 +1,4 @@ import fs from 'node:fs'; - import path, { dirname, isAbsolute, join } from 'node:path'; import { type RsbuildConfig, @@ -8,6 +7,7 @@ import { mergeRsbuildConfig, } from '@rsbuild/core'; import glob from 'fast-glob'; +import { pluginDts } from 'rsbuild-plugin-dts'; import { DEFAULT_CONFIG_NAME, DEFAULT_EXTENSIONS } from './constant'; import type { Format, @@ -294,6 +294,27 @@ const getBundleConfig = (bundle = true): RsbuildConfig => { }; }; +const getDefaultDtsConfig = ( + libConfig: LibConfig, + entryConfig: RsbuildConfig, +): RsbuildConfig => { + const { dts, bundle, output } = libConfig; + + if (dts === false || dts === undefined) return {}; + + return { + plugins: [ + pluginDts({ + bundle: dts?.bundle ?? bundle, + distPath: dts?.distPath ?? output?.distPath?.root ?? './dist', + tsconfigPath: dts?.tsconfigPath, + // TODO: temporarily use main as dts entry + entryPath: entryConfig.source?.entry?.main as string, + }), + ], + }; +}; + export function convertLibConfigToRsbuildConfig( libConfig: LibConfig, configPath: string, @@ -332,7 +353,13 @@ async function postUpdateRsbuildConfig( dirname(configPath), ); - return mergeRsbuildConfig(defaultTargetConfig, defaultEntryConfig); + const defaultDtsConfig = getDefaultDtsConfig(libConfig, defaultEntryConfig); + + return mergeRsbuildConfig( + defaultTargetConfig, + defaultEntryConfig, + defaultDtsConfig, + ); } const getDefaultTargetConfig = (target: string): RsbuildConfig => { diff --git a/packages/core/src/types/config/index.ts b/packages/core/src/types/config/index.ts index b57a89d7e..7451ef723 100644 --- a/packages/core/src/types/config/index.ts +++ b/packages/core/src/types/config/index.ts @@ -23,6 +23,14 @@ export type Syntax = // Support inline browserslist query, like defined in package.json | string[]; +export type Dts = + | { + bundle: boolean; + distPath?: string; + tsconfigPath?: string; + } + | false; + export interface LibConfig extends RsbuildConfig { bundle?: boolean; format?: Format; @@ -31,6 +39,7 @@ export interface LibConfig extends RsbuildConfig { /** Support esX and browserslist query */ syntax?: Syntax; }; + dts?: Dts; } export interface RslibConfig extends RsbuildConfig { diff --git a/packages/core/tests/helper.test.ts b/packages/core/tests/helper.test.ts index f01c1dab7..711238536 100644 --- a/packages/core/tests/helper.test.ts +++ b/packages/core/tests/helper.test.ts @@ -1,4 +1,3 @@ -import { join } from 'node:path'; import { describe, expect, it } from 'vitest'; import { calcLongestCommonPath } from '../src/utils/helper'; diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json index 7cdecd6eb..b0fa3dfa3 100644 --- a/packages/core/tsconfig.json +++ b/packages/core/tsconfig.json @@ -15,5 +15,10 @@ } }, "include": ["src"], - "exclude": ["**/node_modules"] + "exclude": ["**/node_modules"], + "references": [ + { + "path": "../plugin-dts" + } + ] } diff --git a/packages/plugin-dts/modern.config.ts b/packages/plugin-dts/modern.config.ts new file mode 100644 index 000000000..e51db3d49 --- /dev/null +++ b/packages/plugin-dts/modern.config.ts @@ -0,0 +1,38 @@ +import { defineConfig, moduleTools } from '@modern-js/module-tools'; + +const externals = ['@rsbuild/core', /[\\/]compiled[\\/]/, /node:/]; +const define = { + RSLIB_VERSION: require('../core/package.json').version, +}; + +export default defineConfig({ + plugins: [moduleTools()], + buildConfig: [ + { + format: 'cjs', + target: 'es2020', + buildType: 'bundleless', + autoExtension: true, + externals, + dts: false, + shims: true, + define, + }, + { + format: 'esm', + target: 'es2020', + buildType: 'bundleless', + autoExtension: true, + externals, + dts: false, + shims: true, + define, + }, + { + buildType: 'bundleless', + dts: { + only: true, + }, + }, + ], +}); diff --git a/packages/plugin-dts/package.json b/packages/plugin-dts/package.json new file mode 100644 index 000000000..56426defe --- /dev/null +++ b/packages/plugin-dts/package.json @@ -0,0 +1,56 @@ +{ + "name": "rsbuild-plugin-dts", + "version": "0.0.0", + "description": "Dts plugin for Rsbuild", + "homepage": "https://rslib.dev", + "bugs": { + "url": "https://github.com/web-infra-dev/rslib/issues" + }, + "repository": { + "type": "git", + "url": "https://github.com/web-infra-dev/rslib", + "directory": "packages/plugin-dts" + }, + "license": "MIT", + "type": "module", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "require": "./dist/index.cjs" + } + }, + "main": "./dist/index.cjs", + "types": "./dist/index.d.ts", + "files": [ + "dist" + ], + "scripts": { + "build": "modern build", + "dev": "modern build --watch" + }, + "devDependencies": { + "@microsoft/api-extractor": "^7.47.4", + "@rsbuild/core": "1.0.1-beta.8", + "@rslib/tsconfig": "workspace:*", + "typescript": "^5.5.3" + }, + "peerDependencies": { + "@microsoft/api-extractor": "^7", + "@rsbuild/core": "workspace:^1.0.1-beta.0", + "typescript": "^5" + }, + "peerDependenciesMeta": { + "@microsoft/api-extractor": { + "optional": true + } + }, + "engines": { + "node": ">=16.0.0" + }, + "publishConfig": { + "access": "public", + "provenance": true, + "registry": "https://registry.npmjs.org/" + } +} diff --git a/packages/plugin-dts/src/apiExtractor.ts b/packages/plugin-dts/src/apiExtractor.ts new file mode 100644 index 000000000..3a53628c5 --- /dev/null +++ b/packages/plugin-dts/src/apiExtractor.ts @@ -0,0 +1,55 @@ +import { join, relative } from 'node:path'; +import { + Extractor, + ExtractorConfig, + type ExtractorResult, +} from '@microsoft/api-extractor'; +import { logger } from '@rsbuild/core'; + +export type BundleOptions = { + cwd: string; + outDir: string; + entry?: string; + tsconfigPath?: string; +}; + +export function bundleDts(options: BundleOptions) { + const { + cwd, + outDir, + entry = 'index.d.ts', + tsconfigPath = 'tsconfig.json', + } = options; + const untrimmedFilePath = join(cwd, relative(cwd, outDir), 'index.d.ts'); + const internalConfig = { + mainEntryPointFilePath: entry, + // TODO: use !externals + // bundledPackages: [], + dtsRollup: { + enabled: true, + untrimmedFilePath, + }, + compiler: { + tsconfigFilePath: join(cwd, tsconfigPath), + }, + projectFolder: cwd, + }; + + const extractorConfig = ExtractorConfig.prepare({ + configObject: internalConfig, + configObjectFullPath: undefined, + packageJsonFullPath: join(cwd, 'package.json'), + }); + + const extractorResult: ExtractorResult = Extractor.invoke(extractorConfig, { + localBuild: true, + }); + + if (!extractorResult.succeeded) { + throw new Error('API Extractor rollup error'); + } + + logger.info( + `API Extractor writing package typings succeeded: ${untrimmedFilePath}`, + ); +} diff --git a/packages/plugin-dts/src/dts.ts b/packages/plugin-dts/src/dts.ts new file mode 100644 index 000000000..013591e7c --- /dev/null +++ b/packages/plugin-dts/src/dts.ts @@ -0,0 +1,95 @@ +import { basename, dirname, join, relative } from 'node:path'; +import { logger } from '@rsbuild/core'; +import type { DtsGenOptions } from 'src'; +import * as ts from 'typescript'; +import { emitDts } from './tsc'; +import { ensureTempDeclarationDir, loadTsconfig } from './utils'; + +export async function generateDts(data: DtsGenOptions) { + logger.info('Generating DTS...'); + const { options: pluginOptions, isWatch } = data; + const { tsconfigPath, distPath, bundle, entryPath } = pluginOptions; + const cwd = process.cwd(); + const configPath = ts.findConfigFile(cwd, ts.sys.fileExists, tsconfigPath); + if (!configPath) { + logger.error(`tsconfig.json not found in ${cwd}`); + throw new Error(); + } + const { options: rawCompilerOptions } = loadTsconfig(configPath); + const rootDir = rawCompilerOptions.rootDir ?? 'src'; + const outDir = distPath + ? distPath + : rawCompilerOptions.declarationDir || './dist'; + + const getDeclarationDir = (bundle: boolean, distPath?: string) => { + if (bundle) { + return ensureTempDeclarationDir(); + } + return distPath ? distPath : rawCompilerOptions.declarationDir ?? './dist'; + }; + + const declarationDir = getDeclarationDir(bundle, distPath); + let entry = ''; + + if (bundle === true && entryPath) { + const entrySourcePath = join(cwd, entryPath); + const relativePath = relative(rootDir, dirname(entrySourcePath)); + entry = join( + declarationDir!, + relativePath, + basename(entrySourcePath), + ).replace(/\.(m?js|jsx?|m?ts|tsx?|c?js)$/, '.d.ts'); + } + + const bundleDtsIfNeeded = async () => { + if (bundle === true) { + const { bundleDts } = await import('./apiExtractor'); + bundleDts({ + cwd, + outDir, + entry, + tsconfigPath, + }); + } + }; + + const onComplete = async (isSuccess: boolean) => { + if (isSuccess) { + await bundleDtsIfNeeded(); + } + }; + + emitDts( + { + cwd, + configPath, + rootDir, + declarationDir, + }, + onComplete, + isWatch, + ); + + if (!isWatch) { + await bundleDtsIfNeeded(); + } +} + +process.on('message', async (data: DtsGenOptions) => { + if (!data.options) { + return; + } + + try { + await generateDts(data); + } catch (e) { + process.send!('error'); + process.exit(1); + } + + process.send!('success'); + + if (!data.isWatch) { + process.exit(); + } +}); diff --git a/packages/plugin-dts/src/index.ts b/packages/plugin-dts/src/index.ts new file mode 100644 index 000000000..db6fcdee6 --- /dev/null +++ b/packages/plugin-dts/src/index.ts @@ -0,0 +1,67 @@ +import { fork } from 'node:child_process'; +import { extname, join } from 'node:path'; +import type { RsbuildPlugin } from '@rsbuild/core'; + +export type pluginDtsOptions = { + bundle: boolean; + distPath?: string; + tsconfigPath?: string; + entryPath?: string; +}; + +export type DtsGenOptions = { + options: pluginDtsOptions; + isWatch: boolean; +}; + +export const PLUGIN_DTS_NAME = 'rsbuild:dts'; + +// use ts compiler API to generate bundleless dts +// use ts compiler API and api-extractor to generate dts bundle +// TODO: support incremental build, to build one or more projects and their dependencies +// TODO: support autoExtension for dts files +// TODO: deal alias in dts +export const pluginDts = ( + options: pluginDtsOptions = { bundle: false }, +): RsbuildPlugin => ({ + name: PLUGIN_DTS_NAME, + + setup(api) { + const config = api.getRsbuildConfig(); + + options.distPath = + options.distPath ?? config.output?.distPath?.root ?? 'dist'; + + const dtsPromises: Promise[] = []; + + api.onBeforeBuild(({ isWatch }) => { + const jsExtension = extname(__filename); + const childProcess = fork(join(__dirname, `./dts${jsExtension}`), [], { + stdio: 'inherit', + }); + + const sendData = { + options, + isWatch, + }; + + childProcess.send(sendData); + + dtsPromises.push( + new Promise((resolve, reject) => { + childProcess.on('message', (message) => { + if (message === 'success') { + resolve(); + } else if (message === 'error') { + reject(new Error('Error occurred in dts generation')); + } + }); + }), + ); + }); + + api.onAfterBuild(async () => { + await Promise.all(dtsPromises); + }); + }, +}); diff --git a/packages/plugin-dts/src/tsc.ts b/packages/plugin-dts/src/tsc.ts new file mode 100644 index 000000000..fc718e4ed --- /dev/null +++ b/packages/plugin-dts/src/tsc.ts @@ -0,0 +1,131 @@ +import { logger } from '@rsbuild/core'; +import * as ts from 'typescript'; +import { getFileLoc, loadTsconfig } from './utils'; + +export type emitDtsOptions = { + cwd: string; + configPath: string; + rootDir: string; + declarationDir: string; +}; + +export function emitDts( + options: emitDtsOptions, + onComplete: (isSuccess: boolean) => void, + isWatch = false, +) { + const { configPath, declarationDir } = options; + const { options: rawCompilerOptions, fileNames } = loadTsconfig(configPath); + + const compilerOptions = { + ...rawCompilerOptions, + noEmit: false, + declaration: true, + declarationDir, + emitDeclarationOnly: true, + }; + + if (!isWatch) { + const host: ts.CompilerHost = ts.createCompilerHost(compilerOptions); + + const program: ts.Program = ts.createProgram( + fileNames, + compilerOptions, + host, + ); + + const emitResult = program.emit(); + + const allDiagnostics = ts + .getPreEmitDiagnostics(program) + .concat(emitResult.diagnostics); + + const diagnosticMessages: string[] = []; + + for (const diagnostic of allDiagnostics) { + const fileLoc = getFileLoc(diagnostic); + const message = `${fileLoc} error TS${diagnostic.code}: ${ts.flattenDiagnosticMessageText( + diagnostic.messageText, + host.getNewLine(), + )}`; + diagnosticMessages.push(message); + } + + if (diagnosticMessages.length) { + logger.error('Failed to emit declaration files.'); + + for (const message of diagnosticMessages) { + logger.error(message); + } + + throw new Error('TypeScript compilation failed'); + } + + logger.info('TypeScript compilation succeeded\n'); + } else { + const createProgram = ts.createSemanticDiagnosticsBuilderProgram; + const formatHost: ts.FormatDiagnosticsHost = { + getCanonicalFileName: (path) => path, + getCurrentDirectory: ts.sys.getCurrentDirectory, + getNewLine: () => ts.sys.newLine, + }; + + const reportDiagnostic = (diagnostic: ts.Diagnostic) => { + const fileLoc = getFileLoc(diagnostic); + + logger.error( + `${fileLoc} error TS${diagnostic.code}:`, + ts.flattenDiagnosticMessageText( + diagnostic.messageText, + formatHost.getNewLine(), + ), + ); + }; + + const reportWatchStatusChanged: ts.WatchStatusReporter = ( + diagnostic: ts.Diagnostic, + _newLine: string, + _options: ts.CompilerOptions, + errorCount?: number, + ) => { + const message = ts.flattenDiagnosticMessageText( + diagnostic.messageText, + formatHost.getNewLine(), + ); + + // 6031: File change detected. Starting incremental compilation... + // 6032: Starting compilation in watch mode... + if (diagnostic.code === 6031 || diagnostic.code === 6032) { + logger.info(message); + } + + // 6194: 0 errors or 2+ errors! + if (diagnostic.code === 6194) { + if (errorCount === 0) { + logger.info(message); + onComplete(true); + } else { + logger.error(message); + } + } + + // 6193: 1 error + if (diagnostic.code === 6193) { + logger.error(message); + } + }; + + const system = { ...ts.sys }; + + const host = ts.createWatchCompilerHost( + configPath, + compilerOptions, + system, + createProgram, + reportDiagnostic, + reportWatchStatusChanged, + ); + + ts.createWatchProgram(host); + } +} diff --git a/packages/plugin-dts/src/utils.ts b/packages/plugin-dts/src/utils.ts new file mode 100644 index 000000000..547fcca25 --- /dev/null +++ b/packages/plugin-dts/src/utils.ts @@ -0,0 +1,45 @@ +import fs, { writeFileSync } from 'node:fs'; +import path from 'node:path'; +import * as ts from 'typescript'; + +export function loadTsconfig(tsconfigPath: string): ts.ParsedCommandLine { + const configFile = ts.readConfigFile(tsconfigPath, ts.sys.readFile); + const configFileContent = ts.parseJsonConfigFileContent( + configFile.config, + ts.sys, + path.dirname(tsconfigPath), + ); + + return configFileContent; +} + +export const TEMP_FOLDER = '.rslib'; +export const TEMP_DTS_DIR = `${TEMP_FOLDER}/declarations`; + +export function ensureTempDeclarationDir(): string { + const cwd = process.cwd(); + const dirPath = path.join(cwd, TEMP_DTS_DIR); + + if (fs.existsSync(dirPath)) { + return dirPath; + } + + fs.mkdirSync(dirPath, { recursive: true }); + + const gitIgnorePath = path.join(cwd, `${TEMP_FOLDER}/.gitignore`); + writeFileSync(gitIgnorePath, '**/*\n'); + + return dirPath; +} + +export function getFileLoc(diagnostic: ts.Diagnostic): string { + if (diagnostic.file) { + const { line, character } = ts.getLineAndCharacterOfPosition( + diagnostic.file, + diagnostic.start!, + ); + return `${diagnostic.file.fileName}:${line + 1}:${character + 1} - `; + } + + return ''; +} diff --git a/packages/plugin-dts/tsconfig.json b/packages/plugin-dts/tsconfig.json new file mode 100644 index 000000000..6cee48b0e --- /dev/null +++ b/packages/plugin-dts/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "@rslib/tsconfig/base", + "compilerOptions": { + "outDir": "./dist", + "baseUrl": "./", + "rootDir": "src", + "declaration": true, + "composite": true, + "module": "ESNext", + "moduleResolution": "Bundler" + }, + "include": ["src"], + "exclude": ["**/node_modules"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dfbd23894..eea2e69b6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -67,8 +67,8 @@ importers: specifier: 1.43.1 version: 1.43.1 '@rsbuild/core': - specifier: 1.0.1-beta.6 - version: 1.0.1-beta.6 + specifier: 1.0.1-beta.8 + version: 1.0.1-beta.8 '@rslib/core': specifier: workspace:* version: link:../packages/core @@ -95,6 +95,8 @@ importers: e2e/cases/autoExtension/type-module: {} + e2e/cases/dts/bundle: {} + examples/basic: devDependencies: '@rslib/core': @@ -103,9 +105,15 @@ importers: packages/core: dependencies: + '@microsoft/api-extractor': + specifier: ^7 + version: 7.47.2(@types/node@18.19.39) '@rsbuild/core': - specifier: 1.0.1-beta.6 - version: 1.0.1-beta.6 + specifier: 1.0.1-beta.8 + version: 1.0.1-beta.8 + rsbuild-plugin-dts: + specifier: workspace:* + version: link:../plugin-dts devDependencies: '@rslib/tsconfig': specifier: workspace:* @@ -135,6 +143,21 @@ importers: specifier: ^5.5.3 version: 5.5.3 + packages/plugin-dts: + devDependencies: + '@microsoft/api-extractor': + specifier: ^7.47.4 + version: 7.47.4(@types/node@18.19.39) + '@rsbuild/core': + specifier: 1.0.1-beta.8 + version: 1.0.1-beta.8 + '@rslib/tsconfig': + specifier: workspace:* + version: link:../../scripts/tsconfig + typescript: + specifier: ^5.5.3 + version: 5.5.3 + scripts/tsconfig: dependencies: '@tsconfig/strictest': @@ -843,6 +866,26 @@ packages: '@manypkg/get-packages@1.1.3': resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==} + '@microsoft/api-extractor-model@7.29.3': + resolution: {integrity: sha512-kEWjLr2ygL3ku9EGyjeTnL2S5IxyH9NaF1k1UoI0Nzwr4xEJBSWCVsWuF2+0lPUrRPA6mTY95fR264SJ5ETKQA==} + + '@microsoft/api-extractor-model@7.29.4': + resolution: {integrity: sha512-LHOMxmT8/tU1IiiiHOdHFF83Qsi+V8d0kLfscG4EvQE9cafiR8blOYr8SfkQKWB1wgEilQgXJX3MIA4vetDLZw==} + + '@microsoft/api-extractor@7.47.2': + resolution: {integrity: sha512-YWE2HGrSTZaPPSr7xiNizSuViZpC7Jsa7+DwRW5rYVgrMXNbfX/PpBOoSkl5uaz9I2sv2JKLJ75kVNt64BvS3g==} + hasBin: true + + '@microsoft/api-extractor@7.47.4': + resolution: {integrity: sha512-HKm+P4VNzWwvq1Ey+Jfhhj/3MjsD+ka2hbt8L5AcRM95lu1MFOYnz3XlU7Gr79Q/ZhOb7W/imAKeYrOI0bFydg==} + hasBin: true + + '@microsoft/tsdoc-config@0.17.0': + resolution: {integrity: sha512-v/EYRXnCAIHxOHW+Plb6OWuUoMotxTN0GLatnpOb1xq0KuTNw/WI3pamJx/UbsoJP5k9MCw1QxvvhPcF9pH3Zg==} + + '@microsoft/tsdoc@0.15.0': + resolution: {integrity: sha512-HZpPoABogPvjeJOdzCOSJsXeL/SMCBgBZMVC3X3d7YYp2gf31MfxhUoYUNwf1ERPJOnQc0wkFn9trqI6ZEdZuA==} + '@modern-js/core@2.55.0': resolution: {integrity: sha512-eXvJux+mhWJBOCvrqXXbW6ZWbU8+G/5QbmOAF9JFa5ifOpFK92b5lbNBTKFCo7C37i+bTcBmSuhckVzX1Bd5yg==} @@ -1120,8 +1163,8 @@ packages: cpu: [x64] os: [win32] - '@rsbuild/core@1.0.1-beta.6': - resolution: {integrity: sha512-854VVEnOpfit4ZRUS/2aJrsa2h+crZ+MPucYLTDh1Z4H85cnk1DjNiSwRGXERD6MzfnejJALy9/+MW01LFVsQw==} + '@rsbuild/core@1.0.1-beta.8': + resolution: {integrity: sha512-SERxv+2eyS6ihZZ+QqhFaMXVkf3cTNdn2H58AyHLxrx9+T/1DZP2LRLWAcbfgjr8lNTkv9nWcxk0d97pPThLGg==} engines: {node: '>=16.7.0'} hasBin: true @@ -1186,10 +1229,54 @@ packages: resolution: {integrity: sha512-rTGAkDCbq7pyVV2BhkYx0xgK65XEhv4VAkZB5HBhbs2HeB2qkP0yT8NZEgkAtMg5R6Q54dndeZGLFboqYtlF5w==} engines: {node: '>=16.0.0'} - '@rspack/lite-tapable@1.0.0-beta.0': - resolution: {integrity: sha512-EpCgqeLMk2TGahj+UbK5R/2gmPQqR6j6VKRqV0NDIRK5vHeSbVebOIMtDd0Zak0imO9ajbZjbYAg7ZvWVEUnYw==} + '@rspack/lite-tapable@1.0.0-beta.1': + resolution: {integrity: sha512-r4xtbJp6QhW6A1twkgTP0UQkPC9cOT3sFjjjlx22j/q669HJRz+CVTlVcNxPomK7Q3Kg6dVsyv16MjGRl/fl5g==} engines: {node: '>=16.0.0'} + '@rushstack/node-core-library@5.5.0': + resolution: {integrity: sha512-Cl3MYQ74Je5Y/EngMxcA3SpHjGZ/022nKbAO1aycGfQ+7eKyNCBu0oywj5B1f367GCzuHBgy+3BlVLKysHkXZw==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + + '@rushstack/node-core-library@5.5.1': + resolution: {integrity: sha512-ZutW56qIzH8xIOlfyaLQJFx+8IBqdbVCZdnj+XT1MorQ1JqqxHse8vbCpEM+2MjsrqcbxcgDIbfggB1ZSQ2A3g==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + + '@rushstack/rig-package@0.5.2': + resolution: {integrity: sha512-mUDecIJeH3yYGZs2a48k+pbhM6JYwWlgjs2Ca5f2n1G2/kgdgP9D/07oglEGf6mRyXEnazhEENeYTSNDRCwdqA==} + + '@rushstack/rig-package@0.5.3': + resolution: {integrity: sha512-olzSSjYrvCNxUFZowevC3uz8gvKr3WTpHQ7BkpjtRpA3wK+T0ybep/SRUMfr195gBzJm5gaXw0ZMgjIyHqJUow==} + + '@rushstack/terminal@0.13.2': + resolution: {integrity: sha512-t8i0PsGvBHmFBY8pryO3badqFlxQsm2rw3KYrzjcmVkG/WGklKg1qVkr9beAS1Oe8XWDRgj6SkoHkpNjs7aaNw==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + + '@rushstack/terminal@0.13.3': + resolution: {integrity: sha512-fc3zjXOw8E0pXS5t9vTiIPx9gHA0fIdTXsu9mT4WbH+P3mYvnrX0iAQ5a6NvyK1+CqYWBTw/wVNx7SDJkI+WYQ==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + + '@rushstack/ts-command-line@4.22.2': + resolution: {integrity: sha512-xkvrGd6D9dPlI3I401Thc640WNsEPB1sGEmy12a2VJaPQPwhE6Ik0gEVPZJ/2G1w213eaCAdxUY1xpiTulsmpA==} + + '@rushstack/ts-command-line@4.22.3': + resolution: {integrity: sha512-edMpWB3QhFFZ4KtSzS8WNjBgR4PXPPOVrOHMbb7kNpmQ1UFS9HdVtjCXg1H5fG+xYAbeE+TMPcVPUyX2p84STA==} + '@sinclair/typebox@0.27.8': resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} @@ -1202,6 +1289,9 @@ packages: '@tsconfig/strictest@2.0.5': resolution: {integrity: sha512-ec4tjL2Rr0pkZ5hww65c+EEPYwxOi4Ryv+0MtjeaSQRJyq322Q27eOQiFbuNgw2hpL4hB1/W/HBGk3VKS43osg==} + '@types/argparse@1.0.38': + resolution: {integrity: sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==} + '@types/estree@1.0.5': resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} @@ -1267,6 +1357,28 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + ajv-draft-04@1.0.0: + resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==} + peerDependencies: + ajv: ^8.5.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv@8.12.0: + resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} + + ajv@8.13.0: + resolution: {integrity: sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==} + ajv@8.16.0: resolution: {integrity: sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==} @@ -1680,6 +1792,9 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + generic-names@4.0.0: resolution: {integrity: sha512-ySFolZQfw9FoDb3ed9d80Cm9f0+r7qj+HJkWjeD9RBfpxEVTlVhol+gvaQB/78WbwYfbnNh8nWHHBSlg072y6A==} @@ -1736,6 +1851,10 @@ packages: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + human-id@1.0.2: resolution: {integrity: sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==} @@ -1768,6 +1887,10 @@ packages: resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} engines: {node: '>= 4'} + import-lazy@4.0.0: + resolution: {integrity: sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==} + engines: {node: '>=8'} + inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. @@ -1775,6 +1898,10 @@ packages: inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + is-core-module@2.15.0: + resolution: {integrity: sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==} + engines: {node: '>= 0.4'} + is-docker@2.2.1: resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} engines: {node: '>=8'} @@ -1850,6 +1977,9 @@ packages: resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jju@1.4.0: + resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -1935,6 +2065,10 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + magic-string@0.30.10: resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==} @@ -1969,6 +2103,9 @@ packages: resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} engines: {node: '>=12'} + minimatch@3.0.8: + resolution: {integrity: sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==} + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -2099,6 +2236,9 @@ packages: resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} engines: {node: '>=12'} + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} @@ -2255,6 +2395,10 @@ packages: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} + resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + restore-cursor@3.1.0: resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} engines: {node: '>=8'} @@ -2298,6 +2442,11 @@ packages: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true + semver@7.5.4: + resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} + engines: {node: '>=10'} + hasBin: true + semver@7.6.2: resolution: {integrity: sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==} engines: {node: '>=10'} @@ -2383,6 +2532,10 @@ packages: std-env@3.7.0: resolution: {integrity: sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==} + string-argv@0.3.2: + resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} + engines: {node: '>=0.6.19'} + string-hash@1.1.3: resolution: {integrity: sha512-kJUvRUFK49aub+a7T1nNE66EJbZBMnBgoC1UbCZ5n6bsZKBRga4KgBRTMn/pFkeCZSYtNeSyMxPDM0AXWELk2A==} @@ -2405,6 +2558,10 @@ packages: resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} engines: {node: '>=12'} + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + strong-log-transformer@2.1.0: resolution: {integrity: sha512-B3Hgul+z0L9a236FAUC9iZsL+nVHgoCJnqCbN588DjYxvGXaXaaFbfmQ/JhvKjZwsOukuR72XbHv71Qkug0HxA==} engines: {node: '>=4'} @@ -2426,6 +2583,14 @@ packages: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + synckit@0.9.0: resolution: {integrity: sha512-7RnqIMq572L8PeEzKeBINYEJDDxpcH8JEgLwUqBd3TkofhFRbkq4QLR0u+36avGAhCRbk2nnmjcW9SE531hPDg==} engines: {node: ^14.18.0 || >=16.0.0} @@ -2510,6 +2675,11 @@ packages: resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==} engines: {node: '>=14.16'} + typescript@5.4.2: + resolution: {integrity: sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==} + engines: {node: '>=14.17'} + hasBin: true + typescript@5.5.3: resolution: {integrity: sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==} engines: {node: '>=14.17'} @@ -2637,6 +2807,9 @@ packages: yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} @@ -3294,6 +3467,67 @@ snapshots: globby: 11.1.0 read-yaml-file: 1.1.0 + '@microsoft/api-extractor-model@7.29.3(@types/node@18.19.39)': + dependencies: + '@microsoft/tsdoc': 0.15.0 + '@microsoft/tsdoc-config': 0.17.0 + '@rushstack/node-core-library': 5.5.0(@types/node@18.19.39) + transitivePeerDependencies: + - '@types/node' + + '@microsoft/api-extractor-model@7.29.4(@types/node@18.19.39)': + dependencies: + '@microsoft/tsdoc': 0.15.0 + '@microsoft/tsdoc-config': 0.17.0 + '@rushstack/node-core-library': 5.5.1(@types/node@18.19.39) + transitivePeerDependencies: + - '@types/node' + + '@microsoft/api-extractor@7.47.2(@types/node@18.19.39)': + dependencies: + '@microsoft/api-extractor-model': 7.29.3(@types/node@18.19.39) + '@microsoft/tsdoc': 0.15.0 + '@microsoft/tsdoc-config': 0.17.0 + '@rushstack/node-core-library': 5.5.0(@types/node@18.19.39) + '@rushstack/rig-package': 0.5.2 + '@rushstack/terminal': 0.13.2(@types/node@18.19.39) + '@rushstack/ts-command-line': 4.22.2(@types/node@18.19.39) + lodash: 4.17.21 + minimatch: 3.0.8 + resolve: 1.22.8 + semver: 7.5.4 + source-map: 0.6.1 + typescript: 5.4.2 + transitivePeerDependencies: + - '@types/node' + + '@microsoft/api-extractor@7.47.4(@types/node@18.19.39)': + dependencies: + '@microsoft/api-extractor-model': 7.29.4(@types/node@18.19.39) + '@microsoft/tsdoc': 0.15.0 + '@microsoft/tsdoc-config': 0.17.0 + '@rushstack/node-core-library': 5.5.1(@types/node@18.19.39) + '@rushstack/rig-package': 0.5.3 + '@rushstack/terminal': 0.13.3(@types/node@18.19.39) + '@rushstack/ts-command-line': 4.22.3(@types/node@18.19.39) + lodash: 4.17.21 + minimatch: 3.0.8 + resolve: 1.22.8 + semver: 7.5.4 + source-map: 0.6.1 + typescript: 5.4.2 + transitivePeerDependencies: + - '@types/node' + + '@microsoft/tsdoc-config@0.17.0': + dependencies: + '@microsoft/tsdoc': 0.15.0 + ajv: 8.12.0 + jju: 1.4.0 + resolve: 1.22.8 + + '@microsoft/tsdoc@0.15.0': {} + '@modern-js/core@2.55.0': dependencies: '@modern-js/node-bundle-require': 2.55.0 @@ -3548,14 +3782,13 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.18.1': optional: true - '@rsbuild/core@1.0.1-beta.6': + '@rsbuild/core@1.0.1-beta.8': dependencies: '@rspack/core': '@rspack/core-canary@1.0.0-canary-d77b591-20240718094414(@swc/helpers@0.5.11)' - '@rspack/lite-tapable': 1.0.0-beta.0 + '@rspack/lite-tapable': 1.0.0-beta.1 '@swc/helpers': 0.5.11 caniuse-lite: 1.0.30001643 core-js: 3.37.1 - postcss: 8.4.39 optionalDependencies: fsevents: 2.3.3 @@ -3609,7 +3842,75 @@ snapshots: '@rspack/lite-tapable-canary@1.0.0-canary-d77b591-20240718094414': {} - '@rspack/lite-tapable@1.0.0-beta.0': {} + '@rspack/lite-tapable@1.0.0-beta.1': {} + + '@rushstack/node-core-library@5.5.0(@types/node@18.19.39)': + dependencies: + ajv: 8.13.0 + ajv-draft-04: 1.0.0(ajv@8.13.0) + ajv-formats: 3.0.1(ajv@8.13.0) + fs-extra: 7.0.1 + import-lazy: 4.0.0 + jju: 1.4.0 + resolve: 1.22.8 + semver: 7.5.4 + optionalDependencies: + '@types/node': 18.19.39 + + '@rushstack/node-core-library@5.5.1(@types/node@18.19.39)': + dependencies: + ajv: 8.13.0 + ajv-draft-04: 1.0.0(ajv@8.13.0) + ajv-formats: 3.0.1(ajv@8.13.0) + fs-extra: 7.0.1 + import-lazy: 4.0.0 + jju: 1.4.0 + resolve: 1.22.8 + semver: 7.5.4 + optionalDependencies: + '@types/node': 18.19.39 + + '@rushstack/rig-package@0.5.2': + dependencies: + resolve: 1.22.8 + strip-json-comments: 3.1.1 + + '@rushstack/rig-package@0.5.3': + dependencies: + resolve: 1.22.8 + strip-json-comments: 3.1.1 + + '@rushstack/terminal@0.13.2(@types/node@18.19.39)': + dependencies: + '@rushstack/node-core-library': 5.5.0(@types/node@18.19.39) + supports-color: 8.1.1 + optionalDependencies: + '@types/node': 18.19.39 + + '@rushstack/terminal@0.13.3(@types/node@18.19.39)': + dependencies: + '@rushstack/node-core-library': 5.5.1(@types/node@18.19.39) + supports-color: 8.1.1 + optionalDependencies: + '@types/node': 18.19.39 + + '@rushstack/ts-command-line@4.22.2(@types/node@18.19.39)': + dependencies: + '@rushstack/terminal': 0.13.2(@types/node@18.19.39) + '@types/argparse': 1.0.38 + argparse: 1.0.10 + string-argv: 0.3.2 + transitivePeerDependencies: + - '@types/node' + + '@rushstack/ts-command-line@4.22.3(@types/node@18.19.39)': + dependencies: + '@rushstack/terminal': 0.13.3(@types/node@18.19.39) + '@types/argparse': 1.0.38 + argparse: 1.0.10 + string-argv: 0.3.2 + transitivePeerDependencies: + - '@types/node' '@sinclair/typebox@0.27.8': {} @@ -3623,6 +3924,8 @@ snapshots: '@tsconfig/strictest@2.0.5': {} + '@types/argparse@1.0.38': {} + '@types/estree@1.0.5': {} '@types/fs-extra@11.0.4': @@ -3699,6 +4002,28 @@ snapshots: acorn@8.12.1: {} + ajv-draft-04@1.0.0(ajv@8.13.0): + optionalDependencies: + ajv: 8.13.0 + + ajv-formats@3.0.1(ajv@8.13.0): + optionalDependencies: + ajv: 8.13.0 + + ajv@8.12.0: + dependencies: + fast-deep-equal: 3.1.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + uri-js: 4.4.1 + + ajv@8.13.0: + dependencies: + fast-deep-equal: 3.1.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + uri-js: 4.4.1 + ajv@8.16.0: dependencies: fast-deep-equal: 3.1.3 @@ -4153,6 +4478,8 @@ snapshots: fsevents@2.3.3: optional: true + function-bind@1.1.2: {} + generic-names@4.0.0: dependencies: loader-utils: 3.3.1 @@ -4207,6 +4534,10 @@ snapshots: has-flag@4.0.0: {} + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + human-id@1.0.2: {} human-signals@5.0.0: {} @@ -4227,6 +4558,8 @@ snapshots: ignore@5.3.1: {} + import-lazy@4.0.0: {} + inflight@1.0.6: dependencies: once: 1.4.0 @@ -4234,6 +4567,10 @@ snapshots: inherits@2.0.4: {} + is-core-module@2.15.0: + dependencies: + hasown: 2.0.2 + is-docker@2.2.1: {} is-extglob@2.1.1: {} @@ -4285,6 +4622,8 @@ snapshots: jest-get-type@29.6.3: {} + jju@1.4.0: {} + js-tokens@4.0.0: {} js-yaml@3.14.1: @@ -4365,6 +4704,10 @@ snapshots: dependencies: yallist: 3.1.1 + lru-cache@6.0.0: + dependencies: + yallist: 4.0.0 + magic-string@0.30.10: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 @@ -4392,6 +4735,10 @@ snapshots: mimic-fn@4.0.0: {} + minimatch@3.0.8: + dependencies: + brace-expansion: 1.1.11 + minimatch@3.1.2: dependencies: brace-expansion: 1.1.11 @@ -4547,6 +4894,8 @@ snapshots: path-key@4.0.0: {} + path-parse@1.0.7: {} + path-type@4.0.0: {} pathe@1.1.2: {} @@ -4690,6 +5039,12 @@ snapshots: resolve-from@5.0.0: {} + resolve@1.22.8: + dependencies: + is-core-module: 2.15.0 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + restore-cursor@3.1.0: dependencies: onetime: 5.1.2 @@ -4743,6 +5098,10 @@ snapshots: semver@6.3.1: {} + semver@7.5.4: + dependencies: + lru-cache: 6.0.0 + semver@7.6.2: {} set-value@4.1.0: @@ -4815,6 +5174,8 @@ snapshots: std-env@3.7.0: {} + string-argv@0.3.2: {} + string-hash@1.1.3: {} string-width@4.2.3: @@ -4835,6 +5196,8 @@ snapshots: strip-final-newline@3.0.0: {} + strip-json-comments@3.1.1: {} + strong-log-transformer@2.1.0: dependencies: duplexer: 0.1.2 @@ -4860,6 +5223,12 @@ snapshots: dependencies: has-flag: 4.0.0 + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + synckit@0.9.0: dependencies: '@pkgr/core': 0.1.1 @@ -4940,6 +5309,8 @@ snapshots: type-fest@3.13.1: {} + typescript@5.4.2: {} + typescript@5.5.3: {} undici-types@5.26.5: {} @@ -5057,6 +5428,8 @@ snapshots: yallist@3.1.1: {} + yallist@4.0.0: {} + yargs-parser@21.1.1: {} yargs@17.7.2: