From 98552d5c3c8f96ddbe976d4f305ca288b1b79f1f Mon Sep 17 00:00:00 2001 From: Zack Jackson <25274700+ScriptedAlchemy@users.noreply.github.com> Date: Thu, 13 Aug 2026 01:51:05 +0000 Subject: [PATCH 01/33] docs: improve generated llms.txt summaries (#335) --- website/docs/en/guide/cli/doc.mdx | 4 ++++ website/docs/en/guide/formatting.mdx | 4 ++++ website/docs/zh/guide/cli/doc.mdx | 4 ++++ website/docs/zh/guide/formatting.mdx | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/website/docs/en/guide/cli/doc.mdx b/website/docs/en/guide/cli/doc.mdx index 08877b45..fb6494af 100644 --- a/website/docs/en/guide/cli/doc.mdx +++ b/website/docs/en/guide/cli/doc.mdx @@ -1,3 +1,7 @@ +--- +description: 'Develop, build, and preview Rspress documentation sites with the rs doc command.' +--- + # doc import { PackageManagerTabs } from '@rspress/core/theme'; diff --git a/website/docs/en/guide/formatting.mdx b/website/docs/en/guide/formatting.mdx index a6c60054..9090f666 100644 --- a/website/docs/en/guide/formatting.mdx +++ b/website/docs/en/guide/formatting.mdx @@ -1,3 +1,7 @@ +--- +description: 'Format files with Rstack CLI using Prettier-compatible options, plugins, parallel formatting, and a persistent cache.' +--- + # Formatting import { PackageManagerTabs } from '@rspress/core/theme'; diff --git a/website/docs/zh/guide/cli/doc.mdx b/website/docs/zh/guide/cli/doc.mdx index 647184de..cfe4c138 100644 --- a/website/docs/zh/guide/cli/doc.mdx +++ b/website/docs/zh/guide/cli/doc.mdx @@ -1,3 +1,7 @@ +--- +description: '使用 rs doc 命令开发、构建和预览 Rspress 文档站点。' +--- + # doc import { PackageManagerTabs } from '@rspress/core/theme'; diff --git a/website/docs/zh/guide/formatting.mdx b/website/docs/zh/guide/formatting.mdx index 8659e673..7f2f8b7b 100644 --- a/website/docs/zh/guide/formatting.mdx +++ b/website/docs/zh/guide/formatting.mdx @@ -1,3 +1,7 @@ +--- +description: '使用 Rstack CLI 格式化文件,支持与 Prettier 兼容的选项、插件、并行格式化和持久化缓存。' +--- + # 格式化 \{#formatting} import { PackageManagerTabs } from '@rspress/core/theme'; From b6e8661f65942871ef8ea38e0d7c74062a67c92f Mon Sep 17 00:00:00 2001 From: Jiahan Chen Date: Thu, 13 Aug 2026 10:02:34 +0800 Subject: [PATCH 02/33] refactor(fmt): centralize per-file resolution (#334) --- packages/rstack/src/fmt/discovery.ts | 42 ++----------- packages/rstack/src/fmt/fileResolver.ts | 28 +++++++++ packages/rstack/src/fmt/lsp/server.ts | 20 ++----- packages/rstack/src/fmt/stdin.ts | 12 +--- packages/rstack/tests/fmt/discovery.test.ts | 54 ----------------- .../rstack/tests/fmt/fileResolver.test.ts | 59 +++++++++++++++++++ 6 files changed, 97 insertions(+), 118 deletions(-) create mode 100644 packages/rstack/src/fmt/fileResolver.ts create mode 100644 packages/rstack/tests/fmt/fileResolver.test.ts diff --git a/packages/rstack/src/fmt/discovery.ts b/packages/rstack/src/fmt/discovery.ts index 6eca1d83..cf1c3472 100644 --- a/packages/rstack/src/fmt/discovery.ts +++ b/packages/rstack/src/fmt/discovery.ts @@ -1,38 +1,9 @@ import path from 'node:path'; -import { createOptionsResolver, type FmtOptionsResolver } from './config.ts'; import { discoverFmtPaths } from './discoverPaths.ts'; +import { createFmtFileResolver } from './fileResolver.ts'; import { createIgnoreMatcher } from './ignore.ts'; -import type { FmtPluginResolver } from './plugins.ts'; import type { DiscoverFmtFilesOptions, FmtFileRequest } from './types.ts'; -const createFileRequest = ( - filePath: string, - resolveOptions: FmtOptionsResolver, -): FmtFileRequest => ({ - path: filePath, - options: resolveOptions(filePath), -}); - -/** Imports the plugin chunk on first use and shares the resolver across calls. */ -const createLazyPluginResolver = (rootPath: string): (() => Promise) => { - let resolver: Promise | undefined; - - return () => - (resolver ??= import( - /* rspackChunkName: 'fmtPlugins' */ - './plugins.ts' - ).then(({ createPluginResolver }) => createPluginResolver(rootPath))); -}; - -/** Resolves the plugin specifiers of a request whose options configure plugins. */ -const resolveFileRequestPlugins = async ( - file: FmtFileRequest, - getPluginResolver: () => Promise, -): Promise => - file.options.plugins?.length - ? { ...file, options: (await getPluginResolver())(file.options) } - : file; - const createDirMatcher = (dirPath: string): ((filePath: string) => boolean) => { const prefix = dirPath.endsWith(path.sep) ? dirPath : `${dirPath}${path.sep}`; return (filePath) => filePath === dirPath || filePath.startsWith(prefix); @@ -63,14 +34,9 @@ const discoverFmtFiles = async ({ return []; } - const resolveOptions = createOptionsResolver(config); - const getPluginResolver = createLazyPluginResolver(config.rootPath); + const resolveFile = createFmtFileResolver(config); - return Promise.all( - filePaths.map((filePath) => - resolveFileRequestPlugins(createFileRequest(filePath, resolveOptions), getPluginResolver), - ), - ); + return Promise.all(filePaths.map((filePath) => resolveFile(filePath))); }; -export { createFileRequest, createLazyPluginResolver, discoverFmtFiles, resolveFileRequestPlugins }; +export { discoverFmtFiles }; diff --git a/packages/rstack/src/fmt/fileResolver.ts b/packages/rstack/src/fmt/fileResolver.ts new file mode 100644 index 00000000..d6cc0abf --- /dev/null +++ b/packages/rstack/src/fmt/fileResolver.ts @@ -0,0 +1,28 @@ +import { createOptionsResolver } from './config.ts'; +import type { FmtPluginResolver } from './plugins.ts'; +import type { FmtFileRequest, ResolvedFmtConfig } from './types.ts'; + +type FmtFileResolver = (filePath: string) => Promise; + +/** Applies per-file overrides and resolves configured plugin specifiers. */ +const createFmtFileResolver = (config: ResolvedFmtConfig): FmtFileResolver => { + const resolveOptions = createOptionsResolver(config); + let pluginResolver: Promise | undefined; + + return async (filePath) => { + let options = resolveOptions(filePath); + + if (options.plugins?.length) { + pluginResolver ??= import( + /* rspackChunkName: 'fmtPlugins' */ + './plugins.ts' + ).then(({ createPluginResolver }) => createPluginResolver(config.rootPath)); + options = (await pluginResolver)(options); + } + + return { path: filePath, options }; + }; +}; + +export { createFmtFileResolver }; +export type { FmtFileResolver }; diff --git a/packages/rstack/src/fmt/lsp/server.ts b/packages/rstack/src/fmt/lsp/server.ts index d1e1348c..7dfddf68 100644 --- a/packages/rstack/src/fmt/lsp/server.ts +++ b/packages/rstack/src/fmt/lsp/server.ts @@ -9,15 +9,9 @@ import { type InitializeParams, type TextEdit, } from 'vscode-languageserver/node'; -import { createOptionsResolver, type FmtOptionsResolver } from '../config.ts'; -import { - createFileRequest, - createLazyPluginResolver, - resolveFileRequestPlugins, -} from '../discovery.ts'; +import { createFmtFileResolver, type FmtFileResolver } from '../fileResolver.ts'; import { formatFmtSource } from '../format.ts'; import { createIgnoreMatcher, type IgnorePredicate } from '../ignore.ts'; -import type { FmtPluginResolver } from '../plugins.ts'; import type { ResolvedFmtConfig } from '../types.ts'; import { computeMinimalTextEdit } from './minimalEdit.ts'; @@ -35,9 +29,7 @@ type FmtLspSessionOptions = RunFmtLspOptions & { root: string }; interface FmtLspSession { isIgnored: IgnorePredicate; - resolveOptions: FmtOptionsResolver; - /** Resolves plugin specifiers through the file system; cached per session. */ - getPluginResolver: () => Promise; + resolveFile: FmtFileResolver; } const toFilePath = (uri: string): string | undefined => { @@ -122,8 +114,7 @@ const createFmtLspSession = async ({ return { isIgnored, - resolveOptions: createOptionsResolver(config), - getPluginResolver: createLazyPluginResolver(config.rootPath), + resolveFile: createFmtFileResolver(config), }; }; @@ -137,10 +128,7 @@ const formatDocumentSource = async ( return undefined; } - const file = await resolveFileRequestPlugins( - createFileRequest(filePath, session.resolveOptions), - session.getPluginResolver, - ); + const file = await session.resolveFile(filePath); const result = await formatFmtSource(file, () => source); return result.status === 'formatted' ? result.formatted : undefined; diff --git a/packages/rstack/src/fmt/stdin.ts b/packages/rstack/src/fmt/stdin.ts index 90062709..6501ba73 100644 --- a/packages/rstack/src/fmt/stdin.ts +++ b/packages/rstack/src/fmt/stdin.ts @@ -1,10 +1,5 @@ import { resolve } from 'node:path'; -import { createOptionsResolver } from './config.ts'; -import { - createFileRequest, - createLazyPluginResolver, - resolveFileRequestPlugins, -} from './discovery.ts'; +import { createFmtFileResolver } from './fileResolver.ts'; import { formatFmtSource } from './format.ts'; import { createIgnoreMatcher } from './ignore.ts'; import type { ResolvedFmtConfig } from './types.ts'; @@ -83,10 +78,7 @@ const runFmtStdin = async ({ return; } - const file = await resolveFileRequestPlugins( - createFileRequest(absolutePath, createOptionsResolver(config)), - createLazyPluginResolver(config.rootPath), - ); + const file = await createFmtFileResolver(config)(absolutePath); const result = await formatFmtSource(file, () => source); if (result.status === 'unsupported') { diff --git a/packages/rstack/tests/fmt/discovery.test.ts b/packages/rstack/tests/fmt/discovery.test.ts index 171fbaae..4dfd1937 100644 --- a/packages/rstack/tests/fmt/discovery.test.ts +++ b/packages/rstack/tests/fmt/discovery.test.ts @@ -1,6 +1,5 @@ import { mkdirSync } from 'node:fs'; import path from 'node:path'; -import { pathToFileURL } from 'node:url'; import { expect, test } from 'rstack/test'; import { normalizeFmtConfig } from '../../src/fmt/config.ts'; import { discoverFmtFiles } from '../../src/fmt/discovery.ts'; @@ -128,56 +127,3 @@ test('defers parser inference to workers and preserves an explicit parser', asyn }); }); }); - -test('resolves plugins after applying matching overrides', async () => { - await withTempProject(async (rootPath) => { - const pluginEntry = writeProjectFile( - rootPath, - 'node_modules/prettier-plugin-fixture/index.mjs', - `export default { - languages: [ - { name: 'Fixture JSON', parsers: ['json'], extensions: ['.fixture'] }, - { name: 'Fixture TypeScript', parsers: ['babel'], extensions: ['.ts'] }, - ], -}; -`, - ); - writeProjectFile( - rootPath, - 'node_modules/prettier-plugin-fixture/package.json', - JSON.stringify({ name: 'prettier-plugin-fixture', exports: './index.mjs' }), - ); - writeProjectFile(rootPath, 'example.fixture'); - writeProjectFile(rootPath, 'example.ts'); - const config = { - overrides: [ - { - files: '*.fixture', - options: { plugins: ['prettier-plugin-fixture'] }, - }, - { - files: '*.ts', - options: { plugins: ['prettier-plugin-fixture'] }, - }, - { - files: '*.md', - options: { plugins: ['missing-plugin'] }, - }, - ], - }; - - const files = await discover(rootPath, ['example.fixture', 'example.ts'], config); - - expect(files).toHaveLength(2); - expect(files[0]).toMatchObject({ - options: { - plugins: [pathToFileURL(pluginEntry).href], - }, - }); - expect(files[1]).toMatchObject({ - options: { - plugins: [pathToFileURL(pluginEntry).href], - }, - }); - }); -}); diff --git a/packages/rstack/tests/fmt/fileResolver.test.ts b/packages/rstack/tests/fmt/fileResolver.test.ts new file mode 100644 index 00000000..98e1e486 --- /dev/null +++ b/packages/rstack/tests/fmt/fileResolver.test.ts @@ -0,0 +1,59 @@ +import path from 'node:path'; +import { pathToFileURL } from 'node:url'; +import { expect, test } from 'rstack/test'; +import { normalizeFmtConfig } from '../../src/fmt/config.ts'; +import { createFmtFileResolver } from '../../src/fmt/fileResolver.ts'; +import { withTempProject, writeProjectFile } from './helpers.ts'; + +test('applies matching overrides before resolving plugins', async () => { + await withTempProject(async (rootPath) => { + const pluginEntry = writeProjectFile( + rootPath, + 'node_modules/prettier-plugin-fixture/index.mjs', + `export default { + languages: [ + { name: 'Fixture JSON', parsers: ['json'], extensions: ['.fixture'] }, + { name: 'Fixture TypeScript', parsers: ['babel'], extensions: ['.ts'] }, + ], +}; +`, + ); + writeProjectFile( + rootPath, + 'node_modules/prettier-plugin-fixture/package.json', + JSON.stringify({ name: 'prettier-plugin-fixture', exports: './index.mjs' }), + ); + const config = normalizeFmtConfig( + { + overrides: [ + { + files: '*.{fixture,ts}', + options: { plugins: ['prettier-plugin-fixture'] }, + }, + { + files: '*.md', + options: { plugins: ['missing-plugin'] }, + }, + ], + }, + rootPath, + ); + const resolveFile = createFmtFileResolver(config); + + const files = await Promise.all([ + resolveFile(path.join(rootPath, 'example.fixture')), + resolveFile(path.join(rootPath, 'example.ts')), + ]); + + expect(files).toEqual([ + { + path: path.join(rootPath, 'example.fixture'), + options: { plugins: [pathToFileURL(pluginEntry).href] }, + }, + { + path: path.join(rootPath, 'example.ts'), + options: { plugins: [pathToFileURL(pluginEntry).href] }, + }, + ]); + }); +}); From 9873df34c44b25cea24bfd85d20f7ccd4a701220 Mon Sep 17 00:00:00 2001 From: Jiahan Chen Date: Thu, 13 Aug 2026 10:20:58 +0800 Subject: [PATCH 03/33] chore(ci): skip tests for docs-only changes (#337) --- .github/workflows/test.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3062f9f7..e41dfec6 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,6 +12,7 @@ on: permissions: contents: read + pull-requests: read # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: @@ -26,28 +27,47 @@ jobs: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + - uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1 + id: changes + with: + predicate-quantifier: 'every' + filters: | + changed: + - "!**/*.md" + - "!**/*.mdx" + - "!**/_meta.json" + - "!**/_nav.json" + - "!**/dictionary.txt" + - name: Setup Node.js + if: steps.changes.outputs.changed == 'true' uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7 with: node-version: 24.18.1 package-manager-cache: false - name: Install Pnpm + if: steps.changes.outputs.changed == 'true' uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6.0.10 with: run_install: true - name: Build Packages + if: steps.changes.outputs.changed == 'true' run: node --run build - name: Run Rust Tests + if: steps.changes.outputs.changed == 'true' run: cargo test --profile ci --workspace --locked - name: Build Native Binding + if: steps.changes.outputs.changed == 'true' run: pnpm --filter rstack build:native:ci - name: Check Generated Native Files + if: steps.changes.outputs.changed == 'true' run: git diff --exit-code -- packages/rstack/binding.cjs packages/rstack/binding.d.cts - name: Run Test + if: steps.changes.outputs.changed == 'true' run: node --run test From 8535fc252b07f4ae7a051440c46ef6ea4da7a72e Mon Sep 17 00:00:00 2001 From: Jiahan Chen Date: Thu, 13 Aug 2026 10:36:34 +0800 Subject: [PATCH 04/33] perf(fmt): reuse resolved options (#338) --- packages/rstack/src/fmt/config.ts | 29 +++++++++++++++++++---- packages/rstack/src/fmt/plugins.ts | 17 +++++++++---- packages/rstack/tests/fmt/config.test.ts | 23 ++++++++++++++++++ packages/rstack/tests/fmt/plugins.test.ts | 4 +++- 4 files changed, 62 insertions(+), 11 deletions(-) diff --git a/packages/rstack/src/fmt/config.ts b/packages/rstack/src/fmt/config.ts index 362a4527..ee0a5123 100644 --- a/packages/rstack/src/fmt/config.ts +++ b/packages/rstack/src/fmt/config.ts @@ -17,6 +17,20 @@ type ResolveFmtConfigOptions = { type PathMatcher = (filePath: string) => boolean; type FmtOptionsResolver = (filePath: string) => ResolvedFmtOptions; +/** + * Each path from the root represents an ordered sequence of matching overrides. + * A node stores the options merged along that path. + */ +type OptionsCacheNode = { + children: WeakMap; + options: ResolvedFmtOptions; +}; + +const createOptionsCacheNode = (options: ResolvedFmtOptions): OptionsCacheNode => ({ + children: new WeakMap(), + options, +}); + const neverMatches: PathMatcher = () => false; const compileMatchers = ( @@ -96,22 +110,27 @@ const createOptionsResolver = (config: ResolvedFmtConfig): FmtOptionsResolver => } const resolveRelativePath = createRelativePathResolver(config.rootPath); + const rootCacheNode = createOptionsCacheNode(config.baseOptions); return (filePath) => { - let options = config.baseOptions; + let cacheNode = rootCacheNode; const relativeFilePath = resolveRelativePath(filePath); for (const override of config.overrides) { if (!override.options || !override.matches(relativeFilePath)) { continue; } - if (options === config.baseOptions) { - options = { ...options }; + + // Reuse the merged result for this override after the current matched sequence. + let nextCacheNode = cacheNode.children.get(override.options); + if (!nextCacheNode) { + nextCacheNode = createOptionsCacheNode({ ...cacheNode.options, ...override.options }); + cacheNode.children.set(override.options, nextCacheNode); } - Object.assign(options, override.options); + cacheNode = nextCacheNode; } - return options; + return cacheNode.options; }; }; diff --git a/packages/rstack/src/fmt/plugins.ts b/packages/rstack/src/fmt/plugins.ts index 312dfbb1..e7a33e16 100644 --- a/packages/rstack/src/fmt/plugins.ts +++ b/packages/rstack/src/fmt/plugins.ts @@ -94,11 +94,12 @@ const createFingerprintResolver = (): FingerprintResolver => { /** Creates a project-root resolver for plugins in final per-file options. */ const createPluginResolver = (rootPath: string): FmtPluginResolver => { const parentUrl = pathToFileURL(join(rootPath, 'index.js')); - const cache = new Map(); + const pluginCache = new Map(); + const optionsCache = new WeakMap(); const resolvePlugin = (plugin: FmtPluginSpecifier): string => { const specifier = plugin instanceof URL ? plugin.href : plugin; - const cached = cache.get(specifier); + const cached = pluginCache.get(specifier); if (cached !== undefined) { return cached; } @@ -119,11 +120,16 @@ const createPluginResolver = (rootPath: string): FmtPluginResolver => { } } - cache.set(specifier, resolved); + pluginCache.set(specifier, resolved); return resolved; }; return (options) => { + const cached = optionsCache.get(options); + if (cached !== undefined) { + return cached; + } + const { plugins } = options; if (!plugins?.length) { return options; @@ -136,10 +142,11 @@ const createPluginResolver = (rootPath: string): FmtPluginResolver => { } const resolvedPlugins = plugins.map(resolvePlugin); - - return resolvedPlugins.every((plugin, index) => plugin === plugins[index]) + const resolvedOptions = resolvedPlugins.every((plugin, index) => plugin === plugins[index]) ? options : { ...options, plugins: resolvedPlugins }; + optionsCache.set(options, resolvedOptions); + return resolvedOptions; }; }; diff --git a/packages/rstack/tests/fmt/config.test.ts b/packages/rstack/tests/fmt/config.test.ts index c2f32844..fe85d292 100644 --- a/packages/rstack/tests/fmt/config.test.ts +++ b/packages/rstack/tests/fmt/config.test.ts @@ -50,6 +50,29 @@ test('applies basename and path overrides in declaration order', () => { expect(config.baseOptions).toEqual({ singleQuote: false }); }); +test('reuses options for the same override combination', () => { + const config = normalizeFmtConfig( + { + singleQuote: false, + overrides: [ + { files: '*.ts', options: { semi: false } }, + { files: 'src/**/*.ts', options: { singleQuote: true } }, + ], + }, + rootPath, + ); + const resolveOptions = createOptionsResolver(config); + + const first = resolveOptions(path.join(rootPath, 'src/first.ts')); + const second = resolveOptions(path.join(rootPath, 'src/second.ts')); + const outside = resolveOptions(path.join(rootPath, 'outside.ts')); + + expect(first).toBe(second); + expect(first).not.toBe(outside); + expect(first).toEqual({ semi: false, singleQuote: true }); + expect(outside).toEqual({ semi: false, singleQuote: false }); +}); + test('applies overrides outside the config root', () => { const config = normalizeFmtConfig( { diff --git a/packages/rstack/tests/fmt/plugins.test.ts b/packages/rstack/tests/fmt/plugins.test.ts index 80f998e8..162b3e69 100644 --- a/packages/rstack/tests/fmt/plugins.test.ts +++ b/packages/rstack/tests/fmt/plugins.test.ts @@ -40,7 +40,8 @@ test('resolves plugin specifiers from the config root', async () => { ], }; - const resolved = createPluginResolver(rootPath)(options); + const resolvePlugins = createPluginResolver(rootPath); + const resolved = resolvePlugins(options); expect(resolved.plugins).toEqual([ pathToFileURL(packageEntry).href, @@ -50,6 +51,7 @@ test('resolves plugin specifiers from the config root', async () => { 'data:text/javascript,export default {}', ]); expect(options.plugins[0]).toBe('prettier-plugin-packagejson'); + expect(resolvePlugins(options)).toBe(resolved); }); }); From 9c0f1aee25093f6541fbec361215af3ee5a5f452 Mon Sep 17 00:00:00 2001 From: Jiahan Chen Date: Thu, 13 Aug 2026 10:50:15 +0800 Subject: [PATCH 05/33] chore(lint): enable type-aware linting (#339) --- packages/rstack/src/fmt/lsp/server.ts | 2 +- packages/rstack/src/fmt/yukuPlugin.ts | 6 +----- packages/rstack/src/staged.ts | 5 ++++- packages/rstack/tests/cli/staged/index.test.ts | 4 ++-- packages/rstack/tests/fmt/helpers.ts | 2 +- packages/rstack/tests/fmt/lsp/server.test.ts | 12 ++++++------ packages/rstack/tests/fmt/plugins.test.ts | 2 +- packages/rstack/tests/setup/install.test.ts | 2 +- .../rstack/tests/types/resolution-bundler/index.ts | 2 +- .../rstack/tests/types/resolution-nodenext/index.ts | 2 +- rstack.config.ts | 2 +- 11 files changed, 20 insertions(+), 21 deletions(-) diff --git a/packages/rstack/src/fmt/lsp/server.ts b/packages/rstack/src/fmt/lsp/server.ts index 7dfddf68..ec0be83e 100644 --- a/packages/rstack/src/fmt/lsp/server.ts +++ b/packages/rstack/src/fmt/lsp/server.ts @@ -87,7 +87,7 @@ const redirectConsoleToConnection = (connection: Connection): void => { counters.set(key, count); connection.console.log(`${key}: ${count}`); }; - console.countReset = (label?: unknown): void => { + console.countReset = (label?: string): void => { if (label === undefined) { counters.clear(); } else { diff --git a/packages/rstack/src/fmt/yukuPlugin.ts b/packages/rstack/src/fmt/yukuPlugin.ts index 1fa2f646..a22ec9f2 100644 --- a/packages/rstack/src/fmt/yukuPlugin.ts +++ b/packages/rstack/src/fmt/yukuPlugin.ts @@ -423,11 +423,7 @@ const indexToPosition = (text: string, index: number): { column: number; line: n }; }; -const createParseError = (error: Diagnostic, text: string): Diagnostic | SyntaxError => { - if (typeof error?.start !== 'number' || typeof error?.end !== 'number') { - return error; - } - +const createParseError = (error: Diagnostic, text: string): SyntaxError => { const start = indexToPosition(text, error.start); const end = indexToPosition(text, error.end); diff --git a/packages/rstack/src/staged.ts b/packages/rstack/src/staged.ts index b1a8e6dc..4f6c78c2 100644 --- a/packages/rstack/src/staged.ts +++ b/packages/rstack/src/staged.ts @@ -57,7 +57,10 @@ export async function runStagedCLI(args: string[]): Promise { const success = await lintStaged({ allowEmpty: values.allowEmpty, - concurrent: values.concurrent === undefined ? undefined : JSON.parse(values.concurrent), + concurrent: + values.concurrent === undefined + ? undefined + : (JSON.parse(values.concurrent) as boolean | number), config: stagedConfig, cwd: values.cwd, debug: values.debug, diff --git a/packages/rstack/tests/cli/staged/index.test.ts b/packages/rstack/tests/cli/staged/index.test.ts index 5fb293f1..b43a928b 100644 --- a/packages/rstack/tests/cli/staged/index.test.ts +++ b/packages/rstack/tests/cli/staged/index.test.ts @@ -58,9 +58,9 @@ test('should pass default options to lint-staged', async ({ expect }) => { }); test('should set the staged environment', async ({ expect }) => { - mocks.lintStaged.mockImplementation(async () => { + mocks.lintStaged.mockImplementation(() => { expect(process.env.RSTACK_STAGED).toBe('1'); - return true; + return Promise.resolve(true); }); await runStagedCLI([]); diff --git a/packages/rstack/tests/fmt/helpers.ts b/packages/rstack/tests/fmt/helpers.ts index 2a6c8ac3..698708cb 100644 --- a/packages/rstack/tests/fmt/helpers.ts +++ b/packages/rstack/tests/fmt/helpers.ts @@ -17,7 +17,7 @@ export const createFmtCacheContext = (rootPath: string): FmtCacheContext => ({ }); export const withTempProject = async ( - callback: (rootPath: string) => Promise, + callback: (rootPath: string) => void | Promise, ): Promise => { const rootPath = mkdtempSync(path.join(import.meta.dirname, 'test-temp-fmt-')); // Prevent repository-level ignore rules from affecting the fixture. diff --git a/packages/rstack/tests/fmt/lsp/server.test.ts b/packages/rstack/tests/fmt/lsp/server.test.ts index c84475a8..597ca968 100644 --- a/packages/rstack/tests/fmt/lsp/server.test.ts +++ b/packages/rstack/tests/fmt/lsp/server.test.ts @@ -4,7 +4,7 @@ import { createDocumentEdits } from '../../../src/fmt/lsp/server.ts'; test('maps the edit onto the formatted document', async () => { const edits = await createDocumentEdits( () => 'const a = 1;\nconst b=2;\n', - async () => 'const a = 1;\nconst b = 2;\n', + () => Promise.resolve('const a = 1;\nconst b = 2;\n'), ); expect(edits).toEqual([ @@ -18,15 +18,15 @@ test('maps the edit onto the formatted document', async () => { test('returns no edits for an already formatted document', async () => { const getText = () => 'const a = 1;\n'; - expect(await createDocumentEdits(getText, async () => 'const a = 1;\n')).toEqual([]); - expect(await createDocumentEdits(getText, async () => undefined)).toEqual([]); + expect(await createDocumentEdits(getText, () => Promise.resolve('const a = 1;\n'))).toEqual([]); + expect(await createDocumentEdits(getText, () => Promise.resolve(undefined))).toEqual([]); }); test('returns no edits for a document that is not open', async () => { expect( await createDocumentEdits( () => undefined, - async () => '', + () => Promise.resolve(''), ), ).toEqual([]); }); @@ -38,10 +38,10 @@ test('returns no edits when the document changes while it is formatted', async ( const edits = await createDocumentEdits( () => text, - async (source) => { + (source) => { text = 'const b=2;\n'; - return source.replace('const b=2;', 'const b = 2;'); + return Promise.resolve(source.replace('const b=2;', 'const b = 2;')); }, ); diff --git a/packages/rstack/tests/fmt/plugins.test.ts b/packages/rstack/tests/fmt/plugins.test.ts index 162b3e69..842c6db4 100644 --- a/packages/rstack/tests/fmt/plugins.test.ts +++ b/packages/rstack/tests/fmt/plugins.test.ts @@ -4,7 +4,7 @@ import { createFingerprintResolver, createPluginResolver } from '../../src/fmt/p import { withTempProject, writeProjectFile } from './helpers.ts'; test('resolves plugin specifiers from the config root', async () => { - await withTempProject(async (rootPath) => { + await withTempProject((rootPath) => { const packageEntry = writeProjectFile( rootPath, 'node_modules/prettier-plugin-packagejson/import.mjs', diff --git a/packages/rstack/tests/setup/install.test.ts b/packages/rstack/tests/setup/install.test.ts index 355d77c7..a64ea7c7 100644 --- a/packages/rstack/tests/setup/install.test.ts +++ b/packages/rstack/tests/setup/install.test.ts @@ -79,7 +79,7 @@ test('resolves repository context with a single Git process when unchanged', () const starts = readFileSync(tracePath, 'utf8') .trim() .split('\n') - .map((line) => JSON.parse(line)) + .map((line) => JSON.parse(line) as { argv: string[]; event: string }) .filter((event) => event.event === 'start'); expect(starts).toHaveLength(1); expect(starts[0].argv).toContain('rev-parse'); diff --git a/packages/rstack/tests/types/resolution-bundler/index.ts b/packages/rstack/tests/types/resolution-bundler/index.ts index 44477318..c464b7f6 100644 --- a/packages/rstack/tests/types/resolution-bundler/index.ts +++ b/packages/rstack/tests/types/resolution-bundler/index.ts @@ -23,7 +23,7 @@ const configs: Configs = {}; void loadedConfig; void configs; -createRsbuild({ config: appConfig }); +void createRsbuild({ config: appConfig }); define.app(appConfig); define.lib(libConfig); define.doc({}); diff --git a/packages/rstack/tests/types/resolution-nodenext/index.ts b/packages/rstack/tests/types/resolution-nodenext/index.ts index 95bf176a..4b8d3f0a 100644 --- a/packages/rstack/tests/types/resolution-nodenext/index.ts +++ b/packages/rstack/tests/types/resolution-nodenext/index.ts @@ -23,7 +23,7 @@ const configs: Configs = {}; void loadedConfig; void configs; -createRsbuild({ config: appConfig }); +void createRsbuild({ config: appConfig }); define.app(appConfig); define.lib(libConfig); define.doc({}); diff --git a/rstack.config.ts b/rstack.config.ts index 0ad535cf..d6d1bce2 100644 --- a/rstack.config.ts +++ b/rstack.config.ts @@ -6,7 +6,7 @@ define.lint(async () => { const { js, ts } = await import('rstack/lint'); return [ js.configs.recommended, - ts.configs.recommended, + ts.configs.recommendedTypeChecked, { files: ['**/*.{js,jsx,cjs,mjs}'], languageOptions: { From 8b18ff6f5176a73ed5a171bab185cb379ec5359e Mon Sep 17 00:00:00 2001 From: Jiahan Chen Date: Thu, 13 Aug 2026 11:23:36 +0800 Subject: [PATCH 06/33] chore(create-rstack): enable type-aware linting in templates (#340) --- packages/create-rstack/template-app-lit-ts/rstack.config.ts | 2 +- .../create-rstack/template-app-preact-ts/rstack.config.ts | 2 +- .../create-rstack/template-app-react-ts/rstack.config.ts | 2 +- .../create-rstack/template-app-solid-ts/rstack.config.ts | 2 +- .../create-rstack/template-app-svelte-ts/rstack.config.ts | 2 +- .../create-rstack/template-app-vanilla-ts/rstack.config.ts | 2 +- packages/create-rstack/template-app-vue-ts/rstack.config.ts | 2 +- packages/create-rstack/template-app-vue-ts/src/env.d.ts | 6 ++++++ packages/create-rstack/template-doc-i18n/rstack.config.ts | 2 +- packages/create-rstack/template-doc/rstack.config.ts | 2 +- .../create-rstack/template-lib-node-ts/rstack.config.ts | 2 +- .../create-rstack/template-lib-react-ts/rstack.config.ts | 2 +- .../create-rstack/template-lib-solid-ts/rstack.config.ts | 2 +- .../create-rstack/template-lib-svelte-ts/rstack.config.ts | 2 +- packages/create-rstack/template-lib-vue-ts/rstack.config.ts | 2 +- packages/create-rstack/tests/create.test.ts | 3 +++ 16 files changed, 23 insertions(+), 14 deletions(-) create mode 100644 packages/create-rstack/template-app-vue-ts/src/env.d.ts diff --git a/packages/create-rstack/template-app-lit-ts/rstack.config.ts b/packages/create-rstack/template-app-lit-ts/rstack.config.ts index cdfe0ac0..1dac3261 100644 --- a/packages/create-rstack/template-app-lit-ts/rstack.config.ts +++ b/packages/create-rstack/template-app-lit-ts/rstack.config.ts @@ -19,7 +19,7 @@ define.test({ define.lint(async () => { const { js, ts } = await import('rstack/lint'); - return [js.configs.recommended, ts.configs.recommended]; + return [js.configs.recommended, ts.configs.recommendedTypeChecked]; }); define.fmt({ diff --git a/packages/create-rstack/template-app-preact-ts/rstack.config.ts b/packages/create-rstack/template-app-preact-ts/rstack.config.ts index 9ee763c8..8bf4f073 100644 --- a/packages/create-rstack/template-app-preact-ts/rstack.config.ts +++ b/packages/create-rstack/template-app-preact-ts/rstack.config.ts @@ -18,7 +18,7 @@ define.lint(async () => { return [ js.configs.recommended, - ts.configs.recommended, + ts.configs.recommendedTypeChecked, reactPlugin.configs.recommended, reactHooksPlugin.configs.recommended, ]; diff --git a/packages/create-rstack/template-app-react-ts/rstack.config.ts b/packages/create-rstack/template-app-react-ts/rstack.config.ts index 356c98e1..1cbfbf46 100644 --- a/packages/create-rstack/template-app-react-ts/rstack.config.ts +++ b/packages/create-rstack/template-app-react-ts/rstack.config.ts @@ -18,7 +18,7 @@ define.lint(async () => { return [ js.configs.recommended, - ts.configs.recommended, + ts.configs.recommendedTypeChecked, reactPlugin.configs.recommended, reactHooksPlugin.configs.recommended, ]; diff --git a/packages/create-rstack/template-app-solid-ts/rstack.config.ts b/packages/create-rstack/template-app-solid-ts/rstack.config.ts index 355d1b46..6aac365b 100644 --- a/packages/create-rstack/template-app-solid-ts/rstack.config.ts +++ b/packages/create-rstack/template-app-solid-ts/rstack.config.ts @@ -22,7 +22,7 @@ define.test({ define.lint(async () => { const { js, ts } = await import('rstack/lint'); - return [js.configs.recommended, ts.configs.recommended]; + return [js.configs.recommended, ts.configs.recommendedTypeChecked]; }); define.fmt({ diff --git a/packages/create-rstack/template-app-svelte-ts/rstack.config.ts b/packages/create-rstack/template-app-svelte-ts/rstack.config.ts index 66320b37..e834b53d 100644 --- a/packages/create-rstack/template-app-svelte-ts/rstack.config.ts +++ b/packages/create-rstack/template-app-svelte-ts/rstack.config.ts @@ -16,7 +16,7 @@ define.test({ define.lint(async () => { const { js, ts } = await import('rstack/lint'); - return [js.configs.recommended, ts.configs.recommended]; + return [js.configs.recommended, ts.configs.recommendedTypeChecked]; }); define.fmt({ diff --git a/packages/create-rstack/template-app-vanilla-ts/rstack.config.ts b/packages/create-rstack/template-app-vanilla-ts/rstack.config.ts index 349fcfae..5476c2c8 100644 --- a/packages/create-rstack/template-app-vanilla-ts/rstack.config.ts +++ b/packages/create-rstack/template-app-vanilla-ts/rstack.config.ts @@ -12,7 +12,7 @@ define.test({ define.lint(async () => { const { js, ts } = await import('rstack/lint'); - return [js.configs.recommended, ts.configs.recommended]; + return [js.configs.recommended, ts.configs.recommendedTypeChecked]; }); define.fmt({ diff --git a/packages/create-rstack/template-app-vue-ts/rstack.config.ts b/packages/create-rstack/template-app-vue-ts/rstack.config.ts index f2224449..12ea8e76 100644 --- a/packages/create-rstack/template-app-vue-ts/rstack.config.ts +++ b/packages/create-rstack/template-app-vue-ts/rstack.config.ts @@ -16,7 +16,7 @@ define.test({ define.lint(async () => { const { js, ts } = await import('rstack/lint'); - return [js.configs.recommended, ts.configs.recommended]; + return [js.configs.recommended, ts.configs.recommendedTypeChecked]; }); define.fmt({ diff --git a/packages/create-rstack/template-app-vue-ts/src/env.d.ts b/packages/create-rstack/template-app-vue-ts/src/env.d.ts new file mode 100644 index 00000000..8afcdfbb --- /dev/null +++ b/packages/create-rstack/template-app-vue-ts/src/env.d.ts @@ -0,0 +1,6 @@ +declare module '*.vue' { + import type { DefineComponent } from 'vue'; + + const component: DefineComponent; + export default component; +} diff --git a/packages/create-rstack/template-doc-i18n/rstack.config.ts b/packages/create-rstack/template-doc-i18n/rstack.config.ts index 2ab17eff..8e1f8435 100644 --- a/packages/create-rstack/template-doc-i18n/rstack.config.ts +++ b/packages/create-rstack/template-doc-i18n/rstack.config.ts @@ -28,7 +28,7 @@ define.lint(async () => { return [ js.configs.recommended, - ts.configs.recommended, + ts.configs.recommendedTypeChecked, reactPlugin.configs.recommended, reactHooksPlugin.configs.recommended, ]; diff --git a/packages/create-rstack/template-doc/rstack.config.ts b/packages/create-rstack/template-doc/rstack.config.ts index 466b9d5c..77378cff 100644 --- a/packages/create-rstack/template-doc/rstack.config.ts +++ b/packages/create-rstack/template-doc/rstack.config.ts @@ -12,7 +12,7 @@ define.lint(async () => { return [ js.configs.recommended, - ts.configs.recommended, + ts.configs.recommendedTypeChecked, reactPlugin.configs.recommended, reactHooksPlugin.configs.recommended, ]; diff --git a/packages/create-rstack/template-lib-node-ts/rstack.config.ts b/packages/create-rstack/template-lib-node-ts/rstack.config.ts index d0f94060..dc33795b 100644 --- a/packages/create-rstack/template-lib-node-ts/rstack.config.ts +++ b/packages/create-rstack/template-lib-node-ts/rstack.config.ts @@ -13,7 +13,7 @@ define.test({ define.lint(async () => { const { js, ts } = await import('rstack/lint'); - return [js.configs.recommended, ts.configs.recommended]; + return [js.configs.recommended, ts.configs.recommendedTypeChecked]; }); define.fmt({ diff --git a/packages/create-rstack/template-lib-react-ts/rstack.config.ts b/packages/create-rstack/template-lib-react-ts/rstack.config.ts index 89cb5d03..b131e4a8 100644 --- a/packages/create-rstack/template-lib-react-ts/rstack.config.ts +++ b/packages/create-rstack/template-lib-react-ts/rstack.config.ts @@ -28,7 +28,7 @@ define.lint(async () => { return [ js.configs.recommended, - ts.configs.recommended, + ts.configs.recommendedTypeChecked, reactPlugin.configs.recommended, reactHooksPlugin.configs.recommended, ]; diff --git a/packages/create-rstack/template-lib-solid-ts/rstack.config.ts b/packages/create-rstack/template-lib-solid-ts/rstack.config.ts index 25c187d5..02bc776f 100644 --- a/packages/create-rstack/template-lib-solid-ts/rstack.config.ts +++ b/packages/create-rstack/template-lib-solid-ts/rstack.config.ts @@ -78,7 +78,7 @@ define.test(async () => { define.lint(async () => { const { js, ts } = await import('rstack/lint'); - return [js.configs.recommended, ts.configs.recommended]; + return [js.configs.recommended, ts.configs.recommendedTypeChecked]; }); define.fmt({ diff --git a/packages/create-rstack/template-lib-svelte-ts/rstack.config.ts b/packages/create-rstack/template-lib-svelte-ts/rstack.config.ts index 3ac5f03d..0844c4e2 100644 --- a/packages/create-rstack/template-lib-svelte-ts/rstack.config.ts +++ b/packages/create-rstack/template-lib-svelte-ts/rstack.config.ts @@ -26,7 +26,7 @@ define.test({ define.lint(async () => { const { js, ts } = await import('rstack/lint'); - return [js.configs.recommended, ts.configs.recommended]; + return [js.configs.recommended, ts.configs.recommendedTypeChecked]; }); define.fmt({ diff --git a/packages/create-rstack/template-lib-vue-ts/rstack.config.ts b/packages/create-rstack/template-lib-vue-ts/rstack.config.ts index e9c37a60..a372eb1d 100644 --- a/packages/create-rstack/template-lib-vue-ts/rstack.config.ts +++ b/packages/create-rstack/template-lib-vue-ts/rstack.config.ts @@ -25,7 +25,7 @@ define.test({ define.lint(async () => { const { js, ts } = await import('rstack/lint'); - return [js.configs.recommended, ts.configs.recommended]; + return [js.configs.recommended, ts.configs.recommendedTypeChecked]; }); define.fmt({ diff --git a/packages/create-rstack/tests/create.test.ts b/packages/create-rstack/tests/create.test.ts index 32576411..08c23d7e 100644 --- a/packages/create-rstack/tests/create.test.ts +++ b/packages/create-rstack/tests/create.test.ts @@ -205,6 +205,9 @@ test.each(sourceTemplates)( if (template.startsWith('app-')) { files.push('README.md', '.gitignore'); } + if (template === 'app-vue-ts') { + files.push('src/env.d.ts'); + } await expectProjectSetup(projectDirectory, template, configExtension, hasTypeScript); await expectFiles(projectDirectory, files); From 11c56cd4ead1fd5110cb2aee3a2fa4855d89d6c6 Mon Sep 17 00:00:00 2001 From: Jiahan Chen Date: Thu, 13 Aug 2026 12:53:07 +0800 Subject: [PATCH 07/33] perf(fmt): optimize cache serialization (#341) --- packages/rstack/src/fmt/cacheIdentity.ts | 16 +- packages/rstack/src/fmt/cacheStore.ts | 226 +++++++++++++----- packages/rstack/src/fmt/runner.ts | 2 +- packages/rstack/src/fmt/worker.ts | 7 +- packages/rstack/tests/cli/fmt/cache.test.ts | 47 ++-- .../rstack/tests/fmt/cacheIdentity.test.ts | 11 +- packages/rstack/tests/fmt/cacheStore.test.ts | 98 +++++--- packages/rstack/tests/fmt/runnerCache.test.ts | 37 +-- .../tests/fmt/runnerWorkerPreflight.test.ts | 2 +- packages/rstack/tests/fmt/worker.test.ts | 14 +- 10 files changed, 304 insertions(+), 156 deletions(-) diff --git a/packages/rstack/src/fmt/cacheIdentity.ts b/packages/rstack/src/fmt/cacheIdentity.ts index 0bbdbbe1..f7ba278d 100644 --- a/packages/rstack/src/fmt/cacheIdentity.ts +++ b/packages/rstack/src/fmt/cacheIdentity.ts @@ -1,4 +1,4 @@ -import { hash } from 'node:crypto'; +import { hash as createDigest } from 'node:crypto'; import { isAbsolute } from 'node:path'; import stableStringify from 'fast-json-stable-stringify'; import { fmtCacheVersion } from './cacheStore.ts'; @@ -12,7 +12,9 @@ type CacheKeyResolver = (filePath: string) => string | undefined; type OptionsHasher = (options: ResolvedFmtOptions) => string | undefined; type PluginFingerprints = ReadonlyMap; -const sha256 = (content: string | Uint8Array): string => hash('sha256', content, 'hex'); +const cacheHashLength = 16; +const createCacheHash = (content: string | Uint8Array): string => + createDigest('sha256', content, 'base64url').slice(0, cacheHashLength); /** Identifies formatter behavior shared by all cache entries in this process. */ const cacheNamespace: string = JSON.stringify([fmtCacheVersion, RSTACK_VERSION, PRETTIER_VERSION]); @@ -55,7 +57,7 @@ const createOptionsHasher = (pluginFingerprints?: PluginFingerprints): OptionsHa } value = { ...options, plugins: fingerprints }; } - hash = sha256(stableStringify(value)); + hash = createCacheHash(stableStringify(value)); } catch { // Circular or unreadable options cannot be cached. } @@ -65,4 +67,10 @@ const createOptionsHasher = (pluginFingerprints?: PluginFingerprints): OptionsHa }; }; -export { cacheNamespace, createCacheKeyResolver, createOptionsHasher, sha256 }; +export { + cacheHashLength, + cacheNamespace, + createCacheHash, + createCacheKeyResolver, + createOptionsHasher, +}; diff --git a/packages/rstack/src/fmt/cacheStore.ts b/packages/rstack/src/fmt/cacheStore.ts index dfc47b60..0dcf3292 100644 --- a/packages/rstack/src/fmt/cacheStore.ts +++ b/packages/rstack/src/fmt/cacheStore.ts @@ -2,18 +2,40 @@ import { randomUUID } from 'node:crypto'; import { mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises'; import path from 'node:path'; -const fmtCacheFileName = 'v1.json'; -const fmtCacheVersion = 1; +const fmtCacheFileName = 'cache.json'; +const fmtCacheVersion = 2; -type FmtCacheState = 'clean' | 'dirty' | 'unsupported'; -type FmtCacheEntry = - | readonly [contentHash: string, optionsHash: string, state: 'clean' | 'dirty'] - | readonly [contentHash: string | null, optionsHash: string, state: 'unsupported']; +const fileEntryWidth = 4; +const contentHashOffset = 1; +const optionsIndexOffset = 2; +const stateOffset = 3; + +const fmtCacheStates = ['clean', 'dirty', 'unsupported'] as const; +type FmtCacheState = (typeof fmtCacheStates)[number]; +type FmtCacheStateId = 0 | 1 | 2; + +const fmtCacheStateIds = { + clean: 0, + dirty: 1, + unsupported: 2, +} as const satisfies Record; + +type FmtCacheFileValue = string | number; +type FmtCacheEntry = readonly [contentHash: string, optionsHash: string, state: FmtCacheState]; interface FmtCacheFile { version: typeof fmtCacheVersion; namespace: string; - files: Record; + options: string[]; + /** Repeated tuples of file path, content hash, options index, and numeric state. */ + files: FmtCacheFileValue[]; +} + +interface ParsedFmtCacheFile { + cache: FmtCacheFile; + fileOffsets: Map; + optionsIndexes: Map; + optionsUseCounts: number[]; } interface FmtCacheStore { @@ -23,30 +45,19 @@ interface FmtCacheStore { save(): Promise; } -const createEmptyCache = (namespace: string): FmtCacheFile => ({ - version: fmtCacheVersion, - namespace, - files: Object.create(null) as Record, +const createEmptyCache = (namespace: string): ParsedFmtCacheFile => ({ + cache: { + version: fmtCacheVersion, + namespace, + options: [], + files: [], + }, + fileOffsets: new Map(), + optionsIndexes: new Map(), + optionsUseCounts: [], }); -const parseCacheEntry = (value: unknown): FmtCacheEntry | undefined => { - if (!Array.isArray(value) || value.length !== 3 || typeof value[1] !== 'string') { - return; - } - - if (value[2] === 'unsupported') { - return value[0] === null || typeof value[0] === 'string' - ? [value[0], value[1], value[2]] - : undefined; - } - if (typeof value[0] !== 'string' || (value[2] !== 'clean' && value[2] !== 'dirty')) { - return; - } - - return [value[0], value[1], value[2]]; -}; - -const parseCacheFile = (content: string): FmtCacheFile | undefined => { +const parseCacheFile = (content: string): ParsedFmtCacheFile | undefined => { let value: unknown; try { value = JSON.parse(content); @@ -54,35 +65,41 @@ const parseCacheFile = (content: string): FmtCacheFile | undefined => { return; } + if (typeof value !== 'object' || value === null || Array.isArray(value)) { + return; + } + + const cache = value as FmtCacheFile; + const { version, namespace, options, files } = cache; if ( - typeof value !== 'object' || - value === null || - Array.isArray(value) || - !('version' in value) || - value.version !== fmtCacheVersion || - !('namespace' in value) || - typeof value.namespace !== 'string' || - !('files' in value) || - typeof value.files !== 'object' || - value.files === null || - Array.isArray(value.files) + version !== fmtCacheVersion || + typeof namespace !== 'string' || + !Array.isArray(options) || + !Array.isArray(files) || + files.length % fileEntryWidth !== 0 ) { return; } - const files = Object.create(null) as Record; - for (const [filePath, rawEntry] of Object.entries(value.files)) { - const entry = parseCacheEntry(rawEntry); - if (!entry) { - return; - } - files[filePath] = entry; + const optionsIndexes = new Map(); + for (let index = 0; index < options.length; index++) { + optionsIndexes.set(options[index], index); + } + + const fileOffsets = new Map(); + const optionsUseCounts = new Array(options.length).fill(0); + for (let offset = 0; offset < files.length; offset += fileEntryWidth) { + const filePath = files[offset] as string; + const optionsIndex = files[offset + optionsIndexOffset] as number; + fileOffsets.set(filePath, offset); + optionsUseCounts[optionsIndex]++; } return { - version: fmtCacheVersion, - namespace: value.namespace, - files, + cache, + fileOffsets, + optionsIndexes, + optionsUseCounts, }; }; @@ -100,43 +117,124 @@ const getTemporaryPath = (filePath: string): string => class FmtCacheStoreImpl implements FmtCacheStore { readonly #filePath: string; readonly #cache: FmtCacheFile; + readonly #fileOffsets: Map; + readonly #optionsIndexes: Map; + readonly #optionsUseCounts: number[]; #savedContent: string | undefined; #changed: boolean; constructor( filePath: string, - cache: FmtCacheFile, + parsed: ParsedFmtCacheFile, savedContent: string | undefined, changed: boolean, ) { this.#filePath = filePath; - this.#cache = cache; + this.#cache = parsed.cache; + this.#fileOffsets = parsed.fileOffsets; + this.#optionsIndexes = parsed.optionsIndexes; + this.#optionsUseCounts = parsed.optionsUseCounts; this.#savedContent = savedContent; this.#changed = changed; } get(filePath: string): FmtCacheEntry | undefined { - return this.#cache.files[filePath]; + const offset = this.#fileOffsets.get(filePath); + if (offset === undefined) { + return; + } + + const { files, options } = this.#cache; + const contentHash = files[offset + contentHashOffset] as string; + const optionsHash = options[files[offset + optionsIndexOffset] as number]; + const state = fmtCacheStates[files[offset + stateOffset] as FmtCacheStateId]; + return [contentHash, optionsHash, state]; } set(filePath: string, entry: FmtCacheEntry): void { - const current = this.#cache.files[filePath]; - if (current?.[0] === entry[0] && current[1] === entry[1] && current[2] === entry[2]) { - return; + const { files, options } = this.#cache; + const [contentHash, optionsHash, state] = entry; + const stateId = fmtCacheStateIds[state]; + const offset = this.#fileOffsets.get(filePath); + + if (offset !== undefined) { + const currentOptionsIndex = files[offset + optionsIndexOffset] as number; + if ( + files[offset + contentHashOffset] === contentHash && + options[currentOptionsIndex] === optionsHash && + files[offset + stateOffset] === stateId + ) { + return; + } + + const optionsIndex = this.#getOrCreateOptionsIndex(optionsHash); + if (currentOptionsIndex !== optionsIndex) { + this.#optionsUseCounts[currentOptionsIndex]--; + this.#optionsUseCounts[optionsIndex]++; + files[offset + optionsIndexOffset] = optionsIndex; + } + files[offset + contentHashOffset] = contentHash; + files[offset + stateOffset] = stateId; + } else { + const optionsIndex = this.#getOrCreateOptionsIndex(optionsHash); + const nextOffset = files.length; + files.push(filePath, contentHash, optionsIndex, stateId); + this.#fileOffsets.set(filePath, nextOffset); + this.#optionsUseCounts[optionsIndex]++; } - this.#cache.files[filePath] = - entry[2] === 'unsupported' - ? [entry[0], entry[1], 'unsupported'] - : [entry[0], entry[1], entry[2]]; this.#changed = true; } + #getOrCreateOptionsIndex(optionsHash: string): number { + const current = this.#optionsIndexes.get(optionsHash); + if (current !== undefined) { + return current; + } + + const index = this.#cache.options.length; + this.#cache.options.push(optionsHash); + this.#optionsIndexes.set(optionsHash, index); + this.#optionsUseCounts.push(0); + return index; + } + + #compactUnusedOptions(): void { + if (!this.#optionsUseCounts.includes(0)) { + return; + } + + const { files, options } = this.#cache; + const nextOptions: string[] = []; + const nextUseCounts: number[] = []; + const remappedIndexes = new Int32Array(options.length).fill(-1); + for (let index = 0; index < options.length; index++) { + const useCount = this.#optionsUseCounts[index]; + if (useCount > 0) { + remappedIndexes[index] = nextOptions.length; + nextOptions.push(options[index]); + nextUseCounts.push(useCount); + } + } + for (let offset = 0; offset < files.length; offset += fileEntryWidth) { + const currentIndex = files[offset + optionsIndexOffset] as number; + files[offset + optionsIndexOffset] = remappedIndexes[currentIndex]; + } + + options.splice(0, options.length, ...nextOptions); + this.#optionsUseCounts.splice(0, this.#optionsUseCounts.length, ...nextUseCounts); + this.#optionsIndexes.clear(); + for (let index = 0; index < options.length; index++) { + this.#optionsIndexes.set(options[index], index); + } + } + async save(): Promise { if (!this.#changed) { return false; } + this.#compactUnusedOptions(); const content = serializeCache(this.#cache); if (content === this.#savedContent) { this.#changed = false; @@ -164,13 +262,13 @@ const loadFmtCacheStore = async (filePath: string, namespace: string): Promise { return false; } return ( - cache.entry[0] === null && + cache.entry[0] === '' && cache.entry[1] === cache.optionsHash && cache.entry[2] === 'unsupported' && hasDottedBasename(file.path) diff --git a/packages/rstack/src/fmt/worker.ts b/packages/rstack/src/fmt/worker.ts index 1befd4ce..6e6505aa 100644 --- a/packages/rstack/src/fmt/worker.ts +++ b/packages/rstack/src/fmt/worker.ts @@ -12,7 +12,8 @@ interface FormatFileTask { cache?: FmtFileCache; } -const hashContent = (content: string | Uint8Array): string => hash('sha256', content, 'hex'); +const hashContent = (content: string | Uint8Array): string => + hash('sha256', content, 'base64url').slice(0, 16); /** * Use synchronous direct I/O inside the dedicated worker to avoid libuv @@ -44,7 +45,7 @@ const formatFile = async ({ if (cache?.entry && cache.entry[1] === cache.optionsHash) { const { entry } = cache; if (entry[2] === 'unsupported') { - if (entry[0] === null) { + if (entry[0] === '') { if (hasDottedBasename(file.path)) { return { status: 'unsupported' }; } @@ -72,7 +73,7 @@ const formatFile = async ({ status: 'unsupported', cacheEntry: [ hasDottedBasename(file.path) - ? null + ? '' : (contentHash ?? hashContent(sourceBuffer ?? readFileSync(file.path))), cache.optionsHash, 'unsupported', diff --git a/packages/rstack/tests/cli/fmt/cache.test.ts b/packages/rstack/tests/cli/fmt/cache.test.ts index 15e51dea..12c112e2 100644 --- a/packages/rstack/tests/cli/fmt/cache.test.ts +++ b/packages/rstack/tests/cli/fmt/cache.test.ts @@ -4,6 +4,27 @@ import { expectWriteSummary, normalizeDuration, setupFmtTest } from './helpers.t const { projectFileExists, readProjectFile, resolveProjectPath, runFmt, writeProjectFile } = setupFmtTest(); +interface SerializedFmtCache { + version: number; + namespace: string; + options: string[]; + files: (string | number)[]; +} + +const readFmtCache = (filePath: string): SerializedFmtCache => + JSON.parse(readProjectFile(filePath)) as SerializedFmtCache; + +const expectSingleCleanEntry = (cache: SerializedFmtCache, filePath: string): void => { + expect(cache.version).toBe(2); + expect(typeof cache.namespace).toBe('string'); + expect(cache.options).toHaveLength(1); + expect(cache.options[0]).toHaveLength(16); + expect(cache.files).toHaveLength(4); + expect(cache.files[0]).toBe(filePath); + expect(cache.files[1]).toEqual(expect.any(String)); + expect(cache.files.slice(2)).toEqual([0, 0]); +}; + test.each([ ['write', []], ['check', ['--check']], @@ -16,12 +37,7 @@ test.each([ expect(result.status).toBe(0); expect(readProjectFile('.rstack/cache/.gitignore')).toBe('*\n'); - expect(JSON.parse(readProjectFile('.rstack/cache/fmt/v1.json'))).toMatchObject({ - version: 1, - files: { - 'index.ts': [expect.any(String), expect.any(String), 'clean'], - }, - }); + expectSingleCleanEntry(readFmtCache('.rstack/cache/fmt/cache.json'), 'index.ts'); expect(readProjectFile('.rstack/cache/fmt-v1.json')).toBe('legacy'); }); @@ -58,12 +74,7 @@ test.each(['relative', 'absolute'] as const)('uses a %s custom cache location', const result = runFmt(['--cache-location', cacheLocation, 'index.ts']); expect(result.status).toBe(0); - expect(JSON.parse(readProjectFile('custom-cache/v1.json'))).toMatchObject({ - version: 1, - files: { - 'index.ts': [expect.any(String), expect.any(String), 'clean'], - }, - }); + expectSingleCleanEntry(readFmtCache('custom-cache/cache.json'), 'index.ts'); expect(projectFileExists('custom-cache/.gitignore')).toBe(false); expect(projectFileExists('.rstack')).toBe(false); }); @@ -99,26 +110,22 @@ test('uses an explicit config root cache from a subdirectory', () => { expect(result.status).toBe(0); expect(readProjectFile('packages/app/index.ts')).toBe('const value = 1;\n'); - expect(projectFileExists('.rstack/cache/fmt/v1.json')).toBe(true); + expect(projectFileExists('.rstack/cache/fmt/cache.json')).toBe(true); expect(projectFileExists('packages/app/.rstack')).toBe(false); - expect(JSON.parse(readProjectFile('.rstack/cache/fmt/v1.json'))).toMatchObject({ - files: { - 'packages/app/index.ts': [expect.any(String), expect.any(String), 'clean'], - }, - }); + expectSingleCleanEntry(readFmtCache('.rstack/cache/fmt/cache.json'), 'packages/app/index.ts'); }); test('recovers from a corrupted cache', () => { writeProjectFile('index.ts', 'const value = 1;\n'); const first = runFmt(['--check', 'index.ts']); - writeProjectFile('.rstack/cache/fmt/v1.json', '{'); + writeProjectFile('.rstack/cache/fmt/cache.json', '{'); const second = runFmt(['--check', 'index.ts']); expect(second.status).toBe(0); expect(normalizeDuration(second.stdout)).toBe(normalizeDuration(first.stdout)); expect(second.stderr).toBe(first.stderr); - expect(JSON.parse(readProjectFile('.rstack/cache/fmt/v1.json'))).toMatchObject({ version: 1 }); + expect(JSON.parse(readProjectFile('.rstack/cache/fmt/cache.json'))).toMatchObject({ version: 2 }); }); test('formats without a writable cache directory', () => { diff --git a/packages/rstack/tests/fmt/cacheIdentity.test.ts b/packages/rstack/tests/fmt/cacheIdentity.test.ts index e0d48789..933b7229 100644 --- a/packages/rstack/tests/fmt/cacheIdentity.test.ts +++ b/packages/rstack/tests/fmt/cacheIdentity.test.ts @@ -4,10 +4,11 @@ import prettierPkgJson from 'prettier/package.json' with { type: 'json' }; import { expect, test } from 'rstack/test'; import pkgJson from '../../package.json' with { type: 'json' }; import { + cacheHashLength, cacheNamespace, + createCacheHash, createCacheKeyResolver, createOptionsHasher, - sha256, } from '../../src/fmt/cacheIdentity.ts'; import { fmtCacheVersion } from '../../src/fmt/cacheStore.ts'; import type { ResolvedFmtOptions } from '../../src/fmt/types.ts'; @@ -17,7 +18,7 @@ const rootPath = path.join(import.meta.dirname, 'project'); const asOptions = (value: Record): ResolvedFmtOptions => value as ResolvedFmtOptions; -test('creates stable SHA-256 option hashes', () => { +test('creates stable SHA-256-derived option hashes', () => { const hashOptions = createOptionsHasher(); const left: ResolvedFmtOptions = { singleQuote: true, @@ -29,8 +30,8 @@ test('creates stable SHA-256 option hashes', () => { }; expect(hashOptions(left)).toBe(hashOptions(right)); - expect(hashOptions(left)).toHaveLength(64); - expect(sha256('abc')).toBe('ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad'); + expect(hashOptions(left)).toHaveLength(cacheHashLength); + expect(createCacheHash('abc')).toBe('ungWv48Bz-pBQUDe'); }); test('invalidates hashes when final formatter options change', () => { @@ -52,7 +53,7 @@ test('includes plugin fingerprints in option hashes', () => { const first = createOptionsHasher(new Map([[plugin, 'plugin@1']])); const second = createOptionsHasher(new Map([[plugin, 'plugin@2']])); - expect(first({ plugins: [plugin] })).toHaveLength(64); + expect(first({ plugins: [plugin] })).toHaveLength(cacheHashLength); expect(first({ plugins: [new URL(plugin)] })).toBe(first({ plugins: [plugin] })); expect(first({ plugins: [plugin] })).not.toBe(second({ plugins: [plugin] })); }); diff --git a/packages/rstack/tests/fmt/cacheStore.test.ts b/packages/rstack/tests/fmt/cacheStore.test.ts index 713d804d..e6f038b7 100644 --- a/packages/rstack/tests/fmt/cacheStore.test.ts +++ b/packages/rstack/tests/fmt/cacheStore.test.ts @@ -1,21 +1,32 @@ import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from 'node:fs'; import path from 'node:path'; import { expect, test } from 'rstack/test'; -import { fmtCacheVersion, loadFmtCacheStore, type FmtCacheFile } from '../../src/fmt/cacheStore.ts'; +import { + fmtCacheFileName, + fmtCacheVersion, + loadFmtCacheStore, + type FmtCacheFile, +} from '../../src/fmt/cacheStore.ts'; import { withTempProject } from './helpers.ts'; const namespace = 'test-namespace'; -const firstEntry = ['content-a', 'options-a', 'clean'] as const; -const secondEntry = ['content-b', 'options-b', 'dirty'] as const; -const unsupportedEntry = [null, 'options-c', 'unsupported'] as const; -const hashedUnsupportedEntry = ['content-c', 'options-c', 'unsupported'] as const; +const contentA = 'content-a'; +const contentB = 'content-b'; +const contentC = 'content-c'; +const optionsA = 'options-a'; +const optionsB = 'options-b'; +const optionsC = 'options-c'; +const firstEntry = [contentA, optionsA, 'clean'] as const; +const secondEntry = [contentB, optionsB, 'dirty'] as const; +const unsupportedEntry = ['', optionsC, 'unsupported'] as const; +const hashedUnsupportedEntry = [contentC, optionsC, 'unsupported'] as const; const readCache = (filePath: string): FmtCacheFile => JSON.parse(readFileSync(filePath, 'utf8')) as FmtCacheFile; -test('writes entries that can be loaded by another store', async () => { +test('writes flat entries that can be loaded by another store', async () => { await withTempProject(async (rootPath) => { - const cachePath = path.join(rootPath, 'cache', 'fmt-v1.json'); + const cachePath = path.join(rootPath, 'cache', fmtCacheFileName); const store = await loadFmtCacheStore(cachePath, namespace); expect(await store.save()).toBe(false); @@ -26,6 +37,25 @@ test('writes entries that can be loaded by another store', async () => { store.set('script', hashedUnsupportedEntry); expect(await store.save()).toBe(true); expect(await store.save()).toBe(false); + expect(readCache(cachePath)).toEqual({ + version: fmtCacheVersion, + namespace, + options: [optionsA, optionsC], + files: [ + 'src/a.ts', + contentA, + 0, + 0, + 'src/unknown.fixture', + '', + 1, + 2, + 'script', + contentC, + 1, + 2, + ], + }); const loaded = await loadFmtCacheStore(cachePath, namespace); expect(loaded.get('src/a.ts')).toEqual(firstEntry); @@ -36,16 +66,14 @@ test('writes entries that can be loaded by another store', async () => { test('preserves unvisited entries and skips unchanged updates', async () => { await withTempProject(async (rootPath) => { - const cachePath = path.join(rootPath, 'fmt-v1.json'); + const cachePath = path.join(rootPath, fmtCacheFileName); writeFileSync( cachePath, `${JSON.stringify({ version: fmtCacheVersion, namespace, - files: { - 'src/a.ts': firstEntry, - 'src/b.ts': secondEntry, - }, + options: [optionsA, optionsB], + files: ['src/a.ts', contentA, 0, 0, 'src/b.ts', contentB, 1, 1], })}\n`, ); @@ -56,34 +84,30 @@ test('preserves unvisited entries and skips unchanged updates', async () => { store.set('src/a.ts', secondEntry); expect(await store.save()).toBe(true); - expect(readCache(cachePath).files).toEqual({ - 'src/a.ts': secondEntry, - 'src/b.ts': secondEntry, + expect(readCache(cachePath)).toEqual({ + version: fmtCacheVersion, + namespace, + options: [optionsB], + files: ['src/a.ts', contentB, 0, 1, 'src/b.ts', contentB, 0, 1], }); }); }); -test('discards invalid data and entries from another namespace', async () => { +test('discards invalid schemas and other namespaces', async () => { await withTempProject(async (rootPath) => { - const cachePath = path.join(rootPath, 'fmt-v1.json'); + const cachePath = path.join(rootPath, fmtCacheFileName); + const validCache = { + version: fmtCacheVersion, + namespace, + options: [optionsA], + files: ['src/a.ts', contentA, 0, 0], + }; const invalidContents = [ '{invalid', - JSON.stringify({ version: 2, namespace, files: {} }), - JSON.stringify({ - version: fmtCacheVersion, - namespace, - files: { 'src/a.ts': ['content', 'options', 'unknown'] }, - }), - JSON.stringify({ - version: fmtCacheVersion, - namespace, - files: { 'src/a.ts': [42, 'options', 'unsupported'] }, - }), - JSON.stringify({ - version: fmtCacheVersion, - namespace, - files: { 'src/a.ts': [null, 'options', 'clean'] }, - }), + JSON.stringify({ ...validCache, version: fmtCacheVersion - 1 }), + JSON.stringify({ version: fmtCacheVersion, namespace, files: [] }), + JSON.stringify({ ...validCache, files: { 'src/a.ts': firstEntry } }), + JSON.stringify({ ...validCache, files: ['src/a.ts', contentA, 0] }), ]; for (const content of invalidContents) { @@ -95,9 +119,8 @@ test('discards invalid data and entries from another namespace', async () => { writeFileSync( cachePath, JSON.stringify({ - version: fmtCacheVersion, + ...validCache, namespace: 'old-namespace', - files: { 'src/a.ts': firstEntry }, }), ); const store = await loadFmtCacheStore(cachePath, namespace); @@ -106,14 +129,15 @@ test('discards invalid data and entries from another namespace', async () => { expect(readCache(cachePath)).toEqual({ version: fmtCacheVersion, namespace, - files: {}, + options: [], + files: [], }); }); }); test('does not throw or leave temporary files when persistence fails', async () => { await withTempProject(async (rootPath) => { - const cachePath = path.join(rootPath, 'fmt-v1.json'); + const cachePath = path.join(rootPath, fmtCacheFileName); mkdirSync(cachePath); const store = await loadFmtCacheStore(cachePath, namespace); diff --git a/packages/rstack/tests/fmt/runnerCache.test.ts b/packages/rstack/tests/fmt/runnerCache.test.ts index f9432a94..e78a2ab0 100644 --- a/packages/rstack/tests/fmt/runnerCache.test.ts +++ b/packages/rstack/tests/fmt/runnerCache.test.ts @@ -2,7 +2,12 @@ import { readFileSync, statSync, utimesSync, writeFileSync } from 'node:fs'; import path from 'node:path'; import { pathToFileURL } from 'node:url'; import { expect, test } from 'rstack/test'; -import { cacheNamespace, createOptionsHasher, sha256 } from '../../src/fmt/cacheIdentity.ts'; +import { + cacheHashLength, + cacheNamespace, + createCacheHash, + createOptionsHasher, +} from '../../src/fmt/cacheIdentity.ts'; import { loadFmtCacheStore } from '../../src/fmt/cacheStore.ts'; import { runFmtFiles } from '../../src/fmt/runner.ts'; import type { FmtCacheContext, FmtFileRequest, FmtMode } from '../../src/fmt/types.ts'; @@ -36,12 +41,12 @@ for (const mode of ['check', 'list-different'] as const) { const store = await loadFmtCacheStore(cache.filePath, cacheNamespace); expect(store.get('clean.ts')).toEqual([ - sha256(readFileSync(cleanPath)), + createCacheHash(readFileSync(cleanPath)), expect.any(String), 'clean', ]); expect(store.get('dirty.ts')).toEqual([ - sha256(readFileSync(dirtyPath)), + createCacheHash(readFileSync(dirtyPath)), expect.any(String), 'dirty', ]); @@ -79,7 +84,11 @@ test('uses content hashes instead of file metadata', async () => { const secondStore = await loadFmtCacheStore(cache.filePath, cacheNamespace); const secondEntry = secondStore.get('index.ts'); - expect(secondEntry).toEqual([sha256(readFileSync(filePath)), expect.any(String), 'dirty']); + expect(secondEntry).toEqual([ + createCacheHash(readFileSync(filePath)), + expect.any(String), + 'dirty', + ]); expect(secondEntry?.[0]).not.toBe(firstEntry?.[0]); }); }); @@ -101,7 +110,7 @@ test('invalidates entries when final options change', async () => { const store = await loadFmtCacheStore(cache.filePath, cacheNamespace); expect(store.get('index.ts')).toEqual([ - sha256(readFileSync(filePath)), + createCacheHash(readFileSync(filePath)), createOptionsHasher()(changed.options), 'dirty', ]); @@ -121,7 +130,7 @@ test('caches unsupported parser results until final options change', async () => processedFileCount: 0, }); expect((await loadFmtCacheStore(cache.filePath, cacheNamespace)).get('data.unknown')).toEqual([ - null, + '', createOptionsHasher()(unsupported.options), 'unsupported', ]); @@ -135,7 +144,7 @@ test('caches unsupported parser results until final options change', async () => processedFileCount: 1, }); expect((await loadFmtCacheStore(cache.filePath, cacheNamespace)).get('data.unknown')).toEqual([ - sha256(readFileSync(filePath)), + createCacheHash(readFileSync(filePath)), createOptionsHasher()(supported.options), 'dirty', ]); @@ -155,7 +164,7 @@ test('invalidates cached unsupported parser results when content changes without processedFileCount: 0, }); expect((await loadFmtCacheStore(cache.filePath, cacheNamespace)).get('script')).toEqual([ - sha256(readFileSync(filePath)), + createCacheHash(readFileSync(filePath)), createOptionsHasher()(file.options), 'unsupported', ]); @@ -169,7 +178,7 @@ test('invalidates cached unsupported parser results when content changes without processedFileCount: 1, }); expect((await loadFmtCacheStore(cache.filePath, cacheNamespace)).get('script')).toEqual([ - sha256(readFileSync(filePath)), + createCacheHash(readFileSync(filePath)), createOptionsHasher()(file.options), 'dirty', ]); @@ -212,14 +221,14 @@ test('caches only plugins with stable fingerprints', async () => { const firstHash = (await loadFmtCacheStore(cache.filePath, cacheNamespace)).get( 'data.fixture', )?.[1]; - expect(firstHash).toHaveLength(64); + expect(firstHash).toHaveLength(cacheHashLength); writePackageJson('2.0.0'); await run([file], 'check', cache); const secondHash = (await loadFmtCacheStore(cache.filePath, cacheNamespace)).get( 'data.fixture', )?.[1]; - expect(secondHash).toHaveLength(64); + expect(secondHash).toHaveLength(cacheHashLength); expect(secondHash).not.toBe(firstHash); }); }); @@ -281,12 +290,12 @@ test('write persists clean results for misses and hits', async () => { const store = await loadFmtCacheStore(cache.filePath, cacheNamespace); expect(store.get('clean.ts')).toEqual([ - sha256(readFileSync(cleanPath)), + createCacheHash(readFileSync(cleanPath)), expect.any(String), 'clean', ]); expect(store.get('dirty.ts')).toEqual([ - sha256(readFileSync(dirtyPath)), + createCacheHash(readFileSync(dirtyPath)), expect.any(String), 'clean', ]); @@ -318,7 +327,7 @@ test('write converts a dirty entry to clean', async () => { const store = await loadFmtCacheStore(cache.filePath, cacheNamespace); expect(store.get('index.ts')).toEqual([ - sha256(readFileSync(filePath)), + createCacheHash(readFileSync(filePath)), expect.any(String), 'clean', ]); diff --git a/packages/rstack/tests/fmt/runnerWorkerPreflight.test.ts b/packages/rstack/tests/fmt/runnerWorkerPreflight.test.ts index 71d48662..7b9e3b87 100644 --- a/packages/rstack/tests/fmt/runnerWorkerPreflight.test.ts +++ b/packages/rstack/tests/fmt/runnerWorkerPreflight.test.ts @@ -34,7 +34,7 @@ const createCachedUnsupportedFile = async (rootPath: string, fileName: string) = } const store = await loadFmtCacheStore(cache.filePath, cacheNamespace); - store.set(fileName, [null, optionsHash, 'unsupported']); + store.set(fileName, ['', optionsHash, 'unsupported']); await expect(store.save()).resolves.toBe(true); return { cache, file }; diff --git a/packages/rstack/tests/fmt/worker.test.ts b/packages/rstack/tests/fmt/worker.test.ts index 6f3631d5..3ef3d3aa 100644 --- a/packages/rstack/tests/fmt/worker.test.ts +++ b/packages/rstack/tests/fmt/worker.test.ts @@ -1,7 +1,7 @@ import path from 'node:path'; import { readFileSync } from 'node:fs'; import { expect, test } from 'rstack/test'; -import { sha256 } from '../../src/fmt/cacheIdentity.ts'; +import { createCacheHash } from '../../src/fmt/cacheIdentity.ts'; import { formatFile } from '../../src/fmt/worker.ts'; import { withTempProject, writeProjectFile } from './helpers.ts'; @@ -11,7 +11,7 @@ test('returns cached states before resolving the parser', async () => { const filePath = writeProjectFile(rootPath, 'example.ts', source); const noExtensionPath = writeProjectFile(rootPath, 'script', source); const missingPath = path.join(rootPath, 'missing.unknown'); - const contentHash = sha256(source); + const contentHash = createCacheHash(source); const optionsHash = 'options'; for (const [entry, targetPath, shouldWrite, status] of [ @@ -20,8 +20,8 @@ test('returns cached states before resolving the parser', async () => { [[contentHash, optionsHash, 'clean'], filePath, true, 'unchanged'], [[contentHash, optionsHash, 'unsupported'], noExtensionPath, false, 'unsupported'], [[contentHash, optionsHash, 'unsupported'], noExtensionPath, true, 'unsupported'], - [[null, optionsHash, 'unsupported'], missingPath, false, 'unsupported'], - [[null, optionsHash, 'unsupported'], missingPath, true, 'unsupported'], + [['', optionsHash, 'unsupported'], missingPath, false, 'unsupported'], + [['', optionsHash, 'unsupported'], missingPath, true, 'unsupported'], ] as const) { await expect( formatFile({ @@ -54,13 +54,13 @@ test('does not trust path-only unsupported entries for files without extensions' }, shouldWrite: false, cache: { - entry: [null, 'options', 'unsupported'], + entry: ['', 'options', 'unsupported'], optionsHash: 'options', }, }), ).resolves.toEqual({ status: 'changed', - cacheEntry: [sha256(readFileSync(filePath)), 'options', 'dirty'], + cacheEntry: [createCacheHash(readFileSync(filePath)), 'options', 'dirty'], }); }); }); @@ -81,7 +81,7 @@ test('resolves parser support before reading on a cache miss', async () => { }), ).resolves.toEqual({ status: 'unsupported', - cacheEntry: [null, 'options', 'unsupported'], + cacheEntry: ['', 'options', 'unsupported'], }); }); }); From b4fa3e8a7d4cdad5ad2aefcf4b94f76d1645a30a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 13 Aug 2026 05:02:46 +0000 Subject: [PATCH 08/33] chore(deps): update all non-major dependencies (#343) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/lint.yml | 2 +- .github/workflows/release.yml | 2 +- .github/workflows/reusable-native-build.yml | 2 +- .github/workflows/reusable-native-release.yml | 2 +- .github/workflows/test.yml | 4 +- Cargo.lock | 23 +- Cargo.toml | 6 +- .../template-app-preact-ts/package.json | 2 +- .../template-app-preact/package.json | 2 +- .../template-app-react-ts/package.json | 2 +- .../template-app-react/package.json | 2 +- .../template-app-solid-ts/package.json | 2 +- .../template-app-solid/package.json | 2 +- .../template-app-svelte-ts/package.json | 2 +- .../template-app-svelte/package.json | 2 +- .../template-app-vanilla-ts/package.json | 2 +- .../template-app-vanilla/package.json | 2 +- .../template-app-vue-ts/package.json | 2 +- .../template-app-vue/package.json | 2 +- .../template-lib-react-ts/package.json | 2 +- .../template-lib-react/package.json | 2 +- .../template-lib-solid-ts/package.json | 2 +- .../template-lib-solid/package.json | 2 +- .../template-lib-svelte-ts/package.json | 2 +- .../template-lib-vue-ts/package.json | 2 +- .../template-lib-vue/package.json | 2 +- pnpm-lock.yaml | 451 ++++++++++++------ pnpm-workspace.yaml | 12 +- rust-toolchain.toml | 2 +- 29 files changed, 364 insertions(+), 180 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 795132ce..34138418 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -26,7 +26,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7 with: - node-version: 24.18.1 + node-version: 24.19.0 package-manager-cache: false - name: Install Pnpm diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b0e43c23..80e75760 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -71,7 +71,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: - node-version: 24.18.1 + node-version: 24.19.0 package-manager-cache: false - name: Setup Pnpm diff --git a/.github/workflows/reusable-native-build.yml b/.github/workflows/reusable-native-build.yml index d06dbd48..4809a263 100644 --- a/.github/workflows/reusable-native-build.yml +++ b/.github/workflows/reusable-native-build.yml @@ -35,7 +35,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7 with: - node-version: 24.18.1 + node-version: 24.19.0 package-manager-cache: false - name: Install Pnpm diff --git a/.github/workflows/reusable-native-release.yml b/.github/workflows/reusable-native-release.yml index 920a686e..f8643d3b 100644 --- a/.github/workflows/reusable-native-release.yml +++ b/.github/workflows/reusable-native-release.yml @@ -70,7 +70,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7 with: - node-version: 24.18.1 + node-version: 24.19.0 package-manager-cache: false - name: Install Pnpm diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e41dfec6..8a00db11 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -27,7 +27,7 @@ jobs: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - - uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1 + - uses: dorny/paths-filter@ceb8a2b8f2d89434be7ff52d3de7ec3738c5cc9d # v4.0.3 id: changes with: predicate-quantifier: 'every' @@ -43,7 +43,7 @@ jobs: if: steps.changes.outputs.changed == 'true' uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7 with: - node-version: 24.18.1 + node-version: 24.19.0 package-manager-cache: false - name: Install Pnpm diff --git a/Cargo.lock b/Cargo.lock index 345a8ab6..93e66a42 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -190,6 +190,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "libc" +version = "0.2.189" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" + [[package]] name = "libloading" version = "0.9.0" @@ -214,13 +220,14 @@ checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" [[package]] name = "napi" -version = "3.12.0" +version = "3.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f71d6bc097c4a6eb853c3f24991ab8c9f50f57d1f719e305175541482217e36" +checksum = "459197f1592f4c3dbbf9c1b13f5a4599a343e4ef66b96bc340e2a518b36a6662" dependencies = [ "bitflags", "ctor", "futures", + "libc", "napi-build", "napi-sys", "nohash-hasher", @@ -229,15 +236,15 @@ dependencies = [ [[package]] name = "napi-build" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5282704fbe8d49b0cf8b08e3f33233416a528658f205c7e5ace63b582de0b11c" +checksum = "60fdf9b392c50e7c4170fa633bd909490ed7835cea4c046776d1a4dd8d2ae0ab" [[package]] name = "napi-derive" -version = "3.6.2" +version = "3.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d9002b2940f0184444754546e0fcd15182f56948e6f381968b019d549387c42" +checksum = "0fa55ea69990c90b888e9e77044410e304ce7f35de599dc6d0b5c1923d2e59af" dependencies = [ "convert_case", "ctor", @@ -249,9 +256,9 @@ dependencies = [ [[package]] name = "napi-derive-backend" -version = "6.1.1" +version = "6.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d60b5d773ad46c698c8cc2cd9fde0b283d39cbb7f71c04bee633c7bdba4423bd" +checksum = "df4056ac7c18e4438ccf0edaed4340ca0d269278c8ec19284f7b23cb039fd0ae" dependencies = [ "convert_case", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index 4ce85357..f7e5884d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,9 +10,9 @@ rust-version = "1.88" [workspace.dependencies] ignore = { version = "0.4.33", default-features = false } -napi = { version = "3.12.0", default-features = false, features = ["napi9"] } -napi-build = "2.4.0" -napi-derive = "3.6.2" +napi = { version = "3.12.1", default-features = false, features = ["napi9"] } +napi-build = "2.4.1" +napi-derive = "3.6.3" pathdiff = "0.2.3" rstack-ignore = { path = "crates/rstack-ignore" } diff --git a/packages/create-rstack/template-app-preact-ts/package.json b/packages/create-rstack/template-app-preact-ts/package.json index 6c1c71c9..e2265be8 100644 --- a/packages/create-rstack/template-app-preact-ts/package.json +++ b/packages/create-rstack/template-app-preact-ts/package.json @@ -18,7 +18,7 @@ }, "devDependencies": { "@rsbuild/plugin-preact": "^2.0.0", - "@testing-library/jest-dom": "^7.0.0", + "@testing-library/jest-dom": "^7.0.1", "@testing-library/preact": "^3.2.4", "@types/node": "^24.13.3", "happy-dom": "^20.11.2", diff --git a/packages/create-rstack/template-app-preact/package.json b/packages/create-rstack/template-app-preact/package.json index c21f8931..8352b4ef 100644 --- a/packages/create-rstack/template-app-preact/package.json +++ b/packages/create-rstack/template-app-preact/package.json @@ -18,7 +18,7 @@ }, "devDependencies": { "@rsbuild/plugin-preact": "^2.0.0", - "@testing-library/jest-dom": "^7.0.0", + "@testing-library/jest-dom": "^7.0.1", "@testing-library/preact": "^3.2.4", "happy-dom": "^20.11.2", "rstack": "^0.5.2" diff --git a/packages/create-rstack/template-app-react-ts/package.json b/packages/create-rstack/template-app-react-ts/package.json index dcabfd86..5afd8142 100644 --- a/packages/create-rstack/template-app-react-ts/package.json +++ b/packages/create-rstack/template-app-react-ts/package.json @@ -20,7 +20,7 @@ "devDependencies": { "@rsbuild/plugin-react": "^2.1.0", "@testing-library/dom": "^10.4.1", - "@testing-library/jest-dom": "^7.0.0", + "@testing-library/jest-dom": "^7.0.1", "@testing-library/react": "^16.3.2", "@types/node": "^24.13.3", "@types/react": "^19.2.18", diff --git a/packages/create-rstack/template-app-react/package.json b/packages/create-rstack/template-app-react/package.json index b724a854..0d2d0e24 100644 --- a/packages/create-rstack/template-app-react/package.json +++ b/packages/create-rstack/template-app-react/package.json @@ -20,7 +20,7 @@ "devDependencies": { "@rsbuild/plugin-react": "^2.1.0", "@testing-library/dom": "^10.4.1", - "@testing-library/jest-dom": "^7.0.0", + "@testing-library/jest-dom": "^7.0.1", "@testing-library/react": "^16.3.2", "happy-dom": "^20.11.2", "rstack": "^0.5.2" diff --git a/packages/create-rstack/template-app-solid-ts/package.json b/packages/create-rstack/template-app-solid-ts/package.json index 5c38f341..61d0c0d8 100644 --- a/packages/create-rstack/template-app-solid-ts/package.json +++ b/packages/create-rstack/template-app-solid-ts/package.json @@ -20,7 +20,7 @@ "@rsbuild/plugin-babel": "^2.0.1", "@rsbuild/plugin-solid": "^1.2.2", "@solidjs/testing-library": "^0.8.10", - "@testing-library/jest-dom": "^7.0.0", + "@testing-library/jest-dom": "^7.0.1", "@types/node": "^24.13.3", "happy-dom": "^20.11.2", "rstack": "^0.5.2", diff --git a/packages/create-rstack/template-app-solid/package.json b/packages/create-rstack/template-app-solid/package.json index c092fd73..064ec69b 100644 --- a/packages/create-rstack/template-app-solid/package.json +++ b/packages/create-rstack/template-app-solid/package.json @@ -20,7 +20,7 @@ "@rsbuild/plugin-babel": "^2.0.1", "@rsbuild/plugin-solid": "^1.2.2", "@solidjs/testing-library": "^0.8.10", - "@testing-library/jest-dom": "^7.0.0", + "@testing-library/jest-dom": "^7.0.1", "happy-dom": "^20.11.2", "rstack": "^0.5.2" } diff --git a/packages/create-rstack/template-app-svelte-ts/package.json b/packages/create-rstack/template-app-svelte-ts/package.json index 1a00fa3b..3d737117 100644 --- a/packages/create-rstack/template-app-svelte-ts/package.json +++ b/packages/create-rstack/template-app-svelte-ts/package.json @@ -18,7 +18,7 @@ }, "devDependencies": { "@rsbuild/plugin-svelte": "^2.0.1", - "@testing-library/jest-dom": "^7.0.0", + "@testing-library/jest-dom": "^7.0.1", "@testing-library/svelte": "^5.4.2", "@types/node": "^24.13.3", "happy-dom": "^20.11.2", diff --git a/packages/create-rstack/template-app-svelte/package.json b/packages/create-rstack/template-app-svelte/package.json index d3ef1e7c..ad9fd84d 100644 --- a/packages/create-rstack/template-app-svelte/package.json +++ b/packages/create-rstack/template-app-svelte/package.json @@ -18,7 +18,7 @@ }, "devDependencies": { "@rsbuild/plugin-svelte": "^2.0.1", - "@testing-library/jest-dom": "^7.0.0", + "@testing-library/jest-dom": "^7.0.1", "@testing-library/svelte": "^5.4.2", "happy-dom": "^20.11.2", "prettier-plugin-svelte": "^4.1.1", diff --git a/packages/create-rstack/template-app-vanilla-ts/package.json b/packages/create-rstack/template-app-vanilla-ts/package.json index 6736f404..fd6dab91 100644 --- a/packages/create-rstack/template-app-vanilla-ts/package.json +++ b/packages/create-rstack/template-app-vanilla-ts/package.json @@ -15,7 +15,7 @@ }, "devDependencies": { "@testing-library/dom": "^10.4.1", - "@testing-library/jest-dom": "^7.0.0", + "@testing-library/jest-dom": "^7.0.1", "@types/node": "^24.13.3", "happy-dom": "^20.11.2", "rstack": "^0.5.2", diff --git a/packages/create-rstack/template-app-vanilla/package.json b/packages/create-rstack/template-app-vanilla/package.json index 32376dc9..3e2ddcb2 100644 --- a/packages/create-rstack/template-app-vanilla/package.json +++ b/packages/create-rstack/template-app-vanilla/package.json @@ -15,7 +15,7 @@ }, "devDependencies": { "@testing-library/dom": "^10.4.1", - "@testing-library/jest-dom": "^7.0.0", + "@testing-library/jest-dom": "^7.0.1", "happy-dom": "^20.11.2", "rstack": "^0.5.2" } diff --git a/packages/create-rstack/template-app-vue-ts/package.json b/packages/create-rstack/template-app-vue-ts/package.json index f7103c91..26df147d 100644 --- a/packages/create-rstack/template-app-vue-ts/package.json +++ b/packages/create-rstack/template-app-vue-ts/package.json @@ -18,7 +18,7 @@ }, "devDependencies": { "@rsbuild/plugin-vue": "^2.0.1", - "@testing-library/jest-dom": "^7.0.0", + "@testing-library/jest-dom": "^7.0.1", "@types/node": "^24.13.3", "@vue/test-utils": "^2.4.11", "happy-dom": "^20.11.2", diff --git a/packages/create-rstack/template-app-vue/package.json b/packages/create-rstack/template-app-vue/package.json index 03d5df80..551684e5 100644 --- a/packages/create-rstack/template-app-vue/package.json +++ b/packages/create-rstack/template-app-vue/package.json @@ -18,7 +18,7 @@ }, "devDependencies": { "@rsbuild/plugin-vue": "^2.0.1", - "@testing-library/jest-dom": "^7.0.0", + "@testing-library/jest-dom": "^7.0.1", "@vue/test-utils": "^2.4.11", "happy-dom": "^20.11.2", "rstack": "^0.5.2" diff --git a/packages/create-rstack/template-lib-react-ts/package.json b/packages/create-rstack/template-lib-react-ts/package.json index 98d6ae9c..7099cae6 100644 --- a/packages/create-rstack/template-lib-react-ts/package.json +++ b/packages/create-rstack/template-lib-react-ts/package.json @@ -25,7 +25,7 @@ "devDependencies": { "@rsbuild/plugin-react": "^2.1.0", "@testing-library/dom": "^10.4.1", - "@testing-library/jest-dom": "^7.0.0", + "@testing-library/jest-dom": "^7.0.1", "@testing-library/react": "^16.3.2", "@types/node": "^24.13.3", "@types/react": "^19.2.18", diff --git a/packages/create-rstack/template-lib-react/package.json b/packages/create-rstack/template-lib-react/package.json index f9b3c3dc..2ec7b89c 100644 --- a/packages/create-rstack/template-lib-react/package.json +++ b/packages/create-rstack/template-lib-react/package.json @@ -23,7 +23,7 @@ "devDependencies": { "@rsbuild/plugin-react": "^2.1.0", "@testing-library/dom": "^10.4.1", - "@testing-library/jest-dom": "^7.0.0", + "@testing-library/jest-dom": "^7.0.1", "@testing-library/react": "^16.3.2", "@types/react-dom": "^19.2.4", "happy-dom": "^20.11.2", diff --git a/packages/create-rstack/template-lib-solid-ts/package.json b/packages/create-rstack/template-lib-solid-ts/package.json index 17b3132c..f3757028 100644 --- a/packages/create-rstack/template-lib-solid-ts/package.json +++ b/packages/create-rstack/template-lib-solid-ts/package.json @@ -27,7 +27,7 @@ "@rsbuild/plugin-babel": "^2.0.1", "@rsbuild/plugin-solid": "^1.2.2", "@solidjs/testing-library": "^0.8.10", - "@testing-library/jest-dom": "^7.0.0", + "@testing-library/jest-dom": "^7.0.1", "@types/node": "^24.13.3", "happy-dom": "^20.11.2", "rstack": "^0.5.2", diff --git a/packages/create-rstack/template-lib-solid/package.json b/packages/create-rstack/template-lib-solid/package.json index 90567af4..f21d25ae 100644 --- a/packages/create-rstack/template-lib-solid/package.json +++ b/packages/create-rstack/template-lib-solid/package.json @@ -25,7 +25,7 @@ "@rsbuild/plugin-babel": "^2.0.1", "@rsbuild/plugin-solid": "^1.2.2", "@solidjs/testing-library": "^0.8.10", - "@testing-library/jest-dom": "^7.0.0", + "@testing-library/jest-dom": "^7.0.1", "happy-dom": "^20.11.2", "rstack": "^0.5.2", "solid-js": "^1.9.14" diff --git a/packages/create-rstack/template-lib-svelte-ts/package.json b/packages/create-rstack/template-lib-svelte-ts/package.json index 956e0de2..1fbc2c4b 100644 --- a/packages/create-rstack/template-lib-svelte-ts/package.json +++ b/packages/create-rstack/template-lib-svelte-ts/package.json @@ -30,7 +30,7 @@ "rstack": "^0.5.2", "svelte": "^5.56.8", "svelte-check": "^4.7.5", - "svelte2tsx": "^0.7.59", + "svelte2tsx": "^0.7.60", "typescript": "^6.0.3" }, "peerDependencies": { diff --git a/packages/create-rstack/template-lib-vue-ts/package.json b/packages/create-rstack/template-lib-vue-ts/package.json index 1c5146c1..59ee0a24 100644 --- a/packages/create-rstack/template-lib-vue-ts/package.json +++ b/packages/create-rstack/template-lib-vue-ts/package.json @@ -24,7 +24,7 @@ }, "devDependencies": { "@rsbuild/plugin-vue": "^2.0.1", - "@testing-library/jest-dom": "^7.0.0", + "@testing-library/jest-dom": "^7.0.1", "@types/node": "^24.13.3", "@vue/test-utils": "^2.4.11", "happy-dom": "^20.11.2", diff --git a/packages/create-rstack/template-lib-vue/package.json b/packages/create-rstack/template-lib-vue/package.json index 9ed02556..68a08a4b 100644 --- a/packages/create-rstack/template-lib-vue/package.json +++ b/packages/create-rstack/template-lib-vue/package.json @@ -22,7 +22,7 @@ }, "devDependencies": { "@rsbuild/plugin-vue": "^2.0.1", - "@testing-library/jest-dom": "^7.0.0", + "@testing-library/jest-dom": "^7.0.1", "@vue/test-utils": "^2.4.11", "happy-dom": "^20.11.2", "rstack": "^0.5.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c3ad4f86..be9b0d6c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,11 +8,11 @@ settings: catalogs: default: '@napi-rs/cli': - specifier: ^3.8.3 - version: 3.8.3 + specifier: ^3.8.6 + version: 3.8.6 '@rsbuild/core': - specifier: ~2.1.10 - version: 2.1.10 + specifier: ~2.1.11 + version: 2.1.11 '@rsbuild/plugin-react': specifier: ^2.1.0 version: 2.1.0 @@ -56,14 +56,14 @@ catalogs: specifier: ~0.11.6 version: 0.11.6 '@shikijs/transformers': - specifier: ^4.4.2 - version: 4.4.2 + specifier: ^4.4.3 + version: 4.4.3 '@testing-library/dom': specifier: ^10.4.1 version: 10.4.1 '@testing-library/jest-dom': - specifier: ^7.0.0 - version: 7.0.0 + specifier: ^7.0.1 + version: 7.0.1 '@testing-library/react': specifier: ^16.3.2 version: 16.3.2 @@ -86,8 +86,8 @@ catalogs: specifier: 2.1.0 version: 2.1.0 globals: - specifier: ^17.7.0 - version: 17.9.0 + specifier: ^17.10.0 + version: 17.10.0 happy-dom: specifier: ^20.11.2 version: 20.11.2 @@ -149,8 +149,8 @@ catalogs: specifier: 1.0.12 version: 1.0.12 yuku-parser: - specifier: 0.8.4 - version: 0.8.4 + specifier: 0.8.5 + version: 0.8.5 importers: @@ -164,7 +164,7 @@ importers: version: 0.0.4 globals: specifier: 'catalog:' - version: 17.9.0 + version: 17.10.0 heading-case: specifier: 'catalog:' version: 1.1.5 @@ -189,13 +189,13 @@ importers: devDependencies: '@rsbuild/plugin-react': specifier: 'catalog:' - version: 2.1.0(@rsbuild/core@2.1.10)(@rspack/core@2.1.8) + version: 2.1.0(@rsbuild/core@2.1.10)(@rspack/core@2.1.9) '@testing-library/dom': specifier: 'catalog:' version: 10.4.1 '@testing-library/jest-dom': specifier: 'catalog:' - version: 7.0.0(@testing-library/dom@10.4.1) + version: 7.0.1(@testing-library/dom@10.4.1) '@testing-library/react': specifier: 'catalog:' version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.4)(@types/react@19.2.18)(react-dom@19.2.8)(react@19.2.8) @@ -222,7 +222,7 @@ importers: version: 10.4.1 '@testing-library/jest-dom': specifier: 'catalog:' - version: 7.0.0(@testing-library/dom@10.4.1) + version: 7.0.1(@testing-library/dom@10.4.1) '@types/node': specifier: 'catalog:' version: 24.13.3 @@ -277,13 +277,13 @@ importers: devDependencies: '@rsbuild/plugin-react': specifier: 'catalog:' - version: 2.1.0(@rsbuild/core@2.1.10)(@rspack/core@2.1.8) + version: 2.1.0(@rsbuild/core@2.1.10)(@rspack/core@2.1.9) '@testing-library/dom': specifier: 'catalog:' version: 10.4.1 '@testing-library/jest-dom': specifier: 'catalog:' - version: 7.0.0(@testing-library/dom@10.4.1) + version: 7.0.1(@testing-library/dom@10.4.1) '@testing-library/react': specifier: 'catalog:' version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.4)(@types/react@19.2.18)(react-dom@19.2.8)(react@19.2.8) @@ -320,7 +320,7 @@ importers: devDependencies: '@rsbuild/plugin-react': specifier: 'catalog:' - version: 2.1.0(@rsbuild/core@2.1.10)(@rspack/core@2.1.8) + version: 2.1.0(@rsbuild/core@2.1.10)(@rspack/core@2.1.9) '@testing-library/dom': specifier: 'catalog:' version: 10.4.1 @@ -366,7 +366,7 @@ importers: dependencies: '@rsbuild/core': specifier: 'catalog:' - version: 2.1.10 + version: 2.1.11 '@rslib/core': specifier: 'catalog:' version: 1.0.0-beta.2(typescript@7.0.2) @@ -384,11 +384,11 @@ importers: version: 2.1.0 yuku-parser: specifier: 'catalog:' - version: 0.8.4 + version: 0.8.5 devDependencies: '@napi-rs/cli': specifier: 'catalog:' - version: 3.8.3(@types/node@24.13.3)(node-addon-api@7.1.1)(supports-color@8.1.1) + version: 3.8.6(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@types/node@24.13.3)(supports-color@8.1.1) '@rspress/core': specifier: 'catalog:' version: 2.0.19(micromark-util-types@2.0.2)(micromark@4.0.2)(supports-color@8.1.1) @@ -400,7 +400,7 @@ importers: version: 0.2.0 '@rstest/adapter-rsbuild': specifier: 'catalog:' - version: 0.11.6(@rsbuild/core@2.1.10)(@rstest/core@0.11.6) + version: 0.11.6(@rsbuild/core@2.1.11)(@rstest/core@0.11.6) '@rstest/adapter-rslib': specifier: 'catalog:' version: 0.11.6(@rslib/core@1.0.0-beta.2)(@rstest/core@0.11.6)(typescript@7.0.2) @@ -469,7 +469,7 @@ importers: version: 1.14.7(@rspress/core@2.0.19) '@shikijs/transformers': specifier: 'catalog:' - version: 4.4.2 + version: 4.4.3 '@types/node': specifier: 'catalog:' version: 24.13.3 @@ -766,15 +766,21 @@ packages: '@types/react': '>=16' react: '>=16' - '@napi-rs/cli@3.8.3': - resolution: {integrity: sha512-f5vr9ih+ROvX5x9yZ4ywGj+kqcMXTzc4TsXUT4KUmfYlcdKTJ0uROuzeDP6rfDKhCqWo7EL6nBvfMWkhv5TMeQ==} + '@napi-rs/cli@3.8.6': + resolution: {integrity: sha512-FnJ9fghsV9Q4zh2aJGPSvQiUlJRC27B6KhzAXcIW2rlSD8keak3mhXw4tJYa3KJkP9whETfsPwqp/DJRnQg5ng==} engines: {node: ^20.17.0 || ^22.13.0 || >= 23.5.0} hasBin: true peerDependencies: - '@emnapi/runtime': 2.0.0-alpha.3 + '@emnapi/core': ^1.7.1 || ^2.0.0-alpha.4 + '@emnapi/runtime': ^1.7.1 || ^2.0.0-alpha.4 + emnapi: ^1.7.1 || ^2.0.0-alpha.4 peerDependenciesMeta: + '@emnapi/core': + optional: true '@emnapi/runtime': optional: true + emnapi: + optional: true '@napi-rs/cross-toolchain@1.0.3': resolution: {integrity: sha512-ENPfLe4937bsKVTDA6zdABx4pq9w0tHqRrJHyaGxgaPq03a2Bd1unD5XSKjXJjebsABJ+MjAv1A2OvCgK9yehg==} @@ -1275,6 +1281,16 @@ packages: core-js: optional: true + '@rsbuild/core@2.1.11': + resolution: {integrity: sha512-jA/QwZu8wIljp70TjERVoX+vk2cWU+viHpV9EAdKpA6ifu/pFnThEhbV3RFxBvF/9mB3h7ZRUfdDIyknT+9MWA==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + core-js: '>= 3.0.0' + peerDependenciesMeta: + core-js: + optional: true + '@rsbuild/plugin-react@2.1.0': resolution: {integrity: sha512-RQTIAWB/CwPjoWt9iAl+8HixeQVgZ7kEIBrWPCixfITyHdiD84h0YpUTpEUuz6kGHw1KXT9mHZ3Rwy6WG7aRDA==} peerDependencies: @@ -1362,69 +1378,149 @@ packages: cpu: [arm64] os: [darwin] + '@rspack/binding-darwin-arm64@2.1.9': + resolution: {integrity: sha512-sQQgKx+1ckW5GI6w/ozJkoaQM0Skbwj7hFiv+Y2d7+iAB7OVz83LWFrodRl1QGCg1QNuaEmlVo9AUapWUSr/8g==} + cpu: [arm64] + os: [darwin] + '@rspack/binding-darwin-x64@2.1.8': resolution: {integrity: sha512-08pBkFhlD3Y3Qzh94w/Fc3skaIE3e96kl2P14m8+tnYTcglpOfpA2OwS3iHt9fOqy0HjoAVe6/MW3cBgs5iabA==} cpu: [x64] os: [darwin] + '@rspack/binding-darwin-x64@2.1.9': + resolution: {integrity: sha512-kuWzn8JFKJUxSFwX/+rzvZUm4fRrSbXCTCAlzb0iHvP6vftjCFHGpNJfWjD7yX9O7C/dtoGiNT1O1veJytVsWA==} + cpu: [x64] + os: [darwin] + '@rspack/binding-linux-arm64-gnu@2.1.8': resolution: {integrity: sha512-KLniMc9GzhKpVqhPzaJo3KJwzdAllXVVqZIk/uL1QipXOxs57fgM4u7IexKPFVla0o/u1PQG/Ah2YLDmda24Ow==} cpu: [arm64] os: [linux] libc: [glibc] + '@rspack/binding-linux-arm64-gnu@2.1.9': + resolution: {integrity: sha512-rj1TjWGuG9Zc+fmwfvOpRO9npuHMKE4xXSB/BZqZNcH5Uey4NcAo1/GF8zHRoalQrwf0roP9WsFX1tk85rzP/Q==} + cpu: [arm64] + os: [linux] + libc: [glibc] + '@rspack/binding-linux-arm64-musl@2.1.8': resolution: {integrity: sha512-yUKAxHNGnICtw5RnxFWu4dHtsz/tdt7rbeFcsINNVre9HcrRxf5XP+FbOGL/SMxd9oM9XCo10paU2WckTKwbEA==} cpu: [arm64] os: [linux] libc: [musl] + '@rspack/binding-linux-arm64-musl@2.1.9': + resolution: {integrity: sha512-Z2+sS2z9Imt3og0e3Kq4hEumiqTajQBXkl9cqSYj1lwOgmViLAvMX4BlCL1cinIEstixFKQ+xsta9SI6ivCKtg==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rspack/binding-linux-ppc64-gnu@2.1.9': + resolution: {integrity: sha512-xK90IHipRDgxvDF9n90HRNklci0G2Amk0ZMsM3t3YX+/8jIJNcuEPk6hJ1hlY6KZu7U9enqGbNQ7Fe0StBeLVA==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + '@rspack/binding-linux-riscv64-gnu@2.1.8': resolution: {integrity: sha512-gg4S1jaitwYPHR9HZ3zNGH1EK2GXINm66p4kEpOP1gbc+akyOouVF/dMcu9NGPlRg58FbEhVRZYKu7Z/zcpKHg==} cpu: [riscv64] os: [linux] libc: [glibc] + '@rspack/binding-linux-riscv64-gnu@2.1.9': + resolution: {integrity: sha512-aaOwU3voq20Vwmfu1V6UPz8eQJBitBUNbLc08dxHGsmQM+ap6dd4j5xn/i5Y6AfLro2Q3GJvpCayc+dVIOR32g==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + '@rspack/binding-linux-riscv64-musl@2.1.8': resolution: {integrity: sha512-b/aU5j1h368SLNyz5u+flqpZVhzSZ1UIslaj9sZJuAvqkGWv3xsjc/28/PTo/RYXCxd0FNVAxTxWHKvRiAAS8w==} cpu: [riscv64] os: [linux] libc: [musl] + '@rspack/binding-linux-riscv64-musl@2.1.9': + resolution: {integrity: sha512-tF7XnEtpTYyVS8ef96IKUjFhd9lFa9Swv212fcyWxRhxRn4PEYVWpSh/D3NDVX+i69Z7xFDDEoyMUdYBkkVTlw==} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@rspack/binding-linux-s390x-gnu@2.1.9': + resolution: {integrity: sha512-rGmeME3Pd8k/55txP+19ceZJxhVN2mtC8TLzB1ycTrhy8U+ZnN7J8rZSl89LYrZGYewd1UmOcY0QKKy05FS3FA==} + cpu: [s390x] + os: [linux] + libc: [glibc] + '@rspack/binding-linux-x64-gnu@2.1.8': resolution: {integrity: sha512-EyegohSx0BJRqieCg9f/caCqFARRWkqI5hwJt6k530MoOTLeq8I3vsbeg24/2MktwIC1dmJi8bl0+WhPKQs4eQ==} cpu: [x64] os: [linux] libc: [glibc] + '@rspack/binding-linux-x64-gnu@2.1.9': + resolution: {integrity: sha512-YimUCS//wl+AZjXvgVig7sJtPiGs+WNMH4g49F1msB5T40rw0aOopp9O3MdC+LFfRm6vpIJwOHd6alo/UUs7nA==} + cpu: [x64] + os: [linux] + libc: [glibc] + '@rspack/binding-linux-x64-musl@2.1.8': resolution: {integrity: sha512-I6E+goN+UQ297q4r1qdbiAyNCI3t0+a5Y0xDIAPOZfRDRxDTnH/LF8/y65gjsJoKRKyn7zxRC0T/NURTkRNQ9A==} cpu: [x64] os: [linux] libc: [musl] + '@rspack/binding-linux-x64-musl@2.1.9': + resolution: {integrity: sha512-tYJRdoB3IWVVcnGPZqCnRjC5MJle7xHucKkIuKtGbSMS6hzg6B1oKZav1BBw72gxnrW4n2Bwt82TBKQKBUSjmA==} + cpu: [x64] + os: [linux] + libc: [musl] + '@rspack/binding-wasm32-wasi@2.1.8': resolution: {integrity: sha512-om7GAKWAU3lcSvbCon2m7mzw8v9OTrO2LW2MZ1lGe/uVJJmwGGkl9HVoXFyWFLrN6YVFyx8iP+AkN4owDWB9Cw==} cpu: [wasm32] + '@rspack/binding-wasm32-wasi@2.1.9': + resolution: {integrity: sha512-TF6oZRU23x6vHzGuvRFszvEnmC5Yn8PHbKmeZWsUHj4Mtv4tDdDGVdlxj6Kq3pySS6sRknv8gzpRMhXqHD3I5g==} + cpu: [wasm32] + '@rspack/binding-win32-arm64-msvc@2.1.8': resolution: {integrity: sha512-WDnsP/SUb9zbxyGX9XjPw5AXrX86u5oidn0MDdfJduOOqdCSpHwmRjlQ8NUJhbBq9WqVJMFlcab7NwZVWX/yyg==} cpu: [arm64] os: [win32] + '@rspack/binding-win32-arm64-msvc@2.1.9': + resolution: {integrity: sha512-tLt4gbvUelmtJGI3PHtQHZuGpaO2z/ym6+OXAjc6NR2jWbzljardSjONiXVWIi1zmzODt4dD/fL3Ncb+RU/jHQ==} + cpu: [arm64] + os: [win32] + '@rspack/binding-win32-ia32-msvc@2.1.8': resolution: {integrity: sha512-QiMQMPNDiY3dhhaIdaFPzcPDC06cEYkNY89ea+EmDvNVgZq6V+2mFS/WnzZVMeEbGAYJCjsv/ABhhLT1hlYMvg==} cpu: [ia32] os: [win32] + '@rspack/binding-win32-ia32-msvc@2.1.9': + resolution: {integrity: sha512-VznxSrGPb4mvxkTHTdGolEpBOuDW7RICD9Rp266MhYLQG4c0uNcX7+vWF4HbFvB0kN+Gdkj7vz+5shWdrfK72Q==} + cpu: [ia32] + os: [win32] + '@rspack/binding-win32-x64-msvc@2.1.8': resolution: {integrity: sha512-b7sA5eB64vo2mbsuc//MOYzVLeCKHPn0dfP/GmNEoHdWbhRgZ/orZLWurYMQj04ELTLW6YCJEy59g5KRzNYHfw==} cpu: [x64] os: [win32] + '@rspack/binding-win32-x64-msvc@2.1.9': + resolution: {integrity: sha512-P1dGC6t3PJinqN6tBZ+jyou4LvwpD2ygeovKgg5tuYWKFMUwh1v60yX3afOUwaJMEGbHUye7xuYRd84NCMSNOQ==} + cpu: [x64] + os: [win32] + '@rspack/binding@2.1.8': resolution: {integrity: sha512-tmAyHzDbPiy8V7HvQqtuPsbs6dPgwV0YjzW5XrPRV9gzf+Hdm7pvsZJKE1QKO9WV5RuvGYav98xIX6O+abZxzQ==} + '@rspack/binding@2.1.9': + resolution: {integrity: sha512-0ZZj+RE62/jFRwX5czqjjGiMGgzSK0hm7/66PtCKjyZjb2tNAg3WGyWv+ref7684ZAjtbHHpZ+EOGswQYBjklA==} + '@rspack/core@2.1.8': resolution: {integrity: sha512-na1kyA6Mj8/LWw9O3A8NsrG9rNKN3Iq2WiXrEuIwsU5r/Nl/evm3hO7bWKHxgsRyydI6W7okwx3MXgf8rzel6g==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1437,6 +1533,18 @@ packages: '@swc/helpers': optional: true + '@rspack/core@2.1.9': + resolution: {integrity: sha512-kXd5aYrkO+91fYolNYAjUhW/1F9kGmw7PtneNRY6z3KK6ttJgQWMVNypiCkhK3TOcyWPGH42qd0bzHZlH72JaA==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + '@module-federation/runtime-tools': ^0.24.1 || ^2.0.0 + '@swc/helpers': ^0.5.23 + peerDependenciesMeta: + '@module-federation/runtime-tools': + optional: true + '@swc/helpers': + optional: true + '@rspack/plugin-react-refresh@2.0.2': resolution: {integrity: sha512-dGNZiCxQxgAUI9sah7gd8u+O7OJZRCmqtEJNDOd8xW5RqcieC86F7p5qcShyw6onH5pKf57evpr2VjGbaFGkZg==} peerDependencies: @@ -1522,8 +1630,8 @@ packages: resolution: {integrity: sha512-ANMDxuaPsNMdDC1m4vfvhlDmJweMwkE5XitTwrq2rWHx5jM+dlm4MmHt2PP6t0uejfR77SuhrhJ0zEijIF/uhA==} engines: {node: '>=20'} - '@shikijs/core@4.4.2': - resolution: {integrity: sha512-StyzbAyxg2/tBGf78gwbBkGyeQ73lf8UiJArFaQhTQIDqQOCKPCQFanvrs4/Yv3Yfyc+ONInJM6K+FMIf+P+kA==} + '@shikijs/core@4.4.3': + resolution: {integrity: sha512-QCR4q2ZO/ILJEuwiBMel4wdcTDb1JGwfjKTxPDF6x8ixOaluPrVqIn06C99AcRPhmYlBR56d/Fb+GN58GzExpg==} engines: {node: '>=20'} '@shikijs/engine-javascript@4.3.1': @@ -1542,8 +1650,8 @@ packages: resolution: {integrity: sha512-CXQRQOYy1leqQ8ceTeJdmXv/bsUY++6QyLpXJ94LZAAYj5X2SKRdc5ipguv4NPyGVKItB2PPwUpRNe0Sjh5S1A==} engines: {node: '>=20'} - '@shikijs/primitive@4.4.2': - resolution: {integrity: sha512-l6fQQKsOMlz72n38fztmSgZ76MO6KSWuw8o+GJ+FhmqrpC9pIOJNQNXGgbb5yX2AwpzlEHwsaLPnk/8o4Fm+rA==} + '@shikijs/primitive@4.4.3': + resolution: {integrity: sha512-m0wBeLDQDeIxRdUmrCPdQqfuUamDwRL5isCfYbguKD6NiaKpVbsv+3J81DyIKgNW5h4WAIIr8T4EkgQrBBxvaQ==} engines: {node: '>=20'} '@shikijs/rehype@4.3.1': @@ -1554,16 +1662,16 @@ packages: resolution: {integrity: sha512-dgpoJ4WqNi2yTmizQHBJ5zcX6j2lE6icN/0yt4l1kkf16jrY/pwPLoTb1ETsWMz0OBLf9ZNvwmxft+cH+N9qSA==} engines: {node: '>=20'} - '@shikijs/transformers@4.4.2': - resolution: {integrity: sha512-d81PJ9KkR1tVP95FH/9296HTtDo0mh76wv10u9T1YmsZq/UcXgt0OLdBszfUQ1i+umkRMCjDnFbFZU7/tCODTQ==} + '@shikijs/transformers@4.4.3': + resolution: {integrity: sha512-oJSARV6NaWd+rnNJbtnpAdj3Zg0ZVyzsnMgb3vi3HA+35y8lBWUCpOnWsmyiXZIikY+x1BDqrQUgmxfzWh7Jvw==} engines: {node: '>=20'} '@shikijs/types@4.3.1': resolution: {integrity: sha512-CHFxE0jztBIZRHH6gxXE7DXUCFXjReEGxZ/j0rfSLGKZuwp2xBYycEP14875DSa9KLL/6700oxIq6oO6ef9K2g==} engines: {node: '>=20'} - '@shikijs/types@4.4.2': - resolution: {integrity: sha512-PFYitV4vpDr/iPCIhnHp+Q4ftic5N5VeNJ3KQ1O8gn3h2ar8qgwMAXF7tq4m1CWaMS60fV4VqF6vfnWH4F7vqQ==} + '@shikijs/types@4.4.3': + resolution: {integrity: sha512-UEJxmRR++MAGR6hugn0vgVS2W/6lWAts84FFSrnlH9sP0LNol7E5+NQ792pH8liWUhyMyjhTgSUH3k7iD7tc5g==} engines: {node: '>=20'} '@shikijs/vscode-textmate@10.0.2': @@ -1581,11 +1689,15 @@ packages: resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} engines: {node: '>=18'} - '@testing-library/jest-dom@7.0.0': - resolution: {integrity: sha512-HKAH9C6mBo5yBG6yRO5i43L2iisencAo5z+o5P/saHUoY+miC5ivXRxHBJcFyB5ypPNxHJdK3BoF/3O4DIptMg==} + '@testing-library/jest-dom@7.0.1': + resolution: {integrity: sha512-oMDTC3oA+6CXSO2JZnvOI7CA6oVub6kij5ggk9ohwye5slmkwxYDXcPOVxgMw/RQlticjtO0C1RZkR97HgrWMw==} engines: {node: '>=22', npm: '>=6', yarn: '>=1'} peerDependencies: '@testing-library/dom': '>=10 <11' + vitest: '>= 0.32' + peerDependenciesMeta: + vitest: + optional: true '@testing-library/react@16.3.2': resolution: {integrity: sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==} @@ -1795,74 +1907,74 @@ packages: peerDependencies: react: '>=18.3.1' - '@yuku-parser/binding-android-arm64@0.8.4': - resolution: {integrity: sha512-+HIMmv08Zrh9ugIAEMnKBMMePOl7CDxrjc8Vui1+GG2TJHM1yI1+3wo1pnXB6Nj2IiHugDkQw8ycUI6SA2EUkQ==} + '@yuku-parser/binding-android-arm64@0.8.5': + resolution: {integrity: sha512-BJtJvyf/Ma3v57uebPbe7VMUjNwTa3KW0fJn4awBBXyen8aS/i0gUbCDEsjGPY4GvAT41AggcYSep37V5VPENg==} cpu: [arm64] os: [android] - '@yuku-parser/binding-darwin-arm64@0.8.4': - resolution: {integrity: sha512-Elf/B/2m3OsyvxoQnBk8Dtu+9csHkzBNs5Yv9GbHjT3x0kVKNWjFusyZgm41VwxcPDqdpRi8tWxNX7OqXkmf/A==} + '@yuku-parser/binding-darwin-arm64@0.8.5': + resolution: {integrity: sha512-CEzkjuxNjufVmSRlSm1qYGaoRpbp0g03saC8Tz6BesbmBUuP8MSqJa2BSskMbvYkRhKUN4OFCoPJ0XJf7ARTZQ==} cpu: [arm64] os: [darwin] - '@yuku-parser/binding-darwin-x64@0.8.4': - resolution: {integrity: sha512-CjZuMoXnL5XUkVpDqh4WDPwpAw8CwmtHHnTerGkS45So/sNuwkXdyIAEqqIZfaLopi5W/V9NApAT2md9XizjsQ==} + '@yuku-parser/binding-darwin-x64@0.8.5': + resolution: {integrity: sha512-HS7wYfYUi3fTYNrzLNnZUia5DVo/Kf5NRmbh2rNVDKzMUEUfXI7xWdh0OOqIqYI3SsA5AcZOCI357uYb0+2B9Q==} cpu: [x64] os: [darwin] - '@yuku-parser/binding-freebsd-x64@0.8.4': - resolution: {integrity: sha512-ibLKORdz71iI4Vs+fyFgvwQ51P5XcxJIyQLa8cSEWqwptRdo+BTcZHIQEcZnFDPUuvmJ19RRH9CoiJdfhr7pZw==} + '@yuku-parser/binding-freebsd-x64@0.8.5': + resolution: {integrity: sha512-Iq/XcdT3qjV+mxzb6hE4oSlst/+wrJxSsgKu3FkVkV1bxb0UfITfedws/wI356KVr+BM9CeamNkdbchHV4pJlw==} cpu: [x64] os: [freebsd] - '@yuku-parser/binding-linux-arm-gnu@0.8.4': - resolution: {integrity: sha512-Fo3r5fYhGDcFnl+KN+L9PgtiQPS4AIE1n1mG1o5jZ11p7g5yZ/1EjLFmSHAUsoXreun8KjTsFjEL7P1Sb93PZQ==} + '@yuku-parser/binding-linux-arm-gnu@0.8.5': + resolution: {integrity: sha512-vbI/zeUdJEZ8BKUEfOD8ngtPR5/9XdONpRRosw73kOtA1GyipTF1rj75ozLHIVCEybdCB/GSlQ6OjjhuEAKrGA==} cpu: [arm] os: [linux] libc: [glibc] - '@yuku-parser/binding-linux-arm-musl@0.8.4': - resolution: {integrity: sha512-BEB31vUEgXPWf7WkoMPSzzJhpC/wWCBXyysRCCPsw47BJ/OtbQsvJbxX9fFDuSRLy3kbyIV/WbdUTgbQ9COxiw==} + '@yuku-parser/binding-linux-arm-musl@0.8.5': + resolution: {integrity: sha512-3K4kOkOxWbUKoRja+vn7Srn8Nyc66Fr66oFWO+pFA/0KpVtlIGpKY+/KL8QIQdM7swTh+82OVkuFKeFEweVFLg==} cpu: [arm] os: [linux] libc: [musl] - '@yuku-parser/binding-linux-arm64-gnu@0.8.4': - resolution: {integrity: sha512-xGLCRcHn9xVz7JVNyyKtiNJSf503qtUmih9XVSsghgzOmiKUMnHObs69OMMwXN3788tg1jsl11fNjjQlB8idMA==} + '@yuku-parser/binding-linux-arm64-gnu@0.8.5': + resolution: {integrity: sha512-aj2pI9eT3ZAj8mWrC+utYUJwyxSd6ozthHjJfGtcY3MnZuQ4qbO7wm15BMqDgCSrg7az3tnONy1ftVQTWV9inA==} cpu: [arm64] os: [linux] libc: [glibc] - '@yuku-parser/binding-linux-arm64-musl@0.8.4': - resolution: {integrity: sha512-3kNRi8NJT2q6FQRVCUFHIQ99+kXdi8cVJEEUi6+xtFqpMgNrZNnbgAj28ILsDC7zmclaU+v47eUCeJoKLSCbww==} + '@yuku-parser/binding-linux-arm64-musl@0.8.5': + resolution: {integrity: sha512-+T2buVRNtY0QwhUeo8t47HmEpgh7tXMx8htMEdT7O0HHv3eFitwvyuVSdYNOpxo52Sc/0wJ6F4UbZni75aD4Pg==} cpu: [arm64] os: [linux] libc: [musl] - '@yuku-parser/binding-linux-x64-gnu@0.8.4': - resolution: {integrity: sha512-isi62oMy94Z3OXwGs2l2rkqRiRyqLmfHeTRHpA/uWZbsNhnm7IdVvkF7e7wHNKAtd5jwGzOqYSroxKv2fOm7Cw==} + '@yuku-parser/binding-linux-x64-gnu@0.8.5': + resolution: {integrity: sha512-uIoy1uplNUqjq3GW6z+Ea8UCQkLKRPlM4FvqAhYMDwBazkVpE1mNvMqaQqf57ZP8mGTeOf4OF6CuUlenR2ttqg==} cpu: [x64] os: [linux] libc: [glibc] - '@yuku-parser/binding-linux-x64-musl@0.8.4': - resolution: {integrity: sha512-9RsEw2xYHqU/pjSRBTOupWN3sF8uz9stjJdARfz6o0llvF+yfrj5QHmTiocGGBeAI80fvKmDtr2RIQClUzAPcA==} + '@yuku-parser/binding-linux-x64-musl@0.8.5': + resolution: {integrity: sha512-27doVJjvYevPWcakDCpfgZfDAlyhfyY3BwHf5TKtponCrSYBMzrBpD8ChYB1M7B6YOm0M5U9kEA0k1sB6CD4Ow==} cpu: [x64] os: [linux] libc: [musl] - '@yuku-parser/binding-win32-arm64@0.8.4': - resolution: {integrity: sha512-VEZHo9rEGOBKR20sA3vCO00aQvwWND5aLu7YxeX+YupMZJh9hd1f17AbClJN37Q2iL1PCHht+wDTOKX6tZYqXg==} + '@yuku-parser/binding-win32-arm64@0.8.5': + resolution: {integrity: sha512-UIlSKhOLWZUQyDVQzYWAkHQGWnwNw5IxR/YYT2UCy64HLMQGGIxhb3qa/7Rf6yki50FrLx1O9PWgBKXCq7Zxxg==} cpu: [arm64] os: [win32] - '@yuku-parser/binding-win32-x64@0.8.4': - resolution: {integrity: sha512-PeH3VzN1feGjPtDpVEAqf000fPT+nxtw/696LKp/5Z9RJi/MaXpB636QC+5QtrAPSoEnIkyEe+c+mq2QLZPWBA==} + '@yuku-parser/binding-win32-x64@0.8.5': + resolution: {integrity: sha512-helhS0Pt0TwsW9Z5L3V5o27qrnTrmaUTgSpymVUJYlZJgW6Nagk7nS5P3Ez4b1OZXMwc5y5CR6m1niuzL/yYfQ==} cpu: [x64] os: [win32] - '@yuku-toolchain/types@0.8.4': - resolution: {integrity: sha512-p7JE8flrj7ijZ/qLjHi4UwKqMarMD6zumbKXhrjp2I2iLJOuTYiQyci2U36VlXcUlNyzsY7E/mLnKCHotbzJVw==} + '@yuku-toolchain/types@0.8.5': + resolution: {integrity: sha512-ELNzrhwfi9+VCTaj6QcLCb5MlUK6pmVqPqH8bBmer1FTHvgEITnpwB73L/Wx5KKPPVWAokfeeU9V2rJy/9kMlg==} acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} @@ -2044,14 +2156,6 @@ packages: dom-accessibility-api@0.6.3: resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==} - emnapi@2.0.0-alpha.3: - resolution: {integrity: sha512-K9bc9Xx4OwSfhJpdSOpcfIKzn7/6emuubaIorf6I5e7WBAM79665rf6iHr9y50NL4qYMUP/AheTpD1Z4yU1EBw==} - peerDependencies: - node-addon-api: '>= 6.1.0' - peerDependenciesMeta: - node-addon-api: - optional: true - emojis-list@3.0.0: resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==} engines: {node: '>= 4'} @@ -2147,8 +2251,8 @@ packages: git-hooks-list@4.2.1: resolution: {integrity: sha512-WNvqJjOxxs/8ZP9+DWdwWJ7cDsd60NHf39XnD82pDVrKO5q7xfPqpkK6hwEAmBa/ZSEE4IOoR75EzbbIuwGlMw==} - globals@17.9.0: - resolution: {integrity: sha512-m/MvAW61QVU5VDNF1Vj8axt016h8w7L5TU1e9zlab7XIttAT2YAlCwl75K1fOqvMM9apmD7lbCIRhpfkhmxhCg==} + globals@17.10.0: + resolution: {integrity: sha512-V0kztuWST2k8A/VbxAY8+L+7+Rgo3fyA24IHRLrZp7HOzJjV0gHSaZUjK9lpP/IrBSNite2tZ1prhRkinRu1CA==} engines: {node: '>=18'} happy-dom@20.11.2: @@ -3077,11 +3181,11 @@ packages: engines: {node: '>= 14.6'} hasBin: true - yuku-ast@0.8.4: - resolution: {integrity: sha512-s7EWfWIQkaGmsGnyr/BU0jli9YTN5TvrKIsSmALyRD9elumDQInuhv0BrVObENKVCxr9W3Ikmnx5u02KvfuUmw==} + yuku-ast@0.8.5: + resolution: {integrity: sha512-Ez2CI2BnPK/if0tVI7jB9UUDSNibcChjJDEPEKuWPJNRkbvzSoAQrSqpKtdzl8qTPp4ftVb87f/jx5HIKOieQw==} - yuku-parser@0.8.4: - resolution: {integrity: sha512-sw41wouvT5rUmLIp87hmvm5vtF+MRSI3x6yjq6xqpYmtkQj+Ht6N7xRQ8lMhLv8N7JAzughGj0Rfi0jQRSu9HQ==} + yuku-parser@0.8.5: + resolution: {integrity: sha512-t843J9IdYYpcDaW7o3aDPXpTM72FsvkIDYEHtigyGFCvC3EhiIaSGM5WVNZl3lxTv1Dfis6IW3S/yBsBIaCiWw==} zimmerframe@1.1.4: resolution: {integrity: sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==} @@ -3366,7 +3470,7 @@ snapshots: '@types/react': 19.2.18 react: 19.2.8 - '@napi-rs/cli@3.8.3(@types/node@24.13.3)(node-addon-api@7.1.1)(supports-color@8.1.1)': + '@napi-rs/cli@3.8.6(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@types/node@24.13.3)(supports-color@8.1.1)': dependencies: '@inquirer/prompts': 8.5.2(@types/node@24.13.3) '@napi-rs/cross-toolchain': 1.0.3(supports-color@8.1.1) @@ -3374,13 +3478,15 @@ snapshots: '@octokit/rest': 22.0.1 clipanion: 4.0.0-rc.4 colorette: 2.0.20 - emnapi: 2.0.0-alpha.3(node-addon-api@7.1.1) es-toolkit: 1.50.0 js-yaml: 4.3.1 obug: 2.1.4 semver: 7.8.5 typanion: 3.14.0 typescript: 6.0.3 + optionalDependencies: + '@emnapi/core': 1.11.3 + '@emnapi/runtime': 1.11.3 transitivePeerDependencies: - '@napi-rs/cross-toolchain-arm64-target-aarch64' - '@napi-rs/cross-toolchain-arm64-target-armv7' @@ -3393,7 +3499,6 @@ snapshots: - '@napi-rs/cross-toolchain-x64-target-s390x' - '@napi-rs/cross-toolchain-x64-target-x86_64' - '@types/node' - - node-addon-api - supports-color '@napi-rs/cross-toolchain@1.0.3(supports-color@8.1.1)': @@ -3767,9 +3872,16 @@ snapshots: transitivePeerDependencies: - '@module-federation/runtime-tools' - '@rsbuild/plugin-react@2.1.0(@rsbuild/core@2.1.10)(@rspack/core@2.1.8)': + '@rsbuild/core@2.1.11': dependencies: - '@rspack/plugin-react-refresh': 2.0.2(@rspack/core@2.1.8)(react-refresh@0.18.0) + '@rspack/core': 2.1.9(@swc/helpers@0.5.23) + '@swc/helpers': 0.5.23 + transitivePeerDependencies: + - '@module-federation/runtime-tools' + + '@rsbuild/plugin-react@2.1.0(@rsbuild/core@2.1.10)(@rspack/core@2.1.9)': + dependencies: + '@rspack/plugin-react-refresh': 2.0.2(@rspack/core@2.1.9)(react-refresh@0.18.0) react-refresh: 0.18.0 optionalDependencies: '@rsbuild/core': 2.1.10 @@ -3788,8 +3900,8 @@ snapshots: '@rslib/core@1.0.0-beta.2(typescript@7.0.2)': dependencies: - '@rsbuild/core': 2.1.10 - rsbuild-plugin-dts: 1.0.0-beta.2(@rsbuild/core@2.1.10)(typescript@7.0.2) + '@rsbuild/core': 2.1.11 + rsbuild-plugin-dts: 1.0.0-beta.2(@rsbuild/core@2.1.11)(typescript@7.0.2) optionalDependencies: typescript: 7.0.2 transitivePeerDependencies: @@ -3836,27 +3948,57 @@ snapshots: '@rspack/binding-darwin-arm64@2.1.8': optional: true + '@rspack/binding-darwin-arm64@2.1.9': + optional: true + '@rspack/binding-darwin-x64@2.1.8': optional: true + '@rspack/binding-darwin-x64@2.1.9': + optional: true + '@rspack/binding-linux-arm64-gnu@2.1.8': optional: true + '@rspack/binding-linux-arm64-gnu@2.1.9': + optional: true + '@rspack/binding-linux-arm64-musl@2.1.8': optional: true + '@rspack/binding-linux-arm64-musl@2.1.9': + optional: true + + '@rspack/binding-linux-ppc64-gnu@2.1.9': + optional: true + '@rspack/binding-linux-riscv64-gnu@2.1.8': optional: true + '@rspack/binding-linux-riscv64-gnu@2.1.9': + optional: true + '@rspack/binding-linux-riscv64-musl@2.1.8': optional: true + '@rspack/binding-linux-riscv64-musl@2.1.9': + optional: true + + '@rspack/binding-linux-s390x-gnu@2.1.9': + optional: true + '@rspack/binding-linux-x64-gnu@2.1.8': optional: true + '@rspack/binding-linux-x64-gnu@2.1.9': + optional: true + '@rspack/binding-linux-x64-musl@2.1.8': optional: true + '@rspack/binding-linux-x64-musl@2.1.9': + optional: true + '@rspack/binding-wasm32-wasi@2.1.8': dependencies: '@emnapi/core': 1.11.3 @@ -3864,15 +4006,31 @@ snapshots: '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3) optional: true + '@rspack/binding-wasm32-wasi@2.1.9': + dependencies: + '@emnapi/core': 1.11.3 + '@emnapi/runtime': 1.11.3 + '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3) + optional: true + '@rspack/binding-win32-arm64-msvc@2.1.8': optional: true + '@rspack/binding-win32-arm64-msvc@2.1.9': + optional: true + '@rspack/binding-win32-ia32-msvc@2.1.8': optional: true + '@rspack/binding-win32-ia32-msvc@2.1.9': + optional: true + '@rspack/binding-win32-x64-msvc@2.1.8': optional: true + '@rspack/binding-win32-x64-msvc@2.1.9': + optional: true + '@rspack/binding@2.1.8': optionalDependencies: '@rspack/binding-darwin-arm64': 2.1.8 @@ -3888,24 +4046,47 @@ snapshots: '@rspack/binding-win32-ia32-msvc': 2.1.8 '@rspack/binding-win32-x64-msvc': 2.1.8 + '@rspack/binding@2.1.9': + optionalDependencies: + '@rspack/binding-darwin-arm64': 2.1.9 + '@rspack/binding-darwin-x64': 2.1.9 + '@rspack/binding-linux-arm64-gnu': 2.1.9 + '@rspack/binding-linux-arm64-musl': 2.1.9 + '@rspack/binding-linux-ppc64-gnu': 2.1.9 + '@rspack/binding-linux-riscv64-gnu': 2.1.9 + '@rspack/binding-linux-riscv64-musl': 2.1.9 + '@rspack/binding-linux-s390x-gnu': 2.1.9 + '@rspack/binding-linux-x64-gnu': 2.1.9 + '@rspack/binding-linux-x64-musl': 2.1.9 + '@rspack/binding-wasm32-wasi': 2.1.9 + '@rspack/binding-win32-arm64-msvc': 2.1.9 + '@rspack/binding-win32-ia32-msvc': 2.1.9 + '@rspack/binding-win32-x64-msvc': 2.1.9 + '@rspack/core@2.1.8(@swc/helpers@0.5.23)': dependencies: '@rspack/binding': 2.1.8 optionalDependencies: '@swc/helpers': 0.5.23 - '@rspack/plugin-react-refresh@2.0.2(@rspack/core@2.1.8)(react-refresh@0.18.0)': + '@rspack/core@2.1.9(@swc/helpers@0.5.23)': + dependencies: + '@rspack/binding': 2.1.9 + optionalDependencies: + '@swc/helpers': 0.5.23 + + '@rspack/plugin-react-refresh@2.0.2(@rspack/core@2.1.9)(react-refresh@0.18.0)': dependencies: react-refresh: 0.18.0 optionalDependencies: - '@rspack/core': 2.1.8(@swc/helpers@0.5.23) + '@rspack/core': 2.1.9(@swc/helpers@0.5.23) '@rspress/core@2.0.19(micromark-util-types@2.0.2)(micromark@4.0.2)(supports-color@8.1.1)': dependencies: '@mdx-js/mdx': 3.1.1(supports-color@8.1.1) '@mdx-js/react': 3.1.1(@types/react@19.2.18)(react@19.2.8) '@rsbuild/core': 2.1.10 - '@rsbuild/plugin-react': 2.1.0(@rsbuild/core@2.1.10)(@rspack/core@2.1.8) + '@rsbuild/plugin-react': 2.1.0(@rsbuild/core@2.1.10)(@rspack/core@2.1.9) '@rspress/shared': 2.0.19(supports-color@8.1.1) '@shikijs/rehype': 4.3.1 '@types/mdast': 4.0.4 @@ -3978,9 +4159,9 @@ snapshots: '@rstackjs/test-utils@0.2.0': {} - '@rstest/adapter-rsbuild@0.11.6(@rsbuild/core@2.1.10)(@rstest/core@0.11.6)': + '@rstest/adapter-rsbuild@0.11.6(@rsbuild/core@2.1.11)(@rstest/core@0.11.6)': dependencies: - '@rsbuild/core': 2.1.10 + '@rsbuild/core': 2.1.11 '@rstest/core': 0.11.6(happy-dom@20.11.2) '@rstest/adapter-rslib@0.11.6(@rslib/core@1.0.0-beta.2)(@rstest/core@0.11.6)(typescript@7.0.2)': @@ -3992,7 +4173,7 @@ snapshots: '@rstest/core@0.11.6(happy-dom@20.11.2)': dependencies: - '@rsbuild/core': 2.1.10 + '@rsbuild/core': 2.1.11 '@types/chai': 5.2.3 optionalDependencies: happy-dom: 20.11.2 @@ -4008,10 +4189,10 @@ snapshots: '@types/hast': 3.0.5 hast-util-to-html: 9.0.5 - '@shikijs/core@4.4.2': + '@shikijs/core@4.4.3': dependencies: - '@shikijs/primitive': 4.4.2 - '@shikijs/types': 4.4.2 + '@shikijs/primitive': 4.4.3 + '@shikijs/types': 4.4.3 '@shikijs/vscode-textmate': 10.0.2 '@types/hast': 3.0.5 hast-util-to-html: 9.0.5 @@ -4037,9 +4218,9 @@ snapshots: '@shikijs/vscode-textmate': 10.0.2 '@types/hast': 3.0.5 - '@shikijs/primitive@4.4.2': + '@shikijs/primitive@4.4.3': dependencies: - '@shikijs/types': 4.4.2 + '@shikijs/types': 4.4.3 '@shikijs/vscode-textmate': 10.0.2 '@types/hast': 3.0.5 @@ -4056,17 +4237,17 @@ snapshots: dependencies: '@shikijs/types': 4.3.1 - '@shikijs/transformers@4.4.2': + '@shikijs/transformers@4.4.3': dependencies: - '@shikijs/core': 4.4.2 - '@shikijs/types': 4.4.2 + '@shikijs/core': 4.4.3 + '@shikijs/types': 4.4.3 '@shikijs/types@4.3.1': dependencies: '@shikijs/vscode-textmate': 10.0.2 '@types/hast': 3.0.5 - '@shikijs/types@4.4.2': + '@shikijs/types@4.4.3': dependencies: '@shikijs/vscode-textmate': 10.0.2 '@types/hast': 3.0.5 @@ -4092,7 +4273,7 @@ snapshots: picocolors: 1.1.1 pretty-format: 27.5.1 - '@testing-library/jest-dom@7.0.0(@testing-library/dom@10.4.1)': + '@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)': dependencies: '@adobe/css-tools': 4.5.0 '@testing-library/dom': 10.4.1 @@ -4245,43 +4426,43 @@ snapshots: react: 19.2.8 unhead: 2.1.16 - '@yuku-parser/binding-android-arm64@0.8.4': + '@yuku-parser/binding-android-arm64@0.8.5': optional: true - '@yuku-parser/binding-darwin-arm64@0.8.4': + '@yuku-parser/binding-darwin-arm64@0.8.5': optional: true - '@yuku-parser/binding-darwin-x64@0.8.4': + '@yuku-parser/binding-darwin-x64@0.8.5': optional: true - '@yuku-parser/binding-freebsd-x64@0.8.4': + '@yuku-parser/binding-freebsd-x64@0.8.5': optional: true - '@yuku-parser/binding-linux-arm-gnu@0.8.4': + '@yuku-parser/binding-linux-arm-gnu@0.8.5': optional: true - '@yuku-parser/binding-linux-arm-musl@0.8.4': + '@yuku-parser/binding-linux-arm-musl@0.8.5': optional: true - '@yuku-parser/binding-linux-arm64-gnu@0.8.4': + '@yuku-parser/binding-linux-arm64-gnu@0.8.5': optional: true - '@yuku-parser/binding-linux-arm64-musl@0.8.4': + '@yuku-parser/binding-linux-arm64-musl@0.8.5': optional: true - '@yuku-parser/binding-linux-x64-gnu@0.8.4': + '@yuku-parser/binding-linux-x64-gnu@0.8.5': optional: true - '@yuku-parser/binding-linux-x64-musl@0.8.4': + '@yuku-parser/binding-linux-x64-musl@0.8.5': optional: true - '@yuku-parser/binding-win32-arm64@0.8.4': + '@yuku-parser/binding-win32-arm64@0.8.5': optional: true - '@yuku-parser/binding-win32-x64@0.8.4': + '@yuku-parser/binding-win32-x64@0.8.5': optional: true - '@yuku-toolchain/types@0.8.4': {} + '@yuku-toolchain/types@0.8.5': {} acorn-jsx@5.3.2(acorn@8.17.0): dependencies: @@ -4407,10 +4588,6 @@ snapshots: dom-accessibility-api@0.6.3: {} - emnapi@2.0.0-alpha.3(node-addon-api@7.1.1): - optionalDependencies: - node-addon-api: 7.1.1 - emojis-list@3.0.0: {} entities@6.0.1: {} @@ -4502,7 +4679,7 @@ snapshots: git-hooks-list@4.2.1: {} - globals@17.9.0: {} + globals@17.10.0: {} happy-dom@20.11.2: dependencies: @@ -5459,10 +5636,10 @@ snapshots: mdast-util-to-markdown: 2.1.2 unified: 11.0.5 - rsbuild-plugin-dts@1.0.0-beta.2(@rsbuild/core@2.1.10)(typescript@7.0.2): + rsbuild-plugin-dts@1.0.0-beta.2(@rsbuild/core@2.1.11)(typescript@7.0.2): dependencies: '@ast-grep/napi': 0.37.0 - '@rsbuild/core': 2.1.10 + '@rsbuild/core': 2.1.11 optionalDependencies: typescript: 7.0.2 @@ -5811,27 +5988,27 @@ snapshots: yaml@2.9.0: optional: true - yuku-ast@0.8.4: + yuku-ast@0.8.5: dependencies: - '@yuku-toolchain/types': 0.8.4 + '@yuku-toolchain/types': 0.8.5 - yuku-parser@0.8.4: + yuku-parser@0.8.5: dependencies: - '@yuku-toolchain/types': 0.8.4 - yuku-ast: 0.8.4 + '@yuku-toolchain/types': 0.8.5 + yuku-ast: 0.8.5 optionalDependencies: - '@yuku-parser/binding-android-arm64': 0.8.4 - '@yuku-parser/binding-darwin-arm64': 0.8.4 - '@yuku-parser/binding-darwin-x64': 0.8.4 - '@yuku-parser/binding-freebsd-x64': 0.8.4 - '@yuku-parser/binding-linux-arm-gnu': 0.8.4 - '@yuku-parser/binding-linux-arm-musl': 0.8.4 - '@yuku-parser/binding-linux-arm64-gnu': 0.8.4 - '@yuku-parser/binding-linux-arm64-musl': 0.8.4 - '@yuku-parser/binding-linux-x64-gnu': 0.8.4 - '@yuku-parser/binding-linux-x64-musl': 0.8.4 - '@yuku-parser/binding-win32-arm64': 0.8.4 - '@yuku-parser/binding-win32-x64': 0.8.4 + '@yuku-parser/binding-android-arm64': 0.8.5 + '@yuku-parser/binding-darwin-arm64': 0.8.5 + '@yuku-parser/binding-darwin-x64': 0.8.5 + '@yuku-parser/binding-freebsd-x64': 0.8.5 + '@yuku-parser/binding-linux-arm-gnu': 0.8.5 + '@yuku-parser/binding-linux-arm-musl': 0.8.5 + '@yuku-parser/binding-linux-arm64-gnu': 0.8.5 + '@yuku-parser/binding-linux-arm64-musl': 0.8.5 + '@yuku-parser/binding-linux-x64-gnu': 0.8.5 + '@yuku-parser/binding-linux-x64-musl': 0.8.5 + '@yuku-parser/binding-win32-arm64': 0.8.5 + '@yuku-parser/binding-win32-x64': 0.8.5 zimmerframe@1.1.4: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 460655d2..720da26e 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -12,8 +12,8 @@ catalogMode: prefer cleanupUnusedCatalogs: true catalog: - '@napi-rs/cli': '^3.8.3' - '@rsbuild/core': '~2.1.10' + '@napi-rs/cli': '^3.8.6' + '@rsbuild/core': '~2.1.11' '@rsbuild/plugin-react': '^2.1.0' '@rsbuild/plugin-sass': '^2.0.1' '@rslib/core': '~1.0.0-beta.2' @@ -29,16 +29,16 @@ catalog: '@rstest/adapter-rslib': '~0.11.6' '@rstest/core': '~0.11.6' '@testing-library/dom': '^10.4.1' - '@testing-library/jest-dom': '^7.0.0' + '@testing-library/jest-dom': '^7.0.1' '@testing-library/react': '^16.3.2' '@types/micromatch': '^4.0.10' '@types/node': '^24.13.3' '@types/react': '^19.2.18' '@types/react-dom': '^19.2.4' - '@shikijs/transformers': '^4.4.2' + '@shikijs/transformers': '^4.4.3' 'cspell-ban-words': '^0.0.4' 'fast-json-stable-stringify': '2.1.0' - globals: '^17.7.0' + globals: '^17.10.0' 'happy-dom': '^20.11.2' 'heading-case': '^1.1.5' 'import-meta-resolve': '4.2.0' @@ -59,7 +59,7 @@ catalog: 'typescript': '^7.0.2' 'vscode-languageserver': '10.1.0' 'vscode-languageserver-textdocument': '1.0.12' - yuku-parser: '0.8.4' + yuku-parser: '0.8.5' dedupePeers: true diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 6f8397f5..da0237fb 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,5 +1,5 @@ [toolchain] # Required by the release-only -Zlocation-detail=none flag. -channel = "nightly-2026-04-16" +channel = "nightly-2026-08-12" components = ["clippy", "rustfmt"] profile = "minimal" From 66c613864018ebb7b970cd5005a838fc70f0c12c Mon Sep 17 00:00:00 2001 From: Jiahan Chen Date: Thu, 13 Aug 2026 13:30:30 +0800 Subject: [PATCH 09/33] release: v0.6.0 (#342) --- packages/create-rstack/package.json | 2 +- .../template-app-lit-ts/package.json | 2 +- .../template-app-lit/package.json | 2 +- .../template-app-preact-ts/package.json | 2 +- .../template-app-preact/package.json | 2 +- .../template-app-react-ts/package.json | 2 +- .../template-app-react/package.json | 2 +- .../template-app-solid-ts/package.json | 2 +- .../template-app-solid/package.json | 2 +- .../template-app-svelte-ts/package.json | 2 +- .../template-app-svelte/package.json | 2 +- .../template-app-vanilla-ts/package.json | 2 +- .../template-app-vanilla/package.json | 2 +- .../template-app-vue-ts/package.json | 2 +- .../template-app-vue/package.json | 2 +- .../template-doc-i18n/package.json | 2 +- .../create-rstack/template-doc/package.json | 2 +- .../template-lib-node-ts/package.json | 2 +- .../template-lib-node/package.json | 2 +- .../template-lib-react-ts/package.json | 2 +- .../template-lib-react/package.json | 2 +- .../template-lib-solid-ts/package.json | 2 +- .../template-lib-solid/package.json | 2 +- .../template-lib-svelte-ts/package.json | 2 +- .../template-lib-svelte/package.json | 2 +- .../template-lib-vue-ts/package.json | 2 +- .../template-lib-vue/package.json | 2 +- packages/rstack/binding.cjs | 108 +++++++++--------- packages/rstack/package.json | 2 +- 29 files changed, 82 insertions(+), 82 deletions(-) diff --git a/packages/create-rstack/package.json b/packages/create-rstack/package.json index 31f78bd1..3624d1b0 100644 --- a/packages/create-rstack/package.json +++ b/packages/create-rstack/package.json @@ -1,6 +1,6 @@ { "name": "create-rstack", - "version": "3.1.2", + "version": "3.2.0", "description": "Create a new Rstack project", "homepage": "https://rstack.rs", "bugs": { diff --git a/packages/create-rstack/template-app-lit-ts/package.json b/packages/create-rstack/template-app-lit-ts/package.json index aba33ac0..61684891 100644 --- a/packages/create-rstack/template-app-lit-ts/package.json +++ b/packages/create-rstack/template-app-lit-ts/package.json @@ -19,7 +19,7 @@ "devDependencies": { "@types/node": "^24.13.3", "happy-dom": "^20.11.2", - "rstack": "^0.5.2", + "rstack": "^0.6.0", "typescript": "^7.0.2" } } diff --git a/packages/create-rstack/template-app-lit/package.json b/packages/create-rstack/template-app-lit/package.json index 6d260528..21399993 100644 --- a/packages/create-rstack/template-app-lit/package.json +++ b/packages/create-rstack/template-app-lit/package.json @@ -18,6 +18,6 @@ }, "devDependencies": { "happy-dom": "^20.11.2", - "rstack": "^0.5.2" + "rstack": "^0.6.0" } } diff --git a/packages/create-rstack/template-app-preact-ts/package.json b/packages/create-rstack/template-app-preact-ts/package.json index e2265be8..56aac06a 100644 --- a/packages/create-rstack/template-app-preact-ts/package.json +++ b/packages/create-rstack/template-app-preact-ts/package.json @@ -22,7 +22,7 @@ "@testing-library/preact": "^3.2.4", "@types/node": "^24.13.3", "happy-dom": "^20.11.2", - "rstack": "^0.5.2", + "rstack": "^0.6.0", "typescript": "^7.0.2" } } diff --git a/packages/create-rstack/template-app-preact/package.json b/packages/create-rstack/template-app-preact/package.json index 8352b4ef..272497e0 100644 --- a/packages/create-rstack/template-app-preact/package.json +++ b/packages/create-rstack/template-app-preact/package.json @@ -21,6 +21,6 @@ "@testing-library/jest-dom": "^7.0.1", "@testing-library/preact": "^3.2.4", "happy-dom": "^20.11.2", - "rstack": "^0.5.2" + "rstack": "^0.6.0" } } diff --git a/packages/create-rstack/template-app-react-ts/package.json b/packages/create-rstack/template-app-react-ts/package.json index 5afd8142..0fbcb93d 100644 --- a/packages/create-rstack/template-app-react-ts/package.json +++ b/packages/create-rstack/template-app-react-ts/package.json @@ -26,7 +26,7 @@ "@types/react": "^19.2.18", "@types/react-dom": "^19.2.4", "happy-dom": "^20.11.2", - "rstack": "^0.5.2", + "rstack": "^0.6.0", "typescript": "^7.0.2" } } diff --git a/packages/create-rstack/template-app-react/package.json b/packages/create-rstack/template-app-react/package.json index 0d2d0e24..4f0a81e6 100644 --- a/packages/create-rstack/template-app-react/package.json +++ b/packages/create-rstack/template-app-react/package.json @@ -23,6 +23,6 @@ "@testing-library/jest-dom": "^7.0.1", "@testing-library/react": "^16.3.2", "happy-dom": "^20.11.2", - "rstack": "^0.5.2" + "rstack": "^0.6.0" } } diff --git a/packages/create-rstack/template-app-solid-ts/package.json b/packages/create-rstack/template-app-solid-ts/package.json index 61d0c0d8..b15f3a66 100644 --- a/packages/create-rstack/template-app-solid-ts/package.json +++ b/packages/create-rstack/template-app-solid-ts/package.json @@ -23,7 +23,7 @@ "@testing-library/jest-dom": "^7.0.1", "@types/node": "^24.13.3", "happy-dom": "^20.11.2", - "rstack": "^0.5.2", + "rstack": "^0.6.0", "typescript": "^7.0.2" } } diff --git a/packages/create-rstack/template-app-solid/package.json b/packages/create-rstack/template-app-solid/package.json index 064ec69b..d1964a8c 100644 --- a/packages/create-rstack/template-app-solid/package.json +++ b/packages/create-rstack/template-app-solid/package.json @@ -22,6 +22,6 @@ "@solidjs/testing-library": "^0.8.10", "@testing-library/jest-dom": "^7.0.1", "happy-dom": "^20.11.2", - "rstack": "^0.5.2" + "rstack": "^0.6.0" } } diff --git a/packages/create-rstack/template-app-svelte-ts/package.json b/packages/create-rstack/template-app-svelte-ts/package.json index 3d737117..c705ed07 100644 --- a/packages/create-rstack/template-app-svelte-ts/package.json +++ b/packages/create-rstack/template-app-svelte-ts/package.json @@ -23,7 +23,7 @@ "@types/node": "^24.13.3", "happy-dom": "^20.11.2", "prettier-plugin-svelte": "^4.1.1", - "rstack": "^0.5.2", + "rstack": "^0.6.0", "svelte-check": "^4.7.5", "typescript": "^6.0.3" } diff --git a/packages/create-rstack/template-app-svelte/package.json b/packages/create-rstack/template-app-svelte/package.json index ad9fd84d..e5abceee 100644 --- a/packages/create-rstack/template-app-svelte/package.json +++ b/packages/create-rstack/template-app-svelte/package.json @@ -22,6 +22,6 @@ "@testing-library/svelte": "^5.4.2", "happy-dom": "^20.11.2", "prettier-plugin-svelte": "^4.1.1", - "rstack": "^0.5.2" + "rstack": "^0.6.0" } } diff --git a/packages/create-rstack/template-app-vanilla-ts/package.json b/packages/create-rstack/template-app-vanilla-ts/package.json index fd6dab91..19f80fa9 100644 --- a/packages/create-rstack/template-app-vanilla-ts/package.json +++ b/packages/create-rstack/template-app-vanilla-ts/package.json @@ -18,7 +18,7 @@ "@testing-library/jest-dom": "^7.0.1", "@types/node": "^24.13.3", "happy-dom": "^20.11.2", - "rstack": "^0.5.2", + "rstack": "^0.6.0", "typescript": "^7.0.2" } } diff --git a/packages/create-rstack/template-app-vanilla/package.json b/packages/create-rstack/template-app-vanilla/package.json index 3e2ddcb2..6e4dd119 100644 --- a/packages/create-rstack/template-app-vanilla/package.json +++ b/packages/create-rstack/template-app-vanilla/package.json @@ -17,6 +17,6 @@ "@testing-library/dom": "^10.4.1", "@testing-library/jest-dom": "^7.0.1", "happy-dom": "^20.11.2", - "rstack": "^0.5.2" + "rstack": "^0.6.0" } } diff --git a/packages/create-rstack/template-app-vue-ts/package.json b/packages/create-rstack/template-app-vue-ts/package.json index 26df147d..fcd61816 100644 --- a/packages/create-rstack/template-app-vue-ts/package.json +++ b/packages/create-rstack/template-app-vue-ts/package.json @@ -22,7 +22,7 @@ "@types/node": "^24.13.3", "@vue/test-utils": "^2.4.11", "happy-dom": "^20.11.2", - "rstack": "^0.5.2", + "rstack": "^0.6.0", "typescript": "^6.0.3", "vue-tsc": "^3.3.9" } diff --git a/packages/create-rstack/template-app-vue/package.json b/packages/create-rstack/template-app-vue/package.json index 551684e5..7cd20a99 100644 --- a/packages/create-rstack/template-app-vue/package.json +++ b/packages/create-rstack/template-app-vue/package.json @@ -21,6 +21,6 @@ "@testing-library/jest-dom": "^7.0.1", "@vue/test-utils": "^2.4.11", "happy-dom": "^20.11.2", - "rstack": "^0.5.2" + "rstack": "^0.6.0" } } diff --git a/packages/create-rstack/template-doc-i18n/package.json b/packages/create-rstack/template-doc-i18n/package.json index 921e526a..b002b2a2 100644 --- a/packages/create-rstack/template-doc-i18n/package.json +++ b/packages/create-rstack/template-doc-i18n/package.json @@ -18,7 +18,7 @@ "@types/react-dom": "^19.2.4", "react": "^19.2.8", "react-dom": "^19.2.8", - "rstack": "^0.5.2", + "rstack": "^0.6.0", "typescript": "^7.0.2" } } diff --git a/packages/create-rstack/template-doc/package.json b/packages/create-rstack/template-doc/package.json index 4b86ecd8..f11dce21 100644 --- a/packages/create-rstack/template-doc/package.json +++ b/packages/create-rstack/template-doc/package.json @@ -18,7 +18,7 @@ "@types/react-dom": "^19.2.4", "react": "^19.2.8", "react-dom": "^19.2.8", - "rstack": "^0.5.2", + "rstack": "^0.6.0", "typescript": "^7.0.2" } } diff --git a/packages/create-rstack/template-lib-node-ts/package.json b/packages/create-rstack/template-lib-node-ts/package.json index 9f2c7a60..0249c11b 100644 --- a/packages/create-rstack/template-lib-node-ts/package.json +++ b/packages/create-rstack/template-lib-node-ts/package.json @@ -25,7 +25,7 @@ }, "devDependencies": { "@types/node": "^24.13.3", - "rstack": "^0.5.2", + "rstack": "^0.6.0", "typescript": "^7.0.2" }, "engines": { diff --git a/packages/create-rstack/template-lib-node/package.json b/packages/create-rstack/template-lib-node/package.json index d80ee62b..32cec902 100644 --- a/packages/create-rstack/template-lib-node/package.json +++ b/packages/create-rstack/template-lib-node/package.json @@ -22,7 +22,7 @@ "test:watch": "rs test --watch" }, "devDependencies": { - "rstack": "^0.5.2" + "rstack": "^0.6.0" }, "engines": { "node": ">=22.12.0" diff --git a/packages/create-rstack/template-lib-react-ts/package.json b/packages/create-rstack/template-lib-react-ts/package.json index 7099cae6..2f6db0e9 100644 --- a/packages/create-rstack/template-lib-react-ts/package.json +++ b/packages/create-rstack/template-lib-react-ts/package.json @@ -33,7 +33,7 @@ "happy-dom": "^20.11.2", "react": "^19.2.8", "react-dom": "^19.2.8", - "rstack": "^0.5.2", + "rstack": "^0.6.0", "typescript": "^7.0.2" }, "peerDependencies": { diff --git a/packages/create-rstack/template-lib-react/package.json b/packages/create-rstack/template-lib-react/package.json index 2ec7b89c..72e2c7a2 100644 --- a/packages/create-rstack/template-lib-react/package.json +++ b/packages/create-rstack/template-lib-react/package.json @@ -29,7 +29,7 @@ "happy-dom": "^20.11.2", "react": "^19.2.8", "react-dom": "^19.2.8", - "rstack": "^0.5.2" + "rstack": "^0.6.0" }, "peerDependencies": { "react": ">=18.0.0", diff --git a/packages/create-rstack/template-lib-solid-ts/package.json b/packages/create-rstack/template-lib-solid-ts/package.json index f3757028..f40e43bd 100644 --- a/packages/create-rstack/template-lib-solid-ts/package.json +++ b/packages/create-rstack/template-lib-solid-ts/package.json @@ -30,7 +30,7 @@ "@testing-library/jest-dom": "^7.0.1", "@types/node": "^24.13.3", "happy-dom": "^20.11.2", - "rstack": "^0.5.2", + "rstack": "^0.6.0", "solid-js": "^1.9.14", "typescript": "^7.0.2" }, diff --git a/packages/create-rstack/template-lib-solid/package.json b/packages/create-rstack/template-lib-solid/package.json index f21d25ae..3f8a1e54 100644 --- a/packages/create-rstack/template-lib-solid/package.json +++ b/packages/create-rstack/template-lib-solid/package.json @@ -27,7 +27,7 @@ "@solidjs/testing-library": "^0.8.10", "@testing-library/jest-dom": "^7.0.1", "happy-dom": "^20.11.2", - "rstack": "^0.5.2", + "rstack": "^0.6.0", "solid-js": "^1.9.14" }, "peerDependencies": { diff --git a/packages/create-rstack/template-lib-svelte-ts/package.json b/packages/create-rstack/template-lib-svelte-ts/package.json index 1fbc2c4b..faea65d7 100644 --- a/packages/create-rstack/template-lib-svelte-ts/package.json +++ b/packages/create-rstack/template-lib-svelte-ts/package.json @@ -27,7 +27,7 @@ "@types/node": "^24.13.3", "happy-dom": "^20.11.2", "prettier-plugin-svelte": "^4.1.1", - "rstack": "^0.5.2", + "rstack": "^0.6.0", "svelte": "^5.56.8", "svelte-check": "^4.7.5", "svelte2tsx": "^0.7.60", diff --git a/packages/create-rstack/template-lib-svelte/package.json b/packages/create-rstack/template-lib-svelte/package.json index d0c867a9..e64f4746 100644 --- a/packages/create-rstack/template-lib-svelte/package.json +++ b/packages/create-rstack/template-lib-svelte/package.json @@ -24,7 +24,7 @@ "@rsbuild/plugin-svelte": "^2.0.1", "happy-dom": "^20.11.2", "prettier-plugin-svelte": "^4.1.1", - "rstack": "^0.5.2", + "rstack": "^0.6.0", "svelte": "^5.56.8" }, "peerDependencies": { diff --git a/packages/create-rstack/template-lib-vue-ts/package.json b/packages/create-rstack/template-lib-vue-ts/package.json index 59ee0a24..a1932615 100644 --- a/packages/create-rstack/template-lib-vue-ts/package.json +++ b/packages/create-rstack/template-lib-vue-ts/package.json @@ -28,7 +28,7 @@ "@types/node": "^24.13.3", "@vue/test-utils": "^2.4.11", "happy-dom": "^20.11.2", - "rstack": "^0.5.2", + "rstack": "^0.6.0", "typescript": "^6.0.3", "vue": "^3.5.41", "vue-tsc": "^3.3.9" diff --git a/packages/create-rstack/template-lib-vue/package.json b/packages/create-rstack/template-lib-vue/package.json index 68a08a4b..abbff2c4 100644 --- a/packages/create-rstack/template-lib-vue/package.json +++ b/packages/create-rstack/template-lib-vue/package.json @@ -25,7 +25,7 @@ "@testing-library/jest-dom": "^7.0.1", "@vue/test-utils": "^2.4.11", "happy-dom": "^20.11.2", - "rstack": "^0.5.2", + "rstack": "^0.6.0", "vue": "^3.5.41" }, "peerDependencies": { diff --git a/packages/rstack/binding.cjs b/packages/rstack/binding.cjs index 29f79bb3..8ee733a0 100644 --- a/packages/rstack/binding.cjs +++ b/packages/rstack/binding.cjs @@ -77,8 +77,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-android-arm64') const bindingPackageVersion = require('@rstackjs/cli-android-arm64/package.json').version - if (bindingPackageVersion !== '0.5.2' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.2 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -93,8 +93,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-android-arm-eabi') const bindingPackageVersion = require('@rstackjs/cli-android-arm-eabi/package.json').version - if (bindingPackageVersion !== '0.5.2' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.2 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -114,8 +114,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-win32-x64-gnu') const bindingPackageVersion = require('@rstackjs/cli-win32-x64-gnu/package.json').version - if (bindingPackageVersion !== '0.5.2' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.2 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -130,8 +130,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-win32-x64-msvc') const bindingPackageVersion = require('@rstackjs/cli-win32-x64-msvc/package.json').version - if (bindingPackageVersion !== '0.5.2' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.2 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -147,8 +147,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-win32-ia32-msvc') const bindingPackageVersion = require('@rstackjs/cli-win32-ia32-msvc/package.json').version - if (bindingPackageVersion !== '0.5.2' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.2 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -163,8 +163,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-win32-arm64-msvc') const bindingPackageVersion = require('@rstackjs/cli-win32-arm64-msvc/package.json').version - if (bindingPackageVersion !== '0.5.2' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.2 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -182,8 +182,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-darwin-universal') const bindingPackageVersion = require('@rstackjs/cli-darwin-universal/package.json').version - if (bindingPackageVersion !== '0.5.2' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.2 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -198,8 +198,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-darwin-x64') const bindingPackageVersion = require('@rstackjs/cli-darwin-x64/package.json').version - if (bindingPackageVersion !== '0.5.2' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.2 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -214,8 +214,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-darwin-arm64') const bindingPackageVersion = require('@rstackjs/cli-darwin-arm64/package.json').version - if (bindingPackageVersion !== '0.5.2' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.2 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -234,8 +234,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-freebsd-x64') const bindingPackageVersion = require('@rstackjs/cli-freebsd-x64/package.json').version - if (bindingPackageVersion !== '0.5.2' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.2 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -250,8 +250,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-freebsd-arm64') const bindingPackageVersion = require('@rstackjs/cli-freebsd-arm64/package.json').version - if (bindingPackageVersion !== '0.5.2' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.2 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -271,8 +271,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-linux-x64-musl') const bindingPackageVersion = require('@rstackjs/cli-linux-x64-musl/package.json').version - if (bindingPackageVersion !== '0.5.2' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.2 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -287,8 +287,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-linux-x64-gnu') const bindingPackageVersion = require('@rstackjs/cli-linux-x64-gnu/package.json').version - if (bindingPackageVersion !== '0.5.2' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.2 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -305,8 +305,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-linux-arm64-musl') const bindingPackageVersion = require('@rstackjs/cli-linux-arm64-musl/package.json').version - if (bindingPackageVersion !== '0.5.2' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.2 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -321,8 +321,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-linux-arm64-gnu') const bindingPackageVersion = require('@rstackjs/cli-linux-arm64-gnu/package.json').version - if (bindingPackageVersion !== '0.5.2' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.2 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -339,8 +339,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-linux-arm-musleabihf') const bindingPackageVersion = require('@rstackjs/cli-linux-arm-musleabihf/package.json').version - if (bindingPackageVersion !== '0.5.2' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.2 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -355,8 +355,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-linux-arm-gnueabihf') const bindingPackageVersion = require('@rstackjs/cli-linux-arm-gnueabihf/package.json').version - if (bindingPackageVersion !== '0.5.2' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.2 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -373,8 +373,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-linux-loong64-musl') const bindingPackageVersion = require('@rstackjs/cli-linux-loong64-musl/package.json').version - if (bindingPackageVersion !== '0.5.2' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.2 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -389,8 +389,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-linux-loong64-gnu') const bindingPackageVersion = require('@rstackjs/cli-linux-loong64-gnu/package.json').version - if (bindingPackageVersion !== '0.5.2' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.2 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -407,8 +407,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-linux-riscv64-musl') const bindingPackageVersion = require('@rstackjs/cli-linux-riscv64-musl/package.json').version - if (bindingPackageVersion !== '0.5.2' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.2 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -423,8 +423,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-linux-riscv64-gnu') const bindingPackageVersion = require('@rstackjs/cli-linux-riscv64-gnu/package.json').version - if (bindingPackageVersion !== '0.5.2' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.2 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -440,8 +440,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-linux-ppc64-gnu') const bindingPackageVersion = require('@rstackjs/cli-linux-ppc64-gnu/package.json').version - if (bindingPackageVersion !== '0.5.2' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.2 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -456,8 +456,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-linux-s390x-gnu') const bindingPackageVersion = require('@rstackjs/cli-linux-s390x-gnu/package.json').version - if (bindingPackageVersion !== '0.5.2' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.2 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -476,8 +476,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-openharmony-arm64') const bindingPackageVersion = require('@rstackjs/cli-openharmony-arm64/package.json').version - if (bindingPackageVersion !== '0.5.2' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.2 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -492,8 +492,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-openharmony-x64') const bindingPackageVersion = require('@rstackjs/cli-openharmony-x64/package.json').version - if (bindingPackageVersion !== '0.5.2' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.2 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -508,8 +508,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-openharmony-arm') const bindingPackageVersion = require('@rstackjs/cli-openharmony-arm/package.json').version - if (bindingPackageVersion !== '0.5.2' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.5.2 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -648,8 +648,8 @@ if (!nativeBinding || forceWasi) { if (!candidateFailed) { if (process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { const bindingPackageVersion = require('@rstackjs/cli-wasm32-wasi/package.json').version - if (bindingPackageVersion !== '0.5.2') { - throw new Error(`WASI binding package version mismatch, expected 0.5.2 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.0') { + throw new Error(`WASI binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } } wasiBinding = require('@rstackjs/cli-wasm32-wasi') diff --git a/packages/rstack/package.json b/packages/rstack/package.json index a30788f7..5936624f 100644 --- a/packages/rstack/package.json +++ b/packages/rstack/package.json @@ -1,6 +1,6 @@ { "name": "rstack", - "version": "0.5.2", + "version": "0.6.0", "description": "One CLI for JavaScript development, powered by Rstack.", "homepage": "https://rstack.rs", "bugs": { From c65f52f654b6fae54c2369259cb7586d2119b2e8 Mon Sep 17 00:00:00 2001 From: Jiahan Chen Date: Thu, 13 Aug 2026 13:48:17 +0800 Subject: [PATCH 10/33] docs: refine documentation theme styles (#345) --- website/theme/index.scss | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/website/theme/index.scss b/website/theme/index.scss index 4de65755..e9b4f959 100644 --- a/website/theme/index.scss +++ b/website/theme/index.scss @@ -1,11 +1,5 @@ :root { - --rp-c-brand: #ff5e00; - --rp-c-brand-dark: var(--rp-c-brand); - --rp-c-brand-darker: #ff704d; - --rp-c-brand-light: #ff7524; - --rp-c-brand-lighter: #ff7524; - --rp-c-link: var(--rp-c-brand); - --rp-c-brand-tint: rgba(255, 94, 0, 0.07); + --rp-c-text-code: var(--rp-c-text-1); } .dark { @@ -18,3 +12,31 @@ width: 10vw !important; } } + +.rp-doc { + .rp-link, + .rp-link code { + color: inherit; + text-decoration-line: underline; + text-underline-offset: 2px; + text-decoration-color: rgba(0, 0, 0, 0.25); + + &:hover { + opacity: 1; + text-decoration-color: currentColor; + border-bottom: none !important; + } + } +} + +.dark { + .rp-doc { + .rp-link { + text-decoration-color: rgba(255, 255, 255, 0.5); + + &:hover { + text-decoration-color: currentColor; + } + } + } +} From 7c836ccc998cd92eff883bbc7f54b38e86c7599c Mon Sep 17 00:00:00 2001 From: Jiahan Chen Date: Thu, 13 Aug 2026 13:58:46 +0800 Subject: [PATCH 11/33] perf(fmt): skip indexing stale cache files (#346) --- packages/rstack/src/fmt/cacheStore.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/rstack/src/fmt/cacheStore.ts b/packages/rstack/src/fmt/cacheStore.ts index 0dcf3292..af3a6fbd 100644 --- a/packages/rstack/src/fmt/cacheStore.ts +++ b/packages/rstack/src/fmt/cacheStore.ts @@ -57,7 +57,10 @@ const createEmptyCache = (namespace: string): ParsedFmtCacheFile => ({ optionsUseCounts: [], }); -const parseCacheFile = (content: string): ParsedFmtCacheFile | undefined => { +const parseCacheFile = ( + content: string, + expectedNamespace: string, +): ParsedFmtCacheFile | undefined => { let value: unknown; try { value = JSON.parse(content); @@ -73,7 +76,7 @@ const parseCacheFile = (content: string): ParsedFmtCacheFile | undefined => { const { version, namespace, options, files } = cache; if ( version !== fmtCacheVersion || - typeof namespace !== 'string' || + namespace !== expectedNamespace || !Array.isArray(options) || !Array.isArray(files) || files.length % fileEntryWidth !== 0 @@ -262,14 +265,12 @@ const loadFmtCacheStore = async (filePath: string, namespace: string): Promise Date: Thu, 13 Aug 2026 14:47:58 +0800 Subject: [PATCH 12/33] perf(fmt): compact cache options in place (#347) --- packages/rstack/src/fmt/cacheStore.ts | 35 ++++++++++++++------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/packages/rstack/src/fmt/cacheStore.ts b/packages/rstack/src/fmt/cacheStore.ts index af3a6fbd..71622c62 100644 --- a/packages/rstack/src/fmt/cacheStore.ts +++ b/packages/rstack/src/fmt/cacheStore.ts @@ -202,33 +202,34 @@ class FmtCacheStoreImpl implements FmtCacheStore { return index; } + /** Removes unreferenced option hashes and remaps file entries to the compacted indexes. */ #compactUnusedOptions(): void { if (!this.#optionsUseCounts.includes(0)) { return; } const { files, options } = this.#cache; - const nextOptions: string[] = []; - const nextUseCounts: number[] = []; - const remappedIndexes = new Int32Array(options.length).fill(-1); + const counts = this.#optionsUseCounts; + const remap = new Int32Array(options.length).fill(-1); + let nextIndex = 0; + this.#optionsIndexes.clear(); for (let index = 0; index < options.length; index++) { - const useCount = this.#optionsUseCounts[index]; - if (useCount > 0) { - remappedIndexes[index] = nextOptions.length; - nextOptions.push(options[index]); - nextUseCounts.push(useCount); + const count = counts[index]; + if (count > 0) { + const option = options[index]; + remap[index] = nextIndex; + options[nextIndex] = option; + counts[nextIndex] = count; + this.#optionsIndexes.set(option, nextIndex); + nextIndex++; } } - for (let offset = 0; offset < files.length; offset += fileEntryWidth) { - const currentIndex = files[offset + optionsIndexOffset] as number; - files[offset + optionsIndexOffset] = remappedIndexes[currentIndex]; - } + options.length = nextIndex; + counts.length = nextIndex; - options.splice(0, options.length, ...nextOptions); - this.#optionsUseCounts.splice(0, this.#optionsUseCounts.length, ...nextUseCounts); - this.#optionsIndexes.clear(); - for (let index = 0; index < options.length; index++) { - this.#optionsIndexes.set(options[index], index); + for (let offset = 0; offset < files.length; offset += fileEntryWidth) { + const index = files[offset + optionsIndexOffset] as number; + files[offset + optionsIndexOffset] = remap[index]; } } From 0ec1a5620fe7a8864771c7b7fccc9318777d5e69 Mon Sep 17 00:00:00 2001 From: Jiahan Chen Date: Thu, 13 Aug 2026 16:03:15 +0800 Subject: [PATCH 13/33] chore(ci): serialize Windows package tests (#348) --- .github/workflows/test.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8a00db11..6d0ae0dd 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -69,5 +69,10 @@ jobs: run: git diff --exit-code -- packages/rstack/binding.cjs packages/rstack/binding.d.cts - name: Run Test - if: steps.changes.outputs.changed == 'true' + if: steps.changes.outputs.changed == 'true' && runner.os != 'Windows' run: node --run test + + # Run package tests serially on Windows to avoid resource contention between nested test workers. + - name: Run Test (Windows) + if: steps.changes.outputs.changed == 'true' && runner.os == 'Windows' + run: pnpm --workspace-concurrency=1 --filter "./packages/**" test From 5009873db130f2ada9439290ebb00f4829c6849d Mon Sep 17 00:00:00 2001 From: Elecmonkey Date: Thu, 13 Aug 2026 19:48:09 +0800 Subject: [PATCH 14/33] chore(deps): upgrade @rslib/core to 1.0.0-beta.3 (#349) --- packages/rstack/rslib.config.ts | 12 -- pnpm-lock.yaml | 226 ++++++++++++++++++++++++++++---- pnpm-workspace.yaml | 2 +- 3 files changed, 203 insertions(+), 37 deletions(-) diff --git a/packages/rstack/rslib.config.ts b/packages/rstack/rslib.config.ts index a2662b13..70b66090 100644 --- a/packages/rstack/rslib.config.ts +++ b/packages/rstack/rslib.config.ts @@ -54,16 +54,4 @@ export default defineConfig({ ], }, }, - tools: { - rspack: { - module: { - parser: { - javascript: { - // @rstest/adapter-rslib resolves extended tsconfig paths from a runtime base. - createRequire: false, - }, - }, - }, - }, - }, }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index be9b0d6c..014fe63a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,8 +20,8 @@ catalogs: specifier: ^2.0.1 version: 2.0.1 '@rslib/core': - specifier: ~1.0.0-beta.2 - version: 1.0.0-beta.2 + specifier: ~1.0.0-beta.3 + version: 1.0.0-beta.3 '@rslint/core': specifier: ~0.8.0 version: 0.8.0 @@ -189,7 +189,7 @@ importers: devDependencies: '@rsbuild/plugin-react': specifier: 'catalog:' - version: 2.1.0(@rsbuild/core@2.1.10)(@rspack/core@2.1.9) + version: 2.1.0(@rsbuild/core@2.1.10)(@rspack/core@2.1.10) '@testing-library/dom': specifier: 'catalog:' version: 10.4.1 @@ -277,7 +277,7 @@ importers: devDependencies: '@rsbuild/plugin-react': specifier: 'catalog:' - version: 2.1.0(@rsbuild/core@2.1.10)(@rspack/core@2.1.9) + version: 2.1.0(@rsbuild/core@2.1.10)(@rspack/core@2.1.10) '@testing-library/dom': specifier: 'catalog:' version: 10.4.1 @@ -320,7 +320,7 @@ importers: devDependencies: '@rsbuild/plugin-react': specifier: 'catalog:' - version: 2.1.0(@rsbuild/core@2.1.10)(@rspack/core@2.1.9) + version: 2.1.0(@rsbuild/core@2.1.10)(@rspack/core@2.1.10) '@testing-library/dom': specifier: 'catalog:' version: 10.4.1 @@ -369,7 +369,7 @@ importers: version: 2.1.11 '@rslib/core': specifier: 'catalog:' - version: 1.0.0-beta.2(typescript@7.0.2) + version: 1.0.0-beta.3(typescript@7.0.2) '@rslint/core': specifier: 'catalog:' version: 0.8.0 @@ -403,7 +403,7 @@ importers: version: 0.11.6(@rsbuild/core@2.1.11)(@rstest/core@0.11.6) '@rstest/adapter-rslib': specifier: 'catalog:' - version: 0.11.6(@rslib/core@1.0.0-beta.2)(@rstest/core@0.11.6)(typescript@7.0.2) + version: 0.11.6(@rslib/core@1.0.0-beta.3)(@rstest/core@0.11.6)(typescript@7.0.2) '@types/micromatch': specifier: 'catalog:' version: 4.0.10 @@ -1291,6 +1291,16 @@ packages: core-js: optional: true + '@rsbuild/core@2.1.12': + resolution: {integrity: sha512-xRqNHj/svDqeUzXPahmN4BdxEFCU1rxnVdjxyVV7WgsFfH+L3yAoQMJtIXVGhr00IQseDKkc3eonMF3NGrFj2Q==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + core-js: '>= 3.0.0' + peerDependenciesMeta: + core-js: + optional: true + '@rsbuild/plugin-react@2.1.0': resolution: {integrity: sha512-RQTIAWB/CwPjoWt9iAl+8HixeQVgZ7kEIBrWPCixfITyHdiD84h0YpUTpEUuz6kGHw1KXT9mHZ3Rwy6WG7aRDA==} peerDependencies: @@ -1307,8 +1317,8 @@ packages: '@rsbuild/core': optional: true - '@rslib/core@1.0.0-beta.2': - resolution: {integrity: sha512-A0j3MBP8Kga8Qrh7znO2UKf00Sga37PJCiTGUqVVBHb+u58fNoGXZtFAgeH6qKjf5eU1wYt4WptXX/1blOAfRw==} + '@rslib/core@1.0.0-beta.3': + resolution: {integrity: sha512-OtfmaBoGlHo1KYvQ3+B0ZLy3zUsAdoRZfWieaxoJMJ9uKAws2//afFgvUqeSDkkSJDlp8TDdgt4hib+QaFOaGQ==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -1373,6 +1383,11 @@ packages: cpu: [x64] os: [win32] + '@rspack/binding-darwin-arm64@2.1.10': + resolution: {integrity: sha512-DZlcTpbIb2mjeS1aSG4k01UH33Zj7T+k8ZylPK6HmsKs4JvK4wgpWFC78WVv3p/Aj3MZS6DwtDLwpZ2Ihj/fpg==} + cpu: [arm64] + os: [darwin] + '@rspack/binding-darwin-arm64@2.1.8': resolution: {integrity: sha512-kia+eWtyWPvR4ntg1bWYoVU8nLPbUg2fG3zgBEocsTcsh5ZENSiEPxEKymDgMyIMONUqj611E0775cdUBoNmqw==} cpu: [arm64] @@ -1383,6 +1398,11 @@ packages: cpu: [arm64] os: [darwin] + '@rspack/binding-darwin-x64@2.1.10': + resolution: {integrity: sha512-my/0h2LwxCRT6cg3oDDC2e0ZOxQLVajAdIcv0fqnQk5JRNvVuL89PuTutitnSqie1A0/JSL8OQz5XHwmoS3kow==} + cpu: [x64] + os: [darwin] + '@rspack/binding-darwin-x64@2.1.8': resolution: {integrity: sha512-08pBkFhlD3Y3Qzh94w/Fc3skaIE3e96kl2P14m8+tnYTcglpOfpA2OwS3iHt9fOqy0HjoAVe6/MW3cBgs5iabA==} cpu: [x64] @@ -1393,6 +1413,12 @@ packages: cpu: [x64] os: [darwin] + '@rspack/binding-linux-arm64-gnu@2.1.10': + resolution: {integrity: sha512-laevn9g+E5PAUEGqiKe6Ju5KApsuQYp+bPI17XS3Lkl8eqL5pS/BmHYU7QMlst4GzV8+wlruVTMh//+st6Vqzg==} + cpu: [arm64] + os: [linux] + libc: [glibc] + '@rspack/binding-linux-arm64-gnu@2.1.8': resolution: {integrity: sha512-KLniMc9GzhKpVqhPzaJo3KJwzdAllXVVqZIk/uL1QipXOxs57fgM4u7IexKPFVla0o/u1PQG/Ah2YLDmda24Ow==} cpu: [arm64] @@ -1405,6 +1431,12 @@ packages: os: [linux] libc: [glibc] + '@rspack/binding-linux-arm64-musl@2.1.10': + resolution: {integrity: sha512-V71+Qz5G72+ROZXrJn5zxOszdG1AEbO8pcC/itXXtf4yRR6a3bVHKNKGhipBNxb8eI6cnD/01FH1h3ZG655jLw==} + cpu: [arm64] + os: [linux] + libc: [musl] + '@rspack/binding-linux-arm64-musl@2.1.8': resolution: {integrity: sha512-yUKAxHNGnICtw5RnxFWu4dHtsz/tdt7rbeFcsINNVre9HcrRxf5XP+FbOGL/SMxd9oM9XCo10paU2WckTKwbEA==} cpu: [arm64] @@ -1417,12 +1449,24 @@ packages: os: [linux] libc: [musl] + '@rspack/binding-linux-ppc64-gnu@2.1.10': + resolution: {integrity: sha512-U7HlNzHcDtZ+LYOtOJmtx67kHEybZzUUAaP7aEXjGYO5WTCgh/176sW2UYP0rmZLrgUNFUuzn+B98RLaClNaVg==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + '@rspack/binding-linux-ppc64-gnu@2.1.9': resolution: {integrity: sha512-xK90IHipRDgxvDF9n90HRNklci0G2Amk0ZMsM3t3YX+/8jIJNcuEPk6hJ1hlY6KZu7U9enqGbNQ7Fe0StBeLVA==} cpu: [ppc64] os: [linux] libc: [glibc] + '@rspack/binding-linux-riscv64-gnu@2.1.10': + resolution: {integrity: sha512-GMGTJpy9/ecE+5F5IfxZH4bXv0Wx/b2TiehTlCbTksbL+pKpLHYy0rwGdjWDKbmBkhxMMqPiC7PDnn9LbdnnLA==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + '@rspack/binding-linux-riscv64-gnu@2.1.8': resolution: {integrity: sha512-gg4S1jaitwYPHR9HZ3zNGH1EK2GXINm66p4kEpOP1gbc+akyOouVF/dMcu9NGPlRg58FbEhVRZYKu7Z/zcpKHg==} cpu: [riscv64] @@ -1435,6 +1479,12 @@ packages: os: [linux] libc: [glibc] + '@rspack/binding-linux-riscv64-musl@2.1.10': + resolution: {integrity: sha512-rkurnAWc04vIbzG1QCrPBWSJadZvaOt1mazFH3EdiJO8VUiu0I1T9zdiwuDOPrd50lOKIZlcTXbd5aaAkWEnvQ==} + cpu: [riscv64] + os: [linux] + libc: [musl] + '@rspack/binding-linux-riscv64-musl@2.1.8': resolution: {integrity: sha512-b/aU5j1h368SLNyz5u+flqpZVhzSZ1UIslaj9sZJuAvqkGWv3xsjc/28/PTo/RYXCxd0FNVAxTxWHKvRiAAS8w==} cpu: [riscv64] @@ -1447,12 +1497,24 @@ packages: os: [linux] libc: [musl] + '@rspack/binding-linux-s390x-gnu@2.1.10': + resolution: {integrity: sha512-X+DyxkriZEAF/wihI7ERDv+CAS0mbMv36aEuQ+vXzTlvS6cSmpou/r29AHbvIF3NlG1UeAbDVlOs9QrMBZjpUQ==} + cpu: [s390x] + os: [linux] + libc: [glibc] + '@rspack/binding-linux-s390x-gnu@2.1.9': resolution: {integrity: sha512-rGmeME3Pd8k/55txP+19ceZJxhVN2mtC8TLzB1ycTrhy8U+ZnN7J8rZSl89LYrZGYewd1UmOcY0QKKy05FS3FA==} cpu: [s390x] os: [linux] libc: [glibc] + '@rspack/binding-linux-x64-gnu@2.1.10': + resolution: {integrity: sha512-Fat09V6jUuyo9qG7Wyj9cQ31VDfLmokXyBtGqKxY5OvSWHereB7QUub5btbPXHwbp6Iq4aAQyUbbLTzvR1YaBw==} + cpu: [x64] + os: [linux] + libc: [glibc] + '@rspack/binding-linux-x64-gnu@2.1.8': resolution: {integrity: sha512-EyegohSx0BJRqieCg9f/caCqFARRWkqI5hwJt6k530MoOTLeq8I3vsbeg24/2MktwIC1dmJi8bl0+WhPKQs4eQ==} cpu: [x64] @@ -1465,6 +1527,12 @@ packages: os: [linux] libc: [glibc] + '@rspack/binding-linux-x64-musl@2.1.10': + resolution: {integrity: sha512-lhHOnIJ4ClpIlA1f1L8aoxEZivYLjnjq5A6jKKz7BKsm+cHK8kqqEm6lO5KqA5xQT0Lonq1o28bmKHEj6JHInw==} + cpu: [x64] + os: [linux] + libc: [musl] + '@rspack/binding-linux-x64-musl@2.1.8': resolution: {integrity: sha512-I6E+goN+UQ297q4r1qdbiAyNCI3t0+a5Y0xDIAPOZfRDRxDTnH/LF8/y65gjsJoKRKyn7zxRC0T/NURTkRNQ9A==} cpu: [x64] @@ -1477,6 +1545,10 @@ packages: os: [linux] libc: [musl] + '@rspack/binding-wasm32-wasi@2.1.10': + resolution: {integrity: sha512-KY5YbWbuvYcoaLXnV+vzZOvGRCeb6jt4EpVpKdph1h1IJjwX/ju15EQ+GOe3iecZEdf0OttQcNVcwBkLkFT9ag==} + cpu: [wasm32] + '@rspack/binding-wasm32-wasi@2.1.8': resolution: {integrity: sha512-om7GAKWAU3lcSvbCon2m7mzw8v9OTrO2LW2MZ1lGe/uVJJmwGGkl9HVoXFyWFLrN6YVFyx8iP+AkN4owDWB9Cw==} cpu: [wasm32] @@ -1485,6 +1557,11 @@ packages: resolution: {integrity: sha512-TF6oZRU23x6vHzGuvRFszvEnmC5Yn8PHbKmeZWsUHj4Mtv4tDdDGVdlxj6Kq3pySS6sRknv8gzpRMhXqHD3I5g==} cpu: [wasm32] + '@rspack/binding-win32-arm64-msvc@2.1.10': + resolution: {integrity: sha512-z4GWzMLofaDGpAt9Z+MlN88LlUBDm+zM6R2GdOOPM6/4g/h3/+47OP7casmSL3AwTGYBEJqogwt08sRSosB6Cg==} + cpu: [arm64] + os: [win32] + '@rspack/binding-win32-arm64-msvc@2.1.8': resolution: {integrity: sha512-WDnsP/SUb9zbxyGX9XjPw5AXrX86u5oidn0MDdfJduOOqdCSpHwmRjlQ8NUJhbBq9WqVJMFlcab7NwZVWX/yyg==} cpu: [arm64] @@ -1495,6 +1572,11 @@ packages: cpu: [arm64] os: [win32] + '@rspack/binding-win32-ia32-msvc@2.1.10': + resolution: {integrity: sha512-7qcWdsZ+GuGtzKjqgy7wTN7Dso/ezIY8yhx1r2yIbcczdmXj4FhaEampMDp/25HwtKwIGBBoh6HHSt3JWxpTUg==} + cpu: [ia32] + os: [win32] + '@rspack/binding-win32-ia32-msvc@2.1.8': resolution: {integrity: sha512-QiMQMPNDiY3dhhaIdaFPzcPDC06cEYkNY89ea+EmDvNVgZq6V+2mFS/WnzZVMeEbGAYJCjsv/ABhhLT1hlYMvg==} cpu: [ia32] @@ -1505,6 +1587,11 @@ packages: cpu: [ia32] os: [win32] + '@rspack/binding-win32-x64-msvc@2.1.10': + resolution: {integrity: sha512-pgp23pLrzfhGnKycxzr7ifP17lAbWZEfnx1bX8gXtYrnpJ66DRNyTKSzxB6sa/HBWjS1L8PX5TjMZ44WfPydqQ==} + cpu: [x64] + os: [win32] + '@rspack/binding-win32-x64-msvc@2.1.8': resolution: {integrity: sha512-b7sA5eB64vo2mbsuc//MOYzVLeCKHPn0dfP/GmNEoHdWbhRgZ/orZLWurYMQj04ELTLW6YCJEy59g5KRzNYHfw==} cpu: [x64] @@ -1515,12 +1602,27 @@ packages: cpu: [x64] os: [win32] + '@rspack/binding@2.1.10': + resolution: {integrity: sha512-vnu/UP5HnrND15lO9+VeG6eUrbTyycHNQNQ3XEiRiFojuoiGZkIZC3Hbzr8qQH44C6vScPODEPvvIVvLcO2LpQ==} + '@rspack/binding@2.1.8': resolution: {integrity: sha512-tmAyHzDbPiy8V7HvQqtuPsbs6dPgwV0YjzW5XrPRV9gzf+Hdm7pvsZJKE1QKO9WV5RuvGYav98xIX6O+abZxzQ==} '@rspack/binding@2.1.9': resolution: {integrity: sha512-0ZZj+RE62/jFRwX5czqjjGiMGgzSK0hm7/66PtCKjyZjb2tNAg3WGyWv+ref7684ZAjtbHHpZ+EOGswQYBjklA==} + '@rspack/core@2.1.10': + resolution: {integrity: sha512-YSS2/Xxz8uiG/KXDkqOoA3dTetNo/vysk7bAexQOrU8iuq7JuzDTTAwLKvWZnwmvME8M8m5wcM4YvfIwYmidHA==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + '@module-federation/runtime-tools': ^0.24.1 || ^2.0.0 + '@swc/helpers': ^0.5.23 + peerDependenciesMeta: + '@module-federation/runtime-tools': + optional: true + '@swc/helpers': + optional: true + '@rspack/core@2.1.8': resolution: {integrity: sha512-na1kyA6Mj8/LWw9O3A8NsrG9rNKN3Iq2WiXrEuIwsU5r/Nl/evm3hO7bWKHxgsRyydI6W7okwx3MXgf8rzel6g==} engines: {node: ^20.19.0 || >=22.12.0} @@ -2819,8 +2921,8 @@ packages: remark-stringify@11.0.0: resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} - rsbuild-plugin-dts@1.0.0-beta.2: - resolution: {integrity: sha512-xOYa/kw/y29kKFFNjd+CIemlq+CB8E7LhqNkIzg7HT9dYNBVBpZvnnL6OEsOgjeuqzKpGSCRgZN/dDoVOk4VhQ==} + rsbuild-plugin-dts@1.0.0-beta.3: + resolution: {integrity: sha512-Q8x/yyOsy8sNR8sHn0xuZsul7ErT5kXkTmDwCIxQ8esiMCW7QKjfyXDa4kvTxWn7oSQ5NP/O6qZM2vEA07thKw==} engines: {node: ^20.19.0 || >=22.12.0} peerDependencies: '@microsoft/api-extractor': ^7 @@ -3879,9 +3981,16 @@ snapshots: transitivePeerDependencies: - '@module-federation/runtime-tools' - '@rsbuild/plugin-react@2.1.0(@rsbuild/core@2.1.10)(@rspack/core@2.1.9)': + '@rsbuild/core@2.1.12': + dependencies: + '@rspack/core': 2.1.10(@swc/helpers@0.5.23) + '@swc/helpers': 0.5.23 + transitivePeerDependencies: + - '@module-federation/runtime-tools' + + '@rsbuild/plugin-react@2.1.0(@rsbuild/core@2.1.10)(@rspack/core@2.1.10)': dependencies: - '@rspack/plugin-react-refresh': 2.0.2(@rspack/core@2.1.9)(react-refresh@0.18.0) + '@rspack/plugin-react-refresh': 2.0.2(@rspack/core@2.1.10)(react-refresh@0.18.0) react-refresh: 0.18.0 optionalDependencies: '@rsbuild/core': 2.1.10 @@ -3898,10 +4007,10 @@ snapshots: optionalDependencies: '@rsbuild/core': 2.1.10 - '@rslib/core@1.0.0-beta.2(typescript@7.0.2)': + '@rslib/core@1.0.0-beta.3(typescript@7.0.2)': dependencies: - '@rsbuild/core': 2.1.11 - rsbuild-plugin-dts: 1.0.0-beta.2(@rsbuild/core@2.1.11)(typescript@7.0.2) + '@rsbuild/core': 2.1.12 + rsbuild-plugin-dts: 1.0.0-beta.3(@rsbuild/core@2.1.12)(typescript@7.0.2) optionalDependencies: typescript: 7.0.2 transitivePeerDependencies: @@ -3945,60 +4054,97 @@ snapshots: '@rslint/native-win32-x64-msvc@0.8.0': optional: true + '@rspack/binding-darwin-arm64@2.1.10': + optional: true + '@rspack/binding-darwin-arm64@2.1.8': optional: true '@rspack/binding-darwin-arm64@2.1.9': optional: true + '@rspack/binding-darwin-x64@2.1.10': + optional: true + '@rspack/binding-darwin-x64@2.1.8': optional: true '@rspack/binding-darwin-x64@2.1.9': optional: true + '@rspack/binding-linux-arm64-gnu@2.1.10': + optional: true + '@rspack/binding-linux-arm64-gnu@2.1.8': optional: true '@rspack/binding-linux-arm64-gnu@2.1.9': optional: true + '@rspack/binding-linux-arm64-musl@2.1.10': + optional: true + '@rspack/binding-linux-arm64-musl@2.1.8': optional: true '@rspack/binding-linux-arm64-musl@2.1.9': optional: true + '@rspack/binding-linux-ppc64-gnu@2.1.10': + optional: true + '@rspack/binding-linux-ppc64-gnu@2.1.9': optional: true + '@rspack/binding-linux-riscv64-gnu@2.1.10': + optional: true + '@rspack/binding-linux-riscv64-gnu@2.1.8': optional: true '@rspack/binding-linux-riscv64-gnu@2.1.9': optional: true + '@rspack/binding-linux-riscv64-musl@2.1.10': + optional: true + '@rspack/binding-linux-riscv64-musl@2.1.8': optional: true '@rspack/binding-linux-riscv64-musl@2.1.9': optional: true + '@rspack/binding-linux-s390x-gnu@2.1.10': + optional: true + '@rspack/binding-linux-s390x-gnu@2.1.9': optional: true + '@rspack/binding-linux-x64-gnu@2.1.10': + optional: true + '@rspack/binding-linux-x64-gnu@2.1.8': optional: true '@rspack/binding-linux-x64-gnu@2.1.9': optional: true + '@rspack/binding-linux-x64-musl@2.1.10': + optional: true + '@rspack/binding-linux-x64-musl@2.1.8': optional: true '@rspack/binding-linux-x64-musl@2.1.9': optional: true + '@rspack/binding-wasm32-wasi@2.1.10': + dependencies: + '@emnapi/core': 1.11.3 + '@emnapi/runtime': 1.11.3 + '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3) + optional: true + '@rspack/binding-wasm32-wasi@2.1.8': dependencies: '@emnapi/core': 1.11.3 @@ -4013,24 +4159,50 @@ snapshots: '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3) optional: true + '@rspack/binding-win32-arm64-msvc@2.1.10': + optional: true + '@rspack/binding-win32-arm64-msvc@2.1.8': optional: true '@rspack/binding-win32-arm64-msvc@2.1.9': optional: true + '@rspack/binding-win32-ia32-msvc@2.1.10': + optional: true + '@rspack/binding-win32-ia32-msvc@2.1.8': optional: true '@rspack/binding-win32-ia32-msvc@2.1.9': optional: true + '@rspack/binding-win32-x64-msvc@2.1.10': + optional: true + '@rspack/binding-win32-x64-msvc@2.1.8': optional: true '@rspack/binding-win32-x64-msvc@2.1.9': optional: true + '@rspack/binding@2.1.10': + optionalDependencies: + '@rspack/binding-darwin-arm64': 2.1.10 + '@rspack/binding-darwin-x64': 2.1.10 + '@rspack/binding-linux-arm64-gnu': 2.1.10 + '@rspack/binding-linux-arm64-musl': 2.1.10 + '@rspack/binding-linux-ppc64-gnu': 2.1.10 + '@rspack/binding-linux-riscv64-gnu': 2.1.10 + '@rspack/binding-linux-riscv64-musl': 2.1.10 + '@rspack/binding-linux-s390x-gnu': 2.1.10 + '@rspack/binding-linux-x64-gnu': 2.1.10 + '@rspack/binding-linux-x64-musl': 2.1.10 + '@rspack/binding-wasm32-wasi': 2.1.10 + '@rspack/binding-win32-arm64-msvc': 2.1.10 + '@rspack/binding-win32-ia32-msvc': 2.1.10 + '@rspack/binding-win32-x64-msvc': 2.1.10 + '@rspack/binding@2.1.8': optionalDependencies: '@rspack/binding-darwin-arm64': 2.1.8 @@ -4063,6 +4235,12 @@ snapshots: '@rspack/binding-win32-ia32-msvc': 2.1.9 '@rspack/binding-win32-x64-msvc': 2.1.9 + '@rspack/core@2.1.10(@swc/helpers@0.5.23)': + dependencies: + '@rspack/binding': 2.1.10 + optionalDependencies: + '@swc/helpers': 0.5.23 + '@rspack/core@2.1.8(@swc/helpers@0.5.23)': dependencies: '@rspack/binding': 2.1.8 @@ -4075,18 +4253,18 @@ snapshots: optionalDependencies: '@swc/helpers': 0.5.23 - '@rspack/plugin-react-refresh@2.0.2(@rspack/core@2.1.9)(react-refresh@0.18.0)': + '@rspack/plugin-react-refresh@2.0.2(@rspack/core@2.1.10)(react-refresh@0.18.0)': dependencies: react-refresh: 0.18.0 optionalDependencies: - '@rspack/core': 2.1.9(@swc/helpers@0.5.23) + '@rspack/core': 2.1.10(@swc/helpers@0.5.23) '@rspress/core@2.0.19(micromark-util-types@2.0.2)(micromark@4.0.2)(supports-color@8.1.1)': dependencies: '@mdx-js/mdx': 3.1.1(supports-color@8.1.1) '@mdx-js/react': 3.1.1(@types/react@19.2.18)(react@19.2.8) '@rsbuild/core': 2.1.10 - '@rsbuild/plugin-react': 2.1.0(@rsbuild/core@2.1.10)(@rspack/core@2.1.9) + '@rsbuild/plugin-react': 2.1.0(@rsbuild/core@2.1.10)(@rspack/core@2.1.10) '@rspress/shared': 2.0.19(supports-color@8.1.1) '@shikijs/rehype': 4.3.1 '@types/mdast': 4.0.4 @@ -4139,7 +4317,7 @@ snapshots: '@rspress/shared@2.0.19(supports-color@8.1.1)': dependencies: - '@rsbuild/core': 2.1.10 + '@rsbuild/core': 2.1.11 '@shikijs/rehype': 4.3.1 '@types/react': 19.2.18 mdast-util-mdx-jsx: 3.2.0(supports-color@8.1.1) @@ -4164,9 +4342,9 @@ snapshots: '@rsbuild/core': 2.1.11 '@rstest/core': 0.11.6(happy-dom@20.11.2) - '@rstest/adapter-rslib@0.11.6(@rslib/core@1.0.0-beta.2)(@rstest/core@0.11.6)(typescript@7.0.2)': + '@rstest/adapter-rslib@0.11.6(@rslib/core@1.0.0-beta.3)(@rstest/core@0.11.6)(typescript@7.0.2)': dependencies: - '@rslib/core': 1.0.0-beta.2(typescript@7.0.2) + '@rslib/core': 1.0.0-beta.3(typescript@7.0.2) '@rstest/core': 0.11.6(happy-dom@20.11.2) optionalDependencies: typescript: 7.0.2 @@ -5636,10 +5814,10 @@ snapshots: mdast-util-to-markdown: 2.1.2 unified: 11.0.5 - rsbuild-plugin-dts@1.0.0-beta.2(@rsbuild/core@2.1.11)(typescript@7.0.2): + rsbuild-plugin-dts@1.0.0-beta.3(@rsbuild/core@2.1.12)(typescript@7.0.2): dependencies: '@ast-grep/napi': 0.37.0 - '@rsbuild/core': 2.1.11 + '@rsbuild/core': 2.1.12 optionalDependencies: typescript: 7.0.2 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 720da26e..8bf766d0 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -16,7 +16,7 @@ catalog: '@rsbuild/core': '~2.1.11' '@rsbuild/plugin-react': '^2.1.0' '@rsbuild/plugin-sass': '^2.0.1' - '@rslib/core': '~1.0.0-beta.2' + '@rslib/core': '~1.0.0-beta.3' '@rslint/core': '~0.8.0' '@rspress/core': '^2.0.19' '@rspress/plugin-client-redirects': '^2.0.19' From 07fa1303126295ad923f4185c46789047d3f4071 Mon Sep 17 00:00:00 2001 From: Jiahan Chen Date: Thu, 13 Aug 2026 21:55:25 +0800 Subject: [PATCH 15/33] docs: clarify Rstack CLI terminology (#350) --- packages/create-rstack/README.md | 2 +- .../create-rstack/template-common/README.md | 4 ++-- .../create-rstack/template-doc-i18n/README.md | 2 +- packages/create-rstack/template-doc/README.md | 2 +- .../template-lib-node-ts/README.md | 2 +- .../create-rstack/template-lib-node/README.md | 2 +- .../template-lib-react-ts/README.md | 2 +- .../template-lib-react/README.md | 2 +- .../template-lib-solid-ts/README.md | 2 +- .../template-lib-solid/README.md | 2 +- .../template-lib-svelte-ts/README.md | 2 +- .../template-lib-svelte/README.md | 2 +- .../template-lib-vue-ts/README.md | 2 +- .../create-rstack/template-lib-vue/README.md | 2 +- website/docs/en/guide/api-reference.mdx | 6 +++--- website/docs/en/guide/cli/setup.mdx | 20 +++++++++---------- website/docs/en/guide/configuration.mdx | 12 +++++------ website/docs/en/guide/formatting.mdx | 4 ++-- website/docs/en/guide/monorepo.mdx | 18 ++++++++--------- website/docs/en/guide/quick-start.mdx | 12 +++++------ website/docs/en/guide/testing.mdx | 8 ++++---- website/docs/zh/guide/api-reference.mdx | 6 +++--- website/docs/zh/guide/cli/setup.mdx | 20 +++++++++---------- website/docs/zh/guide/configuration.mdx | 14 ++++++------- website/docs/zh/guide/formatting.mdx | 6 +++--- website/docs/zh/guide/monorepo.mdx | 18 ++++++++--------- website/docs/zh/guide/quick-start.mdx | 14 ++++++------- website/docs/zh/guide/testing.mdx | 8 ++++---- 28 files changed, 98 insertions(+), 98 deletions(-) diff --git a/packages/create-rstack/README.md b/packages/create-rstack/README.md index fcac4ec4..42c07e2c 100644 --- a/packages/create-rstack/README.md +++ b/packages/create-rstack/README.md @@ -53,7 +53,7 @@ npx create-rstack --dir my-project --template app-vanilla-ts --no-git ## Documentation -See the [Rstack documentation](https://rstack.rs). +See the [Rstack CLI documentation](https://rstack.rs). ## License diff --git a/packages/create-rstack/template-common/README.md b/packages/create-rstack/template-common/README.md index abd777a3..f1777fb0 100644 --- a/packages/create-rstack/template-common/README.md +++ b/packages/create-rstack/template-common/README.md @@ -21,5 +21,5 @@ Install the dependencies: ## Learn more -- [Rstack documentation](https://rstack.rs) -- [Rstack GitHub repository](https://github.com/rstackjs/rstack-cli) +- [Rstack CLI documentation](https://rstack.rs) +- [Rstack CLI GitHub repository](https://github.com/rstackjs/rstack-cli) diff --git a/packages/create-rstack/template-doc-i18n/README.md b/packages/create-rstack/template-doc-i18n/README.md index ba4906ab..8e0f4ae9 100644 --- a/packages/create-rstack/template-doc-i18n/README.md +++ b/packages/create-rstack/template-doc-i18n/README.md @@ -19,5 +19,5 @@ Install the dependencies: ## Learn more -- [Rstack documentation](https://rstack.rs) +- [Rstack CLI documentation](https://rstack.rs) - [Rspress documentation](https://rspress.rs) diff --git a/packages/create-rstack/template-doc/README.md b/packages/create-rstack/template-doc/README.md index cd9ac929..84ca63bc 100644 --- a/packages/create-rstack/template-doc/README.md +++ b/packages/create-rstack/template-doc/README.md @@ -19,5 +19,5 @@ Install the dependencies: ## Learn more -- [Rstack documentation](https://rstack.rs) +- [Rstack CLI documentation](https://rstack.rs) - [Rspress documentation](https://rspress.rs) diff --git a/packages/create-rstack/template-lib-node-ts/README.md b/packages/create-rstack/template-lib-node-ts/README.md index 93e8a06e..5d6dbbef 100644 --- a/packages/create-rstack/template-lib-node-ts/README.md +++ b/packages/create-rstack/template-lib-node-ts/README.md @@ -20,5 +20,5 @@ Install the dependencies: ## Learn more -- [Rstack documentation](https://rstack.rs) +- [Rstack CLI documentation](https://rstack.rs) - [Rslib documentation](https://rslib.rs) diff --git a/packages/create-rstack/template-lib-node/README.md b/packages/create-rstack/template-lib-node/README.md index 93e8a06e..5d6dbbef 100644 --- a/packages/create-rstack/template-lib-node/README.md +++ b/packages/create-rstack/template-lib-node/README.md @@ -20,5 +20,5 @@ Install the dependencies: ## Learn more -- [Rstack documentation](https://rstack.rs) +- [Rstack CLI documentation](https://rstack.rs) - [Rslib documentation](https://rslib.rs) diff --git a/packages/create-rstack/template-lib-react-ts/README.md b/packages/create-rstack/template-lib-react-ts/README.md index 93e8a06e..5d6dbbef 100644 --- a/packages/create-rstack/template-lib-react-ts/README.md +++ b/packages/create-rstack/template-lib-react-ts/README.md @@ -20,5 +20,5 @@ Install the dependencies: ## Learn more -- [Rstack documentation](https://rstack.rs) +- [Rstack CLI documentation](https://rstack.rs) - [Rslib documentation](https://rslib.rs) diff --git a/packages/create-rstack/template-lib-react/README.md b/packages/create-rstack/template-lib-react/README.md index 93e8a06e..5d6dbbef 100644 --- a/packages/create-rstack/template-lib-react/README.md +++ b/packages/create-rstack/template-lib-react/README.md @@ -20,5 +20,5 @@ Install the dependencies: ## Learn more -- [Rstack documentation](https://rstack.rs) +- [Rstack CLI documentation](https://rstack.rs) - [Rslib documentation](https://rslib.rs) diff --git a/packages/create-rstack/template-lib-solid-ts/README.md b/packages/create-rstack/template-lib-solid-ts/README.md index 93e8a06e..5d6dbbef 100644 --- a/packages/create-rstack/template-lib-solid-ts/README.md +++ b/packages/create-rstack/template-lib-solid-ts/README.md @@ -20,5 +20,5 @@ Install the dependencies: ## Learn more -- [Rstack documentation](https://rstack.rs) +- [Rstack CLI documentation](https://rstack.rs) - [Rslib documentation](https://rslib.rs) diff --git a/packages/create-rstack/template-lib-solid/README.md b/packages/create-rstack/template-lib-solid/README.md index 93e8a06e..5d6dbbef 100644 --- a/packages/create-rstack/template-lib-solid/README.md +++ b/packages/create-rstack/template-lib-solid/README.md @@ -20,5 +20,5 @@ Install the dependencies: ## Learn more -- [Rstack documentation](https://rstack.rs) +- [Rstack CLI documentation](https://rstack.rs) - [Rslib documentation](https://rslib.rs) diff --git a/packages/create-rstack/template-lib-svelte-ts/README.md b/packages/create-rstack/template-lib-svelte-ts/README.md index 93e8a06e..5d6dbbef 100644 --- a/packages/create-rstack/template-lib-svelte-ts/README.md +++ b/packages/create-rstack/template-lib-svelte-ts/README.md @@ -20,5 +20,5 @@ Install the dependencies: ## Learn more -- [Rstack documentation](https://rstack.rs) +- [Rstack CLI documentation](https://rstack.rs) - [Rslib documentation](https://rslib.rs) diff --git a/packages/create-rstack/template-lib-svelte/README.md b/packages/create-rstack/template-lib-svelte/README.md index 93e8a06e..5d6dbbef 100644 --- a/packages/create-rstack/template-lib-svelte/README.md +++ b/packages/create-rstack/template-lib-svelte/README.md @@ -20,5 +20,5 @@ Install the dependencies: ## Learn more -- [Rstack documentation](https://rstack.rs) +- [Rstack CLI documentation](https://rstack.rs) - [Rslib documentation](https://rslib.rs) diff --git a/packages/create-rstack/template-lib-vue-ts/README.md b/packages/create-rstack/template-lib-vue-ts/README.md index 93e8a06e..5d6dbbef 100644 --- a/packages/create-rstack/template-lib-vue-ts/README.md +++ b/packages/create-rstack/template-lib-vue-ts/README.md @@ -20,5 +20,5 @@ Install the dependencies: ## Learn more -- [Rstack documentation](https://rstack.rs) +- [Rstack CLI documentation](https://rstack.rs) - [Rslib documentation](https://rslib.rs) diff --git a/packages/create-rstack/template-lib-vue/README.md b/packages/create-rstack/template-lib-vue/README.md index 93e8a06e..5d6dbbef 100644 --- a/packages/create-rstack/template-lib-vue/README.md +++ b/packages/create-rstack/template-lib-vue/README.md @@ -20,5 +20,5 @@ Install the dependencies: ## Learn more -- [Rstack documentation](https://rstack.rs) +- [Rstack CLI documentation](https://rstack.rs) - [Rslib documentation](https://rslib.rs) diff --git a/website/docs/en/guide/api-reference.mdx b/website/docs/en/guide/api-reference.mdx index 8c61e7fc..dd2eba08 100644 --- a/website/docs/en/guide/api-reference.mdx +++ b/website/docs/en/guide/api-reference.mdx @@ -1,12 +1,12 @@ # API reference -Rstack provides a unified configuration API and re-exports the public APIs of Rsbuild, Rslib, Rstest, and Rslint through dedicated subpaths. Prefer these subpaths to direct imports from each tool's core package so that dependency entry points and tool versions remain aligned with Rstack. +Rstack CLI provides a unified configuration API and re-exports the public APIs of Rsbuild, Rslib, Rstest, and Rslint through dedicated subpaths. Prefer these subpaths to direct imports from each tool's core package so that dependency entry points stay unified and APIs match the tool versions integrated by Rstack CLI. ## Import paths | Import path | Contents | Use case | | ------------------------ | ------------------------------------------------- | --------------------------------------- | -| `rstack` | Rstack configuration API | Register tool configurations | +| `rstack` | Rstack CLI configuration API | Register tool configurations | | `rstack/app` | Public APIs from `@rsbuild/core` | Build applications and extend Rsbuild | | `rstack/lib` | Public APIs from `@rslib/core` | Build libraries and extend Rslib | | `rstack/test` | Public APIs from `@rstest/core` | Write tests and configure test projects | @@ -23,7 +23,7 @@ Import `define` from `rstack` to register tool configurations in `rstack.config. ## Re-exports -The tool-specific subpaths below re-export the public APIs from their corresponding core packages. Using these Rstack entry points keeps dependency entry points and tool versions aligned with the toolchain integrated by Rstack. +The tool-specific subpaths below re-export the public APIs from their corresponding core packages. Using these entry points keeps imports unified and APIs aligned with the tool versions integrated by Rstack CLI. ### `rstack/app` diff --git a/website/docs/en/guide/cli/setup.mdx b/website/docs/en/guide/cli/setup.mdx index e61403d4..2ea8bbe9 100644 --- a/website/docs/en/guide/cli/setup.mdx +++ b/website/docs/en/guide/cli/setup.mdx @@ -99,7 +99,7 @@ Files next to `_` are repository hook scripts. The `_` directory contains genera ## Supported hooks -Rstack supports these client-side Git hooks: +Rstack CLI supports these client-side Git hooks: - `pre-commit` - `pre-merge-commit` @@ -120,7 +120,7 @@ Create a file with the matching name next to the `_` directory. ## Hook runtime -Rstack runs hook scripts with POSIX `sh -e`, forwards Git's arguments and standard input, and returns the hook's exit code. Before running a hook, it changes to the project that installed the hooks and prepends that project's `node_modules/.bin` to `PATH`. +Rstack CLI runs hook scripts with POSIX `sh -e`, forwards Git's arguments and standard input, and returns the hook's exit code. Before running a hook, it changes to the project that installed the hooks and prepends that project's `node_modules/.bin` to `PATH`. ### Disable and debug @@ -130,7 +130,7 @@ Set `RSTACK_HOOKS=0` to skip installation or hook execution: RSTACK_HOOKS=0 git commit -m "Skip hooks" ``` -Set `RSTACK_HOOKS=2` to trace Rstack's hook runtime, including how it invokes the hook script and handles its exit code; to trace commands inside the hook script, add `set -x` to the script: +Set `RSTACK_HOOKS=2` to trace the Rstack CLI hook runtime, including how it invokes the hook script and handles its exit code; to trace commands inside the hook script, add `set -x` to the script: ```bash RSTACK_HOOKS=2 git commit -m "Trace hooks" @@ -138,7 +138,7 @@ RSTACK_HOOKS=2 git commit -m "Trace hooks" ### Configure the hook environment -Before running a hook script, Rstack loads this optional POSIX shell file: +Before running a hook script, Rstack CLI loads this optional POSIX shell file: ```text ${XDG_CONFIG_HOME:-$HOME/.config}/rstack/hooks-init.sh @@ -148,7 +148,7 @@ Use it to initialize a Node.js version manager, update `PATH`, or set `RSTACK_HO ## Monorepo -In a monorepo, the project that provides Rstack may be located in a subdirectory such as `frontend/`. Running `rs setup` from that directory still installs hooks at the Git repository root: +In a monorepo, the project that provides Rstack CLI may be located in a subdirectory such as `frontend/`. Running `rs setup` from that directory still installs hooks at the Git repository root: ```text repo/.rstack/hooks/ @@ -156,7 +156,7 @@ repo/.rstack/hooks/_/ core.hooksPath=.rstack/hooks/_ ``` -Rstack records `frontend` as the project that owns the hooks. Hook scripts remain at the repository root, but run from `frontend`, so they can use its configuration and dependencies without an explicit `cd`: +Rstack CLI records `frontend` as the project that owns the hooks. Hook scripts remain at the repository root, but run from `frontend`, so they can use its configuration and dependencies without an explicit `cd`: ```sh title=".rstack/hooks/pre-commit" rs staged @@ -168,7 +168,7 @@ To change the owner, remove `rs setup` from the previous project's `prepare` scr ## Remove hooks -To remove Rstack-managed hooks: +To remove hooks managed by Rstack CLI: 1. Remove `rs setup` from the `prepare` script. 2. Unset the repository's hooks path: @@ -188,13 +188,13 @@ To remove Rstack-managed hooks: - Rerun `rs setup` to restore generated files and executable permissions. - Check that `RSTACK_HOOKS` is not set to `0` in the environment or initialization file. - If another hooks setup is reported, migrate or remove the conflicting setup before rerunning the command. -- If another Rstack owner is reported, follow the ownership transfer steps in [Monorepo](#monorepo). +- If another project is reported as the hooks owner, follow the ownership transfer steps in [Monorepo](#monorepo). -Hook scripts do not need to be executable because Rstack runs them with `sh`. +Hook scripts do not need to be executable because Rstack CLI runs them with `sh`. ### Command not found -For exit code 127, Rstack prints the effective `PATH`. If a GUI Git client cannot find Node.js or the package manager, initialize them in `hooks-init.sh`. +For exit code 127, Rstack CLI prints the effective `PATH`. If a GUI Git client cannot find Node.js or the package manager, initialize them in `hooks-init.sh`. ### Windows and Yarn diff --git a/website/docs/en/guide/configuration.mdx b/website/docs/en/guide/configuration.mdx index e9db58fe..55288bbd 100644 --- a/website/docs/en/guide/configuration.mdx +++ b/website/docs/en/guide/configuration.mdx @@ -2,7 +2,7 @@ import { PackageManagerTabs } from '@rspress/core/theme'; -Rstack centralizes the configuration for your project's tools in a single file. Define only the configurations your project needs with the `define.*()` APIs. +Rstack CLI centralizes the configuration for your project's tools in a single file. Define only the configurations your project needs with the `define.*()` APIs. ## Configuration file @@ -31,7 +31,7 @@ define.fmt({ The configuration file does not require a default export. Each `define.*()` API can be called at most once; defining the same configuration type more than once throws an error. -By default, Rstack looks for a file with one of the following names: +By default, Rstack CLI looks for a file with one of the following names: - `rstack.config.ts` - `rstack.config.js` @@ -64,7 +64,7 @@ define.app(async () => { ## Configuration APIs -Configuration options follow the formats of the underlying tools. When using APIs and helpers that Rstack re-exports, prefer the `rstack/app`, `rstack/lib`, `rstack/test`, and `rstack/lint` entry points. +Configuration options follow the formats of the underlying tools. When using APIs and helpers that Rstack CLI re-exports, prefer the `rstack/app`, `rstack/lib`, `rstack/test`, and `rstack/lint` entry points. | API | Tool | Commands | | ----------------------------------- | ----------------------------------------------------------------------- | ------------------------------------------------------------------------------- | @@ -121,7 +121,7 @@ define.doc({ }); ``` -`@rspress/core` is an optional dependency of Rstack. Install it in every project that uses the `rs doc` command: +`@rspress/core` is an optional dependency of Rstack CLI. Install it in every project that uses the `rs doc` command: @@ -142,9 +142,9 @@ define.test({ }); ``` -When `extends` is omitted, Rstack automatically connects the test configuration to `define.app()` through the Rsbuild adapter. If no application configuration is defined, it falls back to `define.lib()` through the Rslib adapter. The application configuration takes precedence when both are defined. Set `extends` explicitly to opt out of this automatic inheritance. +When `extends` is omitted, Rstack CLI automatically connects the test configuration to `define.app()` through the Rsbuild adapter. If no application configuration is defined, it falls back to `define.lib()` through the Rslib adapter. The application configuration takes precedence when both are defined. Set `extends` explicitly to opt out of this automatic inheritance. -If the root test configuration does not define `extends` and contains `projects`, Rstack applies automatic inheritance to each inline project that omits its own `extends`. A function-based application or library configuration is resolved once and shared by those projects. String project entries are passed to Rstest unchanged; they load their external configurations independently and do not inherit the current application or library configuration. +If the root test configuration does not define `extends` and contains `projects`, Rstack CLI applies automatic inheritance to each inline project that omits its own `extends`. A function-based application or library configuration is resolved once and shared by those projects. String project entries are passed to Rstest unchanged; they load their external configurations independently and do not inherit the current application or library configuration. > For more guidance on testing, see [Testing](./testing). diff --git a/website/docs/en/guide/formatting.mdx b/website/docs/en/guide/formatting.mdx index 9090f666..c1c3a1ce 100644 --- a/website/docs/en/guide/formatting.mdx +++ b/website/docs/en/guide/formatting.mdx @@ -43,7 +43,7 @@ define.fmt({ }); ``` -In addition to Prettier options and `overrides`, Rstack provides two options: +In addition to Prettier options and `overrides`, Rstack CLI provides two options: - [`ignorePatterns`](#ignore-files): exclude files with Gitignore-compatible patterns. - [`sortPackageJson`](#sort-package-json): sort fields in `package.json` files. The default value is `false`. @@ -196,7 +196,7 @@ You can safely delete `.rstack/cache` to clear cached results. Do not treat the ## Prettier plugins -To add formatting capabilities that are not built into Rstack, install the corresponding [Prettier plugin](https://prettier.io/docs/plugins) and add it to `plugins`. Plugins can be referenced by package name, file path, or URL. Package names and relative paths are resolved from the directory containing the Rstack configuration file. +To add formatting capabilities that are not built into Rstack CLI, install the corresponding [Prettier plugin](https://prettier.io/docs/plugins) and add it to `plugins`. Plugins can be referenced by package name, file path, or URL. Package names and relative paths are resolved from the directory containing the Rstack configuration file. Because `rs fmt` loads plugins in workers, plugin objects cannot be passed directly. Reference each plugin by package name, path, or URL instead. For example, install and enable [`prettier-plugin-tailwindcss`](https://github.com/tailwindlabs/prettier-plugin-tailwindcss): diff --git a/website/docs/en/guide/monorepo.mdx b/website/docs/en/guide/monorepo.mdx index d8b4d501..3ca08420 100644 --- a/website/docs/en/guide/monorepo.mdx +++ b/website/docs/en/guide/monorepo.mdx @@ -1,18 +1,18 @@ --- -description: 'Configure shared Rstack checks, formatting, staged tasks, and project workflows in a monorepo.' +description: 'Use Rstack CLI to configure shared checks, formatting, staged tasks, and project workflows in a monorepo.' --- # Monorepo This guide explains how to use Rstack CLI in a monorepo, including how it works with task orchestrators such as [Turborepo](https://turborepo.com/docs) and [Nx](https://nx.dev/docs/getting-started/intro). -It covers managing Rstack dependencies, configuring lint, formatting, and staged-file tasks at the root, and defining separate configurations for web applications and libraries. +It covers managing the Rstack CLI dependency, configuring lint, formatting, and staged-file tasks at the root, and defining separate configurations for web applications and libraries. ## Project structure The recommended setup has two levels: -- The root manages the shared Rstack version, lint and formatting rules, and staged-file tasks. +- The root manages the shared Rstack CLI version, lint and formatting rules, and staged-file tasks. - Each application or library has its own [Rstack configuration](./configuration) for build, test, or documentation configuration. ```text @@ -29,13 +29,13 @@ The recommended setup has two levels: └── rstack.config.ts ``` -This structure keeps the Rstack version in one place while keeping build and test configuration close to the project that uses it. +This structure keeps the Rstack CLI version in one place while keeping build and test configuration close to the project that uses it. -## Rstack dependency management +## Rstack CLI dependency management \{#rstack-dependency-management} -Declare Rstack in the root `package.json` so projects use one version by default. See [Quick start](./quick-start#install-rstack) for installation instructions. +Declare the `rstack` package in the root `package.json` so projects use one Rstack CLI version by default. See [Quick start](./quick-start#install-rstack) for installation instructions. -If a project needs a different Rstack version from the root, declare that version as a dependency of the project. +If a project needs a different Rstack CLI version from the root, declare that version as a dependency of the project. Project-specific dependencies, such as Rsbuild plugins and testing libraries, should be declared in the projects that use them. @@ -104,9 +104,9 @@ define.lint(async () => { ## Project configuration -For each project that uses [Rstack commands](./quick-start#cli-commands), create a [`rstack.config.ts`](./configuration#configuration-file) and register only the configuration that project needs. +For each project that uses [Rstack CLI commands](./quick-start#cli-commands), create a [`rstack.config.ts`](./configuration#configuration-file) and register only the configuration that project needs. -Rstack loads the configuration from the current working directory. It does not merge a project's configuration with the root configuration. +Rstack CLI loads the configuration from the current working directory. It does not merge a project's configuration with the root configuration. ### Web application diff --git a/website/docs/en/guide/quick-start.mdx b/website/docs/en/guide/quick-start.mdx index cadaf016..902be45d 100644 --- a/website/docs/en/guide/quick-start.mdx +++ b/website/docs/en/guide/quick-start.mdx @@ -6,11 +6,11 @@ description: 'Create a Rstack project or add Rstack CLI to an existing project a import { PackageManagerTabs } from '@rspress/core/theme'; -Rstack CLI brings the Rstack toolchain together with one CLI and one configuration file. This guide shows how to create a new Rstack project or add Rstack to an existing project, and introduces the available workflows. +Rstack CLI brings the Rstack toolchain together with one CLI and one configuration file. This guide shows how to create a new Rstack project or add Rstack CLI to an existing project, and introduces the available workflows. ## Environment preparation -Rstack supports using [Node.js](https://nodejs.org/), [Deno](https://deno.com/), or [Bun](https://bun.sh/) as the JavaScript runtime. +Rstack CLI supports using [Node.js](https://nodejs.org/), [Deno](https://deno.com/), or [Bun](https://bun.sh/) as the JavaScript runtime. Use one of the following installation guides to set up a runtime: @@ -20,7 +20,7 @@ Use one of the following installation guides to set up a runtime: :::tip Version requirements -Rstack requires Node.js 22.12.0 or higher when using Node.js as the runtime. +Rstack CLI requires Node.js 22.12.0 or higher when using Node.js as the runtime. ::: @@ -104,7 +104,7 @@ Options: Available templates: app-vanilla, app-vanilla-ts, app-react, app-react-ts, app-preact, app-preact-ts, app-vue, app-vue-ts, app-lit, app-lit-ts, app-svelte, app-svelte-ts, app-solid, app-solid-ts, lib-node, lib-node-ts, lib-react, lib-react-ts, lib-vue, lib-vue-ts, lib-svelte, lib-svelte-ts, lib-solid, lib-solid-ts, doc, doc-i18n ``` -## Install Rstack +## Install Rstack CLI \{#install-rstack} Install [`rstack`](https://www.npmjs.com/package/rstack) as a development dependency in a project that has a `package.json`: @@ -135,7 +135,7 @@ Add the commands your project needs to the `scripts` field in `package.json`. Fo } ``` -Package scripts use the project-local `rs` binary, so Rstack does not need to be installed globally. +Package scripts use the project-local `rs` binary, so Rstack CLI does not need to be installed globally. The following commands are available: @@ -151,7 +151,7 @@ The following commands are available: - [`rs setup`](./cli/setup): Install repository-level Git hooks. - [`rs staged`](./cli/staged): Run tasks against files staged in Git with lint-staged. -## Configure Rstack +## Configure Rstack CLI \{#configure-rstack} Create `rstack.config.ts` in the project root and register the configurations your project needs. The following is a minimal example for an application with testing and linting: diff --git a/website/docs/en/guide/testing.mdx b/website/docs/en/guide/testing.mdx index 39e494bf..aa4a442a 100644 --- a/website/docs/en/guide/testing.mdx +++ b/website/docs/en/guide/testing.mdx @@ -1,6 +1,6 @@ # Testing -Rstack uses [Rstest](https://rstest.rs/) to run tests. +Rstack CLI uses [Rstest](https://rstest.rs/) to run tests. ```bash rs test @@ -44,7 +44,7 @@ define.test({ }); ``` -When `extends` is omitted, Rstack uses the Rsbuild adapter to extend the test configuration from `define.app()`. If no application configuration is defined, it uses the Rslib adapter with `define.lib()` instead. `define.app()` takes precedence when both are defined. +When `extends` is omitted, Rstack CLI uses the Rsbuild adapter to extend the test configuration from `define.app()`. If no application configuration is defined, it uses the Rslib adapter with `define.lib()` instead. `define.app()` takes precedence when both are defined. ## Multiple projects @@ -78,7 +78,7 @@ define.test({ }); ``` -Rstack applies the corresponding adapter to each inline project that omits `extends`. A function-based `define.app()` or `define.lib()` configuration is resolved once, then shared by those inline projects. +Rstack CLI applies the corresponding adapter to each inline project that omits `extends`. A function-based `define.app()` or `define.lib()` configuration is resolved once, then shared by those inline projects. Run one project by name: @@ -100,7 +100,7 @@ define.test({ }); ``` -Rstack passes string entries to Rstest unchanged. External projects load their own configuration and do not inherit the current `define.app()` or `define.lib()` configuration. Use external projects when each project manages its configuration independently. +Rstack CLI passes string entries to Rstest unchanged. External projects load their own configuration and do not inherit the current `define.app()` or `define.lib()` configuration. Use external projects when each project manages its configuration independently. ## Customize inheritance diff --git a/website/docs/zh/guide/api-reference.mdx b/website/docs/zh/guide/api-reference.mdx index 0f7a2dc3..d61ebb1b 100644 --- a/website/docs/zh/guide/api-reference.mdx +++ b/website/docs/zh/guide/api-reference.mdx @@ -1,12 +1,12 @@ # API 参考 \{#api-reference} -Rstack 提供统一的配置 API,并通过专用子路径重导出 Rsbuild、Rslib、Rstest 和 Rslint 的公开 API。建议优先从这些子路径导入,以统一依赖入口,并确保 API 与 Rstack 集成的工具版本保持一致。 +Rstack CLI 提供统一的配置 API,并通过专用子路径重导出 Rsbuild、Rslib、Rstest 和 Rslint 的公开 API。建议优先从这些子路径导入,而不是直接从各工具的 core 包导入,以统一依赖入口,并确保 API 与 Rstack CLI 集成的工具版本匹配。 ## 导入路径 \{#import-paths} | 导入路径 | 内容 | 使用场景 | | ------------------------ | ----------------------------------------- | ------------------------ | -| `rstack` | Rstack 配置 API | 注册各项工具配置 | +| `rstack` | Rstack CLI 配置 API | 注册各项工具配置 | | `rstack/app` | `@rsbuild/core` 的公开 API | 构建应用及扩展 Rsbuild | | `rstack/lib` | `@rslib/core` 的公开 API | 构建库及扩展 Rslib | | `rstack/test` | `@rstest/core` 的公开 API | 编写测试及配置测试项目 | @@ -23,7 +23,7 @@ Rstack 提供统一的配置 API,并通过专用子路径重导出 Rsbuild、R ## 重导出 \{#re-exports} -以下工具子路径均会重导出对应 core 包的公开 API。通过这些 Rstack 入口导入,可以让依赖入口和工具版本与 Rstack 集成的工具链保持一致。 +以下工具子路径均会重导出对应 core 包的公开 API。通过这些入口导入,可以统一依赖入口,并确保 API 与 Rstack CLI 集成的工具版本匹配。 ### `rstack/app` diff --git a/website/docs/zh/guide/cli/setup.mdx b/website/docs/zh/guide/cli/setup.mdx index 4144e9b6..ea39d804 100644 --- a/website/docs/zh/guide/cli/setup.mdx +++ b/website/docs/zh/guide/cli/setup.mdx @@ -99,7 +99,7 @@ rs setup --help ## 支持的 hooks \{#supported-hooks} -Rstack 支持以下客户端 Git hooks: +Rstack CLI 支持以下客户端 Git hooks: - `pre-commit` - `pre-merge-commit` @@ -120,7 +120,7 @@ Rstack 支持以下客户端 Git hooks: ## Hook 运行时 \{#hook-runtime} -Rstack 使用 POSIX `sh -e` 运行 hook 脚本,并转发 Git 提供的参数和标准输入,同时返回 hook 的退出码。运行 hook 前,Rstack 会切换到安装 hooks 的项目,并将该项目的 `node_modules/.bin` 添加到 `PATH` 开头。 +Rstack CLI 使用 POSIX `sh -e` 运行 hook 脚本,并转发 Git 提供的参数和标准输入,同时返回 hook 的退出码。运行 hook 前,Rstack CLI 会切换到安装 hooks 的项目,并将该项目的 `node_modules/.bin` 添加到 `PATH` 开头。 ### 禁用与调试 \{#disable-and-debug} @@ -130,7 +130,7 @@ Rstack 使用 POSIX `sh -e` 运行 hook 脚本,并转发 Git 提供的参数 RSTACK_HOOKS=0 git commit -m "Skip hooks" ``` -将 `RSTACK_HOOKS` 设为 `2`,可以跟踪 Rstack hook 运行时,包括调用 hook 脚本和处理退出码等步骤;如需跟踪 hook 脚本内部的命令,请在脚本中添加 `set -x`: +将 `RSTACK_HOOKS` 设为 `2`,可以跟踪 Rstack CLI 的 hook 运行时,包括调用 hook 脚本和处理退出码等步骤;如需跟踪 hook 脚本内部的命令,请在脚本中添加 `set -x`: ```bash RSTACK_HOOKS=2 git commit -m "Trace hooks" @@ -138,7 +138,7 @@ RSTACK_HOOKS=2 git commit -m "Trace hooks" ### 配置 hook 运行环境 \{#configure-the-hook-environment} -运行 hook 脚本前,Rstack 会加载以下可选的 POSIX shell 文件: +运行 hook 脚本前,Rstack CLI 会加载以下可选的 POSIX shell 文件: ```text ${XDG_CONFIG_HOME:-$HOME/.config}/rstack/hooks-init.sh @@ -148,7 +148,7 @@ ${XDG_CONFIG_HOME:-$HOME/.config}/rstack/hooks-init.sh ## Monorepo \{#monorepo} -在 monorepo 中,提供 Rstack 的项目可能位于 `frontend/` 等子目录。从该目录运行 `rs setup` 时,hooks 仍会安装到 Git 仓库根目录: +在 monorepo 中,提供 Rstack CLI 的项目可能位于 `frontend/` 等子目录。从该目录运行 `rs setup` 时,hooks 仍会安装到 Git 仓库根目录: ```text repo/.rstack/hooks/ @@ -156,7 +156,7 @@ repo/.rstack/hooks/_/ core.hooksPath=.rstack/hooks/_ ``` -Rstack 会将 `frontend` 记录为负责管理 hooks 的项目。hook 脚本仍位于仓库根目录,但会从 `frontend` 目录运行,因此可以直接使用其中的配置和依赖,无需显式执行 `cd`: +Rstack CLI 会将 `frontend` 记录为负责管理 hooks 的项目。hook 脚本仍位于仓库根目录,但会从 `frontend` 目录运行,因此可以直接使用其中的配置和依赖,无需显式执行 `cd`: ```sh title=".rstack/hooks/pre-commit" rs staged @@ -168,7 +168,7 @@ rs staged ## 移除 hooks \{#remove-hooks} -如需移除由 Rstack 管理的 hooks: +如需移除由 Rstack CLI 管理的 hooks: 1. 从 `prepare` 脚本中移除 `rs setup`。 2. 删除仓库的 hooks 路径配置: @@ -188,13 +188,13 @@ rs staged - 重新运行 `rs setup`,恢复生成文件及其可执行权限。 - 检查环境变量或初始化文件中是否设置了 `RSTACK_HOOKS=0`。 - 如果命令提示存在其他 hooks 配置,请先迁移或移除冲突配置,再重新运行该命令。 -- 如果命令提示存在其他 Rstack owner,请按照 [Monorepo](#monorepo) 中的步骤转移 owner。 +- 如果命令提示其他项目是 hooks owner,请按照 [Monorepo](#monorepo) 中的步骤转移 owner。 -hook 脚本不需要可执行权限,因为 Rstack 会使用 `sh` 运行它。 +hook 脚本不需要可执行权限,因为 Rstack CLI 会使用 `sh` 运行它。 ### 找不到命令 \{#command-not-found} -退出码为 127 时,Rstack 会打印实际生效的 `PATH`。如果 GUI Git 客户端找不到 Node.js 或包管理器,请在 `hooks-init.sh` 中初始化相关环境。 +退出码为 127 时,Rstack CLI 会打印实际生效的 `PATH`。如果 GUI Git 客户端找不到 Node.js 或包管理器,请在 `hooks-init.sh` 中初始化相关环境。 ### Windows 与 Yarn \{#windows-and-yarn} diff --git a/website/docs/zh/guide/configuration.mdx b/website/docs/zh/guide/configuration.mdx index f4cbf631..4e4e51dc 100644 --- a/website/docs/zh/guide/configuration.mdx +++ b/website/docs/zh/guide/configuration.mdx @@ -2,7 +2,7 @@ import { PackageManagerTabs } from '@rspress/core/theme'; -Rstack 将项目所用工具的配置集中到一份文件中。通过 `define.*()` API 定义项目实际需要的配置即可。 +Rstack CLI 将项目所用工具的配置集中到一份文件中。通过 `define.*()` API 定义项目实际需要的配置即可。 ## 配置文件 \{#configuration-file} @@ -31,7 +31,7 @@ define.fmt({ 配置文件无需默认导出。每个 `define.*()` API 最多调用一次;重复定义同一类型的配置会抛出错误。 -Rstack 默认会查找使用以下任一文件名的配置文件: +Rstack CLI 默认会查找使用以下任一文件名的配置文件: - `rstack.config.ts` - `rstack.config.js` @@ -46,7 +46,7 @@ rs build --config ./configs/rstack.config.ts ## 按需加载依赖 \{#loading-dependencies-on-demand} -每次执行 `rs` 命令时,Rstack 都会加载并执行配置文件,然后只解析当前命令需要的配置函数。 +每次执行 `rs` 命令时,Rstack CLI 都会加载并执行配置文件,然后只解析当前命令需要的配置函数。 如果配置需要导入插件或其他工具专属依赖,请使用异步配置函数,并在函数内通过动态 `import()` 加载这些依赖。这样只有解析该配置时才会加载相关依赖。 @@ -64,7 +64,7 @@ define.app(async () => { ## 配置 API \{#configuration-apis} -各 API 沿用底层工具的配置格式。使用 Rstack 已重导出的 API 和辅助函数时,推荐从 `rstack/app`、`rstack/lib`、`rstack/test` 和 `rstack/lint` 入口导入。 +各 API 沿用底层工具的配置格式。使用 Rstack CLI 已重导出的 API 和辅助函数时,推荐从 `rstack/app`、`rstack/lib`、`rstack/test` 和 `rstack/lint` 入口导入。 | API | 底层工具 | 对应命令 | | ----------------------------------- | ----------------------------------------------------------------------- | ------------------------------------------------------------------------------- | @@ -121,7 +121,7 @@ define.doc({ }); ``` -`@rspress/core` 是 Rstack 的可选依赖。每个使用 `rs doc` 命令的项目都需要安装该依赖: +`@rspress/core` 是 Rstack CLI 的可选依赖。每个使用 `rs doc` 命令的项目都需要安装该依赖: @@ -142,9 +142,9 @@ define.test({ }); ``` -未设置 `extends` 时,Rstack 会通过 Rsbuild 适配器让测试配置自动继承 `define.app()`;如果未定义应用配置,则通过 Rslib 适配器回退到 `define.lib()`。二者同时存在时,应用配置的优先级更高。显式设置 `extends` 可关闭自动继承。 +未设置 `extends` 时,Rstack CLI 会通过 Rsbuild 适配器让测试配置自动继承 `define.app()`;如果未定义应用配置,则通过 Rslib 适配器回退到 `define.lib()`。二者同时存在时,应用配置的优先级更高。显式设置 `extends` 可关闭自动继承。 -如果测试根配置未定义 `extends` 且包含 `projects`,Rstack 会为每个未自行设置 `extends` 的内联项目应用自动继承。函数形式的应用或库配置只会解析一次,并由这些项目共享。字符串形式的项目会原样传给 Rstest;它们会独立加载外部配置,不继承当前应用或库的配置。 +如果测试根配置未定义 `extends` 且包含 `projects`,Rstack CLI 会为每个未自行设置 `extends` 的内联项目应用自动继承。函数形式的应用或库配置只会解析一次,并由这些项目共享。字符串形式的项目会原样传给 Rstest;它们会独立加载外部配置,不继承当前应用或库的配置。 > 如需了解更多测试相关用法,请参阅[测试](./testing)。 diff --git a/website/docs/zh/guide/formatting.mdx b/website/docs/zh/guide/formatting.mdx index 7f2f8b7b..157bd54c 100644 --- a/website/docs/zh/guide/formatting.mdx +++ b/website/docs/zh/guide/formatting.mdx @@ -43,7 +43,7 @@ define.fmt({ }); ``` -除了 Prettier 选项和 `overrides`,Rstack 还提供两个选项: +除了 Prettier 选项和 `overrides`,Rstack CLI 还提供两个选项: - [`ignorePatterns`](#ignore-files):使用兼容 Gitignore 的模式排除文件。 - [`sortPackageJson`](#sort-package-json):对 `package.json` 中的字段排序,默认值为 `false`。 @@ -167,7 +167,7 @@ define.fmt({ ### 合并顺序 \{#merge-order} -如果同一文件匹配多条 override 规则,Rstack 会按声明顺序合并配置,后面的值优先。下面的 `README.md` 会同时匹配两条规则,因此最终的 `printWidth` 为 `80`: +如果同一文件匹配多条 override 规则,Rstack CLI 会按声明顺序合并配置,后面的值优先。下面的 `README.md` 会同时匹配两条规则,因此最终的 `printWidth` 为 `80`: ```ts define.fmt({ @@ -196,7 +196,7 @@ rs fmt --no-cache ## Prettier 插件 \{#prettier-plugins} -如果需要使用 Rstack 未内置的格式化能力,可以安装相应的 [Prettier 插件](https://prettier.io/docs/plugins),并添加到 `plugins` 中。插件支持通过包名、文件路径或 URL 引用,其中包名和相对路径基于 Rstack 配置文件所在的目录解析。 +如果需要使用 Rstack CLI 未内置的格式化能力,可以安装相应的 [Prettier 插件](https://prettier.io/docs/plugins),并添加到 `plugins` 中。插件支持通过包名、文件路径或 URL 引用,其中包名和相对路径基于 Rstack 配置文件所在的目录解析。 由于 `rs fmt` 会在 worker 中加载插件,因此不支持直接传入插件对象。请通过包名、路径或 URL 引用插件。例如,安装并启用 [`prettier-plugin-tailwindcss`](https://github.com/tailwindlabs/prettier-plugin-tailwindcss): diff --git a/website/docs/zh/guide/monorepo.mdx b/website/docs/zh/guide/monorepo.mdx index ea1c5ea6..4d780a3b 100644 --- a/website/docs/zh/guide/monorepo.mdx +++ b/website/docs/zh/guide/monorepo.mdx @@ -1,18 +1,18 @@ --- -description: '在 Monorepo 中配置共享的 Rstack 检查、格式化、暂存文件任务和项目工作流。' +description: '在 Monorepo 中使用 Rstack CLI 配置共享检查、格式化、暂存文件任务和项目工作流。' --- # Monorepo 本指南介绍如何在 Monorepo 中使用 Rstack CLI,以及如何让它与 [Turborepo](https://turborepo.com/docs)、[Nx](https://nx.dev/docs/getting-started/intro) 等任务编排工具协同工作。 -主要内容包括管理 Rstack 依赖、在根目录统一配置代码检查、格式化和暂存文件任务,以及为 Web 应用和库项目定义独立配置。 +主要内容包括管理 Rstack CLI 依赖、在根目录统一配置代码检查、格式化和暂存文件任务,以及为 Web 应用和库项目定义独立配置。 ## 目录结构 \{#project-structure} 推荐使用两层配置: -- 根目录统一管理 Rstack 版本、lint 和格式化规则,以及暂存文件任务。 +- 根目录统一管理 Rstack CLI 版本、lint 和格式化规则,以及暂存文件任务。 - 每个应用或库使用自己的 [Rstack 配置](./configuration),定义构建、测试或文档配置。 ```text @@ -29,13 +29,13 @@ description: '在 Monorepo 中配置共享的 Rstack 检查、格式化、暂存 └── rstack.config.ts ``` -这种结构既能统一 Rstack 版本,也能让构建和测试配置靠近实际使用它们的项目。 +这种结构既能统一 Rstack CLI 版本,也能让构建和测试配置靠近实际使用它们的项目。 -## Rstack 依赖管理 \{#rstack-dependency-management} +## Rstack CLI 依赖管理 \{#rstack-dependency-management} -在根目录的 `package.json` 中声明 Rstack,让各个项目默认使用同一个版本。安装方法请参考[快速上手](./quick-start#install-rstack)。 +在根目录的 `package.json` 中声明 `rstack` 包,让各个项目默认使用同一个 Rstack CLI 版本。安装方法请参考[快速上手](./quick-start#install-rstack)。 -如果子项目需要使用与根目录不同版本的 `rstack`,可以在该项目中单独声明对应版本的 `rstack` 依赖。 +如果子项目需要使用与根目录不同版本的 Rstack CLI,可以在该项目中单独声明对应版本的 `rstack` 依赖。 Rsbuild 插件、测试库等项目专属依赖,建议定义在实际使用它们的子项目中。 @@ -104,9 +104,9 @@ define.lint(async () => { ## 子项目配置 \{#project-configuration} -为每个使用 [Rstack 命令](./quick-start#cli-commands)的子项目创建 [`rstack.config.ts`](./configuration#configuration-file),并且只配置该项目需要的功能。 +为每个使用 [Rstack CLI 命令](./quick-start#cli-commands)的子项目创建 [`rstack.config.ts`](./configuration#configuration-file),并且只配置该项目需要的功能。 -Rstack 会加载当前工作目录中的配置,不会将子项目配置与根配置自动合并。 +Rstack CLI 会加载当前工作目录中的配置,不会将子项目配置与根配置自动合并。 ### Web 应用 \{#web-application} diff --git a/website/docs/zh/guide/quick-start.mdx b/website/docs/zh/guide/quick-start.mdx index 1c6aaa6c..aa7352a7 100644 --- a/website/docs/zh/guide/quick-start.mdx +++ b/website/docs/zh/guide/quick-start.mdx @@ -6,11 +6,11 @@ description: '创建 Rstack 项目,或在现有项目中安装 Rstack CLI 并 import { PackageManagerTabs } from '@rspress/core/theme'; -Rstack CLI 通过统一的命令行和配置文件整合 Rstack 工具链。本指南将介绍如何创建新的 Rstack 项目或在现有项目中添加 Rstack,以及可以使用的工作流。 +Rstack CLI 通过统一的命令行和配置文件整合 Rstack 工具链。本指南将介绍如何创建新的 Rstack 项目或在现有项目中添加 Rstack CLI,以及可以使用的工作流。 ## 环境准备 \{#environment-preparation} -Rstack 支持使用 [Node.js](https://nodejs.org/)、[Deno](https://deno.com/) 或 [Bun](https://bun.sh/) 作为 JavaScript 运行时。 +Rstack CLI 支持使用 [Node.js](https://nodejs.org/)、[Deno](https://deno.com/) 或 [Bun](https://bun.sh/) 作为 JavaScript 运行时。 参考以下安装指南,选择一种运行时: @@ -20,7 +20,7 @@ Rstack 支持使用 [Node.js](https://nodejs.org/)、[Deno](https://deno.com/) :::tip 版本要求 -使用 Node.js 作为运行时时,Rstack 要求 Node.js 版本为 22.12.0 或更高版本。 +使用 Node.js 作为运行时时,Rstack CLI 要求 Node.js 版本为 22.12.0 或更高版本。 ::: @@ -104,7 +104,7 @@ Options: Available templates: app-vanilla, app-vanilla-ts, app-react, app-react-ts, app-preact, app-preact-ts, app-vue, app-vue-ts, app-lit, app-lit-ts, app-svelte, app-svelte-ts, app-solid, app-solid-ts, lib-node, lib-node-ts, lib-react, lib-react-ts, lib-vue, lib-vue-ts, lib-svelte, lib-svelte-ts, lib-solid, lib-solid-ts, doc, doc-i18n ``` -## 安装 Rstack \{#install-rstack} +## 安装 Rstack CLI \{#install-rstack} 在已有 `package.json` 的项目中,将 [`rstack`](https://www.npmjs.com/package/rstack) 安装为开发依赖: @@ -135,9 +135,9 @@ Available templates: app-vanilla, app-vanilla-ts, app-react, app-react-ts, app-p } ``` -package scripts 会使用项目本地安装的 `rs` 命令,因此无需全局安装 Rstack。 +package scripts 会使用项目本地安装的 `rs` 命令,因此无需全局安装 Rstack CLI。 -Rstack 提供以下命令: +Rstack CLI 提供以下命令: - [`rs dev`](./cli/dev):启动应用开发服务器。 - [`rs build`](./cli/build):构建应用的生产版本。 @@ -151,7 +151,7 @@ Rstack 提供以下命令: - [`rs setup`](./cli/setup):安装仓库级 Git hooks。 - [`rs staged`](./cli/staged):使用 lint-staged 对 Git 暂存区中的文件运行任务。 -## 配置 Rstack \{#configure-rstack} +## 配置 Rstack CLI \{#configure-rstack} 在项目根目录创建 `rstack.config.ts`,并注册项目所需的配置。以下是一个包含应用、测试和代码检查的最小示例: diff --git a/website/docs/zh/guide/testing.mdx b/website/docs/zh/guide/testing.mdx index ed89dc71..9c629635 100644 --- a/website/docs/zh/guide/testing.mdx +++ b/website/docs/zh/guide/testing.mdx @@ -1,6 +1,6 @@ # 测试 \{#testing} -Rstack 使用 [Rstest](https://rstest.rs/zh/) 运行测试。 +Rstack CLI 使用 [Rstest](https://rstest.rs/zh/) 运行测试。 ```bash rs test @@ -44,7 +44,7 @@ define.test({ }); ``` -未设置 `extends` 时,Rstack 会通过 Rsbuild 适配器让测试配置继承 `define.app()`。如果没有应用配置,则通过 Rslib 适配器回退到 `define.lib()`。同时定义两者时,`define.app()` 的优先级更高。 +未设置 `extends` 时,Rstack CLI 会通过 Rsbuild 适配器让测试配置继承 `define.app()`。如果没有应用配置,则通过 Rslib 适配器回退到 `define.lib()`。同时定义两者时,`define.app()` 的优先级更高。 ## 多项目 \{#multiple-projects} @@ -78,7 +78,7 @@ define.test({ }); ``` -Rstack 会将对应的适配器应用到每个未设置 `extends` 的内联项目。函数形式的 `define.app()` 或 `define.lib()` 配置只会解析一次,再由这些内联项目共享。 +Rstack CLI 会将对应的适配器应用到每个未设置 `extends` 的内联项目。函数形式的 `define.app()` 或 `define.lib()` 配置只会解析一次,再由这些内联项目共享。 按项目名称运行单个项目: @@ -100,7 +100,7 @@ define.test({ }); ``` -Rstack 会将字符串形式的项目原样传给 Rstest。外部项目会加载自己的配置,不会继承当前的 `define.app()` 或 `define.lib()` 配置。每个项目需要独立管理配置时,请使用外部项目。 +Rstack CLI 会将字符串形式的项目原样传给 Rstest。外部项目会加载自己的配置,不会继承当前的 `define.app()` 或 `define.lib()` 配置。每个项目需要独立管理配置时,请使用外部项目。 ## 自定义继承 \{#customize-inheritance} From 2024c93930b3686146cea15311cbd12c27990b41 Mon Sep 17 00:00:00 2001 From: Jiahan Chen Date: Thu, 13 Aug 2026 22:47:00 +0800 Subject: [PATCH 16/33] docs: update website configuration (#351) --- website/rstack.config.ts | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/website/rstack.config.ts b/website/rstack.config.ts index 79821ca1..338cad02 100644 --- a/website/rstack.config.ts +++ b/website/rstack.config.ts @@ -21,7 +21,7 @@ define.doc(async () => { return { root: path.join(import.meta.dirname, 'docs'), title, - icon: 'https://assets.rspack.rs/rspack/favicon-128x128.png', + icon: 'https://assets.rspack.rs/rspack/rspack-claw-logo.svg', logoText: title, description, lang: 'en', @@ -57,6 +57,20 @@ define.doc(async () => { pluginFontOpenSans(), pluginSitemap({ siteUrl }), ], + locales: [ + { + lang: 'en', + label: 'English', + title, + description, + }, + { + lang: 'zh', + label: '简体中文', + title, + description: descriptionZh, + }, + ], themeConfig: { llmsUI: { injectLlmsHint, @@ -76,20 +90,6 @@ define.doc(async () => { editLink: { docRepoBaseUrl: 'https://github.com/rstackjs/rstack-cli/tree/main/website/docs', }, - locales: [ - { - lang: 'en', - label: 'English', - title, - description, - }, - { - lang: 'zh', - label: '简体中文', - title, - description: descriptionZh, - }, - ], }, builderConfig: { plugins: [ From 9129fe0041450258bd9021acf8dcd432977aef74 Mon Sep 17 00:00:00 2001 From: Jiahan Chen Date: Thu, 13 Aug 2026 22:48:21 +0800 Subject: [PATCH 17/33] feat(lint): inject lint exports into config factory (#352) --- packages/rstack/src/config.ts | 13 +++++++++++-- packages/rstack/src/rslintConfig.ts | 8 ++++---- .../rstack/tests/types/resolution-bundler/index.ts | 6 ++++-- .../rstack/tests/types/resolution-nodenext/index.ts | 8 +++++--- 4 files changed, 24 insertions(+), 11 deletions(-) diff --git a/packages/rstack/src/config.ts b/packages/rstack/src/config.ts index f977f6fc..0bf3bc52 100644 --- a/packages/rstack/src/config.ts +++ b/packages/rstack/src/config.ts @@ -11,6 +11,10 @@ import type { StagedConfig } from './staged.ts'; export type RslintConfigDefinition = RslintConfig | (() => Promise); export type RspressConfigDefinition = UserConfig | UserConfigAsyncFn; +type RslintConfigFactory = ( + lint: typeof import('@rslint/core'), +) => RslintConfig | Promise; + export type Configs = { app?: RsbuildConfigDefinition; lib?: RslibConfigDefinition; @@ -125,10 +129,11 @@ type Define = { * Defines the Rslint config for linting. * * This config is used by the `rs lint` command. + * A config factory receives the exports from `rstack/lint`. * * @see {@link https://rstack.rs/config | Rstack configuration guide} */ - lint: (config: RslintConfig | (() => Promise)) => void; + lint: (config: RslintConfig | RslintConfigFactory) => void; /** * Defines the Prettier config for formatting. * @@ -165,7 +170,11 @@ export const define: Define = { lib: (config) => setConfig('lib', config), doc: (config) => setConfig('doc', config), test: (config) => setConfig('test', config), - lint: (config) => setConfig('lint', config), + lint: (config) => + setConfig( + 'lint', + typeof config === 'function' ? async () => config(await import('@rslint/core')) : config, + ), fmt: (config) => setConfig('fmt', config), staged: (config) => setConfig('staged', config), }; diff --git a/packages/rstack/src/rslintConfig.ts b/packages/rstack/src/rslintConfig.ts index c0e953c3..50f13c20 100644 --- a/packages/rstack/src/rslintConfig.ts +++ b/packages/rstack/src/rslintConfig.ts @@ -2,15 +2,15 @@ import { loadRstackConfig } from './config.ts'; import type { RslintConfig } from '@rslint/core'; const { configs } = await loadRstackConfig(); -const lintExports = configs.lint ?? []; +const lintDefinition = configs.lint ?? []; let lintConfig: RslintConfig; // TODO: support function in Rslint core -if (typeof lintExports === 'function') { - lintConfig = await lintExports(); +if (typeof lintDefinition === 'function') { + lintConfig = await lintDefinition(); } else { - lintConfig = lintExports; + lintConfig = lintDefinition; } export default lintConfig; diff --git a/packages/rstack/tests/types/resolution-bundler/index.ts b/packages/rstack/tests/types/resolution-bundler/index.ts index c464b7f6..8853c64e 100644 --- a/packages/rstack/tests/types/resolution-bundler/index.ts +++ b/packages/rstack/tests/types/resolution-bundler/index.ts @@ -11,11 +11,12 @@ import { type LoadRstackConfigOptions, } from 'rstack/config'; import { defineConfig as defineLibConfig } from 'rstack/lib'; -import { js, ts } from 'rstack/lint'; +import { defineConfig as defineLintConfig } from 'rstack/lint'; import { expect as importedExpect, test as importedTest } from 'rstack/test'; const appConfig = defineAppConfig({}); const libConfig = defineLibConfig({}); +const lintConfig = defineLintConfig([]); const loadOptions: LoadRstackConfigOptions = { configFilePath: 'rstack.config.ts' }; const loadedConfig: Promise = loadRstackConfig(loadOptions); const configs: Configs = {}; @@ -26,9 +27,10 @@ void configs; void createRsbuild({ config: appConfig }); define.app(appConfig); define.lib(libConfig); +define.lint(lintConfig); +define.lint(({ js, ts }) => [js.configs.recommended, ts.configs.recommendedTypeChecked]); define.doc({}); define.test({}); -define.lint([js.configs.recommended, ts.configs.recommended]); define.staged({}); importedTest('exposes the Rstest APIs', () => { diff --git a/packages/rstack/tests/types/resolution-nodenext/index.ts b/packages/rstack/tests/types/resolution-nodenext/index.ts index 4b8d3f0a..8853c64e 100644 --- a/packages/rstack/tests/types/resolution-nodenext/index.ts +++ b/packages/rstack/tests/types/resolution-nodenext/index.ts @@ -1,4 +1,4 @@ -// This folder checks Rstack's exports and APIs with NodeNext resolution. +// This folder checks Rstack's exports and APIs with bundler resolution. import 'rstack/test/globals'; import 'rstack/test/importMeta'; import 'rstack/types'; @@ -11,11 +11,12 @@ import { type LoadRstackConfigOptions, } from 'rstack/config'; import { defineConfig as defineLibConfig } from 'rstack/lib'; -import { js, ts } from 'rstack/lint'; +import { defineConfig as defineLintConfig } from 'rstack/lint'; import { expect as importedExpect, test as importedTest } from 'rstack/test'; const appConfig = defineAppConfig({}); const libConfig = defineLibConfig({}); +const lintConfig = defineLintConfig([]); const loadOptions: LoadRstackConfigOptions = { configFilePath: 'rstack.config.ts' }; const loadedConfig: Promise = loadRstackConfig(loadOptions); const configs: Configs = {}; @@ -26,9 +27,10 @@ void configs; void createRsbuild({ config: appConfig }); define.app(appConfig); define.lib(libConfig); +define.lint(lintConfig); +define.lint(({ js, ts }) => [js.configs.recommended, ts.configs.recommendedTypeChecked]); define.doc({}); define.test({}); -define.lint([js.configs.recommended, ts.configs.recommended]); define.staged({}); importedTest('exposes the Rstest APIs', () => { From 9c841ab749aeb93d5b8b1c0fbc9989a62a9cd3e9 Mon Sep 17 00:00:00 2001 From: Jiahan Chen Date: Fri, 14 Aug 2026 10:07:01 +0800 Subject: [PATCH 18/33] refactor(create-rstack): simplify lint configuration (#353) Co-authored-by: swwind --- .../template-app-lit-ts/rstack.config.ts | 9 ++++----- .../template-app-lit/rstack.config.js | 6 +----- .../template-app-preact-ts/rstack.config.ts | 16 ++++++---------- .../template-app-preact/rstack.config.js | 14 +++++--------- .../template-app-react-ts/rstack.config.ts | 16 ++++++---------- .../template-app-react/rstack.config.js | 14 +++++--------- .../template-app-solid-ts/rstack.config.ts | 9 ++++----- .../template-app-solid/rstack.config.js | 6 +----- .../template-app-svelte-ts/rstack.config.ts | 9 ++++----- .../template-app-svelte/rstack.config.js | 6 +----- .../template-app-vanilla-ts/rstack.config.ts | 9 ++++----- .../template-app-vanilla/rstack.config.js | 6 +----- .../template-app-vue-ts/rstack.config.ts | 9 ++++----- .../template-app-vue/rstack.config.js | 6 +----- .../template-doc-i18n/rstack.config.ts | 16 ++++++---------- .../create-rstack/template-doc/rstack.config.ts | 16 ++++++---------- .../template-lib-node-ts/rstack.config.ts | 9 ++++----- .../template-lib-node/rstack.config.js | 6 +----- .../template-lib-react-ts/rstack.config.ts | 16 ++++++---------- .../template-lib-react/rstack.config.js | 14 +++++--------- .../template-lib-solid-ts/rstack.config.ts | 9 ++++----- .../template-lib-solid/rstack.config.js | 6 +----- .../template-lib-svelte-ts/rstack.config.ts | 9 ++++----- .../template-lib-svelte/rstack.config.js | 6 +----- .../template-lib-vue-ts/rstack.config.ts | 9 ++++----- .../template-lib-vue/rstack.config.js | 6 +----- 26 files changed, 90 insertions(+), 167 deletions(-) diff --git a/packages/create-rstack/template-app-lit-ts/rstack.config.ts b/packages/create-rstack/template-app-lit-ts/rstack.config.ts index 1dac3261..84681d01 100644 --- a/packages/create-rstack/template-app-lit-ts/rstack.config.ts +++ b/packages/create-rstack/template-app-lit-ts/rstack.config.ts @@ -16,11 +16,10 @@ define.test({ testEnvironment: 'happy-dom', }); -define.lint(async () => { - const { js, ts } = await import('rstack/lint'); - - return [js.configs.recommended, ts.configs.recommendedTypeChecked]; -}); +define.lint(({ js, ts }) => [ + js.configs.recommended, + ts.configs.recommendedTypeChecked, +]); define.fmt({ singleQuote: true, diff --git a/packages/create-rstack/template-app-lit/rstack.config.js b/packages/create-rstack/template-app-lit/rstack.config.js index d09e1329..5b863543 100644 --- a/packages/create-rstack/template-app-lit/rstack.config.js +++ b/packages/create-rstack/template-app-lit/rstack.config.js @@ -17,11 +17,7 @@ define.test({ testEnvironment: 'happy-dom', }); -define.lint(async () => { - const { js } = await import('rstack/lint'); - - return [js.configs.recommended]; -}); +define.lint(({ js }) => [js.configs.recommended]); define.fmt({ singleQuote: true, diff --git a/packages/create-rstack/template-app-preact-ts/rstack.config.ts b/packages/create-rstack/template-app-preact-ts/rstack.config.ts index 8bf4f073..ee37cab6 100644 --- a/packages/create-rstack/template-app-preact-ts/rstack.config.ts +++ b/packages/create-rstack/template-app-preact-ts/rstack.config.ts @@ -13,16 +13,12 @@ define.test({ setupFiles: ['./tests/rstest.setup.ts'], }); -define.lint(async () => { - const { js, ts, reactHooksPlugin, reactPlugin } = await import('rstack/lint'); - - return [ - js.configs.recommended, - ts.configs.recommendedTypeChecked, - reactPlugin.configs.recommended, - reactHooksPlugin.configs.recommended, - ]; -}); +define.lint(({ js, ts, reactHooksPlugin, reactPlugin }) => [ + js.configs.recommended, + ts.configs.recommendedTypeChecked, + reactPlugin.configs.recommended, + reactHooksPlugin.configs.recommended, +]); define.fmt({ singleQuote: true, diff --git a/packages/create-rstack/template-app-preact/rstack.config.js b/packages/create-rstack/template-app-preact/rstack.config.js index e2b64e47..7959e79f 100644 --- a/packages/create-rstack/template-app-preact/rstack.config.js +++ b/packages/create-rstack/template-app-preact/rstack.config.js @@ -14,15 +14,11 @@ define.test({ setupFiles: ['./tests/rstest.setup.js'], }); -define.lint(async () => { - const { js, reactHooksPlugin, reactPlugin } = await import('rstack/lint'); - - return [ - js.configs.recommended, - reactPlugin.configs.recommended, - reactHooksPlugin.configs.recommended, - ]; -}); +define.lint(({ js, reactHooksPlugin, reactPlugin }) => [ + js.configs.recommended, + reactPlugin.configs.recommended, + reactHooksPlugin.configs.recommended, +]); define.fmt({ singleQuote: true, diff --git a/packages/create-rstack/template-app-react-ts/rstack.config.ts b/packages/create-rstack/template-app-react-ts/rstack.config.ts index 1cbfbf46..76da1357 100644 --- a/packages/create-rstack/template-app-react-ts/rstack.config.ts +++ b/packages/create-rstack/template-app-react-ts/rstack.config.ts @@ -13,16 +13,12 @@ define.test({ setupFiles: ['./tests/rstest.setup.ts'], }); -define.lint(async () => { - const { js, ts, reactPlugin, reactHooksPlugin } = await import('rstack/lint'); - - return [ - js.configs.recommended, - ts.configs.recommendedTypeChecked, - reactPlugin.configs.recommended, - reactHooksPlugin.configs.recommended, - ]; -}); +define.lint(({ js, ts, reactPlugin, reactHooksPlugin }) => [ + js.configs.recommended, + ts.configs.recommendedTypeChecked, + reactPlugin.configs.recommended, + reactHooksPlugin.configs.recommended, +]); define.fmt({ singleQuote: true, diff --git a/packages/create-rstack/template-app-react/rstack.config.js b/packages/create-rstack/template-app-react/rstack.config.js index ddd9f056..9469b706 100644 --- a/packages/create-rstack/template-app-react/rstack.config.js +++ b/packages/create-rstack/template-app-react/rstack.config.js @@ -14,15 +14,11 @@ define.test({ setupFiles: ['./tests/rstest.setup.js'], }); -define.lint(async () => { - const { js, reactHooksPlugin, reactPlugin } = await import('rstack/lint'); - - return [ - js.configs.recommended, - reactPlugin.configs.recommended, - reactHooksPlugin.configs.recommended, - ]; -}); +define.lint(({ js, reactHooksPlugin, reactPlugin }) => [ + js.configs.recommended, + reactPlugin.configs.recommended, + reactHooksPlugin.configs.recommended, +]); define.fmt({ singleQuote: true, diff --git a/packages/create-rstack/template-app-solid-ts/rstack.config.ts b/packages/create-rstack/template-app-solid-ts/rstack.config.ts index 6aac365b..0c2e91b5 100644 --- a/packages/create-rstack/template-app-solid-ts/rstack.config.ts +++ b/packages/create-rstack/template-app-solid-ts/rstack.config.ts @@ -19,11 +19,10 @@ define.test({ setupFiles: ['./tests/rstest.setup.ts'], }); -define.lint(async () => { - const { js, ts } = await import('rstack/lint'); - - return [js.configs.recommended, ts.configs.recommendedTypeChecked]; -}); +define.lint(({ js, ts }) => [ + js.configs.recommended, + ts.configs.recommendedTypeChecked, +]); define.fmt({ singleQuote: true, diff --git a/packages/create-rstack/template-app-solid/rstack.config.js b/packages/create-rstack/template-app-solid/rstack.config.js index 80b7b6f7..ac5ced95 100644 --- a/packages/create-rstack/template-app-solid/rstack.config.js +++ b/packages/create-rstack/template-app-solid/rstack.config.js @@ -20,11 +20,7 @@ define.test({ setupFiles: ['./tests/rstest.setup.js'], }); -define.lint(async () => { - const { js } = await import('rstack/lint'); - - return [js.configs.recommended]; -}); +define.lint(({ js }) => [js.configs.recommended]); define.fmt({ singleQuote: true, diff --git a/packages/create-rstack/template-app-svelte-ts/rstack.config.ts b/packages/create-rstack/template-app-svelte-ts/rstack.config.ts index e834b53d..b09e259c 100644 --- a/packages/create-rstack/template-app-svelte-ts/rstack.config.ts +++ b/packages/create-rstack/template-app-svelte-ts/rstack.config.ts @@ -13,11 +13,10 @@ define.test({ setupFiles: ['./tests/rstest.setup.ts'], }); -define.lint(async () => { - const { js, ts } = await import('rstack/lint'); - - return [js.configs.recommended, ts.configs.recommendedTypeChecked]; -}); +define.lint(({ js, ts }) => [ + js.configs.recommended, + ts.configs.recommendedTypeChecked, +]); define.fmt({ plugins: ['prettier-plugin-svelte'], diff --git a/packages/create-rstack/template-app-svelte/rstack.config.js b/packages/create-rstack/template-app-svelte/rstack.config.js index 742edde8..6450bb86 100644 --- a/packages/create-rstack/template-app-svelte/rstack.config.js +++ b/packages/create-rstack/template-app-svelte/rstack.config.js @@ -14,11 +14,7 @@ define.test({ setupFiles: ['./tests/rstest.setup.js'], }); -define.lint(async () => { - const { js } = await import('rstack/lint'); - - return [js.configs.recommended]; -}); +define.lint(({ js }) => [js.configs.recommended]); define.fmt({ plugins: ['prettier-plugin-svelte'], diff --git a/packages/create-rstack/template-app-vanilla-ts/rstack.config.ts b/packages/create-rstack/template-app-vanilla-ts/rstack.config.ts index 5476c2c8..6e755422 100644 --- a/packages/create-rstack/template-app-vanilla-ts/rstack.config.ts +++ b/packages/create-rstack/template-app-vanilla-ts/rstack.config.ts @@ -9,11 +9,10 @@ define.test({ setupFiles: ['./tests/rstest.setup.ts'], }); -define.lint(async () => { - const { js, ts } = await import('rstack/lint'); - - return [js.configs.recommended, ts.configs.recommendedTypeChecked]; -}); +define.lint(({ js, ts }) => [ + js.configs.recommended, + ts.configs.recommendedTypeChecked, +]); define.fmt({ singleQuote: true, diff --git a/packages/create-rstack/template-app-vanilla/rstack.config.js b/packages/create-rstack/template-app-vanilla/rstack.config.js index 23e75fdf..a9f27d77 100644 --- a/packages/create-rstack/template-app-vanilla/rstack.config.js +++ b/packages/create-rstack/template-app-vanilla/rstack.config.js @@ -10,11 +10,7 @@ define.test({ setupFiles: ['./tests/rstest.setup.js'], }); -define.lint(async () => { - const { js } = await import('rstack/lint'); - - return [js.configs.recommended]; -}); +define.lint(({ js }) => [js.configs.recommended]); define.fmt({ singleQuote: true, diff --git a/packages/create-rstack/template-app-vue-ts/rstack.config.ts b/packages/create-rstack/template-app-vue-ts/rstack.config.ts index 12ea8e76..e1133986 100644 --- a/packages/create-rstack/template-app-vue-ts/rstack.config.ts +++ b/packages/create-rstack/template-app-vue-ts/rstack.config.ts @@ -13,11 +13,10 @@ define.test({ setupFiles: ['./tests/rstest.setup.ts'], }); -define.lint(async () => { - const { js, ts } = await import('rstack/lint'); - - return [js.configs.recommended, ts.configs.recommendedTypeChecked]; -}); +define.lint(({ js, ts }) => [ + js.configs.recommended, + ts.configs.recommendedTypeChecked, +]); define.fmt({ singleQuote: true, diff --git a/packages/create-rstack/template-app-vue/rstack.config.js b/packages/create-rstack/template-app-vue/rstack.config.js index b67b85e1..199e7340 100644 --- a/packages/create-rstack/template-app-vue/rstack.config.js +++ b/packages/create-rstack/template-app-vue/rstack.config.js @@ -14,11 +14,7 @@ define.test({ setupFiles: ['./tests/rstest.setup.js'], }); -define.lint(async () => { - const { js } = await import('rstack/lint'); - - return [js.configs.recommended]; -}); +define.lint(({ js }) => [js.configs.recommended]); define.fmt({ singleQuote: true, diff --git a/packages/create-rstack/template-doc-i18n/rstack.config.ts b/packages/create-rstack/template-doc-i18n/rstack.config.ts index 8e1f8435..e3185a0d 100644 --- a/packages/create-rstack/template-doc-i18n/rstack.config.ts +++ b/packages/create-rstack/template-doc-i18n/rstack.config.ts @@ -23,16 +23,12 @@ define.doc({ ], }); -define.lint(async () => { - const { js, ts, reactPlugin, reactHooksPlugin } = await import('rstack/lint'); - - return [ - js.configs.recommended, - ts.configs.recommendedTypeChecked, - reactPlugin.configs.recommended, - reactHooksPlugin.configs.recommended, - ]; -}); +define.lint(({ js, ts, reactPlugin, reactHooksPlugin }) => [ + js.configs.recommended, + ts.configs.recommendedTypeChecked, + reactPlugin.configs.recommended, + reactHooksPlugin.configs.recommended, +]); define.fmt({ singleQuote: true, diff --git a/packages/create-rstack/template-doc/rstack.config.ts b/packages/create-rstack/template-doc/rstack.config.ts index 77378cff..99bf9d0d 100644 --- a/packages/create-rstack/template-doc/rstack.config.ts +++ b/packages/create-rstack/template-doc/rstack.config.ts @@ -7,16 +7,12 @@ define.doc({ title: 'My Site', }); -define.lint(async () => { - const { js, ts, reactPlugin, reactHooksPlugin } = await import('rstack/lint'); - - return [ - js.configs.recommended, - ts.configs.recommendedTypeChecked, - reactPlugin.configs.recommended, - reactHooksPlugin.configs.recommended, - ]; -}); +define.lint(({ js, ts, reactPlugin, reactHooksPlugin }) => [ + js.configs.recommended, + ts.configs.recommendedTypeChecked, + reactPlugin.configs.recommended, + reactHooksPlugin.configs.recommended, +]); define.fmt({ singleQuote: true, diff --git a/packages/create-rstack/template-lib-node-ts/rstack.config.ts b/packages/create-rstack/template-lib-node-ts/rstack.config.ts index dc33795b..28d8d881 100644 --- a/packages/create-rstack/template-lib-node-ts/rstack.config.ts +++ b/packages/create-rstack/template-lib-node-ts/rstack.config.ts @@ -10,11 +10,10 @@ define.test({ // Configure Rstest }); -define.lint(async () => { - const { js, ts } = await import('rstack/lint'); - - return [js.configs.recommended, ts.configs.recommendedTypeChecked]; -}); +define.lint(({ js, ts }) => [ + js.configs.recommended, + ts.configs.recommendedTypeChecked, +]); define.fmt({ singleQuote: true, diff --git a/packages/create-rstack/template-lib-node/rstack.config.js b/packages/create-rstack/template-lib-node/rstack.config.js index 3f62051d..f193d432 100644 --- a/packages/create-rstack/template-lib-node/rstack.config.js +++ b/packages/create-rstack/template-lib-node/rstack.config.js @@ -10,11 +10,7 @@ define.test({ // Configure Rstest }); -define.lint(async () => { - const { js } = await import('rstack/lint'); - - return [js.configs.recommended]; -}); +define.lint(({ js }) => [js.configs.recommended]); define.fmt({ singleQuote: true, diff --git a/packages/create-rstack/template-lib-react-ts/rstack.config.ts b/packages/create-rstack/template-lib-react-ts/rstack.config.ts index b131e4a8..a6ef9b74 100644 --- a/packages/create-rstack/template-lib-react-ts/rstack.config.ts +++ b/packages/create-rstack/template-lib-react-ts/rstack.config.ts @@ -23,16 +23,12 @@ define.test({ setupFiles: ['./tests/rstest.setup.ts'], }); -define.lint(async () => { - const { js, ts, reactPlugin, reactHooksPlugin } = await import('rstack/lint'); - - return [ - js.configs.recommended, - ts.configs.recommendedTypeChecked, - reactPlugin.configs.recommended, - reactHooksPlugin.configs.recommended, - ]; -}); +define.lint(({ js, ts, reactPlugin, reactHooksPlugin }) => [ + js.configs.recommended, + ts.configs.recommendedTypeChecked, + reactPlugin.configs.recommended, + reactHooksPlugin.configs.recommended, +]); define.fmt({ singleQuote: true, diff --git a/packages/create-rstack/template-lib-react/rstack.config.js b/packages/create-rstack/template-lib-react/rstack.config.js index 3ef9c799..663d1744 100644 --- a/packages/create-rstack/template-lib-react/rstack.config.js +++ b/packages/create-rstack/template-lib-react/rstack.config.js @@ -23,15 +23,11 @@ define.test({ setupFiles: ['./tests/rstest.setup.js'], }); -define.lint(async () => { - const { js, reactHooksPlugin, reactPlugin } = await import('rstack/lint'); - - return [ - js.configs.recommended, - reactPlugin.configs.recommended, - reactHooksPlugin.configs.recommended, - ]; -}); +define.lint(({ js, reactHooksPlugin, reactPlugin }) => [ + js.configs.recommended, + reactPlugin.configs.recommended, + reactHooksPlugin.configs.recommended, +]); define.fmt({ singleQuote: true, diff --git a/packages/create-rstack/template-lib-solid-ts/rstack.config.ts b/packages/create-rstack/template-lib-solid-ts/rstack.config.ts index 02bc776f..04122368 100644 --- a/packages/create-rstack/template-lib-solid-ts/rstack.config.ts +++ b/packages/create-rstack/template-lib-solid-ts/rstack.config.ts @@ -75,11 +75,10 @@ define.test(async () => { }; }); -define.lint(async () => { - const { js, ts } = await import('rstack/lint'); - - return [js.configs.recommended, ts.configs.recommendedTypeChecked]; -}); +define.lint(({ js, ts }) => [ + js.configs.recommended, + ts.configs.recommendedTypeChecked, +]); define.fmt({ singleQuote: true, diff --git a/packages/create-rstack/template-lib-solid/rstack.config.js b/packages/create-rstack/template-lib-solid/rstack.config.js index 75f1d03e..b1eb7d49 100644 --- a/packages/create-rstack/template-lib-solid/rstack.config.js +++ b/packages/create-rstack/template-lib-solid/rstack.config.js @@ -75,11 +75,7 @@ define.test(async () => { }; }); -define.lint(async () => { - const { js } = await import('rstack/lint'); - - return [js.configs.recommended]; -}); +define.lint(({ js }) => [js.configs.recommended]); define.fmt({ singleQuote: true, diff --git a/packages/create-rstack/template-lib-svelte-ts/rstack.config.ts b/packages/create-rstack/template-lib-svelte-ts/rstack.config.ts index 0844c4e2..71f23a4a 100644 --- a/packages/create-rstack/template-lib-svelte-ts/rstack.config.ts +++ b/packages/create-rstack/template-lib-svelte-ts/rstack.config.ts @@ -23,11 +23,10 @@ define.test({ testEnvironment: 'happy-dom', }); -define.lint(async () => { - const { js, ts } = await import('rstack/lint'); - - return [js.configs.recommended, ts.configs.recommendedTypeChecked]; -}); +define.lint(({ js, ts }) => [ + js.configs.recommended, + ts.configs.recommendedTypeChecked, +]); define.fmt({ plugins: ['prettier-plugin-svelte'], diff --git a/packages/create-rstack/template-lib-svelte/rstack.config.js b/packages/create-rstack/template-lib-svelte/rstack.config.js index b7d7ba0f..7b7c5f3c 100644 --- a/packages/create-rstack/template-lib-svelte/rstack.config.js +++ b/packages/create-rstack/template-lib-svelte/rstack.config.js @@ -23,11 +23,7 @@ define.test({ testEnvironment: 'happy-dom', }); -define.lint(async () => { - const { js } = await import('rstack/lint'); - - return [js.configs.recommended]; -}); +define.lint(({ js }) => [js.configs.recommended]); define.fmt({ plugins: ['prettier-plugin-svelte'], diff --git a/packages/create-rstack/template-lib-vue-ts/rstack.config.ts b/packages/create-rstack/template-lib-vue-ts/rstack.config.ts index a372eb1d..a70a064d 100644 --- a/packages/create-rstack/template-lib-vue-ts/rstack.config.ts +++ b/packages/create-rstack/template-lib-vue-ts/rstack.config.ts @@ -22,11 +22,10 @@ define.test({ setupFiles: ['./tests/rstest.setup.ts'], }); -define.lint(async () => { - const { js, ts } = await import('rstack/lint'); - - return [js.configs.recommended, ts.configs.recommendedTypeChecked]; -}); +define.lint(({ js, ts }) => [ + js.configs.recommended, + ts.configs.recommendedTypeChecked, +]); define.fmt({ singleQuote: true, diff --git a/packages/create-rstack/template-lib-vue/rstack.config.js b/packages/create-rstack/template-lib-vue/rstack.config.js index 09a3de03..db019b91 100644 --- a/packages/create-rstack/template-lib-vue/rstack.config.js +++ b/packages/create-rstack/template-lib-vue/rstack.config.js @@ -23,11 +23,7 @@ define.test({ setupFiles: ['./tests/rstest.setup.js'], }); -define.lint(async () => { - const { js } = await import('rstack/lint'); - - return [js.configs.recommended]; -}); +define.lint(({ js }) => [js.configs.recommended]); define.fmt({ singleQuote: true, From bac3906bcf28dcca643f9e94b13e0fff313cf435 Mon Sep 17 00:00:00 2001 From: Jiahan Chen Date: Fri, 14 Aug 2026 10:16:26 +0800 Subject: [PATCH 19/33] refactor(config): use injected lint exports (#354) Co-authored-by: swwind --- examples/app-react/rstack.config.ts | 15 ++++++--------- examples/app-vanilla/rstack.config.ts | 5 +---- examples/documentation/rstack.config.ts | 15 ++++++--------- examples/lib-node/rstack.config.ts | 5 +---- examples/lib-react/rstack.config.ts | 15 ++++++--------- rstack.config.ts | 3 +-- 6 files changed, 21 insertions(+), 37 deletions(-) diff --git a/examples/app-react/rstack.config.ts b/examples/app-react/rstack.config.ts index 4d23b13c..960e215b 100644 --- a/examples/app-react/rstack.config.ts +++ b/examples/app-react/rstack.config.ts @@ -12,12 +12,9 @@ define.test({ setupFiles: ['./tests/rstest.setup.ts'], }); -define.lint(async () => { - const { js, ts, reactPlugin, reactHooksPlugin } = await import('rstack/lint'); - return [ - js.configs.recommended, - ts.configs.recommended, - reactPlugin.configs.recommended, - reactHooksPlugin.configs.recommended, - ]; -}); +define.lint(({ js, ts, reactPlugin, reactHooksPlugin }) => [ + js.configs.recommended, + ts.configs.recommended, + reactPlugin.configs.recommended, + reactHooksPlugin.configs.recommended, +]); diff --git a/examples/app-vanilla/rstack.config.ts b/examples/app-vanilla/rstack.config.ts index 3504d640..9707fbda 100644 --- a/examples/app-vanilla/rstack.config.ts +++ b/examples/app-vanilla/rstack.config.ts @@ -6,7 +6,4 @@ define.test({ setupFiles: ['./tests/rstest.setup.ts'], }); -define.lint(async () => { - const { js, ts } = await import('rstack/lint'); - return [js.configs.recommended, ts.configs.recommended]; -}); +define.lint(({ js, ts }) => [js.configs.recommended, ts.configs.recommended]); diff --git a/examples/documentation/rstack.config.ts b/examples/documentation/rstack.config.ts index f73f1863..10c5a9ad 100644 --- a/examples/documentation/rstack.config.ts +++ b/examples/documentation/rstack.config.ts @@ -7,12 +7,9 @@ define.doc({ title: 'My Site', }); -define.lint(async () => { - const { js, ts, reactPlugin, reactHooksPlugin } = await import('rstack/lint'); - return [ - js.configs.recommended, - ts.configs.recommended, - reactPlugin.configs.recommended, - reactHooksPlugin.configs.recommended, - ]; -}); +define.lint(({ js, ts, reactPlugin, reactHooksPlugin }) => [ + js.configs.recommended, + ts.configs.recommended, + reactPlugin.configs.recommended, + reactHooksPlugin.configs.recommended, +]); diff --git a/examples/lib-node/rstack.config.ts b/examples/lib-node/rstack.config.ts index ccafc8da..ed274a80 100644 --- a/examples/lib-node/rstack.config.ts +++ b/examples/lib-node/rstack.config.ts @@ -6,7 +6,4 @@ define.lib({ syntax: ['node 22'], }); -define.lint(async () => { - const { js, ts } = await import('rstack/lint'); - return [js.configs.recommended, ts.configs.recommended]; -}); +define.lint(({ js, ts }) => [js.configs.recommended, ts.configs.recommended]); diff --git a/examples/lib-react/rstack.config.ts b/examples/lib-react/rstack.config.ts index 31913350..fd97fdae 100644 --- a/examples/lib-react/rstack.config.ts +++ b/examples/lib-react/rstack.config.ts @@ -22,12 +22,9 @@ define.test({ setupFiles: ['./tests/rstest.setup.ts'], }); -define.lint(async () => { - const { js, ts, reactPlugin, reactHooksPlugin } = await import('rstack/lint'); - return [ - js.configs.recommended, - ts.configs.recommended, - reactPlugin.configs.recommended, - reactHooksPlugin.configs.recommended, - ]; -}); +define.lint(({ js, ts, reactPlugin, reactHooksPlugin }) => [ + js.configs.recommended, + ts.configs.recommended, + reactPlugin.configs.recommended, + reactHooksPlugin.configs.recommended, +]); diff --git a/rstack.config.ts b/rstack.config.ts index d6d1bce2..3e20de09 100644 --- a/rstack.config.ts +++ b/rstack.config.ts @@ -1,9 +1,8 @@ // Rstack configuration guide: https://rstack.rs/config import { define } from 'rstack'; -define.lint(async () => { +define.lint(async ({ js, ts }) => { const { default: globals } = await import('globals'); - const { js, ts } = await import('rstack/lint'); return [ js.configs.recommended, ts.configs.recommendedTypeChecked, From c84346224cf68dc44cdb1be5c97ad588bbe46347 Mon Sep 17 00:00:00 2001 From: Jiahan Chen Date: Fri, 14 Aug 2026 10:34:47 +0800 Subject: [PATCH 20/33] docs: simplify lint configuration examples (#355) Co-authored-by: swwind --- website/docs/en/guide/cli/lint.mdx | 8 ++----- website/docs/en/guide/configuration.mdx | 8 ++----- website/docs/en/guide/monorepo.mdx | 28 +++++++++---------------- website/docs/zh/guide/cli/lint.mdx | 8 ++----- website/docs/zh/guide/configuration.mdx | 8 ++----- website/docs/zh/guide/monorepo.mdx | 28 +++++++++---------------- 6 files changed, 28 insertions(+), 60 deletions(-) diff --git a/website/docs/en/guide/cli/lint.mdx b/website/docs/en/guide/cli/lint.mdx index 07b15922..e007abb3 100644 --- a/website/docs/en/guide/cli/lint.mdx +++ b/website/docs/en/guide/cli/lint.mdx @@ -29,14 +29,10 @@ rs lint --type-check ## Configuration -Configure linting through [`define.lint()`](../configuration#define-lint) in the [Rstack configuration file](/guide/configuration#configuration-file). It accepts the standard [Rslint configuration](https://rslint.rs/config/). Presets and plugins can be imported from `rstack/lint` on demand: +Configure linting through [`define.lint()`](../configuration#define-lint) in the [Rstack configuration file](/guide/configuration#configuration-file). It accepts the standard [Rslint configuration](https://rslint.rs/config/). A configuration function receives all exports from `rstack/lint`, so presets and plugins do not need to be imported manually: ```ts title="rstack.config.ts" import { define } from 'rstack'; -define.lint(async () => { - const { js, ts } = await import('rstack/lint'); - - return [js.configs.recommended, ts.configs.recommended]; -}); +define.lint(({ js, ts }) => [js.configs.recommended, ts.configs.recommendedTypeChecked]); ``` diff --git a/website/docs/en/guide/configuration.mdx b/website/docs/en/guide/configuration.mdx index 55288bbd..49d110f6 100644 --- a/website/docs/en/guide/configuration.mdx +++ b/website/docs/en/guide/configuration.mdx @@ -150,16 +150,12 @@ If the root test configuration does not define `extends` and contains `projects` ### `define.lint()` \{#define-lint} -Defines the [Rslint configuration](https://rslint.rs/config/). Pass the configuration directly, or use an async function to load presets and plugins from `rstack/lint` on demand. +Defines the [Rslint configuration](https://rslint.rs/config/). Pass the configuration directly, or use a synchronous or asynchronous function. The function receives all exports from `rstack/lint`, so presets and plugins do not need to be imported manually. ```ts title="rstack.config.ts" import { define } from 'rstack'; -define.lint(async () => { - const { js, ts } = await import('rstack/lint'); - - return [js.configs.recommended, ts.configs.recommended]; -}); +define.lint(({ js, ts }) => [js.configs.recommended, ts.configs.recommendedTypeChecked]); ``` ### `define.fmt()` \{#define-fmt} diff --git a/website/docs/en/guide/monorepo.mdx b/website/docs/en/guide/monorepo.mdx index 3ca08420..152b8ddc 100644 --- a/website/docs/en/guide/monorepo.mdx +++ b/website/docs/en/guide/monorepo.mdx @@ -46,11 +46,7 @@ Use [`define.lint()`](./configuration#define-lint), [`define.fmt()`](./configura ```ts title="rstack.config.ts" import { define } from 'rstack'; -define.lint(async () => { - const { js, ts } = await import('rstack/lint'); - - return [js.configs.recommended, ts.configs.recommended]; -}); +define.lint(({ js, ts }) => [js.configs.recommended, ts.configs.recommendedTypeChecked]); define.fmt({ singleQuote: true, @@ -86,20 +82,16 @@ If some projects need different lint rules, use [`files`](https://rslint.rs/conf ```ts title="rstack.config.ts" import { define } from 'rstack'; -define.lint(async () => { - const { js, ts } = await import('rstack/lint'); - - return [ - js.configs.recommended, - ts.configs.recommended, - { - files: ['apps/web/**/*.{ts,tsx}'], - rules: { - '@typescript-eslint/no-explicit-any': 'off', - }, +define.lint(({ js, ts }) => [ + js.configs.recommended, + ts.configs.recommendedTypeChecked, + { + files: ['apps/web/**/*.{ts,tsx}'], + rules: { + '@typescript-eslint/no-explicit-any': 'off', }, - ]; -}); + }, +]); ``` ## Project configuration diff --git a/website/docs/zh/guide/cli/lint.mdx b/website/docs/zh/guide/cli/lint.mdx index 658ddb8a..48011c5e 100644 --- a/website/docs/zh/guide/cli/lint.mdx +++ b/website/docs/zh/guide/cli/lint.mdx @@ -29,14 +29,10 @@ rs lint --type-check ## 配置 \{#configuration} -在 [Rstack 配置文件](/guide/configuration#configuration-file)中通过 [`define.lint()`](../configuration#define-lint) 配置代码检查。该 API 支持标准的 [Rslint 配置](https://rslint.rs/config/)。预设和插件可以从 `rstack/lint` 按需导入: +在 [Rstack 配置文件](/guide/configuration#configuration-file)中通过 [`define.lint()`](../configuration#define-lint) 配置代码检查。该 API 支持标准的 [Rslint 配置](https://rslint.rs/config/)。配置函数会接收 `rstack/lint` 的全部导出,因此无需手动导入预设和插件: ```ts title="rstack.config.ts" import { define } from 'rstack'; -define.lint(async () => { - const { js, ts } = await import('rstack/lint'); - - return [js.configs.recommended, ts.configs.recommended]; -}); +define.lint(({ js, ts }) => [js.configs.recommended, ts.configs.recommendedTypeChecked]); ``` diff --git a/website/docs/zh/guide/configuration.mdx b/website/docs/zh/guide/configuration.mdx index 4e4e51dc..4f370874 100644 --- a/website/docs/zh/guide/configuration.mdx +++ b/website/docs/zh/guide/configuration.mdx @@ -150,16 +150,12 @@ define.test({ ### `define.lint()` \{#define-lint} -定义 [Rslint 配置](https://rslint.rs/config/)。可以直接传入配置,也可以使用异步函数,按需从 `rstack/lint` 加载预设和插件。 +定义 [Rslint 配置](https://rslint.rs/config/)。可以直接传入配置,也可以传入同步或异步函数。函数会接收 `rstack/lint` 的全部导出,因此无需手动导入预设和插件。 ```ts title="rstack.config.ts" import { define } from 'rstack'; -define.lint(async () => { - const { js, ts } = await import('rstack/lint'); - - return [js.configs.recommended, ts.configs.recommended]; -}); +define.lint(({ js, ts }) => [js.configs.recommended, ts.configs.recommendedTypeChecked]); ``` ### `define.fmt()` \{#define-fmt} diff --git a/website/docs/zh/guide/monorepo.mdx b/website/docs/zh/guide/monorepo.mdx index 4d780a3b..ae93fee3 100644 --- a/website/docs/zh/guide/monorepo.mdx +++ b/website/docs/zh/guide/monorepo.mdx @@ -46,11 +46,7 @@ Rsbuild 插件、测试库等项目专属依赖,建议定义在实际使用它 ```ts title="rstack.config.ts" import { define } from 'rstack'; -define.lint(async () => { - const { js, ts } = await import('rstack/lint'); - - return [js.configs.recommended, ts.configs.recommended]; -}); +define.lint(({ js, ts }) => [js.configs.recommended, ts.configs.recommendedTypeChecked]); define.fmt({ singleQuote: true, @@ -86,20 +82,16 @@ define.staged({ ```ts title="rstack.config.ts" import { define } from 'rstack'; -define.lint(async () => { - const { js, ts } = await import('rstack/lint'); - - return [ - js.configs.recommended, - ts.configs.recommended, - { - files: ['apps/web/**/*.{ts,tsx}'], - rules: { - '@typescript-eslint/no-explicit-any': 'off', - }, +define.lint(({ js, ts }) => [ + js.configs.recommended, + ts.configs.recommendedTypeChecked, + { + files: ['apps/web/**/*.{ts,tsx}'], + rules: { + '@typescript-eslint/no-explicit-any': 'off', }, - ]; -}); + }, +]); ``` ## 子项目配置 \{#project-configuration} From eea28050fcd0be0d8de878342cbcdd8159e77be6 Mon Sep 17 00:00:00 2001 From: Jiahan Chen Date: Fri, 14 Aug 2026 11:19:44 +0800 Subject: [PATCH 21/33] docs(skills): update lint migration guidance (#356) Co-authored-by: swwind --- .agents/skills/migrate-to-rstack-cli/SKILL.md | 16 ++++++++++++---- .../migrate-to-rstack-cli/references/rslint.md | 14 ++++++-------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/.agents/skills/migrate-to-rstack-cli/SKILL.md b/.agents/skills/migrate-to-rstack-cli/SKILL.md index 917de99c..06d61983 100644 --- a/.agents/skills/migrate-to-rstack-cli/SKILL.md +++ b/.agents/skills/migrate-to-rstack-cli/SKILL.md @@ -53,13 +53,21 @@ define.test({ }); ``` -Prefer async config functions and dynamic imports for runtime plugins and presets: +Use dynamic imports in async config functions only for external plugins, presets, and other dependencies: ```ts -define.lint(async () => { - const { js, ts } = await import('rstack/lint'); - return [js.configs.recommended, ts.configs.recommended]; +define.app(async () => { + const { pluginReact } = await import('@rsbuild/plugin-react'); + return { + plugins: [pluginReact()], + }; }); ``` +`define.lint` provides `@rslint/core` APIs to its config factory, so no manual import is needed: + +```ts +define.lint(({ js }) => [js.configs.recommended]); +``` + Rstack loads TypeScript configs as native ESM. Preserve runtime-resolvable file extensions, replace CommonJS globals such as `__dirname`. diff --git a/.agents/skills/migrate-to-rstack-cli/references/rslint.md b/.agents/skills/migrate-to-rstack-cli/references/rslint.md index 96b31d59..41037e8b 100644 --- a/.agents/skills/migrate-to-rstack-cli/references/rslint.md +++ b/.agents/skills/migrate-to-rstack-cli/references/rslint.md @@ -5,22 +5,20 @@ Read this reference when the project uses `@rslint/core`, `rslint.config.*`, `rs ## Steps 1. Replace the `rslint` executable prefix with `rs lint`. For example, replace `rslint --fix` with `rs lint --fix`. -2. Move the old config into `define.lint`, replacing Rslint's `defineConfig()` wrapper and import. Dynamically import presets from `rstack/lint` inside an async config function. -3. Replace direct config/API imports from `@rslint/core` with exports from `rstack/lint` where available. -4. Replace custom `--config` paths with the migrated `rstack.config.*` path. -5. Remove `@rslint/core` only when no uncovered direct runtime API remains. Delete `rslint.config.*`. +2. Move the old config into `define.lint`, replacing Rslint's `defineConfig()` wrapper and import. Receive `@rslint/core` exports from the factory parameter. +3. Replace custom `--config` paths with the migrated `rstack.config.*` path. +4. Remove `@rslint/core` only when no uncovered direct runtime API remains. Delete `rslint.config.*`. ## Config Pattern ```ts import { define } from 'rstack'; -define.lint(async () => { - const { js, ts } = await import('rstack/lint'); - return [js.configs.recommended, ts.configs.recommended]; -}); +define.lint(({ js, ts }) => [js.configs.recommended, ts.configs.recommendedTypeChecked]); ``` +Preserve existing presets and rules during migration. + ## Script Pattern If a script also runs Prettier, migrate its formatting command as described in [prettier.md](prettier.md). From 05c2d21ab26749aba94a2dde50d3a137f677b3a6 Mon Sep 17 00:00:00 2001 From: Jiahan Chen Date: Fri, 14 Aug 2026 11:50:05 +0800 Subject: [PATCH 22/33] release: v0.6.1 (#357) --- packages/create-rstack/package.json | 2 +- .../template-app-lit-ts/package.json | 2 +- .../template-app-lit/package.json | 2 +- .../template-app-preact-ts/package.json | 2 +- .../template-app-preact/package.json | 2 +- .../template-app-react-ts/package.json | 2 +- .../template-app-react/package.json | 2 +- .../template-app-solid-ts/package.json | 2 +- .../template-app-solid/package.json | 2 +- .../template-app-svelte-ts/package.json | 2 +- .../template-app-svelte/package.json | 2 +- .../template-app-vanilla-ts/package.json | 2 +- .../template-app-vanilla/package.json | 2 +- .../template-app-vue-ts/package.json | 2 +- .../template-app-vue/package.json | 2 +- .../template-doc-i18n/package.json | 2 +- .../create-rstack/template-doc/package.json | 2 +- .../template-lib-node-ts/package.json | 2 +- .../template-lib-node/package.json | 2 +- .../template-lib-react-ts/package.json | 2 +- .../template-lib-react/package.json | 2 +- .../template-lib-solid-ts/package.json | 2 +- .../template-lib-solid/package.json | 2 +- .../template-lib-svelte-ts/package.json | 2 +- .../template-lib-svelte/package.json | 2 +- .../template-lib-vue-ts/package.json | 2 +- .../template-lib-vue/package.json | 2 +- packages/rstack/binding.cjs | 108 +++++++++--------- packages/rstack/package.json | 2 +- 29 files changed, 82 insertions(+), 82 deletions(-) diff --git a/packages/create-rstack/package.json b/packages/create-rstack/package.json index 3624d1b0..84e08d10 100644 --- a/packages/create-rstack/package.json +++ b/packages/create-rstack/package.json @@ -1,6 +1,6 @@ { "name": "create-rstack", - "version": "3.2.0", + "version": "3.2.1", "description": "Create a new Rstack project", "homepage": "https://rstack.rs", "bugs": { diff --git a/packages/create-rstack/template-app-lit-ts/package.json b/packages/create-rstack/template-app-lit-ts/package.json index 61684891..df58ecf0 100644 --- a/packages/create-rstack/template-app-lit-ts/package.json +++ b/packages/create-rstack/template-app-lit-ts/package.json @@ -19,7 +19,7 @@ "devDependencies": { "@types/node": "^24.13.3", "happy-dom": "^20.11.2", - "rstack": "^0.6.0", + "rstack": "^0.6.1", "typescript": "^7.0.2" } } diff --git a/packages/create-rstack/template-app-lit/package.json b/packages/create-rstack/template-app-lit/package.json index 21399993..3e3f3b90 100644 --- a/packages/create-rstack/template-app-lit/package.json +++ b/packages/create-rstack/template-app-lit/package.json @@ -18,6 +18,6 @@ }, "devDependencies": { "happy-dom": "^20.11.2", - "rstack": "^0.6.0" + "rstack": "^0.6.1" } } diff --git a/packages/create-rstack/template-app-preact-ts/package.json b/packages/create-rstack/template-app-preact-ts/package.json index 56aac06a..0764ec7f 100644 --- a/packages/create-rstack/template-app-preact-ts/package.json +++ b/packages/create-rstack/template-app-preact-ts/package.json @@ -22,7 +22,7 @@ "@testing-library/preact": "^3.2.4", "@types/node": "^24.13.3", "happy-dom": "^20.11.2", - "rstack": "^0.6.0", + "rstack": "^0.6.1", "typescript": "^7.0.2" } } diff --git a/packages/create-rstack/template-app-preact/package.json b/packages/create-rstack/template-app-preact/package.json index 272497e0..5a72ed4b 100644 --- a/packages/create-rstack/template-app-preact/package.json +++ b/packages/create-rstack/template-app-preact/package.json @@ -21,6 +21,6 @@ "@testing-library/jest-dom": "^7.0.1", "@testing-library/preact": "^3.2.4", "happy-dom": "^20.11.2", - "rstack": "^0.6.0" + "rstack": "^0.6.1" } } diff --git a/packages/create-rstack/template-app-react-ts/package.json b/packages/create-rstack/template-app-react-ts/package.json index 0fbcb93d..dd7ea8c4 100644 --- a/packages/create-rstack/template-app-react-ts/package.json +++ b/packages/create-rstack/template-app-react-ts/package.json @@ -26,7 +26,7 @@ "@types/react": "^19.2.18", "@types/react-dom": "^19.2.4", "happy-dom": "^20.11.2", - "rstack": "^0.6.0", + "rstack": "^0.6.1", "typescript": "^7.0.2" } } diff --git a/packages/create-rstack/template-app-react/package.json b/packages/create-rstack/template-app-react/package.json index 4f0a81e6..803c4abb 100644 --- a/packages/create-rstack/template-app-react/package.json +++ b/packages/create-rstack/template-app-react/package.json @@ -23,6 +23,6 @@ "@testing-library/jest-dom": "^7.0.1", "@testing-library/react": "^16.3.2", "happy-dom": "^20.11.2", - "rstack": "^0.6.0" + "rstack": "^0.6.1" } } diff --git a/packages/create-rstack/template-app-solid-ts/package.json b/packages/create-rstack/template-app-solid-ts/package.json index b15f3a66..b223ec74 100644 --- a/packages/create-rstack/template-app-solid-ts/package.json +++ b/packages/create-rstack/template-app-solid-ts/package.json @@ -23,7 +23,7 @@ "@testing-library/jest-dom": "^7.0.1", "@types/node": "^24.13.3", "happy-dom": "^20.11.2", - "rstack": "^0.6.0", + "rstack": "^0.6.1", "typescript": "^7.0.2" } } diff --git a/packages/create-rstack/template-app-solid/package.json b/packages/create-rstack/template-app-solid/package.json index d1964a8c..ff10813d 100644 --- a/packages/create-rstack/template-app-solid/package.json +++ b/packages/create-rstack/template-app-solid/package.json @@ -22,6 +22,6 @@ "@solidjs/testing-library": "^0.8.10", "@testing-library/jest-dom": "^7.0.1", "happy-dom": "^20.11.2", - "rstack": "^0.6.0" + "rstack": "^0.6.1" } } diff --git a/packages/create-rstack/template-app-svelte-ts/package.json b/packages/create-rstack/template-app-svelte-ts/package.json index c705ed07..63910506 100644 --- a/packages/create-rstack/template-app-svelte-ts/package.json +++ b/packages/create-rstack/template-app-svelte-ts/package.json @@ -23,7 +23,7 @@ "@types/node": "^24.13.3", "happy-dom": "^20.11.2", "prettier-plugin-svelte": "^4.1.1", - "rstack": "^0.6.0", + "rstack": "^0.6.1", "svelte-check": "^4.7.5", "typescript": "^6.0.3" } diff --git a/packages/create-rstack/template-app-svelte/package.json b/packages/create-rstack/template-app-svelte/package.json index e5abceee..e48dff5e 100644 --- a/packages/create-rstack/template-app-svelte/package.json +++ b/packages/create-rstack/template-app-svelte/package.json @@ -22,6 +22,6 @@ "@testing-library/svelte": "^5.4.2", "happy-dom": "^20.11.2", "prettier-plugin-svelte": "^4.1.1", - "rstack": "^0.6.0" + "rstack": "^0.6.1" } } diff --git a/packages/create-rstack/template-app-vanilla-ts/package.json b/packages/create-rstack/template-app-vanilla-ts/package.json index 19f80fa9..1992286f 100644 --- a/packages/create-rstack/template-app-vanilla-ts/package.json +++ b/packages/create-rstack/template-app-vanilla-ts/package.json @@ -18,7 +18,7 @@ "@testing-library/jest-dom": "^7.0.1", "@types/node": "^24.13.3", "happy-dom": "^20.11.2", - "rstack": "^0.6.0", + "rstack": "^0.6.1", "typescript": "^7.0.2" } } diff --git a/packages/create-rstack/template-app-vanilla/package.json b/packages/create-rstack/template-app-vanilla/package.json index 6e4dd119..ad5a99fb 100644 --- a/packages/create-rstack/template-app-vanilla/package.json +++ b/packages/create-rstack/template-app-vanilla/package.json @@ -17,6 +17,6 @@ "@testing-library/dom": "^10.4.1", "@testing-library/jest-dom": "^7.0.1", "happy-dom": "^20.11.2", - "rstack": "^0.6.0" + "rstack": "^0.6.1" } } diff --git a/packages/create-rstack/template-app-vue-ts/package.json b/packages/create-rstack/template-app-vue-ts/package.json index fcd61816..2ca2e7a4 100644 --- a/packages/create-rstack/template-app-vue-ts/package.json +++ b/packages/create-rstack/template-app-vue-ts/package.json @@ -22,7 +22,7 @@ "@types/node": "^24.13.3", "@vue/test-utils": "^2.4.11", "happy-dom": "^20.11.2", - "rstack": "^0.6.0", + "rstack": "^0.6.1", "typescript": "^6.0.3", "vue-tsc": "^3.3.9" } diff --git a/packages/create-rstack/template-app-vue/package.json b/packages/create-rstack/template-app-vue/package.json index 7cd20a99..508b72b5 100644 --- a/packages/create-rstack/template-app-vue/package.json +++ b/packages/create-rstack/template-app-vue/package.json @@ -21,6 +21,6 @@ "@testing-library/jest-dom": "^7.0.1", "@vue/test-utils": "^2.4.11", "happy-dom": "^20.11.2", - "rstack": "^0.6.0" + "rstack": "^0.6.1" } } diff --git a/packages/create-rstack/template-doc-i18n/package.json b/packages/create-rstack/template-doc-i18n/package.json index b002b2a2..99653b4d 100644 --- a/packages/create-rstack/template-doc-i18n/package.json +++ b/packages/create-rstack/template-doc-i18n/package.json @@ -18,7 +18,7 @@ "@types/react-dom": "^19.2.4", "react": "^19.2.8", "react-dom": "^19.2.8", - "rstack": "^0.6.0", + "rstack": "^0.6.1", "typescript": "^7.0.2" } } diff --git a/packages/create-rstack/template-doc/package.json b/packages/create-rstack/template-doc/package.json index f11dce21..72785a93 100644 --- a/packages/create-rstack/template-doc/package.json +++ b/packages/create-rstack/template-doc/package.json @@ -18,7 +18,7 @@ "@types/react-dom": "^19.2.4", "react": "^19.2.8", "react-dom": "^19.2.8", - "rstack": "^0.6.0", + "rstack": "^0.6.1", "typescript": "^7.0.2" } } diff --git a/packages/create-rstack/template-lib-node-ts/package.json b/packages/create-rstack/template-lib-node-ts/package.json index 0249c11b..95e1ff92 100644 --- a/packages/create-rstack/template-lib-node-ts/package.json +++ b/packages/create-rstack/template-lib-node-ts/package.json @@ -25,7 +25,7 @@ }, "devDependencies": { "@types/node": "^24.13.3", - "rstack": "^0.6.0", + "rstack": "^0.6.1", "typescript": "^7.0.2" }, "engines": { diff --git a/packages/create-rstack/template-lib-node/package.json b/packages/create-rstack/template-lib-node/package.json index 32cec902..34fc835d 100644 --- a/packages/create-rstack/template-lib-node/package.json +++ b/packages/create-rstack/template-lib-node/package.json @@ -22,7 +22,7 @@ "test:watch": "rs test --watch" }, "devDependencies": { - "rstack": "^0.6.0" + "rstack": "^0.6.1" }, "engines": { "node": ">=22.12.0" diff --git a/packages/create-rstack/template-lib-react-ts/package.json b/packages/create-rstack/template-lib-react-ts/package.json index 2f6db0e9..2ad075e2 100644 --- a/packages/create-rstack/template-lib-react-ts/package.json +++ b/packages/create-rstack/template-lib-react-ts/package.json @@ -33,7 +33,7 @@ "happy-dom": "^20.11.2", "react": "^19.2.8", "react-dom": "^19.2.8", - "rstack": "^0.6.0", + "rstack": "^0.6.1", "typescript": "^7.0.2" }, "peerDependencies": { diff --git a/packages/create-rstack/template-lib-react/package.json b/packages/create-rstack/template-lib-react/package.json index 72e2c7a2..f91d1744 100644 --- a/packages/create-rstack/template-lib-react/package.json +++ b/packages/create-rstack/template-lib-react/package.json @@ -29,7 +29,7 @@ "happy-dom": "^20.11.2", "react": "^19.2.8", "react-dom": "^19.2.8", - "rstack": "^0.6.0" + "rstack": "^0.6.1" }, "peerDependencies": { "react": ">=18.0.0", diff --git a/packages/create-rstack/template-lib-solid-ts/package.json b/packages/create-rstack/template-lib-solid-ts/package.json index f40e43bd..fa98fcbb 100644 --- a/packages/create-rstack/template-lib-solid-ts/package.json +++ b/packages/create-rstack/template-lib-solid-ts/package.json @@ -30,7 +30,7 @@ "@testing-library/jest-dom": "^7.0.1", "@types/node": "^24.13.3", "happy-dom": "^20.11.2", - "rstack": "^0.6.0", + "rstack": "^0.6.1", "solid-js": "^1.9.14", "typescript": "^7.0.2" }, diff --git a/packages/create-rstack/template-lib-solid/package.json b/packages/create-rstack/template-lib-solid/package.json index 3f8a1e54..836fec38 100644 --- a/packages/create-rstack/template-lib-solid/package.json +++ b/packages/create-rstack/template-lib-solid/package.json @@ -27,7 +27,7 @@ "@solidjs/testing-library": "^0.8.10", "@testing-library/jest-dom": "^7.0.1", "happy-dom": "^20.11.2", - "rstack": "^0.6.0", + "rstack": "^0.6.1", "solid-js": "^1.9.14" }, "peerDependencies": { diff --git a/packages/create-rstack/template-lib-svelte-ts/package.json b/packages/create-rstack/template-lib-svelte-ts/package.json index faea65d7..4241ba47 100644 --- a/packages/create-rstack/template-lib-svelte-ts/package.json +++ b/packages/create-rstack/template-lib-svelte-ts/package.json @@ -27,7 +27,7 @@ "@types/node": "^24.13.3", "happy-dom": "^20.11.2", "prettier-plugin-svelte": "^4.1.1", - "rstack": "^0.6.0", + "rstack": "^0.6.1", "svelte": "^5.56.8", "svelte-check": "^4.7.5", "svelte2tsx": "^0.7.60", diff --git a/packages/create-rstack/template-lib-svelte/package.json b/packages/create-rstack/template-lib-svelte/package.json index e64f4746..b03e95af 100644 --- a/packages/create-rstack/template-lib-svelte/package.json +++ b/packages/create-rstack/template-lib-svelte/package.json @@ -24,7 +24,7 @@ "@rsbuild/plugin-svelte": "^2.0.1", "happy-dom": "^20.11.2", "prettier-plugin-svelte": "^4.1.1", - "rstack": "^0.6.0", + "rstack": "^0.6.1", "svelte": "^5.56.8" }, "peerDependencies": { diff --git a/packages/create-rstack/template-lib-vue-ts/package.json b/packages/create-rstack/template-lib-vue-ts/package.json index a1932615..3b5f7930 100644 --- a/packages/create-rstack/template-lib-vue-ts/package.json +++ b/packages/create-rstack/template-lib-vue-ts/package.json @@ -28,7 +28,7 @@ "@types/node": "^24.13.3", "@vue/test-utils": "^2.4.11", "happy-dom": "^20.11.2", - "rstack": "^0.6.0", + "rstack": "^0.6.1", "typescript": "^6.0.3", "vue": "^3.5.41", "vue-tsc": "^3.3.9" diff --git a/packages/create-rstack/template-lib-vue/package.json b/packages/create-rstack/template-lib-vue/package.json index abbff2c4..d22c4278 100644 --- a/packages/create-rstack/template-lib-vue/package.json +++ b/packages/create-rstack/template-lib-vue/package.json @@ -25,7 +25,7 @@ "@testing-library/jest-dom": "^7.0.1", "@vue/test-utils": "^2.4.11", "happy-dom": "^20.11.2", - "rstack": "^0.6.0", + "rstack": "^0.6.1", "vue": "^3.5.41" }, "peerDependencies": { diff --git a/packages/rstack/binding.cjs b/packages/rstack/binding.cjs index 8ee733a0..6c7528a3 100644 --- a/packages/rstack/binding.cjs +++ b/packages/rstack/binding.cjs @@ -77,8 +77,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-android-arm64') const bindingPackageVersion = require('@rstackjs/cli-android-arm64/package.json').version - if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -93,8 +93,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-android-arm-eabi') const bindingPackageVersion = require('@rstackjs/cli-android-arm-eabi/package.json').version - if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -114,8 +114,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-win32-x64-gnu') const bindingPackageVersion = require('@rstackjs/cli-win32-x64-gnu/package.json').version - if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -130,8 +130,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-win32-x64-msvc') const bindingPackageVersion = require('@rstackjs/cli-win32-x64-msvc/package.json').version - if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -147,8 +147,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-win32-ia32-msvc') const bindingPackageVersion = require('@rstackjs/cli-win32-ia32-msvc/package.json').version - if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -163,8 +163,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-win32-arm64-msvc') const bindingPackageVersion = require('@rstackjs/cli-win32-arm64-msvc/package.json').version - if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -182,8 +182,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-darwin-universal') const bindingPackageVersion = require('@rstackjs/cli-darwin-universal/package.json').version - if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -198,8 +198,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-darwin-x64') const bindingPackageVersion = require('@rstackjs/cli-darwin-x64/package.json').version - if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -214,8 +214,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-darwin-arm64') const bindingPackageVersion = require('@rstackjs/cli-darwin-arm64/package.json').version - if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -234,8 +234,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-freebsd-x64') const bindingPackageVersion = require('@rstackjs/cli-freebsd-x64/package.json').version - if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -250,8 +250,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-freebsd-arm64') const bindingPackageVersion = require('@rstackjs/cli-freebsd-arm64/package.json').version - if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -271,8 +271,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-linux-x64-musl') const bindingPackageVersion = require('@rstackjs/cli-linux-x64-musl/package.json').version - if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -287,8 +287,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-linux-x64-gnu') const bindingPackageVersion = require('@rstackjs/cli-linux-x64-gnu/package.json').version - if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -305,8 +305,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-linux-arm64-musl') const bindingPackageVersion = require('@rstackjs/cli-linux-arm64-musl/package.json').version - if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -321,8 +321,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-linux-arm64-gnu') const bindingPackageVersion = require('@rstackjs/cli-linux-arm64-gnu/package.json').version - if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -339,8 +339,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-linux-arm-musleabihf') const bindingPackageVersion = require('@rstackjs/cli-linux-arm-musleabihf/package.json').version - if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -355,8 +355,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-linux-arm-gnueabihf') const bindingPackageVersion = require('@rstackjs/cli-linux-arm-gnueabihf/package.json').version - if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -373,8 +373,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-linux-loong64-musl') const bindingPackageVersion = require('@rstackjs/cli-linux-loong64-musl/package.json').version - if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -389,8 +389,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-linux-loong64-gnu') const bindingPackageVersion = require('@rstackjs/cli-linux-loong64-gnu/package.json').version - if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -407,8 +407,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-linux-riscv64-musl') const bindingPackageVersion = require('@rstackjs/cli-linux-riscv64-musl/package.json').version - if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -423,8 +423,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-linux-riscv64-gnu') const bindingPackageVersion = require('@rstackjs/cli-linux-riscv64-gnu/package.json').version - if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -440,8 +440,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-linux-ppc64-gnu') const bindingPackageVersion = require('@rstackjs/cli-linux-ppc64-gnu/package.json').version - if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -456,8 +456,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-linux-s390x-gnu') const bindingPackageVersion = require('@rstackjs/cli-linux-s390x-gnu/package.json').version - if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -476,8 +476,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-openharmony-arm64') const bindingPackageVersion = require('@rstackjs/cli-openharmony-arm64/package.json').version - if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -492,8 +492,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-openharmony-x64') const bindingPackageVersion = require('@rstackjs/cli-openharmony-x64/package.json').version - if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -508,8 +508,8 @@ function requireNative() { try { const binding = require('@rstackjs/cli-openharmony-arm') const bindingPackageVersion = require('@rstackjs/cli-openharmony-arm/package.json').version - if (bindingPackageVersion !== '0.6.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { - throw new Error(`Native binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.6.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } return binding } catch (e) { @@ -648,8 +648,8 @@ if (!nativeBinding || forceWasi) { if (!candidateFailed) { if (process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { const bindingPackageVersion = require('@rstackjs/cli-wasm32-wasi/package.json').version - if (bindingPackageVersion !== '0.6.0') { - throw new Error(`WASI binding package version mismatch, expected 0.6.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + if (bindingPackageVersion !== '0.6.1') { + throw new Error(`WASI binding package version mismatch, expected 0.6.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } } wasiBinding = require('@rstackjs/cli-wasm32-wasi') diff --git a/packages/rstack/package.json b/packages/rstack/package.json index 5936624f..df58a421 100644 --- a/packages/rstack/package.json +++ b/packages/rstack/package.json @@ -1,6 +1,6 @@ { "name": "rstack", - "version": "0.6.0", + "version": "0.6.1", "description": "One CLI for JavaScript development, powered by Rstack.", "homepage": "https://rstack.rs", "bugs": { From ae32c79cd4aa033b8a2fac01d19d7a64fdccee79 Mon Sep 17 00:00:00 2001 From: Jiahan Chen Date: Fri, 14 Aug 2026 12:42:40 +0800 Subject: [PATCH 23/33] fix(doc): restart dev server on config changes (#358) --- packages/rstack/rstack.config.ts | 1 + packages/rstack/src/rspressConfig.ts | 29 ++++++- .../tests/config/define-doc/index.test.ts | 2 +- .../config/reload-app-config/index.test.ts | 4 +- .../config/reload-doc-config/docs/index.md | 1 + .../config/reload-doc-config/index.test.ts | 80 +++++++++++++++++++ 6 files changed, 112 insertions(+), 5 deletions(-) create mode 100644 packages/rstack/tests/config/reload-doc-config/docs/index.md create mode 100644 packages/rstack/tests/config/reload-doc-config/index.test.ts diff --git a/packages/rstack/rstack.config.ts b/packages/rstack/rstack.config.ts index 650c9379..09910407 100644 --- a/packages/rstack/rstack.config.ts +++ b/packages/rstack/rstack.config.ts @@ -11,6 +11,7 @@ define.test(async () => { // Temporary projects may contain files that match Rstest's test glob. exclude: ['**/test-temp-*/**'], extends: withRslibConfig(), + testTimeout: 30_000, source: { tsconfigPath: './tests/tsconfig.json', }, diff --git a/packages/rstack/src/rspressConfig.ts b/packages/rstack/src/rspressConfig.ts index ed5efd59..0bf6a60d 100644 --- a/packages/rstack/src/rspressConfig.ts +++ b/packages/rstack/src/rspressConfig.ts @@ -1,3 +1,4 @@ +import type { WatchFiles } from '@rsbuild/core'; import type { UserConfig } from '@rspress/core'; import { loadRstackConfig, type Configs } from './config.ts'; @@ -13,6 +14,30 @@ const resolveRspressConfig = async (configs: Configs): Promise => { }; export default async (): Promise => { - const { configs } = await loadRstackConfig(); - return resolveRspressConfig(configs); + const { configs, filePath, dependencies } = await loadRstackConfig(); + const config = await resolveRspressConfig(configs); + + if (!filePath) { + return config; + } + + const watchFiles = config.builderConfig?.dev?.watchFiles; + const watchConfig: WatchFiles = { + paths: [filePath, ...dependencies], + type: 'restart', + }; + + return { + ...config, + builderConfig: { + ...config.builderConfig, + dev: { + ...config.builderConfig?.dev, + watchFiles: [ + ...(watchFiles ? (Array.isArray(watchFiles) ? watchFiles : [watchFiles]) : []), + watchConfig, + ], + }, + }, + }; }; diff --git a/packages/rstack/tests/config/define-doc/index.test.ts b/packages/rstack/tests/config/define-doc/index.test.ts index 58ce1fc4..464e7580 100644 --- a/packages/rstack/tests/config/define-doc/index.test.ts +++ b/packages/rstack/tests/config/define-doc/index.test.ts @@ -12,4 +12,4 @@ test('should build docs with define.doc config', async ({ prepareDist, execCli, const output = getFileContent(files, 'index.html'); expect(output).toContain(expectedText); -}, 30_000); +}); diff --git a/packages/rstack/tests/config/reload-app-config/index.test.ts b/packages/rstack/tests/config/reload-app-config/index.test.ts index cdf62067..a7f9ab93 100644 --- a/packages/rstack/tests/config/reload-app-config/index.test.ts +++ b/packages/rstack/tests/config/reload-app-config/index.test.ts @@ -45,7 +45,7 @@ define.app({ ); await waitForFile(dist2); -}, 30_000); +}); test('should reload config when an imported file changes', async ({ execCliAsync, logHelper }) => { const configFile = path.join(import.meta.dirname, 'test-temp-import.config.ts'); @@ -70,4 +70,4 @@ define.app({ await writeFile(importedFile, '// changed\n'); await logHelper.expectLog('restarting server as test-temp-imported.ts changed'); -}, 30_000); +}); diff --git a/packages/rstack/tests/config/reload-doc-config/docs/index.md b/packages/rstack/tests/config/reload-doc-config/docs/index.md new file mode 100644 index 00000000..f5a6303d --- /dev/null +++ b/packages/rstack/tests/config/reload-doc-config/docs/index.md @@ -0,0 +1 @@ +# Reload doc config diff --git a/packages/rstack/tests/config/reload-doc-config/index.test.ts b/packages/rstack/tests/config/reload-doc-config/index.test.ts new file mode 100644 index 00000000..0b00474b --- /dev/null +++ b/packages/rstack/tests/config/reload-doc-config/index.test.ts @@ -0,0 +1,80 @@ +import { writeFile } from 'node:fs/promises'; +import path from 'node:path'; +import { getRandomPort } from '@rstackjs/test-utils'; +import { test } from '#test-helpers'; + +test('should restart doc dev server when Rstack config changes', async ({ + execCliAsync, + logHelper, +}) => { + const configFile = path.join(import.meta.dirname, 'test-temp-rstack.config.ts'); + const userWatchFile = path.join(import.meta.dirname, 'test-temp-user-watch.txt'); + + const writeConfig = (title: string) => + writeFile( + configFile, + `import { define } from 'rstack'; + +define.doc({ + root: 'docs', + title: '${title}', + builderConfig: { + dev: { + watchFiles: { + paths: ${JSON.stringify(userWatchFile)}, + type: 'restart', + }, + }, + }, +}); +`, + ); + + await writeFile(userWatchFile, 'initial\n'); + await writeConfig('before config change'); + + execCliAsync(`doc --config test-temp-rstack.config.ts --port ${await getRandomPort()}`); + await logHelper.expectBuildEnd(); + logHelper.clearLogs(); + + await writeConfig('after config change'); + + await logHelper.expectLog('restarting server as test-temp-rstack.config.ts changed'); + await logHelper.expectBuildEnd(); + logHelper.clearLogs(); + + await writeFile(userWatchFile, 'changed\n'); + + await logHelper.expectLog('restarting server as test-temp-user-watch.txt changed'); + await logHelper.expectBuildEnd(); +}); + +test('should restart doc dev server when an imported config file changes', async ({ + execCliAsync, + logHelper, +}) => { + const configFile = path.join(import.meta.dirname, 'test-temp-import.config.ts'); + const importedFile = path.join(import.meta.dirname, 'test-temp-imported.ts'); + + await writeFile(importedFile, "export const title = 'before import change';\n"); + await writeFile( + configFile, + `import { define } from 'rstack'; +import { title } from './test-temp-imported.ts'; + +define.doc({ + root: 'docs', + title, +}); +`, + ); + + execCliAsync(`doc --config test-temp-import.config.ts --port ${await getRandomPort()}`); + await logHelper.expectBuildEnd(); + logHelper.clearLogs(); + + await writeFile(importedFile, "export const title = 'after import change';\n"); + + await logHelper.expectLog('restarting server as test-temp-imported.ts changed'); + await logHelper.expectBuildEnd(); +}); From 9f6f61b6d316c348bdf207ee0efd4df68faf2878 Mon Sep 17 00:00:00 2001 From: Jiahan Chen Date: Fri, 14 Aug 2026 13:22:36 +0800 Subject: [PATCH 24/33] docs: update website logo (#359) --- website/docs/public/horizontal-logo.svg | 1 + website/rstack.config.ts | 2 +- website/theme/index.scss | 4 ++++ 3 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 website/docs/public/horizontal-logo.svg diff --git a/website/docs/public/horizontal-logo.svg b/website/docs/public/horizontal-logo.svg new file mode 100644 index 00000000..ca1eac2d --- /dev/null +++ b/website/docs/public/horizontal-logo.svg @@ -0,0 +1 @@ +Rstack CLI horizontal logo lockup. The claw logo is embedded from the original source without changes. \ No newline at end of file diff --git a/website/rstack.config.ts b/website/rstack.config.ts index 338cad02..aa78c750 100644 --- a/website/rstack.config.ts +++ b/website/rstack.config.ts @@ -22,7 +22,7 @@ define.doc(async () => { root: path.join(import.meta.dirname, 'docs'), title, icon: 'https://assets.rspack.rs/rspack/rspack-claw-logo.svg', - logoText: title, + logo: '/horizontal-logo.svg', description, lang: 'en', llms: true, diff --git a/website/theme/index.scss b/website/theme/index.scss index e9b4f959..9fde95d7 100644 --- a/website/theme/index.scss +++ b/website/theme/index.scss @@ -13,6 +13,10 @@ } } +.rspress-logo { + height: 1.8rem; +} + .rp-doc { .rp-link, .rp-link code { From 78972cb94c40ea66842cca6121867a39068fae8e Mon Sep 17 00:00:00 2001 From: Jiahan Chen Date: Fri, 14 Aug 2026 13:34:12 +0800 Subject: [PATCH 25/33] fix(lib): restart on config changes (#360) --- packages/rstack/src/rslibConfig.ts | 26 +++++- .../config/reload-lib-config/index.test.ts | 90 +++++++++++++++++++ .../config/reload-lib-config/package.json | 4 + .../config/reload-lib-config/src/index.js | 1 + 4 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 packages/rstack/tests/config/reload-lib-config/index.test.ts create mode 100644 packages/rstack/tests/config/reload-lib-config/package.json create mode 100644 packages/rstack/tests/config/reload-lib-config/src/index.js diff --git a/packages/rstack/src/rslibConfig.ts b/packages/rstack/src/rslibConfig.ts index 6f0011ed..b7468aa4 100644 --- a/packages/rstack/src/rslibConfig.ts +++ b/packages/rstack/src/rslibConfig.ts @@ -1,3 +1,4 @@ +import type { WatchFiles } from '@rsbuild/core'; import type { ConfigParams, RslibConfig, RslibConfigDefinition } from '@rslib/core'; import { loadRstackConfig, type Configs } from './config.ts'; @@ -13,8 +14,29 @@ const resolveRslibConfig = async (configs: Configs, params: ConfigParams): Promi }; const loadRslibConfig = (async (params: ConfigParams) => { - const { configs } = await loadRstackConfig(); - return resolveRslibConfig(configs, params); + const { configs, filePath, dependencies } = await loadRstackConfig(); + const config = await resolveRslibConfig(configs, params); + + if (!filePath) { + return config; + } + + const watchFiles = config.dev?.watchFiles; + const watchConfig: WatchFiles = { + paths: [filePath, ...dependencies], + type: 'restart', + }; + + return { + ...config, + dev: { + ...config.dev, + watchFiles: [ + ...(watchFiles ? (Array.isArray(watchFiles) ? watchFiles : [watchFiles]) : []), + watchConfig, + ], + }, + }; }) as RslibConfigDefinition; export default loadRslibConfig; diff --git a/packages/rstack/tests/config/reload-lib-config/index.test.ts b/packages/rstack/tests/config/reload-lib-config/index.test.ts new file mode 100644 index 00000000..a793c158 --- /dev/null +++ b/packages/rstack/tests/config/reload-lib-config/index.test.ts @@ -0,0 +1,90 @@ +import { writeFile } from 'node:fs/promises'; +import path from 'node:path'; +import { waitForFile } from '@rstackjs/test-utils'; +import { test } from '#test-helpers'; + +test('should restart lib watch build when Rstack config changes', async ({ + prepareDist, + execCliAsync, + logHelper, +}) => { + const dist1 = await prepareDist(); + const dist2 = await prepareDist('dist-2'); + const configFile = path.join(import.meta.dirname, 'test-temp-rstack.config.ts'); + const userWatchFile = path.join(import.meta.dirname, 'test-temp-user-watch.txt'); + + const writeConfig = (distPath: string) => + writeFile( + configFile, + `import { define } from 'rstack'; + +define.lib({ + dev: { + watchFiles: { + paths: ${JSON.stringify(userWatchFile)}, + type: 'restart', + }, + }, + output: { + distPath: '${distPath}', + }, +}); +`, + ); + + await writeFile(userWatchFile, 'initial\n'); + await writeConfig('dist'); + + execCliAsync('lib --watch --config test-temp-rstack.config.ts'); + await logHelper.expectLog('build completed, watching for changes...'); + await waitForFile(path.join(dist1, 'index.js')); + logHelper.clearLogs(); + + await writeConfig('dist-2'); + + await logHelper.expectLog('restarting build as test-temp-rstack.config.ts changed'); + await logHelper.expectLog('build completed, watching for changes...'); + await waitForFile(path.join(dist2, 'index.js')); + logHelper.clearLogs(); + + await writeFile(userWatchFile, 'changed\n'); + + await logHelper.expectLog('restarting build as test-temp-user-watch.txt changed'); + await logHelper.expectLog('build completed, watching for changes...'); +}); + +test('should restart lib watch build when an imported config file changes', async ({ + prepareDist, + execCliAsync, + logHelper, +}) => { + const dist1 = await prepareDist('dist-import-1'); + const dist2 = await prepareDist('dist-import-2'); + const configFile = path.join(import.meta.dirname, 'test-temp-import.config.ts'); + const importedFile = path.join(import.meta.dirname, 'test-temp-imported.ts'); + + await writeFile(importedFile, "export const distPath = 'dist-import-1';\n"); + await writeFile( + configFile, + `import { define } from 'rstack'; +import { distPath } from './test-temp-imported.ts'; + +define.lib({ + output: { + distPath, + }, +}); +`, + ); + + execCliAsync('lib --watch --config test-temp-import.config.ts'); + await logHelper.expectLog('build completed, watching for changes...'); + await waitForFile(path.join(dist1, 'index.js')); + logHelper.clearLogs(); + + await writeFile(importedFile, "export const distPath = 'dist-import-2';\n"); + + await logHelper.expectLog('restarting build as test-temp-imported.ts changed'); + await logHelper.expectLog('build completed, watching for changes...'); + await waitForFile(path.join(dist2, 'index.js')); +}); diff --git a/packages/rstack/tests/config/reload-lib-config/package.json b/packages/rstack/tests/config/reload-lib-config/package.json new file mode 100644 index 00000000..e986b24b --- /dev/null +++ b/packages/rstack/tests/config/reload-lib-config/package.json @@ -0,0 +1,4 @@ +{ + "private": true, + "type": "module" +} diff --git a/packages/rstack/tests/config/reload-lib-config/src/index.js b/packages/rstack/tests/config/reload-lib-config/src/index.js new file mode 100644 index 00000000..c62c9ec3 --- /dev/null +++ b/packages/rstack/tests/config/reload-lib-config/src/index.js @@ -0,0 +1 @@ +export const value = 'reload lib config'; From bfb48aab5a39564e3420136f37b7dad47dab42d6 Mon Sep 17 00:00:00 2001 From: Jiahan Chen Date: Fri, 14 Aug 2026 13:41:32 +0800 Subject: [PATCH 26/33] chore: align async config formatting (#361) --- packages/create-rstack/template-app-preact-ts/rstack.config.ts | 1 - packages/create-rstack/template-app-preact/rstack.config.js | 1 - packages/create-rstack/template-app-react-ts/rstack.config.ts | 1 - packages/create-rstack/template-app-react/rstack.config.js | 1 - packages/create-rstack/template-app-solid-ts/rstack.config.ts | 1 - packages/create-rstack/template-app-solid/rstack.config.js | 1 - packages/create-rstack/template-app-svelte-ts/rstack.config.ts | 1 - packages/create-rstack/template-app-svelte/rstack.config.js | 1 - packages/create-rstack/template-app-vue-ts/rstack.config.ts | 1 - packages/create-rstack/template-app-vue/rstack.config.js | 1 - packages/create-rstack/template-lib-react-ts/rstack.config.ts | 1 - packages/create-rstack/template-lib-react/rstack.config.js | 1 - packages/create-rstack/template-lib-solid-ts/rstack.config.ts | 2 -- packages/create-rstack/template-lib-solid/rstack.config.js | 2 -- packages/create-rstack/template-lib-svelte-ts/rstack.config.ts | 1 - packages/create-rstack/template-lib-svelte/rstack.config.js | 1 - packages/create-rstack/template-lib-vue-ts/rstack.config.ts | 1 - packages/create-rstack/template-lib-vue/rstack.config.js | 1 - website/docs/en/guide/configuration.mdx | 1 - website/docs/en/guide/monorepo.mdx | 1 - website/docs/zh/guide/configuration.mdx | 1 - website/docs/zh/guide/monorepo.mdx | 1 - 22 files changed, 24 deletions(-) diff --git a/packages/create-rstack/template-app-preact-ts/rstack.config.ts b/packages/create-rstack/template-app-preact-ts/rstack.config.ts index ee37cab6..e1ec7e4d 100644 --- a/packages/create-rstack/template-app-preact-ts/rstack.config.ts +++ b/packages/create-rstack/template-app-preact-ts/rstack.config.ts @@ -3,7 +3,6 @@ import { define } from 'rstack'; define.app(async () => { const { pluginPreact } = await import('@rsbuild/plugin-preact'); - return { plugins: [pluginPreact()], }; diff --git a/packages/create-rstack/template-app-preact/rstack.config.js b/packages/create-rstack/template-app-preact/rstack.config.js index 7959e79f..0c586e57 100644 --- a/packages/create-rstack/template-app-preact/rstack.config.js +++ b/packages/create-rstack/template-app-preact/rstack.config.js @@ -4,7 +4,6 @@ import { define } from 'rstack'; define.app(async () => { const { pluginPreact } = await import('@rsbuild/plugin-preact'); - return { plugins: [pluginPreact()], }; diff --git a/packages/create-rstack/template-app-react-ts/rstack.config.ts b/packages/create-rstack/template-app-react-ts/rstack.config.ts index 76da1357..b6214713 100644 --- a/packages/create-rstack/template-app-react-ts/rstack.config.ts +++ b/packages/create-rstack/template-app-react-ts/rstack.config.ts @@ -3,7 +3,6 @@ import { define } from 'rstack'; define.app(async () => { const { pluginReact } = await import('@rsbuild/plugin-react'); - return { plugins: [pluginReact()], }; diff --git a/packages/create-rstack/template-app-react/rstack.config.js b/packages/create-rstack/template-app-react/rstack.config.js index 9469b706..e01ac564 100644 --- a/packages/create-rstack/template-app-react/rstack.config.js +++ b/packages/create-rstack/template-app-react/rstack.config.js @@ -4,7 +4,6 @@ import { define } from 'rstack'; define.app(async () => { const { pluginReact } = await import('@rsbuild/plugin-react'); - return { plugins: [pluginReact()], }; diff --git a/packages/create-rstack/template-app-solid-ts/rstack.config.ts b/packages/create-rstack/template-app-solid-ts/rstack.config.ts index 0c2e91b5..17f42c04 100644 --- a/packages/create-rstack/template-app-solid-ts/rstack.config.ts +++ b/packages/create-rstack/template-app-solid-ts/rstack.config.ts @@ -4,7 +4,6 @@ import { define } from 'rstack'; define.app(async () => { const { pluginBabel } = await import('@rsbuild/plugin-babel'); const { pluginSolid } = await import('@rsbuild/plugin-solid'); - return { plugins: [ pluginBabel({ diff --git a/packages/create-rstack/template-app-solid/rstack.config.js b/packages/create-rstack/template-app-solid/rstack.config.js index ac5ced95..035c1408 100644 --- a/packages/create-rstack/template-app-solid/rstack.config.js +++ b/packages/create-rstack/template-app-solid/rstack.config.js @@ -5,7 +5,6 @@ import { define } from 'rstack'; define.app(async () => { const { pluginBabel } = await import('@rsbuild/plugin-babel'); const { pluginSolid } = await import('@rsbuild/plugin-solid'); - return { plugins: [ pluginBabel({ diff --git a/packages/create-rstack/template-app-svelte-ts/rstack.config.ts b/packages/create-rstack/template-app-svelte-ts/rstack.config.ts index b09e259c..aaf917a8 100644 --- a/packages/create-rstack/template-app-svelte-ts/rstack.config.ts +++ b/packages/create-rstack/template-app-svelte-ts/rstack.config.ts @@ -3,7 +3,6 @@ import { define } from 'rstack'; define.app(async () => { const { pluginSvelte } = await import('@rsbuild/plugin-svelte'); - return { plugins: [pluginSvelte()], }; diff --git a/packages/create-rstack/template-app-svelte/rstack.config.js b/packages/create-rstack/template-app-svelte/rstack.config.js index 6450bb86..a1efbfc7 100644 --- a/packages/create-rstack/template-app-svelte/rstack.config.js +++ b/packages/create-rstack/template-app-svelte/rstack.config.js @@ -4,7 +4,6 @@ import { define } from 'rstack'; define.app(async () => { const { pluginSvelte } = await import('@rsbuild/plugin-svelte'); - return { plugins: [pluginSvelte()], }; diff --git a/packages/create-rstack/template-app-vue-ts/rstack.config.ts b/packages/create-rstack/template-app-vue-ts/rstack.config.ts index e1133986..97e764c0 100644 --- a/packages/create-rstack/template-app-vue-ts/rstack.config.ts +++ b/packages/create-rstack/template-app-vue-ts/rstack.config.ts @@ -3,7 +3,6 @@ import { define } from 'rstack'; define.app(async () => { const { pluginVue } = await import('@rsbuild/plugin-vue'); - return { plugins: [pluginVue()], }; diff --git a/packages/create-rstack/template-app-vue/rstack.config.js b/packages/create-rstack/template-app-vue/rstack.config.js index 199e7340..8116b0df 100644 --- a/packages/create-rstack/template-app-vue/rstack.config.js +++ b/packages/create-rstack/template-app-vue/rstack.config.js @@ -4,7 +4,6 @@ import { define } from 'rstack'; define.app(async () => { const { pluginVue } = await import('@rsbuild/plugin-vue'); - return { plugins: [pluginVue()], }; diff --git a/packages/create-rstack/template-lib-react-ts/rstack.config.ts b/packages/create-rstack/template-lib-react-ts/rstack.config.ts index a6ef9b74..8c91acb5 100644 --- a/packages/create-rstack/template-lib-react-ts/rstack.config.ts +++ b/packages/create-rstack/template-lib-react-ts/rstack.config.ts @@ -3,7 +3,6 @@ import { define } from 'rstack'; define.lib(async () => { const { pluginReact } = await import('@rsbuild/plugin-react'); - return { bundle: false, dts: true, diff --git a/packages/create-rstack/template-lib-react/rstack.config.js b/packages/create-rstack/template-lib-react/rstack.config.js index 663d1744..12fc5223 100644 --- a/packages/create-rstack/template-lib-react/rstack.config.js +++ b/packages/create-rstack/template-lib-react/rstack.config.js @@ -4,7 +4,6 @@ import { define } from 'rstack'; define.lib(async () => { const { pluginReact } = await import('@rsbuild/plugin-react'); - return { bundle: false, source: { diff --git a/packages/create-rstack/template-lib-solid-ts/rstack.config.ts b/packages/create-rstack/template-lib-solid-ts/rstack.config.ts index 04122368..3fa4dc06 100644 --- a/packages/create-rstack/template-lib-solid-ts/rstack.config.ts +++ b/packages/create-rstack/template-lib-solid-ts/rstack.config.ts @@ -4,7 +4,6 @@ import { define } from 'rstack'; define.lib(async () => { const { pluginBabel } = await import('@rsbuild/plugin-babel'); const { pluginSolid } = await import('@rsbuild/plugin-solid'); - return { lib: [ { @@ -63,7 +62,6 @@ define.lib(async () => { define.test(async () => { const { pluginBabel } = await import('@rsbuild/plugin-babel'); const { pluginSolid } = await import('@rsbuild/plugin-solid'); - return { setupFiles: ['./tests/rstest.setup.ts'], plugins: [ diff --git a/packages/create-rstack/template-lib-solid/rstack.config.js b/packages/create-rstack/template-lib-solid/rstack.config.js index b1eb7d49..0e2a8f3e 100644 --- a/packages/create-rstack/template-lib-solid/rstack.config.js +++ b/packages/create-rstack/template-lib-solid/rstack.config.js @@ -5,7 +5,6 @@ import { define } from 'rstack'; define.lib(async () => { const { pluginBabel } = await import('@rsbuild/plugin-babel'); const { pluginSolid } = await import('@rsbuild/plugin-solid'); - return { lib: [ { @@ -63,7 +62,6 @@ define.lib(async () => { define.test(async () => { const { pluginBabel } = await import('@rsbuild/plugin-babel'); const { pluginSolid } = await import('@rsbuild/plugin-solid'); - return { setupFiles: ['./tests/rstest.setup.js'], plugins: [ diff --git a/packages/create-rstack/template-lib-svelte-ts/rstack.config.ts b/packages/create-rstack/template-lib-svelte-ts/rstack.config.ts index 71f23a4a..0d168520 100644 --- a/packages/create-rstack/template-lib-svelte-ts/rstack.config.ts +++ b/packages/create-rstack/template-lib-svelte-ts/rstack.config.ts @@ -4,7 +4,6 @@ import { svelteDtsPlugin } from './scripts/rslib-plugin-svelte-dts.ts'; define.lib(async () => { const { pluginSvelte } = await import('@rsbuild/plugin-svelte'); - return { bundle: false, source: { diff --git a/packages/create-rstack/template-lib-svelte/rstack.config.js b/packages/create-rstack/template-lib-svelte/rstack.config.js index 7b7c5f3c..d0ccb0f4 100644 --- a/packages/create-rstack/template-lib-svelte/rstack.config.js +++ b/packages/create-rstack/template-lib-svelte/rstack.config.js @@ -4,7 +4,6 @@ import { define } from 'rstack'; define.lib(async () => { const { pluginSvelte } = await import('@rsbuild/plugin-svelte'); - return { bundle: false, source: { diff --git a/packages/create-rstack/template-lib-vue-ts/rstack.config.ts b/packages/create-rstack/template-lib-vue-ts/rstack.config.ts index a70a064d..e441042e 100644 --- a/packages/create-rstack/template-lib-vue-ts/rstack.config.ts +++ b/packages/create-rstack/template-lib-vue-ts/rstack.config.ts @@ -3,7 +3,6 @@ import { define } from 'rstack'; define.lib(async () => { const { pluginVue } = await import('@rsbuild/plugin-vue'); - return { bundle: false, source: { diff --git a/packages/create-rstack/template-lib-vue/rstack.config.js b/packages/create-rstack/template-lib-vue/rstack.config.js index db019b91..cd42bd0d 100644 --- a/packages/create-rstack/template-lib-vue/rstack.config.js +++ b/packages/create-rstack/template-lib-vue/rstack.config.js @@ -4,7 +4,6 @@ import { define } from 'rstack'; define.lib(async () => { const { pluginVue } = await import('@rsbuild/plugin-vue'); - return { bundle: false, source: { diff --git a/website/docs/en/guide/configuration.mdx b/website/docs/en/guide/configuration.mdx index 49d110f6..9b3d8283 100644 --- a/website/docs/en/guide/configuration.mdx +++ b/website/docs/en/guide/configuration.mdx @@ -55,7 +55,6 @@ import { define } from 'rstack'; define.app(async () => { const { pluginReact } = await import('@rsbuild/plugin-react'); - return { plugins: [pluginReact()], }; diff --git a/website/docs/en/guide/monorepo.mdx b/website/docs/en/guide/monorepo.mdx index 152b8ddc..88c6cfce 100644 --- a/website/docs/en/guide/monorepo.mdx +++ b/website/docs/en/guide/monorepo.mdx @@ -109,7 +109,6 @@ import { define } from 'rstack'; define.app(async () => { const { pluginReact } = await import('@rsbuild/plugin-react'); - return { plugins: [pluginReact()], }; diff --git a/website/docs/zh/guide/configuration.mdx b/website/docs/zh/guide/configuration.mdx index 4f370874..dc3d8fde 100644 --- a/website/docs/zh/guide/configuration.mdx +++ b/website/docs/zh/guide/configuration.mdx @@ -55,7 +55,6 @@ import { define } from 'rstack'; define.app(async () => { const { pluginReact } = await import('@rsbuild/plugin-react'); - return { plugins: [pluginReact()], }; diff --git a/website/docs/zh/guide/monorepo.mdx b/website/docs/zh/guide/monorepo.mdx index ae93fee3..ab8671db 100644 --- a/website/docs/zh/guide/monorepo.mdx +++ b/website/docs/zh/guide/monorepo.mdx @@ -109,7 +109,6 @@ import { define } from 'rstack'; define.app(async () => { const { pluginReact } = await import('@rsbuild/plugin-react'); - return { plugins: [pluginReact()], }; From 41cc37174a2f7d1e0a604a7846703bada32268cc Mon Sep 17 00:00:00 2001 From: Jiahan Chen Date: Fri, 14 Aug 2026 14:01:33 +0800 Subject: [PATCH 27/33] refactor(test): update inline projects example (#362) --- .../rstest-inline-projects/rstack.config.ts | 26 ------------------ .../package.json | 2 +- .../test-inline-projects/rstack.config.ts | 27 +++++++++++++++++++ .../src/App.tsx | 0 .../src/index.tsx | 0 .../tests/dom.test.tsx | 0 .../tests/ssr.test.tsx | 0 .../tsconfig.json | 0 pnpm-lock.yaml | 24 ++++++++++++++--- website/docs/en/guide/testing.mdx | 2 +- website/docs/zh/guide/testing.mdx | 2 +- 11 files changed, 51 insertions(+), 32 deletions(-) delete mode 100644 examples/rstest-inline-projects/rstack.config.ts rename examples/{rstest-inline-projects => test-inline-projects}/package.json (92%) create mode 100644 examples/test-inline-projects/rstack.config.ts rename examples/{rstest-inline-projects => test-inline-projects}/src/App.tsx (100%) rename examples/{rstest-inline-projects => test-inline-projects}/src/index.tsx (100%) rename examples/{rstest-inline-projects => test-inline-projects}/tests/dom.test.tsx (100%) rename examples/{rstest-inline-projects => test-inline-projects}/tests/ssr.test.tsx (100%) rename examples/{rstest-inline-projects => test-inline-projects}/tsconfig.json (100%) diff --git a/examples/rstest-inline-projects/rstack.config.ts b/examples/rstest-inline-projects/rstack.config.ts deleted file mode 100644 index 501912cb..00000000 --- a/examples/rstest-inline-projects/rstack.config.ts +++ /dev/null @@ -1,26 +0,0 @@ -// Rstack configuration guide: https://rstack.rs/config -import { define } from 'rstack'; -import { defineInlineProject } from 'rstack/test'; - -define.app(async () => { - const { pluginReact } = await import('@rsbuild/plugin-react'); - - return { - plugins: [pluginReact()], - }; -}); - -define.test({ - projects: [ - defineInlineProject({ - name: 'ssr', - include: ['./tests/ssr.test.tsx'], - testEnvironment: 'node', - }), - defineInlineProject({ - name: 'dom', - include: ['./tests/dom.test.tsx'], - testEnvironment: 'happy-dom', - }), - ], -}); diff --git a/examples/rstest-inline-projects/package.json b/examples/test-inline-projects/package.json similarity index 92% rename from examples/rstest-inline-projects/package.json rename to examples/test-inline-projects/package.json index 4fea5d03..b1ddaad1 100644 --- a/examples/rstest-inline-projects/package.json +++ b/examples/test-inline-projects/package.json @@ -1,5 +1,5 @@ { - "name": "@examples/rstest-inline-projects", + "name": "@examples/test-inline-projects", "private": true, "type": "module", "scripts": { diff --git a/examples/test-inline-projects/rstack.config.ts b/examples/test-inline-projects/rstack.config.ts new file mode 100644 index 00000000..12fa4e57 --- /dev/null +++ b/examples/test-inline-projects/rstack.config.ts @@ -0,0 +1,27 @@ +// Rstack configuration guide: https://rstack.rs/config +import { define } from 'rstack'; + +define.app(async () => { + const { pluginReact } = await import('@rsbuild/plugin-react'); + return { + plugins: [pluginReact()], + }; +}); + +define.test(async () => { + const { defineInlineProject } = await import('rstack/test'); + return { + projects: [ + defineInlineProject({ + name: 'ssr', + include: ['./tests/ssr.test.tsx'], + testEnvironment: 'node', + }), + defineInlineProject({ + name: 'dom', + include: ['./tests/dom.test.tsx'], + testEnvironment: 'happy-dom', + }), + ], + }; +}); diff --git a/examples/rstest-inline-projects/src/App.tsx b/examples/test-inline-projects/src/App.tsx similarity index 100% rename from examples/rstest-inline-projects/src/App.tsx rename to examples/test-inline-projects/src/App.tsx diff --git a/examples/rstest-inline-projects/src/index.tsx b/examples/test-inline-projects/src/index.tsx similarity index 100% rename from examples/rstest-inline-projects/src/index.tsx rename to examples/test-inline-projects/src/index.tsx diff --git a/examples/rstest-inline-projects/tests/dom.test.tsx b/examples/test-inline-projects/tests/dom.test.tsx similarity index 100% rename from examples/rstest-inline-projects/tests/dom.test.tsx rename to examples/test-inline-projects/tests/dom.test.tsx diff --git a/examples/rstest-inline-projects/tests/ssr.test.tsx b/examples/test-inline-projects/tests/ssr.test.tsx similarity index 100% rename from examples/rstest-inline-projects/tests/ssr.test.tsx rename to examples/test-inline-projects/tests/ssr.test.tsx diff --git a/examples/rstest-inline-projects/tsconfig.json b/examples/test-inline-projects/tsconfig.json similarity index 100% rename from examples/rstest-inline-projects/tsconfig.json rename to examples/test-inline-projects/tsconfig.json diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 014fe63a..2e29deea 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -309,7 +309,7 @@ importers: specifier: 'catalog:' version: 7.0.2 - examples/rstest-inline-projects: + examples/test-inline-projects: dependencies: react: specifier: 'catalog:' @@ -320,7 +320,7 @@ importers: devDependencies: '@rsbuild/plugin-react': specifier: 'catalog:' - version: 2.1.0(@rsbuild/core@2.1.10)(@rspack/core@2.1.10) + version: 2.1.0(@rsbuild/core@2.1.12)(@rspack/core@2.1.10) '@testing-library/dom': specifier: 'catalog:' version: 10.4.1 @@ -3988,6 +3988,15 @@ snapshots: transitivePeerDependencies: - '@module-federation/runtime-tools' + '@rsbuild/plugin-react@2.1.0(@rsbuild/core@2.1.10)': + dependencies: + '@rspack/plugin-react-refresh': 2.0.2(@rspack/core@2.1.10)(react-refresh@0.18.0) + react-refresh: 0.18.0 + optionalDependencies: + '@rsbuild/core': 2.1.10 + transitivePeerDependencies: + - '@rspack/core' + '@rsbuild/plugin-react@2.1.0(@rsbuild/core@2.1.10)(@rspack/core@2.1.10)': dependencies: '@rspack/plugin-react-refresh': 2.0.2(@rspack/core@2.1.10)(react-refresh@0.18.0) @@ -3997,6 +4006,15 @@ snapshots: transitivePeerDependencies: - '@rspack/core' + '@rsbuild/plugin-react@2.1.0(@rsbuild/core@2.1.12)(@rspack/core@2.1.10)': + dependencies: + '@rspack/plugin-react-refresh': 2.0.2(@rspack/core@2.1.10)(react-refresh@0.18.0) + react-refresh: 0.18.0 + optionalDependencies: + '@rsbuild/core': 2.1.12 + transitivePeerDependencies: + - '@rspack/core' + '@rsbuild/plugin-sass@2.0.1(@rsbuild/core@2.1.10)': dependencies: deepmerge: 4.3.1 @@ -4264,7 +4282,7 @@ snapshots: '@mdx-js/mdx': 3.1.1(supports-color@8.1.1) '@mdx-js/react': 3.1.1(@types/react@19.2.18)(react@19.2.8) '@rsbuild/core': 2.1.10 - '@rsbuild/plugin-react': 2.1.0(@rsbuild/core@2.1.10)(@rspack/core@2.1.10) + '@rsbuild/plugin-react': 2.1.0(@rsbuild/core@2.1.10) '@rspress/shared': 2.0.19(supports-color@8.1.1) '@shikijs/rehype': 4.3.1 '@types/mdast': 4.0.4 diff --git a/website/docs/en/guide/testing.mdx b/website/docs/en/guide/testing.mdx index aa4a442a..5fcb5494 100644 --- a/website/docs/en/guide/testing.mdx +++ b/website/docs/en/guide/testing.mdx @@ -86,7 +86,7 @@ Run one project by name: rs test --project dom ``` -See [`examples/rstest-inline-projects`](https://github.com/rstackjs/rstack-cli/tree/main/examples/rstest-inline-projects) for a complete React SSR example using Node.js and happy-dom. +See [`examples/test-inline-projects`](https://github.com/rstackjs/rstack-cli/tree/main/examples/test-inline-projects) for a complete React SSR example using Node.js and happy-dom. ### External projects diff --git a/website/docs/zh/guide/testing.mdx b/website/docs/zh/guide/testing.mdx index 9c629635..fd969ad2 100644 --- a/website/docs/zh/guide/testing.mdx +++ b/website/docs/zh/guide/testing.mdx @@ -86,7 +86,7 @@ Rstack CLI 会将对应的适配器应用到每个未设置 `extends` 的内联 rs test --project dom ``` -完整的 React SSR 示例请参阅 [`examples/rstest-inline-projects`](https://github.com/rstackjs/rstack-cli/tree/main/examples/rstest-inline-projects),该示例使用 Node.js 和 happy-dom 两种测试环境。 +完整的 React SSR 示例请参阅 [`examples/test-inline-projects`](https://github.com/rstackjs/rstack-cli/tree/main/examples/test-inline-projects),该示例使用 Node.js 和 happy-dom 两种测试环境。 ### 外部项目 \{#external-projects} From dd3a04a930c59de6a8f24a5dfa76f60c99af16e8 Mon Sep 17 00:00:00 2001 From: Jiahan Chen Date: Fri, 14 Aug 2026 14:53:29 +0800 Subject: [PATCH 28/33] refactor(create-rstack): remove redundant test configs (#363) --- packages/create-rstack/template-app-lit-ts/rstack.config.ts | 4 ---- packages/create-rstack/template-app-lit/rstack.config.js | 4 ---- packages/create-rstack/template-lib-node-ts/rstack.config.ts | 4 ---- packages/create-rstack/template-lib-node/rstack.config.js | 4 ---- .../create-rstack/template-lib-svelte-ts/rstack.config.ts | 4 ---- packages/create-rstack/template-lib-svelte/rstack.config.js | 4 ---- 6 files changed, 24 deletions(-) diff --git a/packages/create-rstack/template-app-lit-ts/rstack.config.ts b/packages/create-rstack/template-app-lit-ts/rstack.config.ts index 84681d01..d7f664c7 100644 --- a/packages/create-rstack/template-app-lit-ts/rstack.config.ts +++ b/packages/create-rstack/template-app-lit-ts/rstack.config.ts @@ -12,10 +12,6 @@ define.app({ }, }); -define.test({ - testEnvironment: 'happy-dom', -}); - define.lint(({ js, ts }) => [ js.configs.recommended, ts.configs.recommendedTypeChecked, diff --git a/packages/create-rstack/template-app-lit/rstack.config.js b/packages/create-rstack/template-app-lit/rstack.config.js index 5b863543..4a74583c 100644 --- a/packages/create-rstack/template-app-lit/rstack.config.js +++ b/packages/create-rstack/template-app-lit/rstack.config.js @@ -13,10 +13,6 @@ define.app({ }, }); -define.test({ - testEnvironment: 'happy-dom', -}); - define.lint(({ js }) => [js.configs.recommended]); define.fmt({ diff --git a/packages/create-rstack/template-lib-node-ts/rstack.config.ts b/packages/create-rstack/template-lib-node-ts/rstack.config.ts index 28d8d881..76a7cb35 100644 --- a/packages/create-rstack/template-lib-node-ts/rstack.config.ts +++ b/packages/create-rstack/template-lib-node-ts/rstack.config.ts @@ -6,10 +6,6 @@ define.lib({ dts: true, }); -define.test({ - // Configure Rstest -}); - define.lint(({ js, ts }) => [ js.configs.recommended, ts.configs.recommendedTypeChecked, diff --git a/packages/create-rstack/template-lib-node/rstack.config.js b/packages/create-rstack/template-lib-node/rstack.config.js index f193d432..047c2d6c 100644 --- a/packages/create-rstack/template-lib-node/rstack.config.js +++ b/packages/create-rstack/template-lib-node/rstack.config.js @@ -6,10 +6,6 @@ define.lib({ syntax: ['node 22'], }); -define.test({ - // Configure Rstest -}); - define.lint(({ js }) => [js.configs.recommended]); define.fmt({ diff --git a/packages/create-rstack/template-lib-svelte-ts/rstack.config.ts b/packages/create-rstack/template-lib-svelte-ts/rstack.config.ts index 0d168520..b74a4f81 100644 --- a/packages/create-rstack/template-lib-svelte-ts/rstack.config.ts +++ b/packages/create-rstack/template-lib-svelte-ts/rstack.config.ts @@ -18,10 +18,6 @@ define.lib(async () => { }; }); -define.test({ - testEnvironment: 'happy-dom', -}); - define.lint(({ js, ts }) => [ js.configs.recommended, ts.configs.recommendedTypeChecked, diff --git a/packages/create-rstack/template-lib-svelte/rstack.config.js b/packages/create-rstack/template-lib-svelte/rstack.config.js index d0ccb0f4..4bbb928c 100644 --- a/packages/create-rstack/template-lib-svelte/rstack.config.js +++ b/packages/create-rstack/template-lib-svelte/rstack.config.js @@ -18,10 +18,6 @@ define.lib(async () => { }; }); -define.test({ - testEnvironment: 'happy-dom', -}); - define.lint(({ js }) => [js.configs.recommended]); define.fmt({ From cba6e5c35fb0c3225314327adfacfa14fdc109b1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 14 Aug 2026 18:03:41 +0000 Subject: [PATCH 29/33] fix(deps): update all non-major dependencies (#364) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .../template-app-svelte-ts/package.json | 4 +- .../template-app-svelte/package.json | 2 +- .../template-lib-svelte-ts/package.json | 6 +- .../template-lib-svelte/package.json | 2 +- pnpm-lock.yaml | 397 ++++++------------ pnpm-workspace.yaml | 14 +- rust-toolchain.toml | 2 +- 7 files changed, 133 insertions(+), 294 deletions(-) diff --git a/packages/create-rstack/template-app-svelte-ts/package.json b/packages/create-rstack/template-app-svelte-ts/package.json index 63910506..eeafeb60 100644 --- a/packages/create-rstack/template-app-svelte-ts/package.json +++ b/packages/create-rstack/template-app-svelte-ts/package.json @@ -14,7 +14,7 @@ "test:watch": "rs test --watch" }, "dependencies": { - "svelte": "^5.56.8" + "svelte": "^5.56.9" }, "devDependencies": { "@rsbuild/plugin-svelte": "^2.0.1", @@ -24,7 +24,7 @@ "happy-dom": "^20.11.2", "prettier-plugin-svelte": "^4.1.1", "rstack": "^0.6.1", - "svelte-check": "^4.7.5", + "svelte-check": "^4.7.6", "typescript": "^6.0.3" } } diff --git a/packages/create-rstack/template-app-svelte/package.json b/packages/create-rstack/template-app-svelte/package.json index e48dff5e..a0ba16f1 100644 --- a/packages/create-rstack/template-app-svelte/package.json +++ b/packages/create-rstack/template-app-svelte/package.json @@ -14,7 +14,7 @@ "test:watch": "rs test --watch" }, "dependencies": { - "svelte": "^5.56.8" + "svelte": "^5.56.9" }, "devDependencies": { "@rsbuild/plugin-svelte": "^2.0.1", diff --git a/packages/create-rstack/template-lib-svelte-ts/package.json b/packages/create-rstack/template-lib-svelte-ts/package.json index 4241ba47..15ad5f7f 100644 --- a/packages/create-rstack/template-lib-svelte-ts/package.json +++ b/packages/create-rstack/template-lib-svelte-ts/package.json @@ -28,9 +28,9 @@ "happy-dom": "^20.11.2", "prettier-plugin-svelte": "^4.1.1", "rstack": "^0.6.1", - "svelte": "^5.56.8", - "svelte-check": "^4.7.5", - "svelte2tsx": "^0.7.60", + "svelte": "^5.56.9", + "svelte-check": "^4.7.6", + "svelte2tsx": "^0.7.61", "typescript": "^6.0.3" }, "peerDependencies": { diff --git a/packages/create-rstack/template-lib-svelte/package.json b/packages/create-rstack/template-lib-svelte/package.json index b03e95af..5756c287 100644 --- a/packages/create-rstack/template-lib-svelte/package.json +++ b/packages/create-rstack/template-lib-svelte/package.json @@ -25,7 +25,7 @@ "happy-dom": "^20.11.2", "prettier-plugin-svelte": "^4.1.1", "rstack": "^0.6.1", - "svelte": "^5.56.8" + "svelte": "^5.56.9" }, "peerDependencies": { "svelte": "^5.0.0" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2e29deea..13440900 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,8 +11,8 @@ catalogs: specifier: ^3.8.6 version: 3.8.6 '@rsbuild/core': - specifier: ~2.1.11 - version: 2.1.11 + specifier: ~2.1.13 + version: 2.1.13 '@rsbuild/plugin-react': specifier: ^2.1.0 version: 2.1.0 @@ -47,14 +47,14 @@ catalogs: specifier: ^0.2.0 version: 0.2.0 '@rstest/adapter-rsbuild': - specifier: ~0.11.6 - version: 0.11.6 + specifier: ~0.11.8 + version: 0.11.8 '@rstest/adapter-rslib': - specifier: ~0.11.6 - version: 0.11.6 + specifier: ~0.11.8 + version: 0.11.8 '@rstest/core': - specifier: ~0.11.6 - version: 0.11.6 + specifier: ~0.11.8 + version: 0.11.8 '@shikijs/transformers': specifier: ^4.4.3 version: 4.4.3 @@ -86,8 +86,8 @@ catalogs: specifier: 2.1.0 version: 2.1.0 globals: - specifier: ^17.10.0 - version: 17.10.0 + specifier: ^17.11.0 + version: 17.11.0 happy-dom: specifier: ^20.11.2 version: 20.11.2 @@ -131,8 +131,8 @@ catalogs: specifier: 4.0.0 version: 4.0.0 svelte: - specifier: ^5.56.8 - version: 5.56.8 + specifier: ^5.56.9 + version: 5.56.9 tiny-readdir: specifier: 3.1.1 version: 3.1.1 @@ -149,8 +149,8 @@ catalogs: specifier: 1.0.12 version: 1.0.12 yuku-parser: - specifier: 0.8.5 - version: 0.8.5 + specifier: 0.8.7 + version: 0.8.7 importers: @@ -164,7 +164,7 @@ importers: version: 0.0.4 globals: specifier: 'catalog:' - version: 17.10.0 + version: 17.11.0 heading-case: specifier: 'catalog:' version: 1.1.5 @@ -320,7 +320,7 @@ importers: devDependencies: '@rsbuild/plugin-react': specifier: 'catalog:' - version: 2.1.0(@rsbuild/core@2.1.12)(@rspack/core@2.1.10) + version: 2.1.0(@rsbuild/core@2.1.13)(@rspack/core@2.1.10) '@testing-library/dom': specifier: 'catalog:' version: 10.4.1 @@ -366,7 +366,7 @@ importers: dependencies: '@rsbuild/core': specifier: 'catalog:' - version: 2.1.11 + version: 2.1.13 '@rslib/core': specifier: 'catalog:' version: 1.0.0-beta.3(typescript@7.0.2) @@ -375,7 +375,7 @@ importers: version: 0.8.0 '@rstest/core': specifier: 'catalog:' - version: 0.11.6(happy-dom@20.11.2) + version: 0.11.8(happy-dom@20.11.2) prettier: specifier: 'catalog:' version: 3.9.6 @@ -384,7 +384,7 @@ importers: version: 2.1.0 yuku-parser: specifier: 'catalog:' - version: 0.8.5 + version: 0.8.7 devDependencies: '@napi-rs/cli': specifier: 'catalog:' @@ -400,10 +400,10 @@ importers: version: 0.2.0 '@rstest/adapter-rsbuild': specifier: 'catalog:' - version: 0.11.6(@rsbuild/core@2.1.11)(@rstest/core@0.11.6) + version: 0.11.8(@rsbuild/core@2.1.13)(@rstest/core@0.11.8) '@rstest/adapter-rslib': specifier: 'catalog:' - version: 0.11.6(@rslib/core@1.0.0-beta.3)(@rstest/core@0.11.6)(typescript@7.0.2) + version: 0.11.8(@rslib/core@1.0.0-beta.3)(@rstest/core@0.11.8)(typescript@7.0.2) '@types/micromatch': specifier: 'catalog:' version: 4.0.10 @@ -427,7 +427,7 @@ importers: version: 4.0.8 prettier-plugin-svelte: specifier: 'catalog:' - version: 4.1.1(prettier@3.9.6)(svelte@5.56.8) + version: 4.1.1(prettier@3.9.6)(svelte@5.56.9) rslog: specifier: 'catalog:' version: 2.3.0 @@ -436,7 +436,7 @@ importers: version: 4.0.0 svelte: specifier: 'catalog:' - version: 5.56.8 + version: 5.56.9 tiny-readdir: specifier: 'catalog:' version: 3.1.1 @@ -1281,8 +1281,8 @@ packages: core-js: optional: true - '@rsbuild/core@2.1.11': - resolution: {integrity: sha512-jA/QwZu8wIljp70TjERVoX+vk2cWU+viHpV9EAdKpA6ifu/pFnThEhbV3RFxBvF/9mB3h7ZRUfdDIyknT+9MWA==} + '@rsbuild/core@2.1.12': + resolution: {integrity: sha512-xRqNHj/svDqeUzXPahmN4BdxEFCU1rxnVdjxyVV7WgsFfH+L3yAoQMJtIXVGhr00IQseDKkc3eonMF3NGrFj2Q==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -1291,8 +1291,8 @@ packages: core-js: optional: true - '@rsbuild/core@2.1.12': - resolution: {integrity: sha512-xRqNHj/svDqeUzXPahmN4BdxEFCU1rxnVdjxyVV7WgsFfH+L3yAoQMJtIXVGhr00IQseDKkc3eonMF3NGrFj2Q==} + '@rsbuild/core@2.1.13': + resolution: {integrity: sha512-Z+6MzmjOio4+bFZQ24k+7ge/oNCOdXIunAssrswTNE8AIf6mcyXpJZevRXRiOEMZasRPA8VNyh+9JngQLg729Q==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -1393,11 +1393,6 @@ packages: cpu: [arm64] os: [darwin] - '@rspack/binding-darwin-arm64@2.1.9': - resolution: {integrity: sha512-sQQgKx+1ckW5GI6w/ozJkoaQM0Skbwj7hFiv+Y2d7+iAB7OVz83LWFrodRl1QGCg1QNuaEmlVo9AUapWUSr/8g==} - cpu: [arm64] - os: [darwin] - '@rspack/binding-darwin-x64@2.1.10': resolution: {integrity: sha512-my/0h2LwxCRT6cg3oDDC2e0ZOxQLVajAdIcv0fqnQk5JRNvVuL89PuTutitnSqie1A0/JSL8OQz5XHwmoS3kow==} cpu: [x64] @@ -1408,11 +1403,6 @@ packages: cpu: [x64] os: [darwin] - '@rspack/binding-darwin-x64@2.1.9': - resolution: {integrity: sha512-kuWzn8JFKJUxSFwX/+rzvZUm4fRrSbXCTCAlzb0iHvP6vftjCFHGpNJfWjD7yX9O7C/dtoGiNT1O1veJytVsWA==} - cpu: [x64] - os: [darwin] - '@rspack/binding-linux-arm64-gnu@2.1.10': resolution: {integrity: sha512-laevn9g+E5PAUEGqiKe6Ju5KApsuQYp+bPI17XS3Lkl8eqL5pS/BmHYU7QMlst4GzV8+wlruVTMh//+st6Vqzg==} cpu: [arm64] @@ -1425,12 +1415,6 @@ packages: os: [linux] libc: [glibc] - '@rspack/binding-linux-arm64-gnu@2.1.9': - resolution: {integrity: sha512-rj1TjWGuG9Zc+fmwfvOpRO9npuHMKE4xXSB/BZqZNcH5Uey4NcAo1/GF8zHRoalQrwf0roP9WsFX1tk85rzP/Q==} - cpu: [arm64] - os: [linux] - libc: [glibc] - '@rspack/binding-linux-arm64-musl@2.1.10': resolution: {integrity: sha512-V71+Qz5G72+ROZXrJn5zxOszdG1AEbO8pcC/itXXtf4yRR6a3bVHKNKGhipBNxb8eI6cnD/01FH1h3ZG655jLw==} cpu: [arm64] @@ -1443,24 +1427,12 @@ packages: os: [linux] libc: [musl] - '@rspack/binding-linux-arm64-musl@2.1.9': - resolution: {integrity: sha512-Z2+sS2z9Imt3og0e3Kq4hEumiqTajQBXkl9cqSYj1lwOgmViLAvMX4BlCL1cinIEstixFKQ+xsta9SI6ivCKtg==} - cpu: [arm64] - os: [linux] - libc: [musl] - '@rspack/binding-linux-ppc64-gnu@2.1.10': resolution: {integrity: sha512-U7HlNzHcDtZ+LYOtOJmtx67kHEybZzUUAaP7aEXjGYO5WTCgh/176sW2UYP0rmZLrgUNFUuzn+B98RLaClNaVg==} cpu: [ppc64] os: [linux] libc: [glibc] - '@rspack/binding-linux-ppc64-gnu@2.1.9': - resolution: {integrity: sha512-xK90IHipRDgxvDF9n90HRNklci0G2Amk0ZMsM3t3YX+/8jIJNcuEPk6hJ1hlY6KZu7U9enqGbNQ7Fe0StBeLVA==} - cpu: [ppc64] - os: [linux] - libc: [glibc] - '@rspack/binding-linux-riscv64-gnu@2.1.10': resolution: {integrity: sha512-GMGTJpy9/ecE+5F5IfxZH4bXv0Wx/b2TiehTlCbTksbL+pKpLHYy0rwGdjWDKbmBkhxMMqPiC7PDnn9LbdnnLA==} cpu: [riscv64] @@ -1473,12 +1445,6 @@ packages: os: [linux] libc: [glibc] - '@rspack/binding-linux-riscv64-gnu@2.1.9': - resolution: {integrity: sha512-aaOwU3voq20Vwmfu1V6UPz8eQJBitBUNbLc08dxHGsmQM+ap6dd4j5xn/i5Y6AfLro2Q3GJvpCayc+dVIOR32g==} - cpu: [riscv64] - os: [linux] - libc: [glibc] - '@rspack/binding-linux-riscv64-musl@2.1.10': resolution: {integrity: sha512-rkurnAWc04vIbzG1QCrPBWSJadZvaOt1mazFH3EdiJO8VUiu0I1T9zdiwuDOPrd50lOKIZlcTXbd5aaAkWEnvQ==} cpu: [riscv64] @@ -1491,24 +1457,12 @@ packages: os: [linux] libc: [musl] - '@rspack/binding-linux-riscv64-musl@2.1.9': - resolution: {integrity: sha512-tF7XnEtpTYyVS8ef96IKUjFhd9lFa9Swv212fcyWxRhxRn4PEYVWpSh/D3NDVX+i69Z7xFDDEoyMUdYBkkVTlw==} - cpu: [riscv64] - os: [linux] - libc: [musl] - '@rspack/binding-linux-s390x-gnu@2.1.10': resolution: {integrity: sha512-X+DyxkriZEAF/wihI7ERDv+CAS0mbMv36aEuQ+vXzTlvS6cSmpou/r29AHbvIF3NlG1UeAbDVlOs9QrMBZjpUQ==} cpu: [s390x] os: [linux] libc: [glibc] - '@rspack/binding-linux-s390x-gnu@2.1.9': - resolution: {integrity: sha512-rGmeME3Pd8k/55txP+19ceZJxhVN2mtC8TLzB1ycTrhy8U+ZnN7J8rZSl89LYrZGYewd1UmOcY0QKKy05FS3FA==} - cpu: [s390x] - os: [linux] - libc: [glibc] - '@rspack/binding-linux-x64-gnu@2.1.10': resolution: {integrity: sha512-Fat09V6jUuyo9qG7Wyj9cQ31VDfLmokXyBtGqKxY5OvSWHereB7QUub5btbPXHwbp6Iq4aAQyUbbLTzvR1YaBw==} cpu: [x64] @@ -1521,12 +1475,6 @@ packages: os: [linux] libc: [glibc] - '@rspack/binding-linux-x64-gnu@2.1.9': - resolution: {integrity: sha512-YimUCS//wl+AZjXvgVig7sJtPiGs+WNMH4g49F1msB5T40rw0aOopp9O3MdC+LFfRm6vpIJwOHd6alo/UUs7nA==} - cpu: [x64] - os: [linux] - libc: [glibc] - '@rspack/binding-linux-x64-musl@2.1.10': resolution: {integrity: sha512-lhHOnIJ4ClpIlA1f1L8aoxEZivYLjnjq5A6jKKz7BKsm+cHK8kqqEm6lO5KqA5xQT0Lonq1o28bmKHEj6JHInw==} cpu: [x64] @@ -1539,12 +1487,6 @@ packages: os: [linux] libc: [musl] - '@rspack/binding-linux-x64-musl@2.1.9': - resolution: {integrity: sha512-tYJRdoB3IWVVcnGPZqCnRjC5MJle7xHucKkIuKtGbSMS6hzg6B1oKZav1BBw72gxnrW4n2Bwt82TBKQKBUSjmA==} - cpu: [x64] - os: [linux] - libc: [musl] - '@rspack/binding-wasm32-wasi@2.1.10': resolution: {integrity: sha512-KY5YbWbuvYcoaLXnV+vzZOvGRCeb6jt4EpVpKdph1h1IJjwX/ju15EQ+GOe3iecZEdf0OttQcNVcwBkLkFT9ag==} cpu: [wasm32] @@ -1553,10 +1495,6 @@ packages: resolution: {integrity: sha512-om7GAKWAU3lcSvbCon2m7mzw8v9OTrO2LW2MZ1lGe/uVJJmwGGkl9HVoXFyWFLrN6YVFyx8iP+AkN4owDWB9Cw==} cpu: [wasm32] - '@rspack/binding-wasm32-wasi@2.1.9': - resolution: {integrity: sha512-TF6oZRU23x6vHzGuvRFszvEnmC5Yn8PHbKmeZWsUHj4Mtv4tDdDGVdlxj6Kq3pySS6sRknv8gzpRMhXqHD3I5g==} - cpu: [wasm32] - '@rspack/binding-win32-arm64-msvc@2.1.10': resolution: {integrity: sha512-z4GWzMLofaDGpAt9Z+MlN88LlUBDm+zM6R2GdOOPM6/4g/h3/+47OP7casmSL3AwTGYBEJqogwt08sRSosB6Cg==} cpu: [arm64] @@ -1567,11 +1505,6 @@ packages: cpu: [arm64] os: [win32] - '@rspack/binding-win32-arm64-msvc@2.1.9': - resolution: {integrity: sha512-tLt4gbvUelmtJGI3PHtQHZuGpaO2z/ym6+OXAjc6NR2jWbzljardSjONiXVWIi1zmzODt4dD/fL3Ncb+RU/jHQ==} - cpu: [arm64] - os: [win32] - '@rspack/binding-win32-ia32-msvc@2.1.10': resolution: {integrity: sha512-7qcWdsZ+GuGtzKjqgy7wTN7Dso/ezIY8yhx1r2yIbcczdmXj4FhaEampMDp/25HwtKwIGBBoh6HHSt3JWxpTUg==} cpu: [ia32] @@ -1582,11 +1515,6 @@ packages: cpu: [ia32] os: [win32] - '@rspack/binding-win32-ia32-msvc@2.1.9': - resolution: {integrity: sha512-VznxSrGPb4mvxkTHTdGolEpBOuDW7RICD9Rp266MhYLQG4c0uNcX7+vWF4HbFvB0kN+Gdkj7vz+5shWdrfK72Q==} - cpu: [ia32] - os: [win32] - '@rspack/binding-win32-x64-msvc@2.1.10': resolution: {integrity: sha512-pgp23pLrzfhGnKycxzr7ifP17lAbWZEfnx1bX8gXtYrnpJ66DRNyTKSzxB6sa/HBWjS1L8PX5TjMZ44WfPydqQ==} cpu: [x64] @@ -1597,20 +1525,12 @@ packages: cpu: [x64] os: [win32] - '@rspack/binding-win32-x64-msvc@2.1.9': - resolution: {integrity: sha512-P1dGC6t3PJinqN6tBZ+jyou4LvwpD2ygeovKgg5tuYWKFMUwh1v60yX3afOUwaJMEGbHUye7xuYRd84NCMSNOQ==} - cpu: [x64] - os: [win32] - '@rspack/binding@2.1.10': resolution: {integrity: sha512-vnu/UP5HnrND15lO9+VeG6eUrbTyycHNQNQ3XEiRiFojuoiGZkIZC3Hbzr8qQH44C6vScPODEPvvIVvLcO2LpQ==} '@rspack/binding@2.1.8': resolution: {integrity: sha512-tmAyHzDbPiy8V7HvQqtuPsbs6dPgwV0YjzW5XrPRV9gzf+Hdm7pvsZJKE1QKO9WV5RuvGYav98xIX6O+abZxzQ==} - '@rspack/binding@2.1.9': - resolution: {integrity: sha512-0ZZj+RE62/jFRwX5czqjjGiMGgzSK0hm7/66PtCKjyZjb2tNAg3WGyWv+ref7684ZAjtbHHpZ+EOGswQYBjklA==} - '@rspack/core@2.1.10': resolution: {integrity: sha512-YSS2/Xxz8uiG/KXDkqOoA3dTetNo/vysk7bAexQOrU8iuq7JuzDTTAwLKvWZnwmvME8M8m5wcM4YvfIwYmidHA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1635,18 +1555,6 @@ packages: '@swc/helpers': optional: true - '@rspack/core@2.1.9': - resolution: {integrity: sha512-kXd5aYrkO+91fYolNYAjUhW/1F9kGmw7PtneNRY6z3KK6ttJgQWMVNypiCkhK3TOcyWPGH42qd0bzHZlH72JaA==} - engines: {node: ^20.19.0 || >=22.12.0} - peerDependencies: - '@module-federation/runtime-tools': ^0.24.1 || ^2.0.0 - '@swc/helpers': ^0.5.23 - peerDependenciesMeta: - '@module-federation/runtime-tools': - optional: true - '@swc/helpers': - optional: true - '@rspack/plugin-react-refresh@2.0.2': resolution: {integrity: sha512-dGNZiCxQxgAUI9sah7gd8u+O7OJZRCmqtEJNDOd8xW5RqcieC86F7p5qcShyw6onH5pKf57evpr2VjGbaFGkZg==} peerDependencies: @@ -1699,14 +1607,14 @@ packages: '@rstackjs/test-utils@0.2.0': resolution: {integrity: sha512-P+LOo1WE3xYeGkHmEthyq2cIpN69k4LhiB/4UBSceD+nW9hDlhWv8MC0LTLWokZXccWl4ntcfOBjQFllkcBlPA==} - '@rstest/adapter-rsbuild@0.11.6': - resolution: {integrity: sha512-l2bKftH1IEuY3Sj7ZEb+k6OoZf2FO0vTeKfk1Xxo2ons9fL1LHsbNDWEXNw9lNHg0fv92sai6ygQkGkvCpxkjg==} + '@rstest/adapter-rsbuild@0.11.8': + resolution: {integrity: sha512-FIpljMHWjsZzWTBkGqIuvtPFj3ru1SL5FGhMGtvyGjFi126SwCcVHHTIF5hsrs8Ou8vFEF8S5eFxz7hXrzvxKg==} peerDependencies: '@rsbuild/core': ^1.0.0 || ^2.0.0 '@rstest/core': ^0.11.0 - '@rstest/adapter-rslib@0.11.6': - resolution: {integrity: sha512-0NOU3W63TWtbWExgT/gvpbQ5ZtWqW5HepvJ/mNne7FgZfjm2bNwDF2Saglpg/M83KuBpA9xmnrOUQXNosJkCBQ==} + '@rstest/adapter-rslib@0.11.8': + resolution: {integrity: sha512-PnRrCgTbRH+sFuS/6ZbhDAUEl/n0PkhmzQJxZCYQQEl3w+jGOrLQSAMgh9g/Z2XGM1yfbysn+5HZmGH2kL+E6w==} peerDependencies: '@rslib/core': '>=0.18.6 || ^1.0.0-0' '@rstest/core': ^0.11.0 @@ -1715,8 +1623,8 @@ packages: typescript: optional: true - '@rstest/core@0.11.6': - resolution: {integrity: sha512-P3wgYGDF3JmhapwN3p4DnbNV9N6+E+dlbp0coT1lAuXN5Po6bHeP/rduGLsTUIX85qWxmJD7ekF7nlOKm9RoOA==} + '@rstest/core@0.11.8': + resolution: {integrity: sha512-XworMa277b5Cf4/Box18frFjWGP4dO/NIals+Ck/Q8nhe1z1t8j0P67zh6rv5xTdE3CCEfItICGvdjzz6VRhLg==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -2009,74 +1917,74 @@ packages: peerDependencies: react: '>=18.3.1' - '@yuku-parser/binding-android-arm64@0.8.5': - resolution: {integrity: sha512-BJtJvyf/Ma3v57uebPbe7VMUjNwTa3KW0fJn4awBBXyen8aS/i0gUbCDEsjGPY4GvAT41AggcYSep37V5VPENg==} + '@yuku-parser/binding-android-arm64@0.8.7': + resolution: {integrity: sha512-eGKYiUDX7Y0V7tDTmg+JTVnXnjMqfXXsorZ+EDf5kxwchQ3Or1HS14MzI2fw+jFhHR85fCWt+mtX33Yao73hIQ==} cpu: [arm64] os: [android] - '@yuku-parser/binding-darwin-arm64@0.8.5': - resolution: {integrity: sha512-CEzkjuxNjufVmSRlSm1qYGaoRpbp0g03saC8Tz6BesbmBUuP8MSqJa2BSskMbvYkRhKUN4OFCoPJ0XJf7ARTZQ==} + '@yuku-parser/binding-darwin-arm64@0.8.7': + resolution: {integrity: sha512-Re0RHelKLnjEURulY2/KxW+Ngb8zuNA4BRZuMwgGQNzVumT6u4U2N2hc01oeYVNVof0i7GrXE4UCNBgbpRRnjQ==} cpu: [arm64] os: [darwin] - '@yuku-parser/binding-darwin-x64@0.8.5': - resolution: {integrity: sha512-HS7wYfYUi3fTYNrzLNnZUia5DVo/Kf5NRmbh2rNVDKzMUEUfXI7xWdh0OOqIqYI3SsA5AcZOCI357uYb0+2B9Q==} + '@yuku-parser/binding-darwin-x64@0.8.7': + resolution: {integrity: sha512-Hn8DROtQkjlA1ACbPgj4a7eP9IuVOI504oiTwpkWPbpaDWD9KdmnVYCqW+1LfenNK/g7O9NhWGpXEdaCNX7lIA==} cpu: [x64] os: [darwin] - '@yuku-parser/binding-freebsd-x64@0.8.5': - resolution: {integrity: sha512-Iq/XcdT3qjV+mxzb6hE4oSlst/+wrJxSsgKu3FkVkV1bxb0UfITfedws/wI356KVr+BM9CeamNkdbchHV4pJlw==} + '@yuku-parser/binding-freebsd-x64@0.8.7': + resolution: {integrity: sha512-bAP2OV8wRuzplX/jYxv9+vvqQT8JxyNphI8fLfXGL054Xs+4/J5u33cIm3y4rxY8rdoLmmdiJs2Tq7r7lrDRfA==} cpu: [x64] os: [freebsd] - '@yuku-parser/binding-linux-arm-gnu@0.8.5': - resolution: {integrity: sha512-vbI/zeUdJEZ8BKUEfOD8ngtPR5/9XdONpRRosw73kOtA1GyipTF1rj75ozLHIVCEybdCB/GSlQ6OjjhuEAKrGA==} + '@yuku-parser/binding-linux-arm-gnu@0.8.7': + resolution: {integrity: sha512-kTYwJQQgmZeAWdDIWabiReIZMpmfLueIj1tCmjStUtFGhR1Z0qwxonKVfUC4N7h/VhGGzLZ//7O1kgt1QKqgCg==} cpu: [arm] os: [linux] libc: [glibc] - '@yuku-parser/binding-linux-arm-musl@0.8.5': - resolution: {integrity: sha512-3K4kOkOxWbUKoRja+vn7Srn8Nyc66Fr66oFWO+pFA/0KpVtlIGpKY+/KL8QIQdM7swTh+82OVkuFKeFEweVFLg==} + '@yuku-parser/binding-linux-arm-musl@0.8.7': + resolution: {integrity: sha512-uL4jE8HPT2BLlxAXyD10LqgPuXa9eDa0BKpCdSANmzIJghq/2eZo3/gQNtaxPZMupWoxjYzSad9IXrwu7aYPXQ==} cpu: [arm] os: [linux] libc: [musl] - '@yuku-parser/binding-linux-arm64-gnu@0.8.5': - resolution: {integrity: sha512-aj2pI9eT3ZAj8mWrC+utYUJwyxSd6ozthHjJfGtcY3MnZuQ4qbO7wm15BMqDgCSrg7az3tnONy1ftVQTWV9inA==} + '@yuku-parser/binding-linux-arm64-gnu@0.8.7': + resolution: {integrity: sha512-3gVN4pWSKZmXiNX7cU164dR9MPvesCHnlH6nPfpK+yQsCuYphjKKplcb4SnZBrhiqmXbgb2HR0c2TS0IZUPhgA==} cpu: [arm64] os: [linux] libc: [glibc] - '@yuku-parser/binding-linux-arm64-musl@0.8.5': - resolution: {integrity: sha512-+T2buVRNtY0QwhUeo8t47HmEpgh7tXMx8htMEdT7O0HHv3eFitwvyuVSdYNOpxo52Sc/0wJ6F4UbZni75aD4Pg==} + '@yuku-parser/binding-linux-arm64-musl@0.8.7': + resolution: {integrity: sha512-S0mwfEjoLpxzXeZw802Wa4RaELsQiPtWqG6INcy8j4GtvNFtl4LCX3eGO1XLn9pyLAISLzTRyU3zUCBUPin8lg==} cpu: [arm64] os: [linux] libc: [musl] - '@yuku-parser/binding-linux-x64-gnu@0.8.5': - resolution: {integrity: sha512-uIoy1uplNUqjq3GW6z+Ea8UCQkLKRPlM4FvqAhYMDwBazkVpE1mNvMqaQqf57ZP8mGTeOf4OF6CuUlenR2ttqg==} + '@yuku-parser/binding-linux-x64-gnu@0.8.7': + resolution: {integrity: sha512-lnbWdPmerE5D1uH1G4IEZKnPzCrWCStRGrtgpSIe1RibAo5bZIjDbbbPYXmMHCEh4F+x/JaJpElh26a3r+BPbg==} cpu: [x64] os: [linux] libc: [glibc] - '@yuku-parser/binding-linux-x64-musl@0.8.5': - resolution: {integrity: sha512-27doVJjvYevPWcakDCpfgZfDAlyhfyY3BwHf5TKtponCrSYBMzrBpD8ChYB1M7B6YOm0M5U9kEA0k1sB6CD4Ow==} + '@yuku-parser/binding-linux-x64-musl@0.8.7': + resolution: {integrity: sha512-769uwndMvMzUvATWbAcEvyLHKA+DzhHSCl/obBUrRdYfRo26yxui6S8y3z7uJ+Naup7UKrDxrpK7OnQkxkl9KQ==} cpu: [x64] os: [linux] libc: [musl] - '@yuku-parser/binding-win32-arm64@0.8.5': - resolution: {integrity: sha512-UIlSKhOLWZUQyDVQzYWAkHQGWnwNw5IxR/YYT2UCy64HLMQGGIxhb3qa/7Rf6yki50FrLx1O9PWgBKXCq7Zxxg==} + '@yuku-parser/binding-win32-arm64@0.8.7': + resolution: {integrity: sha512-mEB/9PlaAkisJ6KWGz0zvywXoU6+80dTlR2LwS7s/jcXXoU6fm2+sitBZXtqu3+Q4DcDgPxM45uWMCzPs0TSRw==} cpu: [arm64] os: [win32] - '@yuku-parser/binding-win32-x64@0.8.5': - resolution: {integrity: sha512-helhS0Pt0TwsW9Z5L3V5o27qrnTrmaUTgSpymVUJYlZJgW6Nagk7nS5P3Ez4b1OZXMwc5y5CR6m1niuzL/yYfQ==} + '@yuku-parser/binding-win32-x64@0.8.7': + resolution: {integrity: sha512-8vNB2DP0ou61nGb8tc/qfi41gfyDXz1MHr2zqL3nR+cJ6CEbiuWV/l/a/vv151gCgiZLLAyGkQGENpozdg716w==} cpu: [x64] os: [win32] - '@yuku-toolchain/types@0.8.5': - resolution: {integrity: sha512-ELNzrhwfi9+VCTaj6QcLCb5MlUK6pmVqPqH8bBmer1FTHvgEITnpwB73L/Wx5KKPPVWAokfeeU9V2rJy/9kMlg==} + '@yuku-toolchain/types@0.8.7': + resolution: {integrity: sha512-2Z53dNxAJL6UvFoIrDZvYf3zlO8s4VJK4O2hhaB4mXVwwpX/7ajtss3cmfqKvamlNLWyt9FSWs4eoYdlbxpnHA==} acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} @@ -2353,8 +2261,8 @@ packages: git-hooks-list@4.2.1: resolution: {integrity: sha512-WNvqJjOxxs/8ZP9+DWdwWJ7cDsd60NHf39XnD82pDVrKO5q7xfPqpkK6hwEAmBa/ZSEE4IOoR75EzbbIuwGlMw==} - globals@17.10.0: - resolution: {integrity: sha512-V0kztuWST2k8A/VbxAY8+L+7+Rgo3fyA24IHRLrZp7HOzJjV0gHSaZUjK9lpP/IrBSNite2tZ1prhRkinRu1CA==} + globals@17.11.0: + resolution: {integrity: sha512-Z2I8hM+PbJDXQDq3Icgpzv+mPdwr68iZUU9d5WW4FuXfDUQfkZaZuvjMv42/5crNyw154+9+VWXbYrUgDXbxNw==} engines: {node: '>=18'} happy-dom@20.11.2: @@ -3141,8 +3049,8 @@ packages: resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} engines: {node: '>=10'} - svelte@5.56.8: - resolution: {integrity: sha512-PY8LOw7xP6c8IOiVqdo0sbbZVYhXRSfklOQLAUyGBKqjTX0wx/z4l/9J+PmBpmlLnxzEb1NqltxQ5/wZme/Cmg==} + svelte@5.56.9: + resolution: {integrity: sha512-VT8kSnlEg8069w7AiCcAk3Yf5xvMnrGTagVOmU/OpOLHaHnNqXhWZCH/4EVga/bT/HtWhvE6/fHrXLErx7OnJA==} engines: {node: '>=18'} sync-child-process@1.0.2: @@ -3283,11 +3191,11 @@ packages: engines: {node: '>= 14.6'} hasBin: true - yuku-ast@0.8.5: - resolution: {integrity: sha512-Ez2CI2BnPK/if0tVI7jB9UUDSNibcChjJDEPEKuWPJNRkbvzSoAQrSqpKtdzl8qTPp4ftVb87f/jx5HIKOieQw==} + yuku-ast@0.8.7: + resolution: {integrity: sha512-h6+4bDfyootiMB9vckk5uKo5r5j0GHrkr17FQTDNfEsFT3DWlN9uu1HJwQwc64pgmLCI945fWM3lbTIqxjT3GQ==} - yuku-parser@0.8.5: - resolution: {integrity: sha512-t843J9IdYYpcDaW7o3aDPXpTM72FsvkIDYEHtigyGFCvC3EhiIaSGM5WVNZl3lxTv1Dfis6IW3S/yBsBIaCiWw==} + yuku-parser@0.8.7: + resolution: {integrity: sha512-vRD9nwt4L3aYpxNqeSC4WqLv58xrXef0Ong1Mc45CTXTIpvLafx7JO05sczmQZwdLEZvywrLOGdNC5+Rp5N1BQ==} zimmerframe@1.1.4: resolution: {integrity: sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==} @@ -3974,14 +3882,14 @@ snapshots: transitivePeerDependencies: - '@module-federation/runtime-tools' - '@rsbuild/core@2.1.11': + '@rsbuild/core@2.1.12': dependencies: - '@rspack/core': 2.1.9(@swc/helpers@0.5.23) + '@rspack/core': 2.1.10(@swc/helpers@0.5.23) '@swc/helpers': 0.5.23 transitivePeerDependencies: - '@module-federation/runtime-tools' - '@rsbuild/core@2.1.12': + '@rsbuild/core@2.1.13': dependencies: '@rspack/core': 2.1.10(@swc/helpers@0.5.23) '@swc/helpers': 0.5.23 @@ -4006,12 +3914,12 @@ snapshots: transitivePeerDependencies: - '@rspack/core' - '@rsbuild/plugin-react@2.1.0(@rsbuild/core@2.1.12)(@rspack/core@2.1.10)': + '@rsbuild/plugin-react@2.1.0(@rsbuild/core@2.1.13)(@rspack/core@2.1.10)': dependencies: '@rspack/plugin-react-refresh': 2.0.2(@rspack/core@2.1.10)(react-refresh@0.18.0) react-refresh: 0.18.0 optionalDependencies: - '@rsbuild/core': 2.1.12 + '@rsbuild/core': 2.1.13 transitivePeerDependencies: - '@rspack/core' @@ -4027,8 +3935,8 @@ snapshots: '@rslib/core@1.0.0-beta.3(typescript@7.0.2)': dependencies: - '@rsbuild/core': 2.1.12 - rsbuild-plugin-dts: 1.0.0-beta.3(@rsbuild/core@2.1.12)(typescript@7.0.2) + '@rsbuild/core': 2.1.13 + rsbuild-plugin-dts: 1.0.0-beta.3(@rsbuild/core@2.1.13)(typescript@7.0.2) optionalDependencies: typescript: 7.0.2 transitivePeerDependencies: @@ -4078,84 +3986,54 @@ snapshots: '@rspack/binding-darwin-arm64@2.1.8': optional: true - '@rspack/binding-darwin-arm64@2.1.9': - optional: true - '@rspack/binding-darwin-x64@2.1.10': optional: true '@rspack/binding-darwin-x64@2.1.8': optional: true - '@rspack/binding-darwin-x64@2.1.9': - optional: true - '@rspack/binding-linux-arm64-gnu@2.1.10': optional: true '@rspack/binding-linux-arm64-gnu@2.1.8': optional: true - '@rspack/binding-linux-arm64-gnu@2.1.9': - optional: true - '@rspack/binding-linux-arm64-musl@2.1.10': optional: true '@rspack/binding-linux-arm64-musl@2.1.8': optional: true - '@rspack/binding-linux-arm64-musl@2.1.9': - optional: true - '@rspack/binding-linux-ppc64-gnu@2.1.10': optional: true - '@rspack/binding-linux-ppc64-gnu@2.1.9': - optional: true - '@rspack/binding-linux-riscv64-gnu@2.1.10': optional: true '@rspack/binding-linux-riscv64-gnu@2.1.8': optional: true - '@rspack/binding-linux-riscv64-gnu@2.1.9': - optional: true - '@rspack/binding-linux-riscv64-musl@2.1.10': optional: true '@rspack/binding-linux-riscv64-musl@2.1.8': optional: true - '@rspack/binding-linux-riscv64-musl@2.1.9': - optional: true - '@rspack/binding-linux-s390x-gnu@2.1.10': optional: true - '@rspack/binding-linux-s390x-gnu@2.1.9': - optional: true - '@rspack/binding-linux-x64-gnu@2.1.10': optional: true '@rspack/binding-linux-x64-gnu@2.1.8': optional: true - '@rspack/binding-linux-x64-gnu@2.1.9': - optional: true - '@rspack/binding-linux-x64-musl@2.1.10': optional: true '@rspack/binding-linux-x64-musl@2.1.8': optional: true - '@rspack/binding-linux-x64-musl@2.1.9': - optional: true - '@rspack/binding-wasm32-wasi@2.1.10': dependencies: '@emnapi/core': 1.11.3 @@ -4170,40 +4048,24 @@ snapshots: '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3) optional: true - '@rspack/binding-wasm32-wasi@2.1.9': - dependencies: - '@emnapi/core': 1.11.3 - '@emnapi/runtime': 1.11.3 - '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3) - optional: true - '@rspack/binding-win32-arm64-msvc@2.1.10': optional: true '@rspack/binding-win32-arm64-msvc@2.1.8': optional: true - '@rspack/binding-win32-arm64-msvc@2.1.9': - optional: true - '@rspack/binding-win32-ia32-msvc@2.1.10': optional: true '@rspack/binding-win32-ia32-msvc@2.1.8': optional: true - '@rspack/binding-win32-ia32-msvc@2.1.9': - optional: true - '@rspack/binding-win32-x64-msvc@2.1.10': optional: true '@rspack/binding-win32-x64-msvc@2.1.8': optional: true - '@rspack/binding-win32-x64-msvc@2.1.9': - optional: true - '@rspack/binding@2.1.10': optionalDependencies: '@rspack/binding-darwin-arm64': 2.1.10 @@ -4236,23 +4098,6 @@ snapshots: '@rspack/binding-win32-ia32-msvc': 2.1.8 '@rspack/binding-win32-x64-msvc': 2.1.8 - '@rspack/binding@2.1.9': - optionalDependencies: - '@rspack/binding-darwin-arm64': 2.1.9 - '@rspack/binding-darwin-x64': 2.1.9 - '@rspack/binding-linux-arm64-gnu': 2.1.9 - '@rspack/binding-linux-arm64-musl': 2.1.9 - '@rspack/binding-linux-ppc64-gnu': 2.1.9 - '@rspack/binding-linux-riscv64-gnu': 2.1.9 - '@rspack/binding-linux-riscv64-musl': 2.1.9 - '@rspack/binding-linux-s390x-gnu': 2.1.9 - '@rspack/binding-linux-x64-gnu': 2.1.9 - '@rspack/binding-linux-x64-musl': 2.1.9 - '@rspack/binding-wasm32-wasi': 2.1.9 - '@rspack/binding-win32-arm64-msvc': 2.1.9 - '@rspack/binding-win32-ia32-msvc': 2.1.9 - '@rspack/binding-win32-x64-msvc': 2.1.9 - '@rspack/core@2.1.10(@swc/helpers@0.5.23)': dependencies: '@rspack/binding': 2.1.10 @@ -4265,12 +4110,6 @@ snapshots: optionalDependencies: '@swc/helpers': 0.5.23 - '@rspack/core@2.1.9(@swc/helpers@0.5.23)': - dependencies: - '@rspack/binding': 2.1.9 - optionalDependencies: - '@swc/helpers': 0.5.23 - '@rspack/plugin-react-refresh@2.0.2(@rspack/core@2.1.10)(react-refresh@0.18.0)': dependencies: react-refresh: 0.18.0 @@ -4335,7 +4174,7 @@ snapshots: '@rspress/shared@2.0.19(supports-color@8.1.1)': dependencies: - '@rsbuild/core': 2.1.11 + '@rsbuild/core': 2.1.12 '@shikijs/rehype': 4.3.1 '@types/react': 19.2.18 mdast-util-mdx-jsx: 3.2.0(supports-color@8.1.1) @@ -4355,21 +4194,21 @@ snapshots: '@rstackjs/test-utils@0.2.0': {} - '@rstest/adapter-rsbuild@0.11.6(@rsbuild/core@2.1.11)(@rstest/core@0.11.6)': + '@rstest/adapter-rsbuild@0.11.8(@rsbuild/core@2.1.13)(@rstest/core@0.11.8)': dependencies: - '@rsbuild/core': 2.1.11 - '@rstest/core': 0.11.6(happy-dom@20.11.2) + '@rsbuild/core': 2.1.13 + '@rstest/core': 0.11.8(happy-dom@20.11.2) - '@rstest/adapter-rslib@0.11.6(@rslib/core@1.0.0-beta.3)(@rstest/core@0.11.6)(typescript@7.0.2)': + '@rstest/adapter-rslib@0.11.8(@rslib/core@1.0.0-beta.3)(@rstest/core@0.11.8)(typescript@7.0.2)': dependencies: '@rslib/core': 1.0.0-beta.3(typescript@7.0.2) - '@rstest/core': 0.11.6(happy-dom@20.11.2) + '@rstest/core': 0.11.8(happy-dom@20.11.2) optionalDependencies: typescript: 7.0.2 - '@rstest/core@0.11.6(happy-dom@20.11.2)': + '@rstest/core@0.11.8(happy-dom@20.11.2)': dependencies: - '@rsbuild/core': 2.1.11 + '@rsbuild/core': 2.1.12 '@types/chai': 5.2.3 optionalDependencies: happy-dom: 20.11.2 @@ -4622,43 +4461,43 @@ snapshots: react: 19.2.8 unhead: 2.1.16 - '@yuku-parser/binding-android-arm64@0.8.5': + '@yuku-parser/binding-android-arm64@0.8.7': optional: true - '@yuku-parser/binding-darwin-arm64@0.8.5': + '@yuku-parser/binding-darwin-arm64@0.8.7': optional: true - '@yuku-parser/binding-darwin-x64@0.8.5': + '@yuku-parser/binding-darwin-x64@0.8.7': optional: true - '@yuku-parser/binding-freebsd-x64@0.8.5': + '@yuku-parser/binding-freebsd-x64@0.8.7': optional: true - '@yuku-parser/binding-linux-arm-gnu@0.8.5': + '@yuku-parser/binding-linux-arm-gnu@0.8.7': optional: true - '@yuku-parser/binding-linux-arm-musl@0.8.5': + '@yuku-parser/binding-linux-arm-musl@0.8.7': optional: true - '@yuku-parser/binding-linux-arm64-gnu@0.8.5': + '@yuku-parser/binding-linux-arm64-gnu@0.8.7': optional: true - '@yuku-parser/binding-linux-arm64-musl@0.8.5': + '@yuku-parser/binding-linux-arm64-musl@0.8.7': optional: true - '@yuku-parser/binding-linux-x64-gnu@0.8.5': + '@yuku-parser/binding-linux-x64-gnu@0.8.7': optional: true - '@yuku-parser/binding-linux-x64-musl@0.8.5': + '@yuku-parser/binding-linux-x64-musl@0.8.7': optional: true - '@yuku-parser/binding-win32-arm64@0.8.5': + '@yuku-parser/binding-win32-arm64@0.8.7': optional: true - '@yuku-parser/binding-win32-x64@0.8.5': + '@yuku-parser/binding-win32-x64@0.8.7': optional: true - '@yuku-toolchain/types@0.8.5': {} + '@yuku-toolchain/types@0.8.7': {} acorn-jsx@5.3.2(acorn@8.17.0): dependencies: @@ -4875,7 +4714,7 @@ snapshots: git-hooks-list@4.2.1: {} - globals@17.10.0: {} + globals@17.11.0: {} happy-dom@20.11.2: dependencies: @@ -5638,10 +5477,10 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 - prettier-plugin-svelte@4.1.1(prettier@3.9.6)(svelte@5.56.8): + prettier-plugin-svelte@4.1.1(prettier@3.9.6)(svelte@5.56.9): dependencies: prettier: 3.9.6 - svelte: 5.56.8 + svelte: 5.56.9 prettier@3.9.6: {} @@ -5832,10 +5671,10 @@ snapshots: mdast-util-to-markdown: 2.1.2 unified: 11.0.5 - rsbuild-plugin-dts@1.0.0-beta.3(@rsbuild/core@2.1.12)(typescript@7.0.2): + rsbuild-plugin-dts@1.0.0-beta.3(@rsbuild/core@2.1.13)(typescript@7.0.2): dependencies: '@ast-grep/napi': 0.37.0 - '@rsbuild/core': 2.1.12 + '@rsbuild/core': 2.1.13 optionalDependencies: typescript: 7.0.2 @@ -6015,7 +5854,7 @@ snapshots: dependencies: has-flag: 4.0.0 - svelte@5.56.8: + svelte@5.56.9: dependencies: '@jridgewell/remapping': 2.3.5 '@jridgewell/sourcemap-codec': 1.5.5 @@ -6184,27 +6023,27 @@ snapshots: yaml@2.9.0: optional: true - yuku-ast@0.8.5: + yuku-ast@0.8.7: dependencies: - '@yuku-toolchain/types': 0.8.5 + '@yuku-toolchain/types': 0.8.7 - yuku-parser@0.8.5: + yuku-parser@0.8.7: dependencies: - '@yuku-toolchain/types': 0.8.5 - yuku-ast: 0.8.5 + '@yuku-toolchain/types': 0.8.7 + yuku-ast: 0.8.7 optionalDependencies: - '@yuku-parser/binding-android-arm64': 0.8.5 - '@yuku-parser/binding-darwin-arm64': 0.8.5 - '@yuku-parser/binding-darwin-x64': 0.8.5 - '@yuku-parser/binding-freebsd-x64': 0.8.5 - '@yuku-parser/binding-linux-arm-gnu': 0.8.5 - '@yuku-parser/binding-linux-arm-musl': 0.8.5 - '@yuku-parser/binding-linux-arm64-gnu': 0.8.5 - '@yuku-parser/binding-linux-arm64-musl': 0.8.5 - '@yuku-parser/binding-linux-x64-gnu': 0.8.5 - '@yuku-parser/binding-linux-x64-musl': 0.8.5 - '@yuku-parser/binding-win32-arm64': 0.8.5 - '@yuku-parser/binding-win32-x64': 0.8.5 + '@yuku-parser/binding-android-arm64': 0.8.7 + '@yuku-parser/binding-darwin-arm64': 0.8.7 + '@yuku-parser/binding-darwin-x64': 0.8.7 + '@yuku-parser/binding-freebsd-x64': 0.8.7 + '@yuku-parser/binding-linux-arm-gnu': 0.8.7 + '@yuku-parser/binding-linux-arm-musl': 0.8.7 + '@yuku-parser/binding-linux-arm64-gnu': 0.8.7 + '@yuku-parser/binding-linux-arm64-musl': 0.8.7 + '@yuku-parser/binding-linux-x64-gnu': 0.8.7 + '@yuku-parser/binding-linux-x64-musl': 0.8.7 + '@yuku-parser/binding-win32-arm64': 0.8.7 + '@yuku-parser/binding-win32-x64': 0.8.7 zimmerframe@1.1.4: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 8bf766d0..0ea73bd0 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -13,7 +13,7 @@ cleanupUnusedCatalogs: true catalog: '@napi-rs/cli': '^3.8.6' - '@rsbuild/core': '~2.1.11' + '@rsbuild/core': '~2.1.13' '@rsbuild/plugin-react': '^2.1.0' '@rsbuild/plugin-sass': '^2.0.1' '@rslib/core': '~1.0.0-beta.3' @@ -25,9 +25,9 @@ catalog: '@rstackjs/create-toolkit': '2.2.3' '@rstackjs/load-config': ^0.1.2 '@rstackjs/test-utils': ^0.2.0 - '@rstest/adapter-rsbuild': '~0.11.6' - '@rstest/adapter-rslib': '~0.11.6' - '@rstest/core': '~0.11.6' + '@rstest/adapter-rsbuild': '~0.11.8' + '@rstest/adapter-rslib': '~0.11.8' + '@rstest/core': '~0.11.8' '@testing-library/dom': '^10.4.1' '@testing-library/jest-dom': '^7.0.1' '@testing-library/react': '^16.3.2' @@ -38,7 +38,7 @@ catalog: '@shikijs/transformers': '^4.4.3' 'cspell-ban-words': '^0.0.4' 'fast-json-stable-stringify': '2.1.0' - globals: '^17.10.0' + globals: '^17.11.0' 'happy-dom': '^20.11.2' 'heading-case': '^1.1.5' 'import-meta-resolve': '4.2.0' @@ -53,13 +53,13 @@ catalog: rslog: ^2.3.0 'rspress-plugin-font-open-sans': '^1.0.4' 'sort-package-json': '4.0.0' - svelte: '^5.56.8' + svelte: '^5.56.9' tinypool: '2.1.0' tiny-readdir: 3.1.1 'typescript': '^7.0.2' 'vscode-languageserver': '10.1.0' 'vscode-languageserver-textdocument': '1.0.12' - yuku-parser: '0.8.5' + yuku-parser: '0.8.7' dedupePeers: true diff --git a/rust-toolchain.toml b/rust-toolchain.toml index da0237fb..7002caa4 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,5 +1,5 @@ [toolchain] # Required by the release-only -Zlocation-detail=none flag. -channel = "nightly-2026-08-12" +channel = "nightly-2026-08-13" components = ["clippy", "rustfmt"] profile = "minimal" From def8ecb06f797824b87497660e55070c98dfa196 Mon Sep 17 00:00:00 2001 From: Jiahan Chen Date: Sat, 15 Aug 2026 09:51:06 +0800 Subject: [PATCH 30/33] chore(deps): disable TypeScript updates for Vue and Svelte templates (#366) --- .github/renovate.json | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/.github/renovate.json b/.github/renovate.json index 7fb2dd94..eb178041 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -1,4 +1,18 @@ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "extends": ["github>rstackjs/renovate"] + "extends": ["github>rstackjs/renovate"], + "packageRules": [ + { + "description": "Disable TypeScript updates in Svelte and Vue templates until svelte-check, svelte2tsx, and vue-tsc support TypeScript 7", + "matchManagers": ["npm"], + "matchPackageNames": ["typescript"], + "matchFileNames": [ + "packages/create-rstack/template-app-svelte-ts/package.json", + "packages/create-rstack/template-app-vue-ts/package.json", + "packages/create-rstack/template-lib-svelte-ts/package.json", + "packages/create-rstack/template-lib-vue-ts/package.json" + ], + "enabled": false + } + ] } From 19c368e8c377587fac40678bdf933e7da69c12fe Mon Sep 17 00:00:00 2001 From: Jiahan Chen Date: Sat, 15 Aug 2026 11:24:32 +0800 Subject: [PATCH 31/33] docs(website): redesign homepage hero (#367) --- website/i18n.json | 24 ++- website/theme/components/Hero.module.scss | 245 +++++++++++++++++++++- website/theme/components/Hero.tsx | 80 +++++-- website/theme/components/ToolStack.tsx | 13 -- website/theme/index.scss | 4 + website/theme/pages/index.tsx | 8 +- 6 files changed, 332 insertions(+), 42 deletions(-) delete mode 100644 website/theme/components/ToolStack.tsx diff --git a/website/i18n.json b/website/i18n.json index ba475596..a00be44e 100644 --- a/website/i18n.json +++ b/website/i18n.json @@ -3,13 +3,29 @@ "en": "Quick start", "zh": "快速上手" }, + "viewSource": { + "en": "View the code", + "zh": "查看源码" + }, + "copyCommand": { + "en": "Copy command", + "zh": "复制命令" + }, + "copiedCommand": { + "en": "Command copied", + "zh": "命令已复制" + }, + "title": { + "en": "Unified Toolchain for", + "zh": "统一工具链" + }, "subtitle": { - "en": "The Unified JavaScript Toolchain", - "zh": "统一的 JavaScript 工具链" + "en": "Shipping JavaScript Faster", + "zh": "加速 JavaScript 开发" }, "slogan": { - "en": "One CLI, one configuration, one consistent workflow", - "zh": "一个命令行、一份配置、一致的工作流" + "en": "One CLI unifies development, builds, testing, linting, and formatting across all your JavaScript projects. Powered by the Rspack ecosystem.", + "zh": "只需一个 CLI,即可统一所有 JavaScript 项目的开发、构建、测试、代码检查与格式化。由 Rspack 生态驱动。" }, "unifiedCli": { "en": "One CLI", diff --git a/website/theme/components/Hero.module.scss b/website/theme/components/Hero.module.scss index 972082a0..3b4452c9 100644 --- a/website/theme/components/Hero.module.scss +++ b/website/theme/components/Hero.module.scss @@ -1,8 +1,241 @@ -:global { - .rs-oval { - width: 70% !important; - height: 70% !important; - top: calc(50% + 20px) !important; - left: calc(50% + 5px) !important; +.hero { + --hero-title: #111214; + --hero-title-muted: #747474; + --hero-text: #707174; + --hero-border: #d9dbde; + --hero-command-bg: rgba(255, 255, 255, 0.72); + --hero-link: #686a6d; + --hero-link-hover: #111214; + + position: relative; + display: flex; + align-items: center; + justify-content: center; + box-sizing: border-box; + min-height: calc(100svh - var(--rp-nav-height)); + padding: clamp(4.5rem, 9vh, 7rem) 2rem; + overflow: hidden; + background: var(--rp-c-bg); +} + +:global(.dark) .hero { + --hero-title: #f5f5f5; + --hero-title-muted: #9a9a9a; + --hero-text: #a1a3a6; + --hero-border: #3a3c40; + --hero-command-bg: rgba(255, 255, 255, 0.025); + --hero-link: #a6a8ab; + --hero-link-hover: #f5f5f5; +} + +.inner { + display: flex; + flex-direction: column; + align-items: center; + width: 100%; + max-width: 64rem; + text-align: center; + transform: translateY(-1.5rem); +} + +.title { + margin: 0; + color: var(--hero-title); + font-size: clamp(3rem, 4.5vw, 4rem); + font-weight: 600; + line-height: 1.1; + letter-spacing: -0.055em; + text-wrap: balance; + + span { + display: block; + } +} + +.subtitle { + color: var(--hero-title-muted); +} + +.description { + max-width: 42rem; + margin: clamp(2.5rem, 5vh, 3.75rem) 0 0; + color: var(--hero-text); + font-size: clamp(1rem, 1.25vw, 1.25rem); + font-weight: 400; + line-height: 1.5; + letter-spacing: -0.02em; + text-wrap: balance; +} + +.command { + display: grid; + grid-template-columns: auto minmax(0, 1fr) auto; + align-items: center; + box-sizing: border-box; + width: min(100%, 20rem); + min-height: 3.125rem; + margin-top: clamp(2.75rem, 6vh, 4rem); + padding: 0 0.5rem 0 1rem; + color: var(--hero-title); + text-align: left; + border: 1px solid var(--hero-border); + border-radius: 0.5rem; + background: var(--hero-command-bg); + + code, + .prompt { + font-family: + ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', monospace; + font-size: clamp(0.8125rem, 1vw, 0.9375rem); + line-height: 1.4; + } + + code { + padding: 0 0.625rem; + overflow: hidden; + color: inherit; + text-overflow: ellipsis; + white-space: nowrap; + background: transparent; + } +} + +.prompt { + color: var(--hero-text); +} + +.copyButton { + display: inline-flex; + align-items: center; + justify-content: center; + width: 2rem; + height: 2rem; + padding: 0; + color: var(--hero-text); + cursor: pointer; + border: 0; + border-radius: 0.5rem; + background: transparent; + transition: + color 0.2s ease, + background-color 0.2s ease; + + svg { + width: 1.125rem; + height: 1.125rem; + } + + &:hover { + color: var(--hero-link-hover); + background: color-mix(in srgb, var(--hero-title) 7%, transparent); + } + + &:focus-visible { + outline: 2px solid var(--rp-c-brand); + outline-offset: 2px; + } +} + +.links { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: center; + gap: 1rem 2.5rem; + margin-top: clamp(2rem, 4vh, 2.5rem); +} + +.link { + display: inline-flex; + align-items: center; + gap: 0.5rem; + color: var(--hero-link); + font-size: 0.9375rem; + font-weight: 500; + line-height: 1.5; + text-decoration: none; + transition: color 0.2s ease; + + svg { + width: 0.75rem; + height: 0.75rem; + transition: transform 0.2s ease; + } + + &:hover { + color: var(--hero-link-hover); + + svg { + transform: translateX(0.2rem); + } + } + + &:focus-visible { + border-radius: 0.25rem; + outline: 2px solid var(--rp-c-brand); + outline-offset: 4px; + } +} + +@media (max-width: 640px) { + .hero { + min-height: calc(100svh - var(--rp-nav-height)); + padding: 4rem 1.25rem; + } + + .title { + font-size: clamp(2.25rem, 10vw, 2.75rem); + line-height: 1.04; + letter-spacing: -0.055em; + } + + .description { + max-width: 28rem; + margin-top: 2rem; + font-size: 0.9375rem; + line-height: 1.55; + } + + .command { + min-height: 3.25rem; + margin-top: 2.25rem; + padding: 0 0.5rem 0 0.875rem; + border-radius: 0.625rem; + + code, + .prompt { + font-size: 0.8125rem; + } + + code { + padding: 0 0.625rem; + } + } + + .copyButton { + width: 2rem; + height: 2rem; + + svg { + width: 1.125rem; + height: 1.125rem; + } + } + + .links { + gap: 1rem 1.75rem; + margin-top: 2rem; + } + + .link { + font-size: 0.875rem; + } +} + +@media (prefers-reduced-motion: reduce) { + .copyButton, + .link, + .link svg { + transition: none; } } diff --git a/website/theme/components/Hero.tsx b/website/theme/components/Hero.tsx index 7bf503f6..5edc0cf2 100644 --- a/website/theme/components/Hero.tsx +++ b/website/theme/components/Hero.tsx @@ -1,22 +1,76 @@ -import { useI18n, useNavigate } from '@rspress/core/runtime'; -import { Hero as BaseHero } from '@rstack-dev/doc-ui/hero'; +import { useI18n } from '@rspress/core/runtime'; +import { + IconArrowRight, + IconCopy, + IconSuccess, + Link, + SvgWrapper, + copyToClipboard, +} from '@rspress/core/theme-original'; +import { useCallback, useEffect, useRef, useState } from 'react'; import { useI18nUrl } from './utils'; -import './Hero.module.scss'; +import styles from './Hero.module.scss'; + +const createCommand = 'pnpm create rstack'; +const githubUrl = 'https://github.com/rstackjs/rstack-cli'; export function Hero() { - const navigate = useNavigate(); const tUrl = useI18nUrl(); const t = useI18n(); + const [copied, setCopied] = useState(false); + const resetTimer = useRef(undefined); + + const handleCopy = useCallback(async () => { + const copiedSuccessfully = await copyToClipboard(createCommand); + + if (!copiedSuccessfully) { + return; + } + + setCopied(true); + window.clearTimeout(resetTimer.current); + resetTimer.current = window.setTimeout(() => setCopied(false), 1600); + }, []); + + useEffect(() => () => window.clearTimeout(resetTimer.current), []); return ( - navigate(tUrl('/guide/quick-start'))} - title="Rstack CLI" - subTitle={t('subtitle')} - description={t('slogan')} - getStartedButtonText={t('quickStart')} - githubURL="https://github.com/rstackjs/rstack-cli" - /> +
+
+

+ {t('title')} + {t('subtitle')} +

+ +

{t('slogan')}

+ +
+ + {createCommand} + +
+ +
+ + {t('quickStart')} + + + + {t('viewSource')} + + +
+
+
); } diff --git a/website/theme/components/ToolStack.tsx b/website/theme/components/ToolStack.tsx deleted file mode 100644 index c5e3fc57..00000000 --- a/website/theme/components/ToolStack.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { useLang } from '@rspress/core/runtime'; -import { containerStyle } from '@rstack-dev/doc-ui/section-style'; -import { ToolStack as BaseToolStack } from '@rstack-dev/doc-ui/tool-stack'; - -export function ToolStack() { - const lang = useLang(); - - return ( -
- -
- ); -} diff --git a/website/theme/index.scss b/website/theme/index.scss index 9fde95d7..a210d25d 100644 --- a/website/theme/index.scss +++ b/website/theme/index.scss @@ -13,6 +13,10 @@ } } +body:has(#home-hero-title) .rp-nav { + border-bottom: none; +} + .rspress-logo { height: 1.8rem; } diff --git a/website/theme/pages/index.tsx b/website/theme/pages/index.tsx index 084a27d2..cbeb03a2 100644 --- a/website/theme/pages/index.tsx +++ b/website/theme/pages/index.tsx @@ -1,19 +1,15 @@ -import { BackgroundImage } from '@rstack-dev/doc-ui/background-image'; import { CopyRight } from '../components/Copyright'; import { Features } from '../components/Features'; import { Hero } from '../components/Hero'; import { HomeFooter } from '../components/HomeFooter'; -import { ToolStack } from '../components/ToolStack'; export function HomeLayout() { return ( -
- + <> - -
+ ); } From 4ee1c719cafe96382a70b74918c9c153d86b4688 Mon Sep 17 00:00:00 2001 From: Jiahan Chen Date: Sat, 15 Aug 2026 19:54:43 +0800 Subject: [PATCH 32/33] docs: simplify configuration guide comments (#368) --- .agents/skills/migrate-to-rstack-cli/SKILL.md | 2 +- examples/app-react/rstack.config.ts | 2 +- examples/app-vanilla/rstack.config.ts | 2 +- examples/documentation/rstack.config.ts | 2 +- examples/lib-node/rstack.config.ts | 2 +- examples/lib-react/rstack.config.ts | 2 +- examples/test-inline-projects/rstack.config.ts | 2 +- packages/create-rstack/rstack.config.ts | 2 +- .../template-app-lit-ts/rstack.config.ts | 2 +- .../template-app-lit/rstack.config.js | 2 +- .../template-app-preact-ts/rstack.config.ts | 2 +- .../template-app-preact/rstack.config.js | 2 +- .../template-app-react-ts/rstack.config.ts | 2 +- .../template-app-react/rstack.config.js | 2 +- .../template-app-solid-ts/rstack.config.ts | 2 +- .../template-app-solid/rstack.config.js | 2 +- .../template-app-svelte-ts/rstack.config.ts | 2 +- .../template-app-svelte/rstack.config.js | 2 +- .../template-app-vanilla-ts/rstack.config.ts | 2 +- .../template-app-vanilla/rstack.config.js | 2 +- .../template-app-vue-ts/rstack.config.ts | 2 +- .../template-app-vue/rstack.config.js | 2 +- .../template-doc-i18n/rstack.config.ts | 2 +- .../create-rstack/template-doc/rstack.config.ts | 2 +- .../template-lib-node-ts/rstack.config.ts | 2 +- .../template-lib-node/rstack.config.js | 2 +- .../template-lib-react-ts/rstack.config.ts | 2 +- .../template-lib-react/rstack.config.js | 2 +- .../template-lib-solid-ts/rstack.config.ts | 2 +- .../template-lib-solid/rstack.config.js | 2 +- .../template-lib-svelte-ts/rstack.config.ts | 2 +- .../template-lib-svelte/rstack.config.js | 2 +- .../template-lib-vue-ts/rstack.config.ts | 2 +- .../template-lib-vue/rstack.config.js | 2 +- packages/rstack/rstack.config.ts | 2 +- packages/rstack/src/config.ts | 14 +++++++------- rstack.config.ts | 2 +- website/docs/en/guide/configuration.mdx | 2 +- website/docs/en/guide/quick-start.mdx | 2 +- website/docs/zh/guide/configuration.mdx | 2 +- website/docs/zh/guide/quick-start.mdx | 2 +- website/rstack.config.ts | 2 +- 42 files changed, 48 insertions(+), 48 deletions(-) diff --git a/.agents/skills/migrate-to-rstack-cli/SKILL.md b/.agents/skills/migrate-to-rstack-cli/SKILL.md index 06d61983..992cf06c 100644 --- a/.agents/skills/migrate-to-rstack-cli/SKILL.md +++ b/.agents/skills/migrate-to-rstack-cli/SKILL.md @@ -41,7 +41,7 @@ Use one of the default names: `rstack.config.ts`, `.js`, `.mts`, or `.mjs`. Use `rs -c ` or `rs --config ` only for a custom path. ```ts -// Rstack configuration guide: https://rstack.rs/config +// Configuration guide: https://rstack.rs/config import { define } from 'rstack'; define.app({ diff --git a/examples/app-react/rstack.config.ts b/examples/app-react/rstack.config.ts index 960e215b..d6c4a461 100644 --- a/examples/app-react/rstack.config.ts +++ b/examples/app-react/rstack.config.ts @@ -1,4 +1,4 @@ -// Rstack configuration guide: https://rstack.rs/config +// Configuration guide: https://rstack.rs/config import { define } from 'rstack'; define.app(async () => { diff --git a/examples/app-vanilla/rstack.config.ts b/examples/app-vanilla/rstack.config.ts index 9707fbda..6e3bb9a8 100644 --- a/examples/app-vanilla/rstack.config.ts +++ b/examples/app-vanilla/rstack.config.ts @@ -1,4 +1,4 @@ -// Rstack configuration guide: https://rstack.rs/config +// Configuration guide: https://rstack.rs/config import { define } from 'rstack'; define.test({ diff --git a/examples/documentation/rstack.config.ts b/examples/documentation/rstack.config.ts index 10c5a9ad..8d99518f 100644 --- a/examples/documentation/rstack.config.ts +++ b/examples/documentation/rstack.config.ts @@ -1,4 +1,4 @@ -// Rstack configuration guide: https://rstack.rs/config +// Configuration guide: https://rstack.rs/config import { define } from 'rstack'; import path from 'node:path'; diff --git a/examples/lib-node/rstack.config.ts b/examples/lib-node/rstack.config.ts index ed274a80..104652eb 100644 --- a/examples/lib-node/rstack.config.ts +++ b/examples/lib-node/rstack.config.ts @@ -1,4 +1,4 @@ -// Rstack configuration guide: https://rstack.rs/config +// Configuration guide: https://rstack.rs/config import { define } from 'rstack'; define.lib({ diff --git a/examples/lib-react/rstack.config.ts b/examples/lib-react/rstack.config.ts index fd97fdae..ec8669f4 100644 --- a/examples/lib-react/rstack.config.ts +++ b/examples/lib-react/rstack.config.ts @@ -1,4 +1,4 @@ -// Rstack configuration guide: https://rstack.rs/config +// Configuration guide: https://rstack.rs/config import { define } from 'rstack'; define.lib(async () => { diff --git a/examples/test-inline-projects/rstack.config.ts b/examples/test-inline-projects/rstack.config.ts index 12fa4e57..55383b03 100644 --- a/examples/test-inline-projects/rstack.config.ts +++ b/examples/test-inline-projects/rstack.config.ts @@ -1,4 +1,4 @@ -// Rstack configuration guide: https://rstack.rs/config +// Configuration guide: https://rstack.rs/config import { define } from 'rstack'; define.app(async () => { diff --git a/packages/create-rstack/rstack.config.ts b/packages/create-rstack/rstack.config.ts index 923fc17d..7daaf593 100644 --- a/packages/create-rstack/rstack.config.ts +++ b/packages/create-rstack/rstack.config.ts @@ -1,4 +1,4 @@ -// Rstack configuration guide: https://rstack.rs/config +// Configuration guide: https://rstack.rs/config import { define } from 'rstack'; define.lib({ diff --git a/packages/create-rstack/template-app-lit-ts/rstack.config.ts b/packages/create-rstack/template-app-lit-ts/rstack.config.ts index d7f664c7..434eac7d 100644 --- a/packages/create-rstack/template-app-lit-ts/rstack.config.ts +++ b/packages/create-rstack/template-app-lit-ts/rstack.config.ts @@ -1,4 +1,4 @@ -// Rstack configuration guide: https://rstack.rs/config +// Configuration guide: https://rstack.rs/config import { define } from 'rstack'; define.app({ diff --git a/packages/create-rstack/template-app-lit/rstack.config.js b/packages/create-rstack/template-app-lit/rstack.config.js index 4a74583c..e5a6fd11 100644 --- a/packages/create-rstack/template-app-lit/rstack.config.js +++ b/packages/create-rstack/template-app-lit/rstack.config.js @@ -1,5 +1,5 @@ // @ts-check -// Rstack configuration guide: https://rstack.rs/config +// Configuration guide: https://rstack.rs/config import { define } from 'rstack'; define.app({ diff --git a/packages/create-rstack/template-app-preact-ts/rstack.config.ts b/packages/create-rstack/template-app-preact-ts/rstack.config.ts index e1ec7e4d..9fdeba76 100644 --- a/packages/create-rstack/template-app-preact-ts/rstack.config.ts +++ b/packages/create-rstack/template-app-preact-ts/rstack.config.ts @@ -1,4 +1,4 @@ -// Rstack configuration guide: https://rstack.rs/config +// Configuration guide: https://rstack.rs/config import { define } from 'rstack'; define.app(async () => { diff --git a/packages/create-rstack/template-app-preact/rstack.config.js b/packages/create-rstack/template-app-preact/rstack.config.js index 0c586e57..912d57af 100644 --- a/packages/create-rstack/template-app-preact/rstack.config.js +++ b/packages/create-rstack/template-app-preact/rstack.config.js @@ -1,5 +1,5 @@ // @ts-check -// Rstack configuration guide: https://rstack.rs/config +// Configuration guide: https://rstack.rs/config import { define } from 'rstack'; define.app(async () => { diff --git a/packages/create-rstack/template-app-react-ts/rstack.config.ts b/packages/create-rstack/template-app-react-ts/rstack.config.ts index b6214713..cb508e42 100644 --- a/packages/create-rstack/template-app-react-ts/rstack.config.ts +++ b/packages/create-rstack/template-app-react-ts/rstack.config.ts @@ -1,4 +1,4 @@ -// Rstack configuration guide: https://rstack.rs/config +// Configuration guide: https://rstack.rs/config import { define } from 'rstack'; define.app(async () => { diff --git a/packages/create-rstack/template-app-react/rstack.config.js b/packages/create-rstack/template-app-react/rstack.config.js index e01ac564..886b005a 100644 --- a/packages/create-rstack/template-app-react/rstack.config.js +++ b/packages/create-rstack/template-app-react/rstack.config.js @@ -1,5 +1,5 @@ // @ts-check -// Rstack configuration guide: https://rstack.rs/config +// Configuration guide: https://rstack.rs/config import { define } from 'rstack'; define.app(async () => { diff --git a/packages/create-rstack/template-app-solid-ts/rstack.config.ts b/packages/create-rstack/template-app-solid-ts/rstack.config.ts index 17f42c04..d364bf54 100644 --- a/packages/create-rstack/template-app-solid-ts/rstack.config.ts +++ b/packages/create-rstack/template-app-solid-ts/rstack.config.ts @@ -1,4 +1,4 @@ -// Rstack configuration guide: https://rstack.rs/config +// Configuration guide: https://rstack.rs/config import { define } from 'rstack'; define.app(async () => { diff --git a/packages/create-rstack/template-app-solid/rstack.config.js b/packages/create-rstack/template-app-solid/rstack.config.js index 035c1408..da3845a4 100644 --- a/packages/create-rstack/template-app-solid/rstack.config.js +++ b/packages/create-rstack/template-app-solid/rstack.config.js @@ -1,5 +1,5 @@ // @ts-check -// Rstack configuration guide: https://rstack.rs/config +// Configuration guide: https://rstack.rs/config import { define } from 'rstack'; define.app(async () => { diff --git a/packages/create-rstack/template-app-svelte-ts/rstack.config.ts b/packages/create-rstack/template-app-svelte-ts/rstack.config.ts index aaf917a8..f2dec78f 100644 --- a/packages/create-rstack/template-app-svelte-ts/rstack.config.ts +++ b/packages/create-rstack/template-app-svelte-ts/rstack.config.ts @@ -1,4 +1,4 @@ -// Rstack configuration guide: https://rstack.rs/config +// Configuration guide: https://rstack.rs/config import { define } from 'rstack'; define.app(async () => { diff --git a/packages/create-rstack/template-app-svelte/rstack.config.js b/packages/create-rstack/template-app-svelte/rstack.config.js index a1efbfc7..0fb4fac1 100644 --- a/packages/create-rstack/template-app-svelte/rstack.config.js +++ b/packages/create-rstack/template-app-svelte/rstack.config.js @@ -1,5 +1,5 @@ // @ts-check -// Rstack configuration guide: https://rstack.rs/config +// Configuration guide: https://rstack.rs/config import { define } from 'rstack'; define.app(async () => { diff --git a/packages/create-rstack/template-app-vanilla-ts/rstack.config.ts b/packages/create-rstack/template-app-vanilla-ts/rstack.config.ts index 6e755422..dfe1edc1 100644 --- a/packages/create-rstack/template-app-vanilla-ts/rstack.config.ts +++ b/packages/create-rstack/template-app-vanilla-ts/rstack.config.ts @@ -1,4 +1,4 @@ -// Rstack configuration guide: https://rstack.rs/config +// Configuration guide: https://rstack.rs/config import { define } from 'rstack'; define.app({ diff --git a/packages/create-rstack/template-app-vanilla/rstack.config.js b/packages/create-rstack/template-app-vanilla/rstack.config.js index a9f27d77..cf825efc 100644 --- a/packages/create-rstack/template-app-vanilla/rstack.config.js +++ b/packages/create-rstack/template-app-vanilla/rstack.config.js @@ -1,5 +1,5 @@ // @ts-check -// Rstack configuration guide: https://rstack.rs/config +// Configuration guide: https://rstack.rs/config import { define } from 'rstack'; define.app({ diff --git a/packages/create-rstack/template-app-vue-ts/rstack.config.ts b/packages/create-rstack/template-app-vue-ts/rstack.config.ts index 97e764c0..0c8fe28e 100644 --- a/packages/create-rstack/template-app-vue-ts/rstack.config.ts +++ b/packages/create-rstack/template-app-vue-ts/rstack.config.ts @@ -1,4 +1,4 @@ -// Rstack configuration guide: https://rstack.rs/config +// Configuration guide: https://rstack.rs/config import { define } from 'rstack'; define.app(async () => { diff --git a/packages/create-rstack/template-app-vue/rstack.config.js b/packages/create-rstack/template-app-vue/rstack.config.js index 8116b0df..1cf8b2e1 100644 --- a/packages/create-rstack/template-app-vue/rstack.config.js +++ b/packages/create-rstack/template-app-vue/rstack.config.js @@ -1,5 +1,5 @@ // @ts-check -// Rstack configuration guide: https://rstack.rs/config +// Configuration guide: https://rstack.rs/config import { define } from 'rstack'; define.app(async () => { diff --git a/packages/create-rstack/template-doc-i18n/rstack.config.ts b/packages/create-rstack/template-doc-i18n/rstack.config.ts index e3185a0d..87a0190d 100644 --- a/packages/create-rstack/template-doc-i18n/rstack.config.ts +++ b/packages/create-rstack/template-doc-i18n/rstack.config.ts @@ -1,4 +1,4 @@ -// Rstack configuration guide: https://rstack.rs/config +// Configuration guide: https://rstack.rs/config import path from 'node:path'; import { define } from 'rstack'; diff --git a/packages/create-rstack/template-doc/rstack.config.ts b/packages/create-rstack/template-doc/rstack.config.ts index 99bf9d0d..4a65ede6 100644 --- a/packages/create-rstack/template-doc/rstack.config.ts +++ b/packages/create-rstack/template-doc/rstack.config.ts @@ -1,4 +1,4 @@ -// Rstack configuration guide: https://rstack.rs/config +// Configuration guide: https://rstack.rs/config import path from 'node:path'; import { define } from 'rstack'; diff --git a/packages/create-rstack/template-lib-node-ts/rstack.config.ts b/packages/create-rstack/template-lib-node-ts/rstack.config.ts index 76a7cb35..09769776 100644 --- a/packages/create-rstack/template-lib-node-ts/rstack.config.ts +++ b/packages/create-rstack/template-lib-node-ts/rstack.config.ts @@ -1,4 +1,4 @@ -// Rstack configuration guide: https://rstack.rs/config +// Configuration guide: https://rstack.rs/config import { define } from 'rstack'; define.lib({ diff --git a/packages/create-rstack/template-lib-node/rstack.config.js b/packages/create-rstack/template-lib-node/rstack.config.js index 047c2d6c..6080e25d 100644 --- a/packages/create-rstack/template-lib-node/rstack.config.js +++ b/packages/create-rstack/template-lib-node/rstack.config.js @@ -1,5 +1,5 @@ // @ts-check -// Rstack configuration guide: https://rstack.rs/config +// Configuration guide: https://rstack.rs/config import { define } from 'rstack'; define.lib({ diff --git a/packages/create-rstack/template-lib-react-ts/rstack.config.ts b/packages/create-rstack/template-lib-react-ts/rstack.config.ts index 8c91acb5..1aeb4946 100644 --- a/packages/create-rstack/template-lib-react-ts/rstack.config.ts +++ b/packages/create-rstack/template-lib-react-ts/rstack.config.ts @@ -1,4 +1,4 @@ -// Rstack configuration guide: https://rstack.rs/config +// Configuration guide: https://rstack.rs/config import { define } from 'rstack'; define.lib(async () => { diff --git a/packages/create-rstack/template-lib-react/rstack.config.js b/packages/create-rstack/template-lib-react/rstack.config.js index 12fc5223..76fdfda3 100644 --- a/packages/create-rstack/template-lib-react/rstack.config.js +++ b/packages/create-rstack/template-lib-react/rstack.config.js @@ -1,5 +1,5 @@ // @ts-check -// Rstack configuration guide: https://rstack.rs/config +// Configuration guide: https://rstack.rs/config import { define } from 'rstack'; define.lib(async () => { diff --git a/packages/create-rstack/template-lib-solid-ts/rstack.config.ts b/packages/create-rstack/template-lib-solid-ts/rstack.config.ts index 3fa4dc06..c61c28e5 100644 --- a/packages/create-rstack/template-lib-solid-ts/rstack.config.ts +++ b/packages/create-rstack/template-lib-solid-ts/rstack.config.ts @@ -1,4 +1,4 @@ -// Rstack configuration guide: https://rstack.rs/config +// Configuration guide: https://rstack.rs/config import { define } from 'rstack'; define.lib(async () => { diff --git a/packages/create-rstack/template-lib-solid/rstack.config.js b/packages/create-rstack/template-lib-solid/rstack.config.js index 0e2a8f3e..974cf85d 100644 --- a/packages/create-rstack/template-lib-solid/rstack.config.js +++ b/packages/create-rstack/template-lib-solid/rstack.config.js @@ -1,5 +1,5 @@ // @ts-check -// Rstack configuration guide: https://rstack.rs/config +// Configuration guide: https://rstack.rs/config import { define } from 'rstack'; define.lib(async () => { diff --git a/packages/create-rstack/template-lib-svelte-ts/rstack.config.ts b/packages/create-rstack/template-lib-svelte-ts/rstack.config.ts index b74a4f81..6aeaf38c 100644 --- a/packages/create-rstack/template-lib-svelte-ts/rstack.config.ts +++ b/packages/create-rstack/template-lib-svelte-ts/rstack.config.ts @@ -1,4 +1,4 @@ -// Rstack configuration guide: https://rstack.rs/config +// Configuration guide: https://rstack.rs/config import { define } from 'rstack'; import { svelteDtsPlugin } from './scripts/rslib-plugin-svelte-dts.ts'; diff --git a/packages/create-rstack/template-lib-svelte/rstack.config.js b/packages/create-rstack/template-lib-svelte/rstack.config.js index 4bbb928c..7a952e06 100644 --- a/packages/create-rstack/template-lib-svelte/rstack.config.js +++ b/packages/create-rstack/template-lib-svelte/rstack.config.js @@ -1,5 +1,5 @@ // @ts-check -// Rstack configuration guide: https://rstack.rs/config +// Configuration guide: https://rstack.rs/config import { define } from 'rstack'; define.lib(async () => { diff --git a/packages/create-rstack/template-lib-vue-ts/rstack.config.ts b/packages/create-rstack/template-lib-vue-ts/rstack.config.ts index e441042e..c30a51b2 100644 --- a/packages/create-rstack/template-lib-vue-ts/rstack.config.ts +++ b/packages/create-rstack/template-lib-vue-ts/rstack.config.ts @@ -1,4 +1,4 @@ -// Rstack configuration guide: https://rstack.rs/config +// Configuration guide: https://rstack.rs/config import { define } from 'rstack'; define.lib(async () => { diff --git a/packages/create-rstack/template-lib-vue/rstack.config.js b/packages/create-rstack/template-lib-vue/rstack.config.js index cd42bd0d..42ec7988 100644 --- a/packages/create-rstack/template-lib-vue/rstack.config.js +++ b/packages/create-rstack/template-lib-vue/rstack.config.js @@ -1,5 +1,5 @@ // @ts-check -// Rstack configuration guide: https://rstack.rs/config +// Configuration guide: https://rstack.rs/config import { define } from 'rstack'; define.lib(async () => { diff --git a/packages/rstack/rstack.config.ts b/packages/rstack/rstack.config.ts index 09910407..8abe863e 100644 --- a/packages/rstack/rstack.config.ts +++ b/packages/rstack/rstack.config.ts @@ -1,4 +1,4 @@ -// Rstack configuration guide: https://rstack.rs/config +// Configuration guide: https://rstack.rs/config import { define } from 'rstack'; define.test(async () => { diff --git a/packages/rstack/src/config.ts b/packages/rstack/src/config.ts index 0bf3bc52..222e6ff3 100644 --- a/packages/rstack/src/config.ts +++ b/packages/rstack/src/config.ts @@ -94,7 +94,7 @@ type Define = { * * This config is used by the `rs dev`, `rs build`, and `rs preview` commands. * - * @see {@link https://rstack.rs/config | Rstack configuration guide} + * @see {@link https://rstack.rs/config | Configuration guide} */ app: (config: RsbuildConfigDefinition) => void; /** @@ -102,7 +102,7 @@ type Define = { * * This config is used by the `rs lib` command. * - * @see {@link https://rstack.rs/config | Rstack configuration guide} + * @see {@link https://rstack.rs/config | Configuration guide} */ lib: (config: RslibConfigDefinition) => void; /** @@ -110,7 +110,7 @@ type Define = { * * This config is used by the `rs doc` command. * - * @see {@link https://rstack.rs/config | Rstack configuration guide} + * @see {@link https://rstack.rs/config | Configuration guide} */ doc: (config: RspressConfigDefinition) => void; /** @@ -122,7 +122,7 @@ type Define = { * falls back to `define.lib`. For multi-project configs, this applies to every inline * project without an explicit `extends`. The app config takes precedence when both are defined. * - * @see {@link https://rstack.rs/config | Rstack configuration guide} + * @see {@link https://rstack.rs/config | Configuration guide} */ test: (config: RstestConfigExport) => void; /** @@ -131,7 +131,7 @@ type Define = { * This config is used by the `rs lint` command. * A config factory receives the exports from `rstack/lint`. * - * @see {@link https://rstack.rs/config | Rstack configuration guide} + * @see {@link https://rstack.rs/config | Configuration guide} */ lint: (config: RslintConfig | RslintConfigFactory) => void; /** @@ -139,7 +139,7 @@ type Define = { * * This config will be used by the `rs fmt` command. * - * @see {@link https://rstack.rs/config | Rstack configuration guide} + * @see {@link https://rstack.rs/config | Configuration guide} */ fmt: (config: FmtConfigDefinition) => void; /** @@ -147,7 +147,7 @@ type Define = { * * This config is used by the `rs staged` command. * - * @see {@link https://rstack.rs/config | Rstack configuration guide} + * @see {@link https://rstack.rs/config | Configuration guide} */ staged: (config: StagedConfig) => void; }; diff --git a/rstack.config.ts b/rstack.config.ts index 3e20de09..68b2ef8f 100644 --- a/rstack.config.ts +++ b/rstack.config.ts @@ -1,4 +1,4 @@ -// Rstack configuration guide: https://rstack.rs/config +// Configuration guide: https://rstack.rs/config import { define } from 'rstack'; define.lint(async ({ js, ts }) => { diff --git a/website/docs/en/guide/configuration.mdx b/website/docs/en/guide/configuration.mdx index 9b3d8283..ff057d24 100644 --- a/website/docs/en/guide/configuration.mdx +++ b/website/docs/en/guide/configuration.mdx @@ -9,7 +9,7 @@ Rstack CLI centralizes the configuration for your project's tools in a single fi Create `rstack.config.ts` in the project root and call the relevant `define.*()` APIs: ```ts title="rstack.config.ts" -// Rstack configuration guide: https://rstack.rs/config +// Configuration guide: https://rstack.rs/config import { define } from 'rstack'; define.app({ diff --git a/website/docs/en/guide/quick-start.mdx b/website/docs/en/guide/quick-start.mdx index 902be45d..ec64840d 100644 --- a/website/docs/en/guide/quick-start.mdx +++ b/website/docs/en/guide/quick-start.mdx @@ -156,7 +156,7 @@ The following commands are available: Create `rstack.config.ts` in the project root and register the configurations your project needs. The following is a minimal example for an application with testing and linting: ```ts title="rstack.config.ts" -// Rstack configuration guide: https://rstack.rs/config +// Configuration guide: https://rstack.rs/config import { define } from 'rstack'; define.app({ diff --git a/website/docs/zh/guide/configuration.mdx b/website/docs/zh/guide/configuration.mdx index dc3d8fde..5f15b77b 100644 --- a/website/docs/zh/guide/configuration.mdx +++ b/website/docs/zh/guide/configuration.mdx @@ -9,7 +9,7 @@ Rstack CLI 将项目所用工具的配置集中到一份文件中。通过 `defi 在项目根目录创建 `rstack.config.ts`,并调用对应的 `define.*()` API: ```ts title="rstack.config.ts" -// Rstack configuration guide: https://rstack.rs/config +// Configuration guide: https://rstack.rs/config import { define } from 'rstack'; define.app({ diff --git a/website/docs/zh/guide/quick-start.mdx b/website/docs/zh/guide/quick-start.mdx index aa7352a7..4cc43cca 100644 --- a/website/docs/zh/guide/quick-start.mdx +++ b/website/docs/zh/guide/quick-start.mdx @@ -156,7 +156,7 @@ Rstack CLI 提供以下命令: 在项目根目录创建 `rstack.config.ts`,并注册项目所需的配置。以下是一个包含应用、测试和代码检查的最小示例: ```ts title="rstack.config.ts" -// Rstack configuration guide: https://rstack.rs/config +// Configuration guide: https://rstack.rs/config import { define } from 'rstack'; define.app({ diff --git a/website/rstack.config.ts b/website/rstack.config.ts index aa78c750..8e1fd234 100644 --- a/website/rstack.config.ts +++ b/website/rstack.config.ts @@ -1,4 +1,4 @@ -// Rstack configuration guide: https://rstack.rs/config +// Configuration guide: https://rstack.rs/config import path from 'node:path'; import { define } from 'rstack'; From 0b7774443b685ea5d2087910c32c9c447f833285 Mon Sep 17 00:00:00 2001 From: Jiahan Chen Date: Sun, 16 Aug 2026 08:34:52 +0800 Subject: [PATCH 33/33] chore(fmt): use default print width (#369) --- .../references/rslint.md | 5 +- .../test-inline-projects/tests/dom.test.tsx | 4 +- packages/create-rstack/src/index.ts | 49 +++++-- packages/create-rstack/tests/create.test.ts | 127 ++++++++++++++---- packages/rstack/rslib.config.ts | 3 +- packages/rstack/src/cli/args.ts | 50 +++++-- packages/rstack/src/cli/commandHelp.ts | 126 +++++++++++++---- packages/rstack/src/cli/commands.ts | 37 ++++- packages/rstack/src/config.ts | 22 ++- packages/rstack/src/fmt/cacheIdentity.ts | 19 ++- packages/rstack/src/fmt/cacheStore.ts | 17 ++- packages/rstack/src/fmt/cli.ts | 43 ++++-- packages/rstack/src/fmt/config.ts | 31 ++++- packages/rstack/src/fmt/discoverPaths.ts | 96 ++++++++++--- packages/rstack/src/fmt/discovery.ts | 4 +- packages/rstack/src/fmt/fileResolver.ts | 4 +- packages/rstack/src/fmt/format.ts | 3 +- packages/rstack/src/fmt/ignore.ts | 8 +- packages/rstack/src/fmt/lsp/minimalEdit.ts | 16 ++- packages/rstack/src/fmt/lsp/server.ts | 97 +++++++------ packages/rstack/src/fmt/pathHelpers.ts | 11 +- packages/rstack/src/fmt/plugins.ts | 28 +++- packages/rstack/src/fmt/prettierPlugins.ts | 5 +- packages/rstack/src/fmt/runner.ts | 25 +++- packages/rstack/src/fmt/types.ts | 8 +- packages/rstack/src/fmt/worker.ts | 3 +- packages/rstack/src/fmt/workerPool.ts | 10 +- packages/rstack/src/fmt/yukuPlugin.ts | 123 ++++++++++++----- packages/rstack/src/native/index.ts | 4 +- packages/rstack/src/projectCache.ts | 10 +- packages/rstack/src/rsbuildConfig.ts | 12 +- packages/rstack/src/rslibConfig.ts | 17 ++- packages/rstack/src/rspressConfig.ts | 6 +- packages/rstack/src/rstestConfig.ts | 16 ++- packages/rstack/src/setup/hooks.ts | 15 ++- packages/rstack/src/setup/index.ts | 8 +- packages/rstack/src/setup/install.ts | 96 ++++++++++--- packages/rstack/src/staged.ts | 12 +- packages/rstack/tests/cli/args.test.ts | 23 ++-- packages/rstack/tests/cli/check.test.ts | 8 +- packages/rstack/tests/cli/fmt/cache.test.ts | 102 +++++++++----- packages/rstack/tests/cli/fmt/config.test.ts | 43 ++++-- packages/rstack/tests/cli/fmt/files.test.ts | 37 +++-- packages/rstack/tests/cli/fmt/helpers.ts | 33 ++++- packages/rstack/tests/cli/fmt/lsp.test.ts | 43 ++++-- packages/rstack/tests/cli/fmt/lspClient.ts | 48 +++++-- .../rstack/tests/cli/fmt/patterns.test.ts | 14 +- packages/rstack/tests/cli/fmt/stdin.test.ts | 45 +++++-- packages/rstack/tests/cli/fmt/vue.test.ts | 12 +- packages/rstack/tests/cli/setup/index.test.ts | 48 +++++-- .../tests/cli/specify-config/index.test.ts | 6 +- packages/rstack/tests/cli/staged/fmt.test.ts | 40 ++++-- .../tests/config/define-app-lib/index.test.ts | 4 +- .../tests/config/define-app/index.test.ts | 6 +- .../tests/config/define-doc/index.test.ts | 6 +- .../tests/config/define-lib/index.test.ts | 6 +- .../tests/config/define-lint/index.test.ts | 6 +- .../define-test-projects-app/index.test.ts | 4 +- .../define-test-projects-lib/index.test.ts | 4 +- .../tests/config/load-config/index.test.ts | 7 +- .../config/reload-app-config/index.test.ts | 19 ++- .../config/reload-doc-config/index.test.ts | 45 +++++-- .../config/reload-lib-config/index.test.ts | 27 +++- .../tests/exports/test-subpath/index.test.ts | 9 +- .../rstack/tests/fmt/cacheIdentity.test.ts | 16 ++- packages/rstack/tests/fmt/cacheStore.test.ts | 12 +- packages/rstack/tests/fmt/config.test.ts | 13 +- .../rstack/tests/fmt/discoverPaths.test.ts | 110 ++++++++++----- packages/rstack/tests/fmt/discovery.test.ts | 50 +++++-- .../rstack/tests/fmt/fileResolver.test.ts | 5 +- packages/rstack/tests/fmt/helpers.ts | 16 ++- packages/rstack/tests/fmt/ignore.test.ts | 29 +++- .../rstack/tests/fmt/lsp/minimalEdit.test.ts | 47 +++++-- packages/rstack/tests/fmt/lsp/server.test.ts | 13 +- packages/rstack/tests/fmt/plugins.test.ts | 10 +- packages/rstack/tests/fmt/runner.test.ts | 40 ++++-- packages/rstack/tests/fmt/runnerCache.test.ts | 94 +++++++++---- .../tests/fmt/runnerWorkerPreflight.test.ts | 20 ++- packages/rstack/tests/fmt/worker.test.ts | 20 ++- packages/rstack/tests/fmt/yukuPlugin.test.ts | 48 ++++--- packages/rstack/tests/helpers/cli.ts | 27 ++-- packages/rstack/tests/helpers/cliTest.ts | 26 +++- packages/rstack/tests/helpers/logs.ts | 4 +- .../rstack/tests/setup/directories.test.ts | 44 ++++-- packages/rstack/tests/setup/helpers.ts | 24 +++- packages/rstack/tests/setup/hooks.test.ts | 33 +++-- packages/rstack/tests/setup/install.test.ts | 66 ++++++--- .../rstack/tests/setup/runtime-errors.test.ts | 4 +- packages/rstack/tests/setup/runtime.test.ts | 24 +++- .../tests/types/resolution-bundler/index.ts | 9 +- .../tests/types/resolution-nodenext/index.ts | 9 +- rstack.config.ts | 12 +- scripts/benchmark-fmt-discovery.js | 10 +- scripts/prepare-release.js | 9 +- website/docs/en/guide/ai.mdx | 5 +- website/docs/en/guide/cli/_meta.json | 14 +- website/docs/en/guide/cli/lint.mdx | 5 +- website/docs/en/guide/configuration.mdx | 5 +- website/docs/en/guide/monorepo.mdx | 5 +- website/docs/zh/guide/ai.mdx | 5 +- website/docs/zh/guide/cli/_meta.json | 14 +- website/docs/zh/guide/cli/lint.mdx | 5 +- website/docs/zh/guide/configuration.mdx | 5 +- website/docs/zh/guide/monorepo.mdx | 5 +- website/rstack.config.ts | 16 ++- website/theme/components/Copyright.tsx | 5 +- website/theme/components/Features.tsx | 10 +- website/theme/components/Hero.module.scss | 3 +- website/theme/components/Hero.tsx | 7 +- 109 files changed, 2087 insertions(+), 681 deletions(-) diff --git a/.agents/skills/migrate-to-rstack-cli/references/rslint.md b/.agents/skills/migrate-to-rstack-cli/references/rslint.md index 41037e8b..5e9b6d43 100644 --- a/.agents/skills/migrate-to-rstack-cli/references/rslint.md +++ b/.agents/skills/migrate-to-rstack-cli/references/rslint.md @@ -14,7 +14,10 @@ Read this reference when the project uses `@rslint/core`, `rslint.config.*`, `rs ```ts import { define } from 'rstack'; -define.lint(({ js, ts }) => [js.configs.recommended, ts.configs.recommendedTypeChecked]); +define.lint(({ js, ts }) => [ + js.configs.recommended, + ts.configs.recommendedTypeChecked, +]); ``` Preserve existing presets and rules during migration. diff --git a/examples/test-inline-projects/tests/dom.test.tsx b/examples/test-inline-projects/tests/dom.test.tsx index ed6910fc..c096f3d2 100644 --- a/examples/test-inline-projects/tests/dom.test.tsx +++ b/examples/test-inline-projects/tests/dom.test.tsx @@ -5,5 +5,7 @@ import App from '../src/App'; test('renders the app in a DOM environment', () => { render(); - expect(screen.getByRole('heading', { name: 'Rstack React SSR' })).toBeTruthy(); + expect( + screen.getByRole('heading', { name: 'Rstack React SSR' }), + ).toBeTruthy(); }); diff --git a/packages/create-rstack/src/index.ts b/packages/create-rstack/src/index.ts index f6f32f78..1429da78 100644 --- a/packages/create-rstack/src/index.ts +++ b/packages/create-rstack/src/index.ts @@ -5,7 +5,13 @@ import { create, select, } from '@rstackjs/create-toolkit'; -import { access, appendFile, mkdir, readFile, writeFile } from 'node:fs/promises'; +import { + access, + appendFile, + mkdir, + readFile, + writeFile, +} from 'node:fs/promises'; import path from 'node:path'; const packageRoot = path.join(import.meta.dirname, '..'); @@ -87,12 +93,15 @@ const getTemplateName = async ({ template }: Argv): Promise => { }), ); - return resolveTemplateName(documentationType === 'basic' ? 'doc' : 'doc-i18n'); + return resolveTemplateName( + documentationType === 'basic' ? 'doc' : 'doc-i18n', + ); } const templateType = checkCancel( await select({ - message: projectType === 'app' ? 'Select framework' : 'Select library type', + message: + projectType === 'app' ? 'Select framework' : 'Select library type', options: projectType === 'app' ? [ @@ -129,12 +138,32 @@ const getTemplateName = async ({ template }: Argv): Promise => { }; const getStagedConfig = (templateName: string): string => { - const scriptExtensions = ['js', 'jsx', 'ts', 'tsx', 'mjs', 'cjs', 'mts', 'cts']; - const formatExtensions = ['json', 'jsonc', 'md', 'mdx', 'css', 'html', 'yml', 'yaml']; + const scriptExtensions = [ + 'js', + 'jsx', + 'ts', + 'tsx', + 'mjs', + 'cjs', + 'mts', + 'cts', + ]; + const formatExtensions = [ + 'json', + 'jsonc', + 'md', + 'mdx', + 'css', + 'html', + 'yml', + 'yaml', + ]; const componentExtensions = ['svelte', 'vue']; const templateFormatExtensions = [ ...formatExtensions, - ...componentExtensions.filter((extension) => templateName.includes(extension)), + ...componentExtensions.filter((extension) => + templateName.includes(extension), + ), ]; return [ @@ -157,7 +186,9 @@ const injectStagedSetup = async ({ return; } - const configExtension = await access(path.join(distFolder, 'rstack.config.ts')).then( + const configExtension = await access( + path.join(distFolder, 'rstack.config.ts'), + ).then( () => 'ts', () => 'js', ); @@ -167,8 +198,8 @@ const injectStagedSetup = async ({ }; packageJson.scripts = Object.fromEntries( - Object.entries({ ...packageJson.scripts, prepare: 'rs setup' }).sort(([left], [right]) => - left.localeCompare(right), + Object.entries({ ...packageJson.scripts, prepare: 'rs setup' }).sort( + ([left], [right]) => left.localeCompare(right), ), ); diff --git a/packages/create-rstack/tests/create.test.ts b/packages/create-rstack/tests/create.test.ts index 08c23d7e..63a44649 100644 --- a/packages/create-rstack/tests/create.test.ts +++ b/packages/create-rstack/tests/create.test.ts @@ -31,29 +31,65 @@ type SourceTemplate = { const sourceTemplates: SourceTemplate[] = [ { template: 'app-vanilla', sourceExtension: 'js', testFile: 'dom.test.js' }, - { template: 'app-vanilla-ts', sourceExtension: 'ts', testFile: 'dom.test.ts' }, + { + template: 'app-vanilla-ts', + sourceExtension: 'ts', + testFile: 'dom.test.ts', + }, { template: 'app-react', sourceExtension: 'jsx', testFile: 'index.test.jsx' }, - { template: 'app-react-ts', sourceExtension: 'tsx', testFile: 'index.test.tsx' }, - { template: 'app-preact', sourceExtension: 'jsx', testFile: 'index.test.jsx' }, - { template: 'app-preact-ts', sourceExtension: 'tsx', testFile: 'index.test.tsx' }, + { + template: 'app-react-ts', + sourceExtension: 'tsx', + testFile: 'index.test.tsx', + }, + { + template: 'app-preact', + sourceExtension: 'jsx', + testFile: 'index.test.jsx', + }, + { + template: 'app-preact-ts', + sourceExtension: 'tsx', + testFile: 'index.test.tsx', + }, { template: 'app-vue', sourceExtension: 'js', testFile: 'index.test.js' }, { template: 'app-vue-ts', sourceExtension: 'ts', testFile: 'index.test.ts' }, { template: 'app-lit', sourceExtension: 'js', testFile: 'index.test.js' }, { template: 'app-lit-ts', sourceExtension: 'ts', testFile: 'index.test.ts' }, { template: 'app-svelte', sourceExtension: 'js', testFile: 'index.test.js' }, - { template: 'app-svelte-ts', sourceExtension: 'ts', testFile: 'index.test.ts' }, + { + template: 'app-svelte-ts', + sourceExtension: 'ts', + testFile: 'index.test.ts', + }, { template: 'app-solid', sourceExtension: 'jsx', testFile: 'index.test.jsx' }, - { template: 'app-solid-ts', sourceExtension: 'tsx', testFile: 'index.test.tsx' }, + { + template: 'app-solid-ts', + sourceExtension: 'tsx', + testFile: 'index.test.tsx', + }, { template: 'lib-node', sourceExtension: 'js', testFile: 'index.test.js' }, { template: 'lib-node-ts', sourceExtension: 'ts', testFile: 'index.test.ts' }, { template: 'lib-react', sourceExtension: 'jsx', testFile: 'index.test.jsx' }, - { template: 'lib-react-ts', sourceExtension: 'tsx', testFile: 'index.test.tsx' }, + { + template: 'lib-react-ts', + sourceExtension: 'tsx', + testFile: 'index.test.tsx', + }, { template: 'lib-vue', sourceExtension: 'js', testFile: 'index.test.js' }, { template: 'lib-vue-ts', sourceExtension: 'ts', testFile: 'index.test.ts' }, { template: 'lib-svelte', sourceExtension: 'js', testFile: 'index.test.js' }, - { template: 'lib-svelte-ts', sourceExtension: 'ts', testFile: 'index.test.ts' }, + { + template: 'lib-svelte-ts', + sourceExtension: 'ts', + testFile: 'index.test.ts', + }, { template: 'lib-solid', sourceExtension: 'jsx', testFile: 'index.test.jsx' }, - { template: 'lib-solid-ts', sourceExtension: 'tsx', testFile: 'index.test.tsx' }, + { + template: 'lib-solid-ts', + sourceExtension: 'tsx', + testFile: 'index.test.tsx', + }, ]; const docTemplates = [ @@ -74,14 +110,25 @@ const docTemplates = [ ]; const getCheckScript = (template: string, hasTypeScript: boolean): string => - hasTypeScript && !templatesWithoutTypeCheck.has(template) ? typeCheckScript : checkScript; + hasTypeScript && !templatesWithoutTypeCheck.has(template) + ? typeCheckScript + : checkScript; -const readProjectPackage = async (projectDirectory: string): Promise => - JSON.parse(await readFile(path.join(projectDirectory, 'package.json'), 'utf8')) as ProjectPackage; +const readProjectPackage = async ( + projectDirectory: string, +): Promise => + JSON.parse( + await readFile(path.join(projectDirectory, 'package.json'), 'utf8'), + ) as ProjectPackage; -const expectFiles = async (projectDirectory: string, files: string[]): Promise => { +const expectFiles = async ( + projectDirectory: string, + files: string[], +): Promise => { for (const file of files) { - await expect(access(path.join(projectDirectory, file))).resolves.toBeUndefined(); + await expect( + access(path.join(projectDirectory, file)), + ).resolves.toBeUndefined(); } }; @@ -92,10 +139,16 @@ const expectStagedSetup = async ( ): Promise => { expect(scripts.prepare).toBe('rs setup'); expect( - await readFile(path.join(projectDirectory, '.rstack', 'hooks', 'pre-commit'), 'utf8'), + await readFile( + path.join(projectDirectory, '.rstack', 'hooks', 'pre-commit'), + 'utf8', + ), ).toBe('rs staged\n'); expect( - await readFile(path.join(projectDirectory, `rstack.config.${configExtension}`), 'utf8'), + await readFile( + path.join(projectDirectory, `rstack.config.${configExtension}`), + 'utf8', + ), ).toContain('define.staged({'); }; @@ -109,7 +162,10 @@ const expectNoStagedSetup = async ( access(path.join(projectDirectory, '.rstack', 'hooks', 'pre-commit')), ).rejects.toThrow(); expect( - await readFile(path.join(projectDirectory, `rstack.config.${configExtension}`), 'utf8'), + await readFile( + path.join(projectDirectory, `rstack.config.${configExtension}`), + 'utf8', + ), ).not.toContain('define.staged({'); }; @@ -122,8 +178,14 @@ const expectProjectSetup = async ( const packageJson = await readProjectPackage(projectDirectory); expect(packageJson.name).toBe('my-app'); - expect(packageJson.scripts.check).toBe(getCheckScript(template, hasTypeScript)); - await expectStagedSetup(projectDirectory, configExtension, packageJson.scripts); + expect(packageJson.scripts.check).toBe( + getCheckScript(template, hasTypeScript), + ); + await expectStagedSetup( + projectDirectory, + configExtension, + packageJson.scripts, + ); const tsconfig = access(path.join(projectDirectory, 'tsconfig.json')); if (hasTypeScript) { @@ -135,7 +197,9 @@ const expectProjectSetup = async ( afterEach(async () => { await Promise.all( - tempDirectories.splice(0).map((directory) => rm(directory, { recursive: true, force: true })), + tempDirectories + .splice(0) + .map((directory) => rm(directory, { recursive: true, force: true })), ); }); @@ -154,7 +218,8 @@ const createProject = async ( tempDirectories.push(tempDirectory); if (initializeGitIn) { - const gitDirectory = initializeGitIn === 'project' ? projectDirectory : tempDirectory; + const gitDirectory = + initializeGitIn === 'project' ? projectDirectory : tempDirectory; await mkdir(gitDirectory, { recursive: true }); await execFileAsync('git', ['init', '--quiet'], { cwd: gitDirectory }); } @@ -209,14 +274,22 @@ test.each(sourceTemplates)( files.push('src/env.d.ts'); } - await expectProjectSetup(projectDirectory, template, configExtension, hasTypeScript); + await expectProjectSetup( + projectDirectory, + template, + configExtension, + hasTypeScript, + ); await expectFiles(projectDirectory, files); }, ); -test.each(docTemplates)('creates the $template template', async ({ template, files }) => { - const projectDirectory = await createProject(template); +test.each(docTemplates)( + 'creates the $template template', + async ({ template, files }) => { + const projectDirectory = await createProject(template); - await expectProjectSetup(projectDirectory, template, 'ts', true); - await expectFiles(projectDirectory, files); -}); + await expectProjectSetup(projectDirectory, template, 'ts', true); + await expectFiles(projectDirectory, files); + }, +); diff --git a/packages/rstack/rslib.config.ts b/packages/rstack/rslib.config.ts index 70b66090..2f26a5fc 100644 --- a/packages/rstack/rslib.config.ts +++ b/packages/rstack/rslib.config.ts @@ -2,7 +2,8 @@ import { defineConfig } from '@rslib/core'; import prettierPkgJson from 'prettier/package.json' with { type: 'json' }; import pkgJson from './package.json' with { type: 'json' }; -const fullyMinifiedChunks = /(?:fmt(?:Lsp|Plugins)?|sortPackageJsonPlugin|staged)\.js$/; +const fullyMinifiedChunks = + /(?:fmt(?:Lsp|Plugins)?|sortPackageJsonPlugin|staged)\.js$/; export default defineConfig({ dts: true, diff --git a/packages/rstack/src/cli/args.ts b/packages/rstack/src/cli/args.ts index cf55aa88..29d13f52 100644 --- a/packages/rstack/src/cli/args.ts +++ b/packages/rstack/src/cli/args.ts @@ -5,7 +5,10 @@ import { type ParseArgsOptionsConfig, } from 'node:util'; -type ParseArgsOptionDescriptor = Omit & { +type ParseArgsOptionDescriptor = Omit< + NodeParseArgsOptionDescriptor, + 'default' +> & { default?: never; }; @@ -13,11 +16,14 @@ type ParseArgsConfig = Omit & { options?: Record; }; -type CamelCase = Value extends `${infer Head}-${infer Tail}` - ? `${Head}${Capitalize>}` - : Value; +type CamelCase = + Value extends `${infer Head}-${infer Tail}` + ? `${Head}${Capitalize>}` + : Value; -type NodeParseArgsResult = ReturnType>; +type NodeParseArgsResult = ReturnType< + typeof nodeParseArgs +>; type ParseArgsResult = Omit< NodeParseArgsResult, @@ -25,7 +31,9 @@ type ParseArgsResult = Omit< > & { values: { [ - Name in keyof NodeParseArgsResult['values'] as CamelCase + Name in keyof NodeParseArgsResult['values'] as CamelCase< + Name & string + > ]: NodeParseArgsResult['values'][Name]; }; }; @@ -34,16 +42,20 @@ const KEBAB_CASE_REGEXP = /-([a-z])/g; const toCamelCase = (value: string): string => value.includes('-') - ? value.replace(KEBAB_CASE_REGEXP, (_, character: string) => character.toUpperCase()) + ? value.replace(KEBAB_CASE_REGEXP, (_, character: string) => + character.toUpperCase(), + ) : value; -export function parseArgs( - config?: Config, -): ParseArgsResult { +export function parseArgs< + const Config extends ParseArgsConfig = ParseArgsConfig, +>(config?: Config): ParseArgsResult { const options: ParseArgsOptionsConfig = {}; const optionNames: [originalName: string, camelName: string][] = []; - for (const [originalName, descriptor] of Object.entries(config?.options ?? {})) { + for (const [originalName, descriptor] of Object.entries( + config?.options ?? {}, + )) { const camelName = toCamelCase(originalName); optionNames.push([originalName, camelName]); options[originalName] = descriptor; @@ -61,7 +73,8 @@ export function parseArgs', 'Specify Rstack config file path']; +const CONFIG_OPTION: HelpItem = [ + '-c, --config ', + 'Specify Rstack config file path', +]; const HELP_OPTION: HelpItem = ['-h, --help', 'Display this help message']; const VERSION_OPTION: HelpItem = ['-v, --version', 'Display version number']; const CONFIG_HELP_OPTIONS = [CONFIG_OPTION, HELP_OPTION]; -const OPEN_OPTION: HelpItem = ['-o, --open [url]', 'Open the page in browser on startup']; -const PORT_OPTION: HelpItem = ['--port ', 'Set the port number for the server']; +const OPEN_OPTION: HelpItem = [ + '-o, --open [url]', + 'Open the page in browser on startup', +]; +const PORT_OPTION: HelpItem = [ + '--port ', + 'Set the port number for the server', +]; const STRICT_PORT_OPTION: HelpItem = [ '--strict-port', 'Exit if the specified port is already in use', ]; -const HOST_OPTION: HelpItem = ['--host [host]', 'Set the host that the server listens to']; -const BASE_OPTION: HelpItem = ['--base ', 'Set the base path and override config.base']; -const SERVER_OPTIONS = [OPEN_OPTION, PORT_OPTION, STRICT_PORT_OPTION, HOST_OPTION]; +const HOST_OPTION: HelpItem = [ + '--host [host]', + 'Set the host that the server listens to', +]; +const BASE_OPTION: HelpItem = [ + '--base ', + 'Set the base path and override config.base', +]; +const SERVER_OPTIONS = [ + OPEN_OPTION, + PORT_OPTION, + STRICT_PORT_OPTION, + HOST_OPTION, +]; const TEST_UPDATE_OPTION: HelpItem = ['-u, --update', 'Update snapshot files']; const TEST_COVERAGE_OPTION: HelpItem = ['--coverage', 'Enable code coverage']; -const TEST_PROJECT_OPTION: HelpItem = ['--project ', 'Filter test projects by name']; +const TEST_PROJECT_OPTION: HelpItem = [ + '--project ', + 'Filter test projects by name', +]; const TEST_NAME_OPTION: HelpItem = [ '-t, --test-name-pattern ', 'Run tests with names matching the pattern', @@ -76,8 +99,14 @@ const TEST_OPTIONS = [ TEST_NAME_OPTION, ]; -const LIB_WATCH_OPTION: HelpItem = ['-w, --watch', 'Enable watch mode and rebuild on changes']; -const LIB_DTS_OPTION: HelpItem = ['--dts', 'Emit declaration files (use --no-dts to disable)']; +const LIB_WATCH_OPTION: HelpItem = [ + '-w, --watch', + 'Enable watch mode and rebuild on changes', +]; +const LIB_DTS_OPTION: HelpItem = [ + '--dts', + 'Emit declaration files (use --no-dts to disable)', +]; const LIB_BUILD_OPTIONS = [LIB_WATCH_OPTION, LIB_DTS_OPTION]; const commandHint = (command: string): HelpSection => ({ @@ -123,7 +152,10 @@ const HELP_DEFINITIONS = { sections: [ { title: 'Options', - items: [['--type-check', 'Enable TypeScript type checking'], ...CONFIG_HELP_OPTIONS], + items: [ + ['--type-check', 'Enable TypeScript type checking'], + ...CONFIG_HELP_OPTIONS, + ], }, ], }, @@ -144,7 +176,10 @@ const HELP_DEFINITIONS = { { title: 'Options', items: [ - ['-w, --watch', 'Enable watch mode to automatically rebuild on file changes'], + [ + '-w, --watch', + 'Enable watch mode to automatically rebuild on file changes', + ], ['--dist-path ', 'Set the root directory of output files'], ['--source-map', 'Enable source map'], ...CONFIG_HELP_OPTIONS, @@ -228,7 +263,11 @@ const HELP_DEFINITIONS = { commandHint('test'), { title: 'Options', - items: [['-w, --watch', 'Enable watch mode'], ...TEST_OPTIONS, ...CONFIG_HELP_OPTIONS], + items: [ + ['-w, --watch', 'Enable watch mode'], + ...TEST_OPTIONS, + ...CONFIG_HELP_OPTIONS, + ], }, ], }, @@ -273,7 +312,10 @@ const HELP_DEFINITIONS = { ['--print-location', 'Print test locations'], ['--summary', 'Print a summary'], TEST_PROJECT_OPTION, - ['-t, --test-name-pattern ', 'List tests with names matching the pattern'], + [ + '-t, --test-name-pattern ', + 'List tests with names matching the pattern', + ], ...CONFIG_HELP_OPTIONS, ], }, @@ -339,7 +381,10 @@ const HELP_DEFINITIONS = { { title: 'Options', items: [ - ['--output ', 'Set the output path for inspection results (default: .rsbuild)'], + [ + '--output ', + 'Set the output path for inspection results (default: .rsbuild)', + ], ['--verbose', 'Show complete function definitions in output'], ...CONFIG_HELP_OPTIONS, ], @@ -366,9 +411,15 @@ const HELP_DEFINITIONS = { ['--fix', 'Automatically fix problems'], ['--type-check', 'Enable TypeScript type checking'], ['--type-check-only', 'Run only TypeScript type checking'], - ['--format ', 'Set output format (default | jsonline | github | gitlab)'], + [ + '--format ', + 'Set output format (default | jsonline | github | gitlab)', + ], ['--quiet', 'Report errors only'], - ['--timing [all|N]', 'Print a per-rule timing table (all rules or top N)'], + [ + '--timing [all|N]', + 'Print a per-rule timing table (all rules or top N)', + ], ['--max-warnings ', 'Set the maximum number of warnings'], ['--rule ', 'Override a rule (repeatable)'], ['--no-color', 'Disable colored output'], @@ -388,14 +439,23 @@ const HELP_DEFINITIONS = { ['-w, --write', 'Write formatted files in place (default)'], ['--check', 'Check whether files are formatted'], ['-l, --list-different', 'Print paths of unformatted files'], - ['--ignore-path ', 'Path to an additional ignore file (repeatable)'], + [ + '--ignore-path ', + 'Path to an additional ignore file (repeatable)', + ], ['-u, --ignore-unknown', 'Ignore unknown files'], ['--no-cache', 'Disable the formatting cache'], ['--cache-location ', 'Path to the formatting cache directory'], - ['--no-error-on-unmatched-pattern', 'Do not error when no files match'], + [ + '--no-error-on-unmatched-pattern', + 'Do not error when no files match', + ], ['--with-node-modules', 'Process files inside node_modules'], ['--parallel-workers ', 'Number of parallel workers'], - ['--stdin-filepath ', 'Format stdin as if it were saved at '], + [ + '--stdin-filepath ', + 'Format stdin as if it were saved at ', + ], ['--lsp', 'Run a language server on stdio'], ...CONFIG_HELP_OPTIONS, ], @@ -409,7 +469,10 @@ const HELP_DEFINITIONS = { { title: 'Options', items: [ - ['--allow-empty', 'Allow empty commits when tasks revert all staged changes'], + [ + '--allow-empty', + 'Allow empty commits when tasks revert all staged changes', + ], [ '-p, --concurrent ', 'The number of tasks to run concurrently, or false for serial', @@ -435,7 +498,10 @@ const HELP_DEFINITIONS = { { title: 'Options', items: [ - ['--hooks-dir ', 'Specify hooks directory relative to the Git repository root'], + [ + '--hooks-dir ', + 'Specify hooks directory relative to the Git repository root', + ], HELP_OPTION, ], }, @@ -444,10 +510,15 @@ const HELP_DEFINITIONS = { } satisfies Record; const renderItems = (items: readonly HelpItem[]): string => { - const labelWidth = items.reduce((width, [label]) => Math.max(width, label.length), 0); + const labelWidth = items.reduce( + (width, [label]) => Math.max(width, label.length), + 0, + ); return items - .map(([label, description]) => ` ${label.padEnd(labelWidth)} ${description}`) + .map( + ([label, description]) => ` ${label.padEnd(labelWidth)} ${description}`, + ) .join('\n'); }; @@ -459,7 +530,11 @@ const renderSection = (section: HelpSection): string => { return section.dim ? color.dim(section.content) : section.content; }; -const renderHelp = ({ usage, description, sections = [] }: HelpDefinition): string => { +const renderHelp = ({ + usage, + description, + sections = [], +}: HelpDefinition): string => { const blocks = [ color.bold(`Rstack v${RSTACK_VERSION}`), `${color.cyan('Usage')}:\n${color.yellow(` $ ${usage}`)}`, @@ -474,4 +549,5 @@ const renderHelp = ({ usage, description, sections = [] }: HelpDefinition): stri return blocks.join('\n\n'); }; -export const renderCommandHelp = (topic: HelpTopic): string => renderHelp(HELP_DEFINITIONS[topic]); +export const renderCommandHelp = (topic: HelpTopic): string => + renderHelp(HELP_DEFINITIONS[topic]); diff --git a/packages/rstack/src/cli/commands.ts b/packages/rstack/src/cli/commands.ts index 07ed732e..4368dbea 100644 --- a/packages/rstack/src/cli/commands.ts +++ b/packages/rstack/src/cli/commands.ts @@ -18,7 +18,11 @@ async function runRsbuildCLI(args: string[]): Promise { const argv = [ process.execPath, 'rsbuild', - ...insertConfigArg(args, '--config', join(import.meta.dirname, 'rsbuildConfig.js')), + ...insertConfigArg( + args, + '--config', + join(import.meta.dirname, 'rsbuildConfig.js'), + ), ]; const { runCLI } = await import('@rsbuild/core'); @@ -46,7 +50,11 @@ async function runRstestCLI(args: string[]): Promise { const argv = [ process.execPath, 'rstest', - ...insertConfigArg(args, '--config', join(import.meta.dirname, 'rstestConfig.js')), + ...insertConfigArg( + args, + '--config', + join(import.meta.dirname, 'rstestConfig.js'), + ), ]; const { runCLI } = await import('@rstest/core'); @@ -70,7 +78,11 @@ async function runRslibCLI(args: string[]): Promise { const argv = [ process.execPath, 'rslib', - ...insertConfigArg(args, '--config', join(import.meta.dirname, 'rslibConfig.js')), + ...insertConfigArg( + args, + '--config', + join(import.meta.dirname, 'rslibConfig.js'), + ), ]; const { runCLI } = await import('@rslib/core'); @@ -83,7 +95,9 @@ const isMissingRspressCoreError = (error: unknown): boolean => { } const code = 'code' in error ? error.code : undefined; - return code === 'ERR_MODULE_NOT_FOUND' && error.message.includes('@rspress/core'); + return ( + code === 'ERR_MODULE_NOT_FOUND' && error.message.includes('@rspress/core') + ); }; async function runRspressCLI(args: string[]): Promise { @@ -103,7 +117,11 @@ async function runRspressCLI(args: string[]): Promise { const argv = [ process.execPath, 'rspress', - ...insertConfigArg(args, '--config', join(import.meta.dirname, 'rspressConfig.js')), + ...insertConfigArg( + args, + '--config', + join(import.meta.dirname, 'rspressConfig.js'), + ), ]; try { @@ -128,7 +146,11 @@ async function runRslintCLI(args: string[]): Promise { const argv = [ process.execPath, 'rslint', - ...insertConfigArg(args, '--config', join(import.meta.dirname, 'rslintConfig.js')), + ...insertConfigArg( + args, + '--config', + join(import.meta.dirname, 'rslintConfig.js'), + ), ]; const { runCLI } = await import('@rslint/core'); @@ -171,7 +193,8 @@ export async function setupCommands(): Promise { // when the config is later loaded from another directory. The motivating case // is `rs fmt --lsp`, which loads the config from the LSP workspace root the // client reports, and that root need not be the process working directory. - getConfigState().configPath = configPath === undefined ? undefined : resolve(configPath); + getConfigState().configPath = + configPath === undefined ? undefined : resolve(configPath); if (!command || command === '-h' || command === '--help') { return printCommandHelp('root'); diff --git a/packages/rstack/src/config.ts b/packages/rstack/src/config.ts index 222e6ff3..ecc3983b 100644 --- a/packages/rstack/src/config.ts +++ b/packages/rstack/src/config.ts @@ -8,7 +8,8 @@ import type { RstestConfigExport } from '@rstest/core'; import type { FmtConfigDefinition } from './fmt/types.ts'; import type { StagedConfig } from './staged.ts'; -export type RslintConfigDefinition = RslintConfig | (() => Promise); +export type RslintConfigDefinition = + RslintConfig | (() => Promise); export type RspressConfigDefinition = UserConfig | UserConfigAsyncFn; type RslintConfigFactory = ( @@ -62,7 +63,8 @@ type ConfigState = { declare global { // rslint-disable-next-line no-var - var __rstackConfigSessionStorage: AsyncLocalStorage | undefined; + var __rstackConfigSessionStorage: + AsyncLocalStorage | undefined; // rslint-disable-next-line no-var var __rstackCliState: ConfigState | undefined; } @@ -72,7 +74,8 @@ const getConfigSessionStorage = (): AsyncLocalStorage => { // imports the internal Rstack config. Keep the storage on globalThis so // every module instance reads and writes the same active session. if (!globalThis.__rstackConfigSessionStorage) { - globalThis.__rstackConfigSessionStorage = new AsyncLocalStorage(); + globalThis.__rstackConfigSessionStorage = + new AsyncLocalStorage(); } return globalThis.__rstackConfigSessionStorage; @@ -152,11 +155,16 @@ type Define = { staged: (config: StagedConfig) => void; }; -const setConfig = (type: T, config: Configs[T]): void => { +const setConfig = ( + type: T, + config: Configs[T], +): void => { const session = getConfigSessionStorage().getStore(); if (!session?.active) { - throw new Error(`The "${type}" config must be defined while loading an Rstack config.`); + throw new Error( + `The "${type}" config must be defined while loading an Rstack config.`, + ); } if (type in session.configs) { @@ -173,7 +181,9 @@ export const define: Define = { lint: (config) => setConfig( 'lint', - typeof config === 'function' ? async () => config(await import('@rslint/core')) : config, + typeof config === 'function' + ? async () => config(await import('@rslint/core')) + : config, ), fmt: (config) => setConfig('fmt', config), staged: (config) => setConfig('staged', config), diff --git a/packages/rstack/src/fmt/cacheIdentity.ts b/packages/rstack/src/fmt/cacheIdentity.ts index f7ba278d..81d7bdd6 100644 --- a/packages/rstack/src/fmt/cacheIdentity.ts +++ b/packages/rstack/src/fmt/cacheIdentity.ts @@ -17,7 +17,11 @@ const createCacheHash = (content: string | Uint8Array): string => createDigest('sha256', content, 'base64url').slice(0, cacheHashLength); /** Identifies formatter behavior shared by all cache entries in this process. */ -const cacheNamespace: string = JSON.stringify([fmtCacheVersion, RSTACK_VERSION, PRETTIER_VERSION]); +const cacheNamespace: string = JSON.stringify([ + fmtCacheVersion, + RSTACK_VERSION, + PRETTIER_VERSION, +]); /** Creates project-relative POSIX cache keys without repeating path setup. */ const createCacheKeyResolver = (rootPath: string): CacheKeyResolver => { @@ -30,7 +34,9 @@ const createCacheKeyResolver = (rootPath: string): CacheKeyResolver => { }; /** Hashes final per-file options and memoizes option objects shared by many files. */ -const createOptionsHasher = (pluginFingerprints?: PluginFingerprints): OptionsHasher => { +const createOptionsHasher = ( + pluginFingerprints?: PluginFingerprints, +): OptionsHasher => { const hashes = new WeakMap(); return (options) => { @@ -47,8 +53,13 @@ const createOptionsHasher = (pluginFingerprints?: PluginFingerprints): OptionsHa const fingerprints: string[] = []; for (const plugin of plugins) { const key = - plugin instanceof URL ? plugin.href : typeof plugin === 'string' ? plugin : undefined; - const fingerprint = key === undefined ? undefined : pluginFingerprints?.get(key); + plugin instanceof URL + ? plugin.href + : typeof plugin === 'string' + ? plugin + : undefined; + const fingerprint = + key === undefined ? undefined : pluginFingerprints?.get(key); if (fingerprint === undefined) { hashes.set(options, null); return undefined; diff --git a/packages/rstack/src/fmt/cacheStore.ts b/packages/rstack/src/fmt/cacheStore.ts index 71622c62..abecddae 100644 --- a/packages/rstack/src/fmt/cacheStore.ts +++ b/packages/rstack/src/fmt/cacheStore.ts @@ -21,7 +21,11 @@ const fmtCacheStateIds = { } as const satisfies Record; type FmtCacheFileValue = string | number; -type FmtCacheEntry = readonly [contentHash: string, optionsHash: string, state: FmtCacheState]; +type FmtCacheEntry = readonly [ + contentHash: string, + optionsHash: string, + state: FmtCacheState, +]; interface FmtCacheFile { version: typeof fmtCacheVersion; @@ -106,7 +110,8 @@ const parseCacheFile = ( }; }; -const serializeCache = (cache: FmtCacheFile): string => `${JSON.stringify(cache)}\n`; +const serializeCache = (cache: FmtCacheFile): string => + `${JSON.stringify(cache)}\n`; const isFileNotFoundError = (error: unknown): error is NodeJS.ErrnoException => error instanceof Error && 'code' in error && error.code === 'ENOENT'; @@ -150,7 +155,8 @@ class FmtCacheStoreImpl implements FmtCacheStore { const { files, options } = this.#cache; const contentHash = files[offset + contentHashOffset] as string; const optionsHash = options[files[offset + optionsIndexOffset] as number]; - const state = fmtCacheStates[files[offset + stateOffset] as FmtCacheStateId]; + const state = + fmtCacheStates[files[offset + stateOffset] as FmtCacheStateId]; return [contentHash, optionsHash, state]; } @@ -261,7 +267,10 @@ class FmtCacheStoreImpl implements FmtCacheStore { } } -const loadFmtCacheStore = async (filePath: string, namespace: string): Promise => { +const loadFmtCacheStore = async ( + filePath: string, + namespace: string, +): Promise => { const emptyCache = createEmptyCache(namespace); try { diff --git a/packages/rstack/src/fmt/cli.ts b/packages/rstack/src/fmt/cli.ts index 6bd314f2..7b13f498 100644 --- a/packages/rstack/src/fmt/cli.ts +++ b/packages/rstack/src/fmt/cli.ts @@ -35,15 +35,25 @@ const parseMaxWorkers = (value: string | undefined): number | undefined => { } const maxWorkers = Number(value); - if (!/^\d+$/.test(value) || !Number.isSafeInteger(maxWorkers) || maxWorkers < 1) { - throw new Error('The --parallel-workers option must be a positive integer.'); + if ( + !/^\d+$/.test(value) || + !Number.isSafeInteger(maxWorkers) || + maxWorkers < 1 + ) { + throw new Error( + 'The --parallel-workers option must be a positive integer.', + ); } return maxWorkers; }; /** Rejects the mode flags and file arguments that a server-like option replaces. */ -const assertExclusiveMode = (option: string, hasMode: boolean, positionals: string[]): void => { +const assertExclusiveMode = ( + option: string, + hasMode: boolean, + positionals: string[], +): void => { if (hasMode) { throw new Error( `The ${option} option cannot be used with --write, --check, or --list-different.`, @@ -82,7 +92,9 @@ const parseFmtArgs = (args: string[]): ParsedFmtCLIArgs => { const listDifferent = values.listDifferent; const modes = [write, check, listDifferent].filter(Boolean); if (modes.length > 1) { - throw new Error('The --write, --check, and --list-different options cannot be used together.'); + throw new Error( + 'The --write, --check, and --list-different options cannot be used together.', + ); } const mode = check ? 'check' : listDifferent ? 'list-different' : 'write'; @@ -130,14 +142,17 @@ const parseFmtArgs = (args: string[]): ParsedFmtCLIArgs => { }; }; -const createDisplayPathResolver = (cwd: string): ((filePath: string) => string) => { +const createDisplayPathResolver = ( + cwd: string, +): ((filePath: string) => string) => { const resolveRelativePath = createRelativePathResolver(cwd); return (filePath) => toPosixPath(resolveRelativePath(filePath)); }; const prettyTime = (seconds: number): string => { - const format = (time: string, unit: 'm' | 's') => color.bold(`${time}${unit}`); + const format = (time: string, unit: 'm' | 's') => + color.bold(`${time}${unit}`); if (seconds < 10) { const digits = seconds >= 0.01 ? 2 : 3; @@ -156,7 +171,10 @@ const prettyTime = (seconds: number): string => { return minutesLabel; } - const secondsLabel = format(remainingSeconds.toFixed(remainingSeconds % 1 === 0 ? 0 : 1), 's'); + const secondsLabel = format( + remainingSeconds.toFixed(remainingSeconds % 1 === 0 ? 0 : 1), + 's', + ); return `${minutesLabel} ${secondsLabel}`; }; @@ -171,7 +189,9 @@ const reportNoSupportedFiles = (patterns: string[]): void => { const targets = (patterns.length ? patterns : ['.']) .map((pattern) => color.cyan(JSON.stringify(pattern))) .join(', '); - logger.error(`No supported files matched ${targets}, or all matching files were ignored.`); + logger.error( + `No supported files matched ${targets}, or all matching files were ignored.`, + ); process.exitCode = 2; }; @@ -303,7 +323,9 @@ const runFmtCLI = async (args: string[]): Promise => { return; } - const cacheDirPath = cacheLocation ? path.resolve(cwd, cacheLocation) : undefined; + const cacheDirPath = cacheLocation + ? path.resolve(cwd, cacheLocation) + : undefined; if (cacheDirPath) { const cacheDirPrefix = cacheDirPath.endsWith(path.sep) ? cacheDirPath @@ -327,7 +349,8 @@ const runFmtCLI = async (args: string[]): Promise => { if (files.length === 0) { // Staged tasks may pass only paths excluded by formatter ignore rules. - const allowUnmatched = noErrorOnUnmatchedPattern || process.env.RSTACK_STAGED === '1'; + const allowUnmatched = + noErrorOnUnmatchedPattern || process.env.RSTACK_STAGED === '1'; if (allowUnmatched) { return; } diff --git a/packages/rstack/src/fmt/config.ts b/packages/rstack/src/fmt/config.ts index ee0a5123..5e4c543d 100644 --- a/packages/rstack/src/fmt/config.ts +++ b/packages/rstack/src/fmt/config.ts @@ -26,7 +26,9 @@ type OptionsCacheNode = { options: ResolvedFmtOptions; }; -const createOptionsCacheNode = (options: ResolvedFmtOptions): OptionsCacheNode => ({ +const createOptionsCacheNode = ( + options: ResolvedFmtOptions, +): OptionsCacheNode => ({ children: new WeakMap(), options, }); @@ -52,7 +54,9 @@ const compileMatchers = ( return micromatch.matcher(patterns[0], options); } - const matchers = patterns.map((pattern) => micromatch.matcher(pattern, options)); + const matchers = patterns.map((pattern) => + micromatch.matcher(pattern, options), + ); return (filePath) => { for (const matches of matchers) { @@ -79,7 +83,11 @@ const createPathMatcher = ( } } - const basenameMatcher = compileMatchers(basenamePatterns, excludedPatterns, true); + const basenameMatcher = compileMatchers( + basenamePatterns, + excludedPatterns, + true, + ); const pathMatcher = compileMatchers(pathPatterns, excludedPatterns, false); if (!basenameMatcher || !pathMatcher) { @@ -89,7 +97,10 @@ const createPathMatcher = ( }; /** Splits a flat config into project-level formatting options and rules. */ -const normalizeFmtConfig = (config: FmtConfig | undefined, rootPath: string): ResolvedFmtConfig => { +const normalizeFmtConfig = ( + config: FmtConfig | undefined, + rootPath: string, +): ResolvedFmtConfig => { const { ignorePatterns = [], overrides = [], ...baseOptions } = config ?? {}; return { @@ -104,7 +115,9 @@ const normalizeFmtConfig = (config: FmtConfig | undefined, rootPath: string): Re }; /** Creates a reusable resolver for applying per-file formatter overrides. */ -const createOptionsResolver = (config: ResolvedFmtConfig): FmtOptionsResolver => { +const createOptionsResolver = ( + config: ResolvedFmtConfig, +): FmtOptionsResolver => { if (config.overrides.length === 0) { return () => config.baseOptions; } @@ -124,7 +137,10 @@ const createOptionsResolver = (config: ResolvedFmtConfig): FmtOptionsResolver => // Reuse the merged result for this override after the current matched sequence. let nextCacheNode = cacheNode.children.get(override.options); if (!nextCacheNode) { - nextCacheNode = createOptionsCacheNode({ ...cacheNode.options, ...override.options }); + nextCacheNode = createOptionsCacheNode({ + ...cacheNode.options, + ...override.options, + }); cacheNode.children.set(override.options, nextCacheNode); } cacheNode = nextCacheNode; @@ -140,7 +156,8 @@ const resolveFmtConfig = async ({ configFilePath, cwd, }: ResolveFmtConfigOptions): Promise => { - const config = typeof definition === 'function' ? await definition() : definition; + const config = + typeof definition === 'function' ? await definition() : definition; const rootPath = configFilePath ? dirname(configFilePath) : cwd; return normalizeFmtConfig(config, rootPath); diff --git a/packages/rstack/src/fmt/discoverPaths.ts b/packages/rstack/src/fmt/discoverPaths.ts index 0a213400..32e94431 100644 --- a/packages/rstack/src/fmt/discoverPaths.ts +++ b/packages/rstack/src/fmt/discoverPaths.ts @@ -142,7 +142,10 @@ class GitIgnoreFiles { } /** Matches one directory's entries in a single native call. */ - matchDirents(parentPath: string, dirents: Dirent[]): boolean | number | Uint8Array | undefined { + matchDirents( + parentPath: string, + dirents: Dirent[], + ): boolean | number | Uint8Array | undefined { if (!this.#hasRules || dirents.length === 0) { return; } @@ -156,7 +159,11 @@ class GitIgnoreFiles { if (dirents.length === 1) { const dirent = dirents[0]; - return this.#matcher!.isIgnoredChild(relativeParent, dirent.name, dirent.isDirectory()); + return this.#matcher!.isIgnoredChild( + relativeParent, + dirent.name, + dirent.isDirectory(), + ); } const names = new Array(dirents.length); @@ -168,7 +175,11 @@ class GitIgnoreFiles { names[index] = dirent.name; directoryMask |= Number(dirent.isDirectory()) << index; } - return this.#matcher!.isIgnoredBatchMask(relativeParent, names, directoryMask >>> 0); + return this.#matcher!.isIgnoredBatchMask( + relativeParent, + names, + directoryMask >>> 0, + ); } const directoryFlags = new Uint8Array(dirents.length); @@ -188,9 +199,14 @@ class GitIgnoreFiles { } // Ignore files may disappear or become unreadable during traversal. - const loading = readFile(path.join(directoryPath, '.gitignore'), 'utf8').then( + const loading = readFile( + path.join(directoryPath, '.gitignore'), + 'utf8', + ).then( (content) => { - const relativePath = toPosixPath(this.#resolveRelativePath(directoryPath)); + const relativePath = toPosixPath( + this.#resolveRelativePath(directoryPath), + ); this.#matcher ??= new (loadNativeBinding().GitIgnoreMatcher)(); this.#hasRules = this.#matcher.addSource(relativePath, content); }, @@ -222,7 +238,8 @@ const createTraversalOptions = ( if (dirent.isDirectory()) { return ( - (dirent as GitIgnoreDirent)[gitIgnored] === true || isIgnored?.(targetPath, true) === true + (dirent as GitIgnoreDirent)[gitIgnored] === true || + isIgnored?.(targetPath, true) === true ); } @@ -298,7 +315,14 @@ const discoverDirectoryFiles = async ( const result = await readdir( rootPath, - createTraversalOptions(gitIgnore, ignoredDirNames, signal, onError, isIncluded, isIgnored), + createTraversalOptions( + gitIgnore, + ignoredDirNames, + signal, + onError, + isIncluded, + isIgnored, + ), ); // tiny-readdir only handles fulfilled onDirents promises, so rethrow after its counter settles. @@ -310,7 +334,9 @@ const discoverDirectoryFiles = async ( }; const normalizeGlob = (cwd: string, pattern: string): string => { - const relativePattern = path.isAbsolute(pattern) ? path.relative(cwd, pattern) : pattern; + const relativePattern = path.isAbsolute(pattern) + ? path.relative(cwd, pattern) + : pattern; return toPosixPath(relativePattern); }; @@ -334,7 +360,10 @@ const classifyPatterns = async ( const entries = await Promise.all( patterns.map(async (pattern): Promise => { if (pattern.startsWith('!')) { - return { kind: 'negative-glob', value: normalizeGlob(cwd, pattern.slice(1)) }; + return { + kind: 'negative-glob', + value: normalizeGlob(cwd, pattern.slice(1)), + }; } const filePath = path.resolve(cwd, pattern); @@ -344,7 +373,9 @@ const classifyPatterns = async ( const stats = await lstatSafe(filePath); if (stats?.isFile()) { - return isBinaryPath(filePath) ? undefined : { kind: 'file', value: filePath }; + return isBinaryPath(filePath) + ? undefined + : { kind: 'file', value: filePath }; } if (stats?.isDirectory()) { return { kind: 'directory', value: filePath }; @@ -389,11 +420,15 @@ const classifyPatterns = async ( }; const getOutermostPaths = (paths: string[]): string[] => { - const sortedPaths = [...new Set(paths)].sort((left, right) => left.length - right.length); + const sortedPaths = [...new Set(paths)].sort( + (left, right) => left.length - right.length, + ); const outermostPaths: string[] = []; for (const filePath of sortedPaths) { - if (!outermostPaths.some((parentPath) => isPathInside(parentPath, filePath))) { + if ( + !outermostPaths.some((parentPath) => isPathInside(parentPath, filePath)) + ) { outermostPaths.push(filePath); } } @@ -402,8 +437,14 @@ const getOutermostPaths = (paths: string[]): string[] => { }; /** Merges overlapping roots; micromatch remains responsible for glob syntax. */ -const getTraversalRoots = (cwd: string, directories: string[], globs: string[]): string[] => { - const globRoots = globs.map((pattern) => path.resolve(cwd, micromatch.scan(pattern).base || '.')); +const getTraversalRoots = ( + cwd: string, + directories: string[], + globs: string[], +): string[] => { + const globRoots = globs.map((pattern) => + path.resolve(cwd, micromatch.scan(pattern).base || '.'), + ); return getOutermostPaths([...directories, ...globRoots]); }; @@ -431,9 +472,13 @@ const discoverFmtPaths = async ({ negativeGlobs, } = await classifyPatterns(cwd, patterns, ignoredDirNames); const directoryRoots = getOutermostPaths(directories); - const globMatchers = globs.map((pattern) => micromatch.matcher(pattern, { dot: true })); + const globMatchers = globs.map((pattern) => + micromatch.matcher(pattern, { dot: true }), + ); const candidates = new Set( - isIgnored ? explicitFiles.filter((filePath) => !isIgnored(filePath, false)) : explicitFiles, + isIgnored + ? explicitFiles.filter((filePath) => !isIgnored(filePath, false)) + : explicitFiles, ); const traversalRoots = getTraversalRoots(cwd, directoryRoots, globs); @@ -447,7 +492,10 @@ const discoverFmtPaths = async ({ } await gitIgnore.loadThrough(rootPath); - if (gitIgnore.isIgnored(rootPath, true) || isIgnored?.(rootPath, true) === true) { + if ( + gitIgnore.isIgnored(rootPath, true) || + isIgnored?.(rootPath, true) === true + ) { return []; } @@ -457,7 +505,11 @@ const discoverFmtPaths = async ({ const isIncluded = includesAll ? undefined : (filePath: string): boolean => { - if (directoryRoots.some((directoryPath) => isPathInside(directoryPath, filePath))) { + if ( + directoryRoots.some((directoryPath) => + isPathInside(directoryPath, filePath), + ) + ) { return true; } @@ -465,7 +517,13 @@ const discoverFmtPaths = async ({ return globMatchers.some((matches) => matches(relativePath)); }; - return discoverDirectoryFiles(rootPath, gitIgnore, ignoredDirNames, isIncluded, isIgnored); + return discoverDirectoryFiles( + rootPath, + gitIgnore, + ignoredDirNames, + isIncluded, + isIgnored, + ); }), ); diff --git a/packages/rstack/src/fmt/discovery.ts b/packages/rstack/src/fmt/discovery.ts index cf1c3472..8e238de1 100644 --- a/packages/rstack/src/fmt/discovery.ts +++ b/packages/rstack/src/fmt/discovery.ts @@ -19,7 +19,9 @@ const discoverFmtFiles = async ({ config, }: DiscoverFmtFilesOptions): Promise => { const isIgnored = await createIgnoreMatcher({ config, cwd, ignorePaths }); - const isExcluded = excludedDirPath ? createDirMatcher(excludedDirPath) : undefined; + const isExcluded = excludedDirPath + ? createDirMatcher(excludedDirPath) + : undefined; const shouldIgnore = isExcluded ? (filePath: string, isDirectory = false) => isExcluded(filePath) || isIgnored(filePath, isDirectory) diff --git a/packages/rstack/src/fmt/fileResolver.ts b/packages/rstack/src/fmt/fileResolver.ts index d6cc0abf..aa74151c 100644 --- a/packages/rstack/src/fmt/fileResolver.ts +++ b/packages/rstack/src/fmt/fileResolver.ts @@ -16,7 +16,9 @@ const createFmtFileResolver = (config: ResolvedFmtConfig): FmtFileResolver => { pluginResolver ??= import( /* rspackChunkName: 'fmtPlugins' */ './plugins.ts' - ).then(({ createPluginResolver }) => createPluginResolver(config.rootPath)); + ).then(({ createPluginResolver }) => + createPluginResolver(config.rootPath), + ); options = (await pluginResolver)(options); } diff --git a/packages/rstack/src/fmt/format.ts b/packages/rstack/src/fmt/format.ts index 0aa653af..d2aac91c 100644 --- a/packages/rstack/src/fmt/format.ts +++ b/packages/rstack/src/fmt/format.ts @@ -12,7 +12,8 @@ import type { FmtFileRequest } from './types.ts'; type PrettierPlugins = NonNullable; type FormatFmtSourceResult = - { status: 'unsupported' } | { status: 'formatted'; source: string; formatted: string }; + | { status: 'unsupported' } + | { status: 'formatted'; source: string; formatted: string }; const fileInfoOptions = { ignorePath: [], diff --git a/packages/rstack/src/fmt/ignore.ts b/packages/rstack/src/fmt/ignore.ts index 6874394c..48e52105 100644 --- a/packages/rstack/src/fmt/ignore.ts +++ b/packages/rstack/src/fmt/ignore.ts @@ -29,10 +29,14 @@ const createDefaultMatcher = (): IgnorePredicate => { const createSourceMatcher = (sources: IgnoreSource[]): IgnorePredicate => { const matcher = new (loadNativeBinding().IgnoreMatcher)(sources); - return (filePath, isDirectory = false) => matcher.isIgnored(filePath, isDirectory); + return (filePath, isDirectory = false) => + matcher.isIgnored(filePath, isDirectory); }; -const loadIgnoreSource = async (cwd: string, ignorePath: string): Promise => { +const loadIgnoreSource = async ( + cwd: string, + ignorePath: string, +): Promise => { const filePath = path.resolve(cwd, ignorePath); let patterns: string; diff --git a/packages/rstack/src/fmt/lsp/minimalEdit.ts b/packages/rstack/src/fmt/lsp/minimalEdit.ts index d391d955..97cfba7f 100644 --- a/packages/rstack/src/fmt/lsp/minimalEdit.ts +++ b/packages/rstack/src/fmt/lsp/minimalEdit.ts @@ -8,8 +8,10 @@ interface MinimalEdit { const CARRIAGE_RETURN = 0x0d; const LINE_FEED = 0x0a; -const isHighSurrogate = (code: number): boolean => code >= 0xd800 && code <= 0xdbff; -const isLowSurrogate = (code: number): boolean => code >= 0xdc00 && code <= 0xdfff; +const isHighSurrogate = (code: number): boolean => + code >= 0xd800 && code <= 0xdbff; +const isLowSurrogate = (code: number): boolean => + code >= 0xdc00 && code <= 0xdfff; /** * True when `index` splits a unit that occupies a single position: a surrogate @@ -33,7 +35,10 @@ const splitsIndivisibleUnit = (text: string, index: number): boolean => { * ends instead of replacing the whole document, which keeps selections, folds, * and undo history intact. Offsets are converted to positions by the caller. */ -const computeMinimalEdit = (source: string, formatted: string): MinimalEdit | undefined => { +const computeMinimalEdit = ( + source: string, + formatted: string, +): MinimalEdit | undefined => { if (source === formatted) { return undefined; } @@ -109,7 +114,10 @@ interface MinimalTextEdit { * `\r\n`, or a lone `\r`, like the protocol's. `computeMinimalEdit` keeping * boundaries out of surrogate pairs and `\r\n` is what makes the mapping exact. */ -const computeMinimalTextEdit = (source: string, formatted: string): MinimalTextEdit | undefined => { +const computeMinimalTextEdit = ( + source: string, + formatted: string, +): MinimalTextEdit | undefined => { const edit = computeMinimalEdit(source, formatted); if (!edit) { return undefined; diff --git a/packages/rstack/src/fmt/lsp/server.ts b/packages/rstack/src/fmt/lsp/server.ts index ec0be83e..f2a5742f 100644 --- a/packages/rstack/src/fmt/lsp/server.ts +++ b/packages/rstack/src/fmt/lsp/server.ts @@ -9,7 +9,10 @@ import { type InitializeParams, type TextEdit, } from 'vscode-languageserver/node'; -import { createFmtFileResolver, type FmtFileResolver } from '../fileResolver.ts'; +import { + createFmtFileResolver, + type FmtFileResolver, +} from '../fileResolver.ts'; import { formatFmtSource } from '../format.ts'; import { createIgnoreMatcher, type IgnorePredicate } from '../ignore.ts'; import type { ResolvedFmtConfig } from '../types.ts'; @@ -67,7 +70,8 @@ const redirectConsoleToConnection = (connection: Connection): void => { connection.console.log(serializeConsoleArguments(args)); console.trace = (...args: unknown[]): void => { const stack = new Error().stack?.replace(/(.+\n){2}/, '') ?? ''; - const message = args.length === 0 ? 'Trace' : `Trace: ${serializeConsoleArguments(args)}`; + const message = + args.length === 0 ? 'Trace' : `Trace: ${serializeConsoleArguments(args)}`; connection.console.log(`${message}\n${stack}`); }; console.assert = (assertion?: unknown, ...args: unknown[]): void => { @@ -99,7 +103,9 @@ const redirectConsoleToConnection = (connection: Connection): void => { const resolveWorkspaceRoot = (params: InitializeParams): string | undefined => { const rootUri = params.workspaceFolders?.[0]?.uri ?? params.rootUri; - return (rootUri ? toFilePath(rootUri) : undefined) ?? params.rootPath ?? undefined; + return ( + (rootUri ? toFilePath(rootUri) : undefined) ?? params.rootPath ?? undefined + ); }; /** Loads everything a formatting request needs, once per server lifetime. */ @@ -155,7 +161,10 @@ const createDocumentEdits = async ( return []; } - const edit = formatted === undefined ? undefined : computeMinimalTextEdit(source, formatted); + const edit = + formatted === undefined + ? undefined + : computeMinimalTextEdit(source, formatted); return edit ? [edit] : []; }; @@ -198,25 +207,27 @@ const startFmtLsp = (options: RunFmtLspOptions, onExit: () => void): void => { // TODO: watch the config file and reset the session when it changes. const getSession = (): Promise => - (sessionPromise ??= createFmtLspSession({ ...options, root }).catch((error: unknown) => { - // Retry on the next request rather than caching the failure forever. - sessionPromise = undefined; - // A workspace that cannot be set up returns no edits for every document, - // which looks like "nothing to format" in editors that hide the server - // log, so it is shown to the user instead of only being logged. Repeats - // of the same failure stay silent so saving a file cannot spam the editor. - const message = `rs fmt cannot format this workspace: ${String(error)}`; - if (reportedSessionError !== message) { - reportedSessionError = message; - // A notification rather than `window.showErrorMessage`, which sends a - // request the server would then wait on for a response it does not need. - void connection.sendNotification(ShowMessageNotification.type, { - type: MessageType.Error, - message, - }); - } - throw error; - })); + (sessionPromise ??= createFmtLspSession({ ...options, root }).catch( + (error: unknown) => { + // Retry on the next request rather than caching the failure forever. + sessionPromise = undefined; + // A workspace that cannot be set up returns no edits for every document, + // which looks like "nothing to format" in editors that hide the server + // log, so it is shown to the user instead of only being logged. Repeats + // of the same failure stay silent so saving a file cannot spam the editor. + const message = `rs fmt cannot format this workspace: ${String(error)}`; + if (reportedSessionError !== message) { + reportedSessionError = message; + // A notification rather than `window.showErrorMessage`, which sends a + // request the server would then wait on for a response it does not need. + void connection.sendNotification(ShowMessageNotification.type, { + type: MessageType.Error, + message, + }); + } + throw error; + }, + )); connection.onExit(onExit); @@ -234,26 +245,30 @@ const startFmtLsp = (options: RunFmtLspOptions, onExit: () => void): void => { }; }); - connection.onDocumentFormatting(async ({ textDocument }): Promise => { - const filePath = toFilePath(textDocument.uri); - if (!filePath) { - return []; - } + connection.onDocumentFormatting( + async ({ textDocument }): Promise => { + const filePath = toFilePath(textDocument.uri); + if (!filePath) { + return []; + } - // A formatting failure must never disrupt editing; unsupported, ignored, - // and unparsable documents all resolve to "no edits". - try { - const session = await getSession(); + // A formatting failure must never disrupt editing; unsupported, ignored, + // and unparsable documents all resolve to "no edits". + try { + const session = await getSession(); - return await createDocumentEdits( - () => documents.get(textDocument.uri), - (source) => formatDocumentSource(session, filePath, source), - ); - } catch (error) { - connection.console.error(`Failed to format "${filePath}": ${String(error)}`); - return []; - } - }); + return await createDocumentEdits( + () => documents.get(textDocument.uri), + (source) => formatDocumentSource(session, filePath, source), + ); + } catch (error) { + connection.console.error( + `Failed to format "${filePath}": ${String(error)}`, + ); + return []; + } + }, + ); connection.listen(); }; diff --git a/packages/rstack/src/fmt/pathHelpers.ts b/packages/rstack/src/fmt/pathHelpers.ts index 1ad48566..a8f72f9e 100644 --- a/packages/rstack/src/fmt/pathHelpers.ts +++ b/packages/rstack/src/fmt/pathHelpers.ts @@ -3,10 +3,14 @@ import path from 'node:path'; type RelativePathResolver = (filePath: string) => string; const toPosixPath: (filePath: string) => string = - path.sep === '\\' ? (filePath) => filePath.replaceAll('\\', '/') : (filePath) => filePath; + path.sep === '\\' + ? (filePath) => filePath.replaceAll('\\', '/') + : (filePath) => filePath; const createRelativePathResolver = (rootPath: string): RelativePathResolver => { - const rootPrefix = rootPath.endsWith(path.sep) ? rootPath : `${rootPath}${path.sep}`; + const rootPrefix = rootPath.endsWith(path.sep) + ? rootPath + : `${rootPath}${path.sep}`; return (filePath) => filePath === rootPath @@ -17,7 +21,8 @@ const createRelativePathResolver = (rootPath: string): RelativePathResolver => { }; /** Prettier only inspects a file's shebang when its basename contains no dot. */ -const hasDottedBasename = (filePath: string): boolean => path.basename(filePath).includes('.'); +const hasDottedBasename = (filePath: string): boolean => + path.basename(filePath).includes('.'); export { createRelativePathResolver, hasDottedBasename, toPosixPath }; export type { RelativePathResolver }; diff --git a/packages/rstack/src/fmt/plugins.ts b/packages/rstack/src/fmt/plugins.ts index e7a33e16..263bcb32 100644 --- a/packages/rstack/src/fmt/plugins.ts +++ b/packages/rstack/src/fmt/plugins.ts @@ -1,5 +1,11 @@ import { readFile, realpath } from 'node:fs/promises'; -import { isAbsolute, join, relative, resolve as resolvePath, sep } from 'node:path'; +import { + isAbsolute, + join, + relative, + resolve as resolvePath, + sep, +} from 'node:path'; import { fileURLToPath, pathToFileURL } from 'node:url'; import { moduleResolve } from 'import-meta-resolve'; import type { Options as PrettierOptions } from 'prettier'; @@ -8,12 +14,16 @@ import type { FmtPluginSpecifier, ResolvedFmtOptions } from './types.ts'; type FmtPlugin = NonNullable[number]; type FmtPluginResolver = (options: ResolvedFmtOptions) => ResolvedFmtOptions; -type FingerprintResolver = (plugin: FmtPluginSpecifier) => Promise; +type FingerprintResolver = ( + plugin: FmtPluginSpecifier, +) => Promise; const resolveModuleUrl = (specifier: string, parentUrl: URL): string => moduleResolve(specifier, parentUrl).href; -const isFmtPluginSpecifier = (plugin: FmtPlugin): plugin is FmtPluginSpecifier => +const isFmtPluginSpecifier = ( + plugin: FmtPlugin, +): plugin is FmtPluginSpecifier => typeof plugin === 'string' || plugin instanceof URL; const getPackageRoot = (entryPath: string): string | undefined => { @@ -38,7 +48,9 @@ const getPackageRoot = (entryPath: string): string | undefined => { return entryPath.slice(0, end); }; -const fingerprintPlugin = async (pluginUrl: string): Promise => { +const fingerprintPlugin = async ( + pluginUrl: string, +): Promise => { try { const url = new URL(pluginUrl); if (url.protocol !== 'file:') { @@ -53,7 +65,9 @@ const fingerprintPlugin = async (pluginUrl: string): Promise return undefined; } - const pkg: unknown = JSON.parse(await readFile(join(packageRoot, 'package.json'), 'utf8')); + const pkg: unknown = JSON.parse( + await readFile(join(packageRoot, 'package.json'), 'utf8'), + ); if ( typeof pkg !== 'object' || pkg === null || @@ -142,7 +156,9 @@ const createPluginResolver = (rootPath: string): FmtPluginResolver => { } const resolvedPlugins = plugins.map(resolvePlugin); - const resolvedOptions = resolvedPlugins.every((plugin, index) => plugin === plugins[index]) + const resolvedOptions = resolvedPlugins.every( + (plugin, index) => plugin === plugins[index], + ) ? options : { ...options, plugins: resolvedPlugins }; optionsCache.set(options, resolvedOptions); diff --git a/packages/rstack/src/fmt/prettierPlugins.ts b/packages/rstack/src/fmt/prettierPlugins.ts index 829d7e6d..a88a600e 100644 --- a/packages/rstack/src/fmt/prettierPlugins.ts +++ b/packages/rstack/src/fmt/prettierPlugins.ts @@ -24,7 +24,10 @@ const getPrettierPlugins = async ( ): Promise => { const plugins = options.sortPackageJson === true && /(^|[/\\])package\.json$/.test(filePath) - ? [...defaultFmtPlugins, (await import('./sortPackageJsonPlugin.ts')).sortPackageJsonPlugin] + ? [ + ...defaultFmtPlugins, + (await import('./sortPackageJsonPlugin.ts')).sortPackageJsonPlugin, + ] : defaultFmtPlugins; return options.plugins?.length ? [...plugins, ...options.plugins] : plugins; diff --git a/packages/rstack/src/fmt/runner.ts b/packages/rstack/src/fmt/runner.ts index cc2340f4..89ad3a9a 100644 --- a/packages/rstack/src/fmt/runner.ts +++ b/packages/rstack/src/fmt/runner.ts @@ -1,4 +1,8 @@ -import { cacheNamespace, createCacheKeyResolver, createOptionsHasher } from './cacheIdentity.ts'; +import { + cacheNamespace, + createCacheKeyResolver, + createOptionsHasher, +} from './cacheIdentity.ts'; import { loadFmtCacheStore } from './cacheStore.ts'; import type { FmtCacheEntry, FmtCacheStore } from './cacheStore.ts'; import { hasDottedBasename } from './pathHelpers.ts'; @@ -77,7 +81,10 @@ const loadPluginFingerprints = async ( ); const resolveFingerprint = createFingerprintResolver(); const entries = await Promise.all( - Array.from(plugins, async ([key, plugin]) => [key, await resolveFingerprint(plugin)] as const), + Array.from( + plugins, + async ([key, plugin]) => [key, await resolveFingerprint(plugin)] as const, + ), ); const fingerprints = new Map(); for (const [key, fingerprint] of entries) { @@ -89,7 +96,10 @@ const loadPluginFingerprints = async ( }; /** Resolves the portable cache identity before work is dispatched. */ -const createRunTask = (file: FmtFileRequest, cache?: RunCache): FmtFileRunTask => { +const createRunTask = ( + file: FmtFileRequest, + cache?: RunCache, +): FmtFileRunTask => { let key: string | undefined; let fileCache: FmtFileCache | undefined; @@ -207,7 +217,9 @@ const runWithWorkers = async ( workerPool.workerCount >= minPriorityWorkers ? await runPriorityTasks(tasks, shouldWrite, workerPool.formatFile) : await Promise.all( - tasks.map((task) => runFmtFile(task, shouldWrite, workerPool.formatFile)), + tasks.map((task) => + runFmtFile(task, shouldWrite, workerPool.formatFile), + ), ); const processedFiles: FmtFileResult[] = []; let processedFileCount = 0; @@ -277,7 +289,10 @@ const runFmtFiles = async ({ return { ...result, - exitCode: files.length > 0 && result.processedFileCount === 0 ? 2 : getExitCode(result.files), + exitCode: + files.length > 0 && result.processedFileCount === 0 + ? 2 + : getExitCode(result.files), }; }; diff --git a/packages/rstack/src/fmt/types.ts b/packages/rstack/src/fmt/types.ts index 23e2dd6f..90d50a31 100644 --- a/packages/rstack/src/fmt/types.ts +++ b/packages/rstack/src/fmt/types.ts @@ -1,4 +1,7 @@ -import type { Config as PrettierConfig, Options as PrettierOptions } from 'prettier'; +import type { + Config as PrettierConfig, + Options as PrettierOptions, +} from 'prettier'; import type { FmtCacheEntry } from './cacheStore.ts'; /** Plugin objects cannot cross worker boundaries and are not planned for support. */ @@ -25,7 +28,8 @@ type FmtOverride = Omit & { options?: FmtOptions; }; -interface FmtConfig extends Omit, FmtBuiltinOptions { +interface FmtConfig + extends Omit, FmtBuiltinOptions { plugins?: FmtPluginSpecifier[]; overrides?: FmtOverride[]; /** Gitignore-compatible patterns relative to the Rstack config root. */ diff --git a/packages/rstack/src/fmt/worker.ts b/packages/rstack/src/fmt/worker.ts index 6e6505aa..35d47f49 100644 --- a/packages/rstack/src/fmt/worker.ts +++ b/packages/rstack/src/fmt/worker.ts @@ -74,7 +74,8 @@ const formatFile = async ({ cacheEntry: [ hasDottedBasename(file.path) ? '' - : (contentHash ?? hashContent(sourceBuffer ?? readFileSync(file.path))), + : (contentHash ?? + hashContent(sourceBuffer ?? readFileSync(file.path))), cache.optionsHash, 'unsupported', ], diff --git a/packages/rstack/src/fmt/workerPool.ts b/packages/rstack/src/fmt/workerPool.ts index 41bded06..800e4768 100644 --- a/packages/rstack/src/fmt/workerPool.ts +++ b/packages/rstack/src/fmt/workerPool.ts @@ -22,7 +22,10 @@ interface FmtWorkerPool { * scheduling and memory pressure. */ const getWorkerCount = (fileCount: number, maxWorkers?: number): number => - Math.min(fileCount, maxWorkers ?? Math.min(8, Math.max(1, availableParallelism() - 1))); + Math.min( + fileCount, + maxWorkers ?? Math.min(8, Math.max(1, availableParallelism() - 1)), + ); const getWorkerUrl = (): URL => { // Source tests run after build and exercise the same worker artifact as the CLI. @@ -33,7 +36,10 @@ const getWorkerUrl = (): URL => { }; /** Creates and starts every worker before formatting can begin. */ -const createWorkerPool = async (fileCount: number, maxWorkers?: number): Promise => { +const createWorkerPool = async ( + fileCount: number, + maxWorkers?: number, +): Promise => { const workerCount = getWorkerCount(fileCount, maxWorkers); const pool = new Tinypool({ filename: getWorkerUrl().href, diff --git a/packages/rstack/src/fmt/yukuPlugin.ts b/packages/rstack/src/fmt/yukuPlugin.ts index a22ec9f2..824af9fb 100644 --- a/packages/rstack/src/fmt/yukuPlugin.ts +++ b/packages/rstack/src/fmt/yukuPlugin.ts @@ -70,7 +70,8 @@ const locStart = (node: Locatable): number => { return firstDecorator ? Math.min(locStart(firstDecorator), start) : start; }; -const locEndWithFullText = (node: Locatable): number => (node.range?.[1] ?? node.end) as number; +const locEndWithFullText = (node: Locatable): number => + (node.range?.[1] ?? node.end) as number; const locEnd = (node: Locatable): number => { switch (node.type) { @@ -89,7 +90,9 @@ const locEnd = (node: Locatable): number => { return node.label ? locEnd(node.label) : locStart(node) + 'break'.length; case 'ContinueStatement': - return node.label ? locEnd(node.label) : locStart(node) + 'continue'.length; + return node.label + ? locEnd(node.label) + : locStart(node) + 'continue'.length; case 'DebuggerStatement': return locStart(node) + 'debugger'.length; @@ -136,10 +139,13 @@ const hasPragmaFrom = (originalText: string, pragmas: Set): boolean => { return false; }; -const hasPragma = (text: string): boolean => hasPragmaFrom(text, FORMAT_PRAGMAS); -const hasIgnorePragma = (text: string): boolean => hasPragmaFrom(text, FORMAT_IGNORE_PRAGMAS); +const hasPragma = (text: string): boolean => + hasPragmaFrom(text, FORMAT_PRAGMAS); +const hasIgnorePragma = (text: string): boolean => + hasPragmaFrom(text, FORMAT_IGNORE_PRAGMAS); -const getVisitorKeys = estreePrinter.getVisitorKeys as ((node: AstNode) => string[]) | undefined; +const getVisitorKeys = estreePrinter.getVisitorKeys as + ((node: AstNode) => string[]) | undefined; if (!getVisitorKeys) { throw new Error('The Prettier ESTree printer does not expose visitor keys.'); @@ -158,7 +164,10 @@ const asAstNode = (value: unknown): AstNode => { return value; }; -const withExtra = (node: AstNode, extra: Record): Record => ({ +const withExtra = ( + node: AstNode, + extra: Record, +): Record => ({ ...(node.extra !== null && typeof node.extra === 'object' ? (node.extra as Record) : undefined), @@ -201,7 +210,10 @@ const mergeNestedJsdocComments = (comments: PrettierComment[]): void => { } }; -const stripComments = (originalText: string, comments: PrettierComment[]): string => { +const stripComments = ( + originalText: string, + comments: PrettierComment[], +): string => { if (comments.length === 0) { return originalText; } @@ -287,7 +299,10 @@ const isUnbalancedLogicalTree = (node: AstNode): boolean => { return false; } - return node.right.type === 'LogicalExpression' && node.operator === node.right.operator; + return ( + node.right.type === 'LogicalExpression' && + node.operator === node.right.operator + ); }; const rebalanceLogicalTree = (node: AstNode): AstNode => { @@ -351,7 +366,9 @@ const postprocess = ( .filter(isTypeCastComment) .map((comment) => locEnd(comment)); - const previousCommentEnd = typeCastCommentEnds.findLast((end) => end <= start); + const previousCommentEnd = typeCastCommentEnds.findLast( + (end) => end <= start, + ); const shouldKeepParentheses = previousCommentEnd !== undefined && text.slice(previousCommentEnd, start).trim().length === 0; @@ -402,12 +419,17 @@ const postprocess = ( return undefined; }, onLeave(node) { - return isUnbalancedLogicalTree(node) ? rebalanceLogicalTree(node) : undefined; + return isUnbalancedLogicalTree(node) + ? rebalanceLogicalTree(node) + : undefined; }, }) as AstNode; }; -const indexToPosition = (text: string, index: number): { column: number; line: number } => { +const indexToPosition = ( + text: string, + index: number, +): { column: number; line: number } => { const lineBreakBefore = index === 0 ? -1 : text.lastIndexOf('\n', index - 1); let line = 1; @@ -427,10 +449,13 @@ const createParseError = (error: Diagnostic, text: string): SyntaxError => { const start = indexToPosition(text, error.start); const end = indexToPosition(text, error.end); - return Object.assign(new SyntaxError(`${error.message} (${start.line}:${start.column})`), { - cause: error, - loc: { start, end }, - }); + return Object.assign( + new SyntaxError(`${error.message} (${start.line}:${start.column})`), + { + cause: error, + loc: { start, end }, + }, + ); }; const parseWithOptions = (text: string, options: ParseOptions): ParseResult => { @@ -460,7 +485,10 @@ const getSourceType = (filepath: string): SourceType | undefined => { return undefined; }; -const getLanguageCombinations = (text: string, filepath: string): SourceLang[] => { +const getLanguageCombinations = ( + text: string, + filepath: string, +): SourceLang[] => { const normalizedPath = filepath.toLowerCase(); if (JS_TS_FILE_REGEXP.test(normalizedPath)) { @@ -493,25 +521,48 @@ const tryCombinations = (combinations: (() => ParseResult)[]): ParseResult => { throw new Error('No Yuku parser combinations were provided.'); }; -const parseJavaScript = (text: string, options: ParserOptions): AstNode => { +const parseJavaScript = ( + text: string, + options: ParserOptions, +): AstNode => { const sourceType = getSourceType(options.filepath); - const combinations = (sourceType ? [sourceType] : SOURCE_TYPE_COMBINATIONS).map( - (candidate) => () => parseWithOptions(text, { sourceType: candidate, lang: 'jsx' }), + const combinations = ( + sourceType ? [sourceType] : SOURCE_TYPE_COMBINATIONS + ).map( + (candidate) => () => + parseWithOptions(text, { sourceType: candidate, lang: 'jsx' }), ); const { program, comments } = tryCombinations(combinations); - return postprocess(program as unknown as AstNode, comments as PrettierComment[], text, 'yuku-js'); + return postprocess( + program as unknown as AstNode, + comments as PrettierComment[], + text, + 'yuku-js', + ); }; -const parseTypeScript = (text: string, options: ParserOptions): AstNode => { +const parseTypeScript = ( + text: string, + options: ParserOptions, +): AstNode => { const sourceType = getSourceType(options.filepath); const languages = getLanguageCombinations(text, options.filepath); - const combinations = (sourceType ? [sourceType] : SOURCE_TYPE_COMBINATIONS).flatMap((candidate) => - languages.map((lang) => () => parseWithOptions(text, { sourceType: candidate, lang })), + const combinations = ( + sourceType ? [sourceType] : SOURCE_TYPE_COMBINATIONS + ).flatMap((candidate) => + languages.map( + (lang) => () => parseWithOptions(text, { sourceType: candidate, lang }), + ), ); const { program, comments } = tryCombinations(combinations); - return postprocess(program as unknown as AstNode, comments as PrettierComment[], text, 'yuku-ts'); + return postprocess( + program as unknown as AstNode, + comments as PrettierComment[], + text, + 'yuku-ts', + ); }; const createParser = ( @@ -530,17 +581,19 @@ const parserNames = new Map([ ['typescript', 'yuku-ts'], ]); -const languages: SupportLanguage[] = estreePlugin.languages.flatMap((language) => { - const parsers = [ - ...new Set( - language.parsers - .map((parser) => parserNames.get(parser)) - .filter((parser): parser is string => parser !== undefined), - ), - ]; - - return parsers.length > 0 ? [{ ...language, parsers }] : []; -}); +const languages: SupportLanguage[] = estreePlugin.languages.flatMap( + (language) => { + const parsers = [ + ...new Set( + language.parsers + .map((parser) => parserNames.get(parser)) + .filter((parser): parser is string => parser !== undefined), + ), + ]; + + return parsers.length > 0 ? [{ ...language, parsers }] : []; + }, +); const yukuPlugin: Plugin = { languages, diff --git a/packages/rstack/src/native/index.ts b/packages/rstack/src/native/index.ts index bf682324..c760309e 100644 --- a/packages/rstack/src/native/index.ts +++ b/packages/rstack/src/native/index.ts @@ -6,5 +6,7 @@ export type NativeBinding = typeof import('../../binding.cjs'); const require = createRequire(import.meta.url); export const loadNativeBinding = (): NativeBinding => { const packageJsonPath = require.resolve('rstack/package.json'); - return require(path.join(path.dirname(packageJsonPath), 'binding.cjs')) as NativeBinding; + return require( + path.join(path.dirname(packageJsonPath), 'binding.cjs'), + ) as NativeBinding; }; diff --git a/packages/rstack/src/projectCache.ts b/packages/rstack/src/projectCache.ts index 86d0ffcb..39894d22 100644 --- a/packages/rstack/src/projectCache.ts +++ b/packages/rstack/src/projectCache.ts @@ -4,13 +4,17 @@ import path from 'node:path'; const cacheGitignore = '*\n'; type ProjectCacheResult = - { status: 'available'; path: string } | { status: 'unavailable'; path: string; error: unknown }; + | { status: 'available'; path: string } + | { status: 'unavailable'; path: string; error: unknown }; /** Returns the disposable cache directory for a resolved Rstack project root. */ -const getProjectCacheDir = (rootPath: string): string => path.join(rootPath, '.rstack', 'cache'); +const getProjectCacheDir = (rootPath: string): string => + path.join(rootPath, '.rstack', 'cache'); /** Creates the project cache directory without making cache failures fatal. */ -const ensureProjectCacheDir = async (rootPath: string): Promise => { +const ensureProjectCacheDir = async ( + rootPath: string, +): Promise => { const cachePath = getProjectCacheDir(rootPath); const ignorePath = path.join(cachePath, '.gitignore'); diff --git a/packages/rstack/src/rsbuildConfig.ts b/packages/rstack/src/rsbuildConfig.ts index 01385c44..02935da8 100644 --- a/packages/rstack/src/rsbuildConfig.ts +++ b/packages/rstack/src/rsbuildConfig.ts @@ -1,4 +1,8 @@ -import type { ConfigParams, RsbuildConfigDefinition, WatchFiles } from '@rsbuild/core'; +import type { + ConfigParams, + RsbuildConfigDefinition, + WatchFiles, +} from '@rsbuild/core'; import { loadRstackConfig, type Configs } from './config.ts'; const resolveRsbuildConfig = async (configs: Configs, params: ConfigParams) => { @@ -31,7 +35,11 @@ const loadRsbuildConfig: RsbuildConfigDefinition = async (params) => { dev: { ...config.dev, watchFiles: [ - ...(watchFiles ? (Array.isArray(watchFiles) ? watchFiles : [watchFiles]) : []), + ...(watchFiles + ? Array.isArray(watchFiles) + ? watchFiles + : [watchFiles] + : []), watchConfig, ], }, diff --git a/packages/rstack/src/rslibConfig.ts b/packages/rstack/src/rslibConfig.ts index b7468aa4..a3159c63 100644 --- a/packages/rstack/src/rslibConfig.ts +++ b/packages/rstack/src/rslibConfig.ts @@ -1,8 +1,15 @@ import type { WatchFiles } from '@rsbuild/core'; -import type { ConfigParams, RslibConfig, RslibConfigDefinition } from '@rslib/core'; +import type { + ConfigParams, + RslibConfig, + RslibConfigDefinition, +} from '@rslib/core'; import { loadRstackConfig, type Configs } from './config.ts'; -const resolveRslibConfig = async (configs: Configs, params: ConfigParams): Promise => { +const resolveRslibConfig = async ( + configs: Configs, + params: ConfigParams, +): Promise => { const libConfig = configs.lib; if (!libConfig) { return {}; @@ -32,7 +39,11 @@ const loadRslibConfig = (async (params: ConfigParams) => { dev: { ...config.dev, watchFiles: [ - ...(watchFiles ? (Array.isArray(watchFiles) ? watchFiles : [watchFiles]) : []), + ...(watchFiles + ? Array.isArray(watchFiles) + ? watchFiles + : [watchFiles] + : []), watchConfig, ], }, diff --git a/packages/rstack/src/rspressConfig.ts b/packages/rstack/src/rspressConfig.ts index 0bf6a60d..68bb41c5 100644 --- a/packages/rstack/src/rspressConfig.ts +++ b/packages/rstack/src/rspressConfig.ts @@ -34,7 +34,11 @@ export default async (): Promise => { dev: { ...config.builderConfig?.dev, watchFiles: [ - ...(watchFiles ? (Array.isArray(watchFiles) ? watchFiles : [watchFiles]) : []), + ...(watchFiles + ? Array.isArray(watchFiles) + ? watchFiles + : [watchFiles] + : []), watchConfig, ], }, diff --git a/packages/rstack/src/rstestConfig.ts b/packages/rstack/src/rstestConfig.ts index b28d61d2..119c7112 100644 --- a/packages/rstack/src/rstestConfig.ts +++ b/packages/rstack/src/rstestConfig.ts @@ -14,7 +14,8 @@ const resolveAutomaticExtends = async ( /* rspackChunkName: 'adapterRsbuild' */ '@rstest/adapter-rsbuild' ); - const config = typeof appConfig === 'function' ? await appConfig(params) : appConfig; + const config = + typeof appConfig === 'function' ? await appConfig(params) : appConfig; return withRsbuildConfig({ config, @@ -27,7 +28,8 @@ const resolveAutomaticExtends = async ( /* rspackChunkName: 'adapterRslib' */ '@rstest/adapter-rslib' ); - const config = typeof libConfig === 'function' ? await libConfig(params) : libConfig; + const config = + typeof libConfig === 'function' ? await libConfig(params) : libConfig; return withRslibConfig({ config, @@ -51,7 +53,11 @@ const injectExtends = ( }; }; -const extendsConfig = async (configs: Configs, testConfig: RstestConfig, params: ConfigParams) => { +const extendsConfig = async ( + configs: Configs, + testConfig: RstestConfig, + params: ConfigParams, +) => { if ('extends' in testConfig) { return testConfig; } @@ -73,7 +79,9 @@ const extendsConfig = async (configs: Configs, testConfig: RstestConfig, params: return { ...testConfig, projects: testConfig.projects.map((project) => - typeof project === 'string' ? project : injectExtends(project, automaticExtends), + typeof project === 'string' + ? project + : injectExtends(project, automaticExtends), ), }; }; diff --git a/packages/rstack/src/setup/hooks.ts b/packages/rstack/src/setup/hooks.ts index 676da734..7a6e523c 100644 --- a/packages/rstack/src/setup/hooks.ts +++ b/packages/rstack/src/setup/hooks.ts @@ -24,7 +24,10 @@ const quoteShellPath = (value: string): string => { process.platform === 'win32' ? value .replaceAll('\\', '/') - .replace(/^([A-Za-z]):\//u, (_, drive: string) => `/${drive.toLowerCase()}/`) + .replace( + /^([A-Za-z]):\//u, + (_, drive: string) => `/${drive.toLowerCase()}/`, + ) : value; return `'${shellPath.replaceAll("'", `'"'"'`)}'`; @@ -78,7 +81,8 @@ rs_run "$@" export const createHookFiles = ( nodeExecutable: string = process.execPath, ): Record => { - const messageShim = createShim(`# Keep the message file valid after changing directories. + const messageShim = + createShim(`# Keep the message file valid after changing directories. [ -n "\${1-}" ] || exit 1 case "$1" in /*|[A-Za-z]:/*) ;; @@ -90,7 +94,8 @@ case "$1" in esac `); - const prePushShim = createShim(`# Keep a local remote path valid after changing directories. + const prePushShim = + createShim(`# Keep a local remote path valid after changing directories. rs_remote_name=\${1-} rs_remote_location=\${2-} [ -n "$rs_remote_name" ] && [ -n "$rs_remote_location" ] || exit 1 @@ -109,7 +114,9 @@ set -- "$rs_remote_name" "$rs_remote_location" "$@" `); const defaultShim = createShim(); - const files: Record = { runner: createRunner(nodeExecutable) }; + const files: Record = { + runner: createRunner(nodeExecutable), + }; for (const name of hookNames) { files[name] = name.endsWith('-msg') diff --git a/packages/rstack/src/setup/index.ts b/packages/rstack/src/setup/index.ts index c090404f..ef597323 100644 --- a/packages/rstack/src/setup/index.ts +++ b/packages/rstack/src/setup/index.ts @@ -16,7 +16,9 @@ export const runSetupCLI = async (args: string[]): Promise => { const hooksDirs = values.hooksDir; if (hooksDirs && hooksDirs.length > 1) { - throw new Error('The --hooks-dir option cannot be specified more than once.'); + throw new Error( + 'The --hooks-dir option cannot be specified more than once.', + ); } const hooksDir = hooksDirs?.[0]; @@ -39,7 +41,9 @@ export const runSetupCLI = async (args: string[]): Promise => { } const reason = - result.reason === 'disabled' ? 'disabled by RSTACK_HOOKS' : 'not a Git repository'; + result.reason === 'disabled' + ? 'disabled by RSTACK_HOOKS' + : 'not a Git repository'; logger.info(`Git hooks setup skipped: ${color.yellow(reason)}.`); return; } diff --git a/packages/rstack/src/setup/install.ts b/packages/rstack/src/setup/install.ts index 81d4198f..eae7c186 100644 --- a/packages/rstack/src/setup/install.ts +++ b/packages/rstack/src/setup/install.ts @@ -1,5 +1,12 @@ import { spawnSync } from 'node:child_process'; -import { chmodSync, existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from 'node:fs'; +import { + chmodSync, + existsSync, + mkdirSync, + readFileSync, + statSync, + writeFileSync, +} from 'node:fs'; import path from 'node:path'; import { createHookFiles, hookNames } from './hooks.ts'; @@ -54,7 +61,10 @@ const resolveHooksDir = (hooksDir: string): string | FailedInstallResult => { const resolvedDir = hooksDir.replaceAll('\\', '/'); if (resolvedDir.length === 0) { - return fail('invalid-hooks-directory', 'Git hooks directory must not be empty.'); + return fail( + 'invalid-hooks-directory', + 'Git hooks directory must not be empty.', + ); } if (path.isAbsolute(resolvedDir)) { @@ -65,15 +75,20 @@ const resolveHooksDir = (hooksDir: string): string | FailedInstallResult => { } if (resolvedDir.includes('..')) { - return fail('invalid-hooks-directory', 'Git hooks directory must not contain "..".'); + return fail( + 'invalid-hooks-directory', + 'Git hooks directory must not contain "..".', + ); } return resolvedDir; }; -const runGit = (cwd: string, args: string[]) => spawnSync('git', args, { cwd, encoding: 'utf8' }); +const runGit = (cwd: string, args: string[]) => + spawnSync('git', args, { cwd, encoding: 'utf8' }); -const removeLineEnding = (value: string): string => value.replace(/\r?\n$/u, ''); +const removeLineEnding = (value: string): string => + value.replace(/\r?\n$/u, ''); const gitFailure = ( error: NodeJS.ErrnoException | undefined, @@ -83,7 +98,10 @@ const gitFailure = ( return fail('git-not-found', 'Git command not found.'); } - return fail('git-command-failed', `Failed to run Git: ${error?.message || stderr.trim()}`); + return fail( + 'git-command-failed', + `Failed to run Git: ${error?.message || stderr.trim()}`, + ); }; const resolveGitContext = (cwd: string): GitContext | InstallResult => { @@ -123,23 +141,33 @@ const resolveGitContext = (cwd: string): GitContext | InstallResult => { } if (!gitRoot || !gitCommonDirectory || !effectiveHooksDirectory) { - return fail('git-command-failed', 'Failed to resolve the Git repository paths.'); + return fail( + 'git-command-failed', + 'Failed to resolve the Git repository paths.', + ); } return { defaultHooksDirectory: path.join(gitCommonDirectory, 'hooks'), effectiveHooksDirectory, gitRoot, - projectPath: repositoryPrefix.replaceAll('\\', '/').replace(/\/$/u, '') || '.', + projectPath: + repositoryPrefix.replaceAll('\\', '/').replace(/\/$/u, '') || '.', }; }; -const isCurrentFile = (filePath: string, content: string, executable = false): boolean => { +const isCurrentFile = ( + filePath: string, + content: string, + executable = false, +): boolean => { try { // Windows does not expose POSIX executable bits, but Git for Windows still runs hook shims. return ( readFileSync(filePath, 'utf8') === content && - (!executable || process.platform === 'win32' || (statSync(filePath).mode & 0o777) === 0o755) + (!executable || + process.platform === 'win32' || + (statSync(filePath).mode & 0o777) === 0o755) ); } catch { return false; @@ -153,7 +181,9 @@ const readOwner = (directory: string): string | undefined => { try { const content = readFileSync(path.join(directory, ownerFileName), 'utf8'); const owner = removeLineEnding(content); - return content === `${owner}\n` && owner.length > 0 && !/[\r\n]/u.test(owner) + return content === `${owner}\n` && + owner.length > 0 && + !/[\r\n]/u.test(owner) ? owner : undefined; } catch { @@ -163,13 +193,21 @@ const readOwner = (directory: string): string | undefined => { const displayPath = (gitRoot: string, filePath: string): string => { const relativePath = path.relative(gitRoot, filePath).replaceAll('\\', '/'); - return relativePath.length > 0 && !relativePath.startsWith('../') ? relativePath : filePath; + return relativePath.length > 0 && !relativePath.startsWith('../') + ? relativePath + : filePath; }; const ownerConflict = (project: string): SkippedInstallResult => - skip('owned-by-another-project', `Git hooks are already managed by Rstack project "${project}"`); + skip( + 'owned-by-another-project', + `Git hooks are already managed by Rstack project "${project}"`, + ); -const directoryConflict = (gitRoot: string, directory: string): SkippedInstallResult => +const directoryConflict = ( + gitRoot: string, + directory: string, +): SkippedInstallResult => skip( 'hooks-directory-conflict', `the hooks directory "${displayPath(gitRoot, directory)}" is not managed by Rstack`, @@ -191,7 +229,8 @@ const claimOwner = ( // Exclusive creation makes concurrent prepare scripts agree on one owner. writeFileSync(ownerPath, `${project}\n`, { flag: 'wx' }); } catch (error) { - const code = error instanceof Error && 'code' in error ? error.code : undefined; + const code = + error instanceof Error && 'code' in error ? error.code : undefined; if (code !== 'EEXIST') { throw error; } @@ -200,7 +239,9 @@ const claimOwner = ( if (!concurrentOwner) { return directoryConflict(gitRoot, directory); } - return concurrentOwner === project ? undefined : ownerConflict(concurrentOwner); + return concurrentOwner === project + ? undefined + : ownerConflict(concurrentOwner); } return undefined; @@ -228,11 +269,19 @@ export const installHooks = ({ return context; } - const { defaultHooksDirectory, effectiveHooksDirectory, gitRoot, projectPath } = context; + const { + defaultHooksDirectory, + effectiveHooksDirectory, + gitRoot, + projectPath, + } = context; const hooksPath = `${resolvedDir}/${generatedDirectoryName}`; const directory = path.join(gitRoot, resolvedDir, generatedDirectoryName); const hooksPathMatches = isSamePath(effectiveHooksDirectory, directory); - const usesDefaultHooks = isSamePath(effectiveHooksDirectory, defaultHooksDirectory); + const usesDefaultHooks = isSamePath( + effectiveHooksDirectory, + defaultHooksDirectory, + ); if (!hooksPathMatches && !usesDefaultHooks) { const activeOwner = readOwner(effectiveHooksDirectory); @@ -269,7 +318,9 @@ export const installHooks = ({ const unchanged = hooksPathMatches && isCurrentFile(path.join(directory, '.gitignore'), gitignore) && - files.every(([name, content]) => isCurrentFile(path.join(directory, name), content, true)); + files.every(([name, content]) => + isCurrentFile(path.join(directory, name), content, true), + ); if (unchanged) { return { status: 'unchanged', hooksPath }; } @@ -293,7 +344,12 @@ export const installHooks = ({ } // Point Git at the generated directory only after every runtime file is ready. - const configured = runGit(cwd, ['config', '--local', 'core.hooksPath', hooksPath]); + const configured = runGit(cwd, [ + 'config', + '--local', + 'core.hooksPath', + hooksPath, + ]); if (configured.error || configured.status === null) { return gitFailure(configured.error, configured.stderr); } diff --git a/packages/rstack/src/staged.ts b/packages/rstack/src/staged.ts index 4f6c78c2..e364c490 100644 --- a/packages/rstack/src/staged.ts +++ b/packages/rstack/src/staged.ts @@ -3,13 +3,16 @@ import { parseArgs } from './cli/args.ts'; import { printCommandHelp } from './cli/help.ts'; import { loadRstackConfig } from './config.ts'; -export type StagedSyncTaskGenerator = (stagedFileNames: readonly string[]) => string | string[]; +export type StagedSyncTaskGenerator = ( + stagedFileNames: readonly string[], +) => string | string[]; export type StagedAsyncTaskGenerator = ( stagedFileNames: readonly string[], ) => Promise; -export type StagedTaskGenerator = StagedSyncTaskGenerator | StagedAsyncTaskGenerator; +export type StagedTaskGenerator = + StagedSyncTaskGenerator | StagedAsyncTaskGenerator; export type StagedFunctionTask = { title: string; @@ -17,7 +20,10 @@ export type StagedFunctionTask = { }; export type StagedTask = - string | StagedFunctionTask | StagedTaskGenerator | (string | StagedTaskGenerator)[]; + | string + | StagedFunctionTask + | StagedTaskGenerator + | (string | StagedTaskGenerator)[]; export type StagedConfig = Record | StagedTaskGenerator; diff --git a/packages/rstack/tests/cli/args.test.ts b/packages/rstack/tests/cli/args.test.ts index 2063dce9..93c4db5b 100644 --- a/packages/rstack/tests/cli/args.test.ts +++ b/packages/rstack/tests/cli/args.test.ts @@ -4,17 +4,20 @@ import { parseArgs } from '../../src/cli/args.ts'; test.each([ ['--long-option', 'kebab'], ['--longOption', 'camel'], -] as const)('accepts %s and returns only a camel-case value', (option, value) => { - const { values } = parseArgs({ - args: [option, value], - options: { - 'long-option': { type: 'string' }, - }, - }); +] as const)( + 'accepts %s and returns only a camel-case value', + (option, value) => { + const { values } = parseArgs({ + args: [option, value], + options: { + 'long-option': { type: 'string' }, + }, + }); - expect(values).toEqual({ longOption: value }); - expect('long-option' in values).toBe(false); -}); + expect(values).toEqual({ longOption: value }); + expect('long-option' in values).toBe(false); + }, +); test('combines repeated kebab-case and camel-case values', () => { const { values } = parseArgs({ diff --git a/packages/rstack/tests/cli/check.test.ts b/packages/rstack/tests/cli/check.test.ts index 87b92845..a2b975a9 100644 --- a/packages/rstack/tests/cli/check.test.ts +++ b/packages/rstack/tests/cli/check.test.ts @@ -65,7 +65,9 @@ test('enables type checking only with --type-check', () => { expect(withoutTypeCheck.status).toBe(0); expect(withTypeCheck.status).toBe(1); - expect(`${withTypeCheck.stdout}\n${withTypeCheck.stderr}`).toContain('TS2322'); + expect(`${withTypeCheck.stdout}\n${withTypeCheck.stderr}`).toContain( + 'TS2322', + ); }); test('does not run the formatting check when lint fails', () => { @@ -75,6 +77,8 @@ test('does not run the formatting check when lint fails', () => { const result = runCheck(); expect(result.status).toBe(1); - expect(`${result.stdout}\n${result.stderr}`).toContain("Unexpected 'debugger' statement"); + expect(`${result.stdout}\n${result.stderr}`).toContain( + "Unexpected 'debugger' statement", + ); expect(result.stdout).not.toContain('Checking formatting...'); }); diff --git a/packages/rstack/tests/cli/fmt/cache.test.ts b/packages/rstack/tests/cli/fmt/cache.test.ts index 12c112e2..d5f98a3c 100644 --- a/packages/rstack/tests/cli/fmt/cache.test.ts +++ b/packages/rstack/tests/cli/fmt/cache.test.ts @@ -1,8 +1,17 @@ import { expect, test } from 'rstack/test'; -import { expectWriteSummary, normalizeDuration, setupFmtTest } from './helpers.ts'; - -const { projectFileExists, readProjectFile, resolveProjectPath, runFmt, writeProjectFile } = - setupFmtTest(); +import { + expectWriteSummary, + normalizeDuration, + setupFmtTest, +} from './helpers.ts'; + +const { + projectFileExists, + readProjectFile, + resolveProjectPath, + runFmt, + writeProjectFile, +} = setupFmtTest(); interface SerializedFmtCache { version: number; @@ -14,7 +23,10 @@ interface SerializedFmtCache { const readFmtCache = (filePath: string): SerializedFmtCache => JSON.parse(readProjectFile(filePath)) as SerializedFmtCache; -const expectSingleCleanEntry = (cache: SerializedFmtCache, filePath: string): void => { +const expectSingleCleanEntry = ( + cache: SerializedFmtCache, + filePath: string, +): void => { expect(cache.version).toBe(2); expect(typeof cache.namespace).toBe('string'); expect(cache.options).toHaveLength(1); @@ -37,7 +49,10 @@ test.each([ expect(result.status).toBe(0); expect(readProjectFile('.rstack/cache/.gitignore')).toBe('*\n'); - expectSingleCleanEntry(readFmtCache('.rstack/cache/fmt/cache.json'), 'index.ts'); + expectSingleCleanEntry( + readFmtCache('.rstack/cache/fmt/cache.json'), + 'index.ts', + ); expect(readProjectFile('.rstack/cache/fmt-v1.json')).toBe('legacy'); }); @@ -67,52 +82,69 @@ test('--no-cache bypasses cache reads and writes', () => { expect(projectFileExists('.rstack/cache/.gitignore')).toBe(false); }); -test.each(['relative', 'absolute'] as const)('uses a %s custom cache location', (kind) => { - const cacheLocation = kind === 'relative' ? 'custom-cache' : resolveProjectPath('custom-cache'); - writeProjectFile('index.ts', 'const value = 1;\n'); - - const result = runFmt(['--cache-location', cacheLocation, 'index.ts']); - - expect(result.status).toBe(0); - expectSingleCleanEntry(readFmtCache('custom-cache/cache.json'), 'index.ts'); - expect(projectFileExists('custom-cache/.gitignore')).toBe(false); - expect(projectFileExists('.rstack')).toBe(false); -}); - -test.each(['.', '..'])('rejects a custom cache location at %s', (cacheLocation) => { - const result = runFmt(['--cache-location', cacheLocation, '.']); - - expect(result.status).toBe(2); - expect(result.stdout).toBe(''); - expect(result.stderr).toContain( - 'The --cache-location directory cannot be the current working directory or an ancestor.', - ); -}); +test.each(['relative', 'absolute'] as const)( + 'uses a %s custom cache location', + (kind) => { + const cacheLocation = + kind === 'relative' ? 'custom-cache' : resolveProjectPath('custom-cache'); + writeProjectFile('index.ts', 'const value = 1;\n'); + + const result = runFmt(['--cache-location', cacheLocation, 'index.ts']); + + expect(result.status).toBe(0); + expectSingleCleanEntry(readFmtCache('custom-cache/cache.json'), 'index.ts'); + expect(projectFileExists('custom-cache/.gitignore')).toBe(false); + expect(projectFileExists('.rstack')).toBe(false); + }, +); + +test.each(['.', '..'])( + 'rejects a custom cache location at %s', + (cacheLocation) => { + const result = runFmt(['--cache-location', cacheLocation, '.']); + + expect(result.status).toBe(2); + expect(result.stdout).toBe(''); + expect(result.stderr).toContain( + 'The --cache-location directory cannot be the current working directory or an ancestor.', + ); + }, +); test('excludes the custom cache directory from formatting', () => { const cacheLocation = 'custom-cache'; writeProjectFile('index.ts', 'const value = 1;\n'); writeProjectFile('custom-cache/nested/ignored.ts', 'const value=2'); - expect(runFmt(['--cache-location', cacheLocation, 'index.ts']).status).toBe(0); + expect(runFmt(['--cache-location', cacheLocation, 'index.ts']).status).toBe( + 0, + ); const result = runFmt(['--cache-location', cacheLocation, '.']); expect(result.status).toBe(0); expectWriteSummary(result.stdout, 2, 0); - expect(readProjectFile('custom-cache/nested/ignored.ts')).toBe('const value=2'); + expect(readProjectFile('custom-cache/nested/ignored.ts')).toBe( + 'const value=2', + ); }); test('uses an explicit config root cache from a subdirectory', () => { const appPath = resolveProjectPath('packages/app'); writeProjectFile('packages/app/index.ts', 'const value=1'); - const result = runFmt(['index.ts', '--config', '../../rstack.config.ts'], appPath); + const result = runFmt( + ['index.ts', '--config', '../../rstack.config.ts'], + appPath, + ); expect(result.status).toBe(0); expect(readProjectFile('packages/app/index.ts')).toBe('const value = 1;\n'); expect(projectFileExists('.rstack/cache/fmt/cache.json')).toBe(true); expect(projectFileExists('packages/app/.rstack')).toBe(false); - expectSingleCleanEntry(readFmtCache('.rstack/cache/fmt/cache.json'), 'packages/app/index.ts'); + expectSingleCleanEntry( + readFmtCache('.rstack/cache/fmt/cache.json'), + 'packages/app/index.ts', + ); }); test('recovers from a corrupted cache', () => { @@ -123,9 +155,13 @@ test('recovers from a corrupted cache', () => { const second = runFmt(['--check', 'index.ts']); expect(second.status).toBe(0); - expect(normalizeDuration(second.stdout)).toBe(normalizeDuration(first.stdout)); + expect(normalizeDuration(second.stdout)).toBe( + normalizeDuration(first.stdout), + ); expect(second.stderr).toBe(first.stderr); - expect(JSON.parse(readProjectFile('.rstack/cache/fmt/cache.json'))).toMatchObject({ version: 2 }); + expect( + JSON.parse(readProjectFile('.rstack/cache/fmt/cache.json')), + ).toMatchObject({ version: 2 }); }); test('formats without a writable cache directory', () => { diff --git a/packages/rstack/tests/cli/fmt/config.test.ts b/packages/rstack/tests/cli/fmt/config.test.ts index d5947aae..5cda6c72 100644 --- a/packages/rstack/tests/cli/fmt/config.test.ts +++ b/packages/rstack/tests/cli/fmt/config.test.ts @@ -6,7 +6,8 @@ import { sortedPackageJson, } from './helpers.ts'; -const { readProjectFile, runFmt, writeFixturePlugin, writeProjectFile } = setupFmtTest(); +const { readProjectFile, runFmt, writeFixturePlugin, writeProjectFile } = + setupFmtTest(); test('does not sort package.json by default', () => { writeProjectFile('package.json', packageJsonSource); @@ -35,7 +36,9 @@ define.fmt({ sortPackageJson: true }); expect(result.status).toBe(0); expect(result.stderr).toBe(''); expect(readProjectFile('package.json')).toBe(sortedPackageJson); - expect(readProjectFile('packages/example/package.json')).toBe(sortedPackageJson); + expect(readProjectFile('packages/example/package.json')).toBe( + sortedPackageJson, + ); }); test('supports configuring the worker count', () => { @@ -52,17 +55,28 @@ test('supports configuring the worker count', () => { }); test('does not load Prettier config or ignore files', () => { - writeProjectFile('.prettierrc.json', '{ "singleQuote": true, "semi": false }\n'); + writeProjectFile( + '.prettierrc.json', + '{ "singleQuote": true, "semi": false }\n', + ); writeProjectFile('.prettierignore', 'index.ts\n'); - writeProjectFile('.editorconfig', 'root = true\n\n[*]\nindent_style = space\nindent_size = 8\n'); - writeProjectFile('index.ts', "function getMessage(){\n return 'hello'\n}"); + writeProjectFile( + '.editorconfig', + 'root = true\n\n[*]\nindent_style = space\nindent_size = 8\n', + ); + writeProjectFile( + 'index.ts', + "function getMessage(){\n return 'hello'\n}", + ); const result = runFmt(['index.ts']); expect(result.status).toBe(0); expectWriteSummary(result.stdout, 1, 1); expect(result.stderr).toBe(''); - expect(readProjectFile('index.ts')).toBe('function getMessage() {\n return "hello";\n}\n'); + expect(readProjectFile('index.ts')).toBe( + 'function getMessage() {\n return "hello";\n}\n', + ); }); test('applies repeated ignore paths', () => { @@ -84,8 +98,12 @@ test('applies repeated ignore paths', () => { expect(result.status).toBe(0); expectWriteSummary(result.stdout, 1, 1); expect(result.stderr).toBe(''); - expect(readProjectFile('src/ignored-by-root.ts')).toBe('const root="ignored"'); - expect(readProjectFile('src/ignored-by-extra.ts')).toBe('const extra="ignored"'); + expect(readProjectFile('src/ignored-by-root.ts')).toBe( + 'const root="ignored"', + ); + expect(readProjectFile('src/ignored-by-extra.ts')).toBe( + 'const extra="ignored"', + ); expect(readProjectFile('src/index.ts')).toBe('const index = "formatted";\n'); }); @@ -96,7 +114,9 @@ test('returns exit code 2 for an unreadable ignore path', () => { expect(result.status).toBe(2); expect(result.stdout).toBe(''); - expect(result.stderr).toContain('Failed to read ignore file "missing.ignore".'); + expect(result.stderr).toContain( + 'Failed to read ignore file "missing.ignore".', + ); expect(readProjectFile('index.ts')).toBe('const value=true'); }); @@ -156,7 +176,10 @@ define.fmt({ }); test('returns exit code 2 for config errors', () => { - writeProjectFile('rstack.config.ts', 'throw new Error("invalid fmt config");\n'); + writeProjectFile( + 'rstack.config.ts', + 'throw new Error("invalid fmt config");\n', + ); const result = runFmt(['index.ts']); diff --git a/packages/rstack/tests/cli/fmt/files.test.ts b/packages/rstack/tests/cli/fmt/files.test.ts index d650eac1..f0368df4 100644 --- a/packages/rstack/tests/cli/fmt/files.test.ts +++ b/packages/rstack/tests/cli/fmt/files.test.ts @@ -1,6 +1,10 @@ import { expect, test } from 'rstack/test'; import { normalizeHelpOutput } from '#test-helpers'; -import { expectWriteSummary, normalizeDuration, setupFmtTest } from './helpers.ts'; +import { + expectWriteSummary, + normalizeDuration, + setupFmtTest, +} from './helpers.ts'; const { readProjectFile, runCLI, runFmt, writeProjectFile } = setupFmtTest(); @@ -77,7 +81,9 @@ test('formats files in node_modules with --with-node-modules', () => { expect(result.status).toBe(0); expectWriteSummary(result.stdout, 1, 1); expect(result.stderr).toBe(''); - expect(readProjectFile('node_modules/example/index.ts')).toBe('const message = "hello";\n'); + expect(readProjectFile('node_modules/example/index.ts')).toBe( + 'const message = "hello";\n', + ); }); test('summarizes write mode when no files change', () => { @@ -116,18 +122,21 @@ test('checks formatting without writing files', () => { expect(formattedResult.stderr).toBe(''); }); -test.each(['-l', '--list-different'])('lists only paths that differ with %s', (option) => { - const source = 'const message="hello"'; - writeProjectFile('src/index.ts', source); - writeProjectFile('src/formatted.ts', 'const formatted = true;\n'); - - const result = runFmt([option, 'src/*.ts']); - - expect(result.status).toBe(1); - expect(result.stdout).toBe('src/index.ts\n'); - expect(result.stderr).toBe(''); - expect(readProjectFile('src/index.ts')).toBe(source); -}); +test.each(['-l', '--list-different'])( + 'lists only paths that differ with %s', + (option) => { + const source = 'const message="hello"'; + writeProjectFile('src/index.ts', source); + writeProjectFile('src/formatted.ts', 'const formatted = true;\n'); + + const result = runFmt([option, 'src/*.ts']); + + expect(result.status).toBe(1); + expect(result.stdout).toBe('src/index.ts\n'); + expect(result.stderr).toBe(''); + expect(readProjectFile('src/index.ts')).toBe(source); + }, +); test('returns exit code 2 for formatting errors', () => { writeProjectFile('index.ts', 'const value = ;'); diff --git a/packages/rstack/tests/cli/fmt/helpers.ts b/packages/rstack/tests/cli/fmt/helpers.ts index c33f7ecf..d3b62229 100644 --- a/packages/rstack/tests/cli/fmt/helpers.ts +++ b/packages/rstack/tests/cli/fmt/helpers.ts @@ -1,5 +1,12 @@ import { type SpawnSyncReturns, spawnSync } from 'node:child_process'; -import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { + existsSync, + mkdirSync, + mkdtempSync, + readFileSync, + rmSync, + writeFileSync, +} from 'node:fs'; import path from 'node:path'; import { afterEach, beforeEach, expect } from 'rstack/test'; import { RSTACK_BIN_PATH } from '#test-helpers'; @@ -9,7 +16,11 @@ export const packageJsonSource = export const sortedPackageJson = '{\n "name": "fixture",\n "version": "1.0.0",\n "type": "module",\n "dependencies": {\n "a": "1.0.0",\n "z": "1.0.0"\n }\n}\n'; -type RunCLI = (args: string[], input?: string, cwd?: string) => SpawnSyncReturns; +type RunCLI = ( + args: string[], + input?: string, + cwd?: string, +) => SpawnSyncReturns; type FmtTestHarness = { projectFileExists: (filePath: string) => boolean; @@ -42,15 +53,19 @@ export const expectWriteSummary = ( const message = writtenCount ? `Formatted ${writtenCount} of ${matchedFileCount} ${files} in .` : `Checked ${matchedFileCount} ${files} in . No changes needed.`; - expect(normalizeDuration(output)).toBe(`start Formatting...\nsuccess ${message}\n`); + expect(normalizeDuration(output)).toBe( + `start Formatting...\nsuccess ${message}\n`, + ); }; export const setupFmtTest = (): FmtTestHarness => { let projectPath: string; - const resolveProjectPath = (filePath: string): string => path.join(projectPath, filePath); + const resolveProjectPath = (filePath: string): string => + path.join(projectPath, filePath); - const projectFileExists = (filePath: string): boolean => existsSync(resolveProjectPath(filePath)); + const projectFileExists = (filePath: string): boolean => + existsSync(resolveProjectPath(filePath)); const writeProjectFile = (filePath: string, content: string): void => { const absolutePath = resolveProjectPath(filePath); @@ -64,7 +79,10 @@ export const setupFmtTest = (): FmtTestHarness => { const writeFixturePlugin = (): void => { writeProjectFile( 'node_modules/prettier-plugin-fixture/package.json', - JSON.stringify({ name: 'prettier-plugin-fixture', exports: './index.mjs' }), + JSON.stringify({ + name: 'prettier-plugin-fixture', + exports: './index.mjs', + }), ); writeProjectFile( 'node_modules/prettier-plugin-fixture/index.mjs', @@ -86,7 +104,8 @@ export const setupFmtTest = (): FmtTestHarness => { const runFmt = (args: string[] = [], cwd = projectPath) => runCLI(['fmt', ...args], undefined, cwd); - const runFmtStdin = (args: string[], input: string) => runCLI(['fmt', ...args], input); + const runFmtStdin = (args: string[], input: string) => + runCLI(['fmt', ...args], input); beforeEach(() => { projectPath = mkdtempSync(path.join(import.meta.dirname, 'test-temp-fmt-')); diff --git a/packages/rstack/tests/cli/fmt/lsp.test.ts b/packages/rstack/tests/cli/fmt/lsp.test.ts index 4309feca..4e0ba51d 100644 --- a/packages/rstack/tests/cli/fmt/lsp.test.ts +++ b/packages/rstack/tests/cli/fmt/lsp.test.ts @@ -1,6 +1,11 @@ import { expect, test } from 'rstack/test'; import { setupFmtTest } from './helpers.ts'; -import { applyTextEdits, type LspClient, startLspServer, toFileUri } from './lspClient.ts'; +import { + applyTextEdits, + type LspClient, + startLspServer, + toFileUri, +} from './lspClient.ts'; const { resolveProjectPath, runFmt, writeProjectFile } = setupFmtTest(); @@ -27,7 +32,11 @@ const withLspServer = async ( } }; -const openDocument = (client: LspClient, filePath: string, text: string): string => { +const openDocument = ( + client: LspClient, + filePath: string, + text: string, +): string => { const uri = toFileUri(resolveProjectPath(filePath)); client.openDocument(uri, 'typescript', text); @@ -87,7 +96,9 @@ test( const edits = await client.formatDocument(uri); - expect(applyTextEdits(source, edits)).toBe('const inBuffer = "buffer";\n'); + expect(applyTextEdits(source, edits)).toBe( + 'const inBuffer = "buffer";\n', + ); }); }, TEST_TIMEOUT, @@ -252,8 +263,16 @@ test( await withLspServer( async (client) => { await client.initialize(resolveProjectPath('.')); - const ignoredUri = openDocument(client, 'src/ignored.ts', 'const ignored="ignored"\n'); - const formattedUri = openDocument(client, 'src/index.ts', 'const x=1\n'); + const ignoredUri = openDocument( + client, + 'src/ignored.ts', + 'const ignored="ignored"\n', + ); + const formattedUri = openDocument( + client, + 'src/index.ts', + 'const x=1\n', + ); expect(await client.formatDocument(ignoredUri)).toEqual([]); // The ignore file was read rather than reported as missing. @@ -330,7 +349,11 @@ define.fmt({ ignorePatterns: ['src/ignored.ts'] }); await withLspServer(async (client) => { await client.initialize(); - const uri = openDocument(client, 'src/ignored.ts', 'const ignored="ignored"\n'); + const uri = openDocument( + client, + 'src/ignored.ts', + 'const ignored="ignored"\n', + ); expect(await client.formatDocument(uri)).toEqual([]); }); @@ -379,12 +402,16 @@ test('returns exit code 2 for file arguments with --lsp', () => { const result = runFmt(['--lsp', 'src/index.ts']); expect(result.status).toBe(2); - expect(result.stderr).toContain('The --lsp option cannot be used with file arguments.'); + expect(result.stderr).toContain( + 'The --lsp option cannot be used with file arguments.', + ); }); test('returns exit code 2 for --stdin-filepath with --lsp', () => { const result = runFmt(['--lsp', '--stdin-filepath', 'src/index.ts']); expect(result.status).toBe(2); - expect(result.stderr).toContain('The --lsp option cannot be used with --stdin-filepath.'); + expect(result.stderr).toContain( + 'The --lsp option cannot be used with --stdin-filepath.', + ); }); diff --git a/packages/rstack/tests/cli/fmt/lspClient.ts b/packages/rstack/tests/cli/fmt/lspClient.ts index 31c2bb58..c2ac899a 100644 --- a/packages/rstack/tests/cli/fmt/lspClient.ts +++ b/packages/rstack/tests/cli/fmt/lspClient.ts @@ -13,14 +13,19 @@ type JsonRpcMessage = { }; export type Position = { line: number; character: number }; -export type TextEdit = { range: { start: Position; end: Position }; newText: string }; +export type TextEdit = { + range: { start: Position; end: Position }; + newText: string; +}; export type ShownMessage = { type: number; message: string }; export type LspClient = { notify: (method: string, params: unknown) => void; /** Initializes the server with `root` as the workspace root; defaults to the spawn cwd. */ - initialize: (root?: string) => Promise<{ capabilities: Record }>; + initialize: ( + root?: string, + ) => Promise<{ capabilities: Record }>; openDocument: (uri: string, languageId: string, text: string) => void; formatDocument: (uri: string) => Promise; /** `window/showMessage` notifications received so far, in order. */ @@ -34,13 +39,19 @@ const CONTENT_LENGTH_REGEXP = /content-length:\s*(\d+)/i; /** A header block is `key: value` lines separated by `\r\n` and nothing else. */ const HEADER_BLOCK_REGEXP = /^[^\r\n:]+:[^\r\n]*(?:\r\n[^\r\n:]+:[^\r\n]*)*$/; -export const toFileUri = (filePath: string): string => pathToFileURL(filePath).href; +export const toFileUri = (filePath: string): string => + pathToFileURL(filePath).href; /** Applies LSP text edits to a document, mirroring an editor. */ export const applyTextEdits = (text: string, edits: TextEdit[]): string => - TextDocument.applyEdits(TextDocument.create('file:///document', 'plaintext', 1, text), edits); + TextDocument.applyEdits( + TextDocument.create('file:///document', 'plaintext', 1, text), + edits, + ); -const readMessage = (buffer: Buffer): { message: JsonRpcMessage; rest: Buffer } | undefined => { +const readMessage = ( + buffer: Buffer, +): { message: JsonRpcMessage; rest: Buffer } | undefined => { const headerEnd = buffer.indexOf('\r\n\r\n'); if (headerEnd === -1) { return undefined; @@ -50,7 +61,9 @@ const readMessage = (buffer: Buffer): { message: JsonRpcMessage; rest: Buffer } // Real clients fall out of sync here, so anything that is not a header is a // failure rather than something to skip over. if (!HEADER_BLOCK_REGEXP.test(headers)) { - throw new Error(`Unexpected bytes on stdout before a message: ${JSON.stringify(headers)}.`); + throw new Error( + `Unexpected bytes on stdout before a message: ${JSON.stringify(headers)}.`, + ); } const contentLength = CONTENT_LENGTH_REGEXP.exec(headers); @@ -65,7 +78,9 @@ const readMessage = (buffer: Buffer): { message: JsonRpcMessage; rest: Buffer } } return { - message: JSON.parse(buffer.subarray(bodyStart, bodyEnd).toString('utf8')) as JsonRpcMessage, + message: JSON.parse( + buffer.subarray(bodyStart, bodyEnd).toString('utf8'), + ) as JsonRpcMessage, rest: buffer.subarray(bodyEnd), }; }; @@ -128,18 +143,26 @@ export const startLspServer = (cwd: string, args: string[] = []): LspClient => { const closed = new Promise((resolve) => { childProcess.once('close', (code) => { exitCode = code; - fail(new Error(`The language server exited with code ${code}.\n${stderr}`)); + fail( + new Error(`The language server exited with code ${code}.\n${stderr}`), + ); resolve(code); }); }); const send = (message: Record): void => { - const body = Buffer.from(JSON.stringify({ jsonrpc: '2.0', ...message }), 'utf8'); + const body = Buffer.from( + JSON.stringify({ jsonrpc: '2.0', ...message }), + 'utf8', + ); childProcess.stdin.write(`Content-Length: ${body.byteLength}\r\n\r\n`); childProcess.stdin.write(body); }; - const request = (method: string, params: unknown): Promise => { + const request = ( + method: string, + params: unknown, + ): Promise => { if (failure) { return Promise.reject(failure); } @@ -147,7 +170,10 @@ export const startLspServer = (cwd: string, args: string[] = []): LspClient => { const id = nextId++; return new Promise((resolve, reject) => { - pending.set(id, { resolve: resolve as (result: unknown) => void, reject }); + pending.set(id, { + resolve: resolve as (result: unknown) => void, + reject, + }); send({ id, method, params }); }); }; diff --git a/packages/rstack/tests/cli/fmt/patterns.test.ts b/packages/rstack/tests/cli/fmt/patterns.test.ts index 52ec4480..b87eee16 100644 --- a/packages/rstack/tests/cli/fmt/patterns.test.ts +++ b/packages/rstack/tests/cli/fmt/patterns.test.ts @@ -19,7 +19,11 @@ test('returns exit code 2 when no files match', () => { test('allows no files to match with --no-error-on-unmatched-pattern', () => { for (const modeArgs of [[], ['--check'], ['--list-different']]) { - const result = runFmt([...modeArgs, '--no-error-on-unmatched-pattern', 'missing/**/*.ts']); + const result = runFmt([ + ...modeArgs, + '--no-error-on-unmatched-pattern', + 'missing/**/*.ts', + ]); expect(result.status).toBe(0); expect(result.stdout).toBe(''); @@ -78,7 +82,9 @@ test('supports -u as an alias for --ignore-unknown', () => { const result = runFmt(['-u', 'notes.unknown']); expect(result.status).toBe(0); - expect(result.stdout).toBe('start Formatting...\nsuccess No supported files to format.\n'); + expect(result.stdout).toBe( + 'start Formatting...\nsuccess No supported files to format.\n', + ); expect(result.stderr).toBe(''); }); @@ -87,7 +93,9 @@ test('does not treat unmatched patterns as unknown files', () => { expect(result.status).toBe(2); expect(result.stdout).toBe(''); - expect(result.stderr).toContain('No supported files matched "missing/**/*.unknown"'); + expect(result.stderr).toContain( + 'No supported files matched "missing/**/*.unknown"', + ); }); test('does not treat unsupported files as unmatched patterns', () => { diff --git a/packages/rstack/tests/cli/fmt/stdin.test.ts b/packages/rstack/tests/cli/fmt/stdin.test.ts index 21e5a4c5..ebf0e676 100644 --- a/packages/rstack/tests/cli/fmt/stdin.test.ts +++ b/packages/rstack/tests/cli/fmt/stdin.test.ts @@ -1,10 +1,17 @@ import { expect, test } from 'rstack/test'; -import { packageJsonSource, setupFmtTest, sortedPackageJson } from './helpers.ts'; +import { + packageJsonSource, + setupFmtTest, + sortedPackageJson, +} from './helpers.ts'; const { projectFileExists, runFmtStdin, writeProjectFile } = setupFmtTest(); test('formats stdin for the given filepath', () => { - const result = runFmtStdin(['--stdin-filepath', 'src/index.ts'], 'const message="hello"'); + const result = runFmtStdin( + ['--stdin-filepath', 'src/index.ts'], + 'const message="hello"', + ); expect(result.status).toBe(0); expect(result.stdout).toBe('const message = "hello";\n'); @@ -31,7 +38,10 @@ define.fmt({ `, ); - const result = runFmtStdin(['--stdin-filepath', 'src/index.test.ts'], 'const test="test"'); + const result = runFmtStdin( + ['--stdin-filepath', 'src/index.test.ts'], + 'const test="test"', + ); expect(result.status).toBe(0); expect(result.stdout).toBe("const test = 'test'\n"); @@ -47,7 +57,10 @@ define.fmt({ sortPackageJson: true }); `, ); - const result = runFmtStdin(['--stdin-filepath', 'package.json'], packageJsonSource); + const result = runFmtStdin( + ['--stdin-filepath', 'package.json'], + packageJsonSource, + ); expect(result.status).toBe(0); expect(result.stdout).toBe(sortedPackageJson); @@ -99,11 +112,16 @@ test('returns exit code 2 when no parser can be inferred for stdin', () => { expect(result.status).toBe(2); expect(result.stdout).toBe(''); - expect(result.stderr).toContain('No parser could be inferred for "data.unknown".'); + expect(result.stderr).toContain( + 'No parser could be inferred for "data.unknown".', + ); }); test('ignores stdin when no parser can be inferred with --ignore-unknown', () => { - const result = runFmtStdin(['--stdin-filepath', 'data.unknown', '--ignore-unknown'], 'value'); + const result = runFmtStdin( + ['--stdin-filepath', 'data.unknown', '--ignore-unknown'], + 'value', + ); expect(result.status).toBe(0); expect(result.stdout).toBe(''); @@ -111,7 +129,10 @@ test('ignores stdin when no parser can be inferred with --ignore-unknown', () => }); test('returns exit code 2 for stdin parse errors', () => { - const result = runFmtStdin(['--stdin-filepath', 'index.ts'], 'const value = ;'); + const result = runFmtStdin( + ['--stdin-filepath', 'index.ts'], + 'const value = ;', + ); expect(result.status).toBe(2); expect(result.stdout).toBe(''); @@ -121,7 +142,10 @@ test('returns exit code 2 for stdin parse errors', () => { test.each(['--write', '--check', '--list-different'])( 'returns exit code 2 for %s with --stdin-filepath', (option) => { - const result = runFmtStdin(['--stdin-filepath', 'index.ts', option], 'const value=1'); + const result = runFmtStdin( + ['--stdin-filepath', 'index.ts', option], + 'const value=1', + ); expect(result.status).toBe(2); expect(result.stdout).toBe(''); @@ -132,7 +156,10 @@ test.each(['--write', '--check', '--list-different'])( ); test('returns exit code 2 for file arguments with --stdin-filepath', () => { - const result = runFmtStdin(['--stdin-filepath', 'index.ts', 'src/other.ts'], 'const value=1'); + const result = runFmtStdin( + ['--stdin-filepath', 'index.ts', 'src/other.ts'], + 'const value=1', + ); expect(result.status).toBe(2); expect(result.stdout).toBe(''); diff --git a/packages/rstack/tests/cli/fmt/vue.test.ts b/packages/rstack/tests/cli/fmt/vue.test.ts index ffa19c6a..bdfe2f79 100644 --- a/packages/rstack/tests/cli/fmt/vue.test.ts +++ b/packages/rstack/tests/cli/fmt/vue.test.ts @@ -6,13 +6,17 @@ const { readProjectFile, runFmt, writeProjectFile } = setupFmtTest(); test.each([ { name: 'TypeScript', - source: '\n', - expected: '\n', + source: + '\n', + expected: + '\n', }, { name: 'TSX', - source: '\n', - expected: '\n', + source: + '\n', + expected: + '\n', }, ])('formats $name embedded in Vue files', ({ source, expected }) => { writeProjectFile('App.vue', source); diff --git a/packages/rstack/tests/cli/setup/index.test.ts b/packages/rstack/tests/cli/setup/index.test.ts index 3f29104f..0780fd4a 100644 --- a/packages/rstack/tests/cli/setup/index.test.ts +++ b/packages/rstack/tests/cli/setup/index.test.ts @@ -1,5 +1,11 @@ import { spawnSync } from 'node:child_process'; -import { existsSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'; +import { + existsSync, + mkdirSync, + mkdtempSync, + rmSync, + writeFileSync, +} from 'node:fs'; import path from 'node:path'; import { afterEach, beforeEach } from 'rstack/test'; import { normalizeHelpOutput, RSTACK_BIN_PATH, test } from '#test-helpers'; @@ -61,7 +67,9 @@ test('reports missing and repeated hooks directory options', ({ expect }) => { const repeated = runSetup(['--hooks-dir', 'first', '--hooks-dir', 'second']); expect(repeated.status).toBe(1); - expect(repeated.stderr).toContain('The --hooks-dir option cannot be specified more than once.'); + expect(repeated.stderr).toContain( + 'The --hooks-dir option cannot be specified more than once.', + ); }); test('rejects invalid hooks directory options', ({ expect }) => { @@ -80,27 +88,42 @@ test('rejects invalid hooks directory options', ({ expect }) => { expect(parent.stderr).toContain('Git hooks directory must not contain "..".'); }); -test('installs hooks silently without loading Rstack config', ({ execCli, expect }) => { +test('installs hooks silently without loading Rstack config', ({ + execCli, + expect, +}) => { initRepository(); - writeFileSync(path.join(cwd, 'rstack.config.ts'), 'throw new Error("must not load");\n'); + writeFileSync( + path.join(cwd, 'rstack.config.ts'), + 'throw new Error("must not load");\n', + ); expect(execCli('setup', { cwd, env })).toBe(''); expect(git(['config', '--local', '--get', 'core.hooksPath'])).toBe(hooksPath); expect(existsSync(path.join(cwd, hooksPath, 'runner'))).toBe(true); - expect(existsSync(path.join(cwd, '.rstack', 'hooks', 'pre-commit'))).toBe(false); + expect(existsSync(path.join(cwd, '.rstack', 'hooks', 'pre-commit'))).toBe( + false, + ); expect(execCli('setup', { cwd, env })).toBe(''); }); -test('installs root-relative hooks and reports owner conflicts', ({ execCli, expect }) => { +test('installs root-relative hooks and reports owner conflicts', ({ + execCli, + expect, +}) => { initRepository(); const frontend = path.join(cwd, 'frontend'); const docs = path.join(cwd, 'docs'); mkdirSync(frontend); mkdirSync(docs); - expect(execCli('setup --hooks-dir "custom hooks"', { cwd: frontend, env })).toBe(''); - expect(git(['config', '--local', '--get', 'core.hooksPath'])).toBe('custom hooks/_'); + expect( + execCli('setup --hooks-dir "custom hooks"', { cwd: frontend, env }), + ).toBe(''); + expect(git(['config', '--local', '--get', 'core.hooksPath'])).toBe( + 'custom hooks/_', + ); expect(existsSync(path.join(cwd, 'custom hooks', '_', 'runner'))).toBe(true); const conflict = runSetup(['--hooks-dir', 'custom hooks'], docs); @@ -110,7 +133,10 @@ test('installs root-relative hooks and reports owner conflicts', ({ execCli, exp ); }); -test('skips non-Git directories without creating files', ({ execCli, expect }) => { +test('skips non-Git directories without creating files', ({ + execCli, + expect, +}) => { expect(execCli('setup', { cwd, env })).toContain( 'info Git hooks setup skipped: not a Git repository.', ); @@ -120,7 +146,9 @@ test('skips non-Git directories without creating files', ({ execCli, expect }) = test('skips setup when hooks are disabled', ({ execCli, expect }) => { const output = execCli('setup', { cwd, env: { ...env, RSTACK_HOOKS: '0' } }); - expect(output).toContain('info Git hooks setup skipped: disabled by RSTACK_HOOKS.'); + expect(output).toContain( + 'info Git hooks setup skipped: disabled by RSTACK_HOOKS.', + ); expect(existsSync(path.join(cwd, '.rstack'))).toBe(false); }); diff --git a/packages/rstack/tests/cli/specify-config/index.test.ts b/packages/rstack/tests/cli/specify-config/index.test.ts index 99a4d5e2..504f991c 100644 --- a/packages/rstack/tests/cli/specify-config/index.test.ts +++ b/packages/rstack/tests/cli/specify-config/index.test.ts @@ -1,7 +1,11 @@ import { getDistFiles, getFileContent } from '@rstackjs/test-utils'; import { test } from '#test-helpers'; -test('should build with rstack --config', async ({ prepareDist, execCli, expect }) => { +test('should build with rstack --config', async ({ + prepareDist, + execCli, + expect, +}) => { const distPath = await prepareDist(); execCli('build --config ./custom.config.ts'); diff --git a/packages/rstack/tests/cli/staged/fmt.test.ts b/packages/rstack/tests/cli/staged/fmt.test.ts index fa156f59..875a5e27 100644 --- a/packages/rstack/tests/cli/staged/fmt.test.ts +++ b/packages/rstack/tests/cli/staged/fmt.test.ts @@ -21,7 +21,9 @@ const git = (args: string[]): string => { }); if (result.status !== 0) { - throw new Error(result.stderr || `Git exited with status ${result.status}.`); + throw new Error( + result.stderr || `Git exited with status ${result.status}.`, + ); } return result.stdout; @@ -35,7 +37,9 @@ const runStaged = () => }); beforeEach(() => { - projectPath = mkdtempSync(path.join(import.meta.dirname, 'test-temp-staged-fmt-')); + projectPath = mkdtempSync( + path.join(import.meta.dirname, 'test-temp-staged-fmt-'), + ); env = { ...process.env, GIT_CONFIG_GLOBAL: path.join(projectPath, 'global.gitconfig'), @@ -74,11 +78,21 @@ test('formats staged files with rs fmt and applies ignore rules', () => { const result = runStaged(); expect(result.status).toBe(0); - expect(readProjectFile('file with spaces.ts')).toBe('const spaced = "spaced";\n'); - expect(readProjectFile('ignored-by-git.ts')).toBe('const gitIgnored = "git ignored";\n'); - expect(readProjectFile('ignored-by-fmt.ts')).toBe('const fmtIgnored="fmt ignored"'); - expect(git(['show', ':file with spaces.ts'])).toBe('const spaced = "spaced";\n'); - expect(git(['show', ':ignored-by-git.ts'])).toBe('const gitIgnored = "git ignored";\n'); + expect(readProjectFile('file with spaces.ts')).toBe( + 'const spaced = "spaced";\n', + ); + expect(readProjectFile('ignored-by-git.ts')).toBe( + 'const gitIgnored = "git ignored";\n', + ); + expect(readProjectFile('ignored-by-fmt.ts')).toBe( + 'const fmtIgnored="fmt ignored"', + ); + expect(git(['show', ':file with spaces.ts'])).toBe( + 'const spaced = "spaced";\n', + ); + expect(git(['show', ':ignored-by-git.ts'])).toBe( + 'const gitIgnored = "git ignored";\n', + ); }); test('allows rs fmt when all staged files are ignored', () => { @@ -91,7 +105,9 @@ test('allows rs fmt when all staged files are ignored', () => { expect(result.status).toBe(0); expect(readProjectFile('ignored-by-fmt.ts')).toBe(source); expect(git(['show', ':ignored-by-fmt.ts'])).toBe(source); - expect(`${result.stdout}\n${result.stderr}`).not.toContain('No supported files matched'); + expect(`${result.stdout}\n${result.stderr}`).not.toContain( + 'No supported files matched', + ); }); test('still rejects staged files unsupported by rs fmt', () => { @@ -101,7 +117,9 @@ test('still rejects staged files unsupported by rs fmt', () => { const result = runStaged(); expect(result.status).toBe(1); - expect(`${result.stdout}\n${result.stderr}`).toContain('No supported files matched'); + expect(`${result.stdout}\n${result.stderr}`).toContain( + 'No supported files matched', + ); }); test('allows staged files unsupported by rs fmt with --ignore-unknown', () => { @@ -120,7 +138,9 @@ define.staged({ const result = runStaged(); expect(result.status).toBe(0); - expect(`${result.stdout}\n${result.stderr}`).not.toContain('No supported files matched'); + expect(`${result.stdout}\n${result.stderr}`).not.toContain( + 'No supported files matched', + ); }); test('propagates rs fmt failures', () => { diff --git a/packages/rstack/tests/config/define-app-lib/index.test.ts b/packages/rstack/tests/config/define-app-lib/index.test.ts index 99f6a8a5..3ed77ad4 100644 --- a/packages/rstack/tests/config/define-app-lib/index.test.ts +++ b/packages/rstack/tests/config/define-app-lib/index.test.ts @@ -1,5 +1,7 @@ import { test } from '#test-helpers'; -test('should prefer define.app when app and lib are both defined', ({ execCli }) => { +test('should prefer define.app when app and lib are both defined', ({ + execCli, +}) => { execCli('test'); }); diff --git a/packages/rstack/tests/config/define-app/index.test.ts b/packages/rstack/tests/config/define-app/index.test.ts index 73bbe51f..745ea7bd 100644 --- a/packages/rstack/tests/config/define-app/index.test.ts +++ b/packages/rstack/tests/config/define-app/index.test.ts @@ -4,7 +4,11 @@ import { test } from '#test-helpers'; const expectedText = 'define.app works'; -test('should build app with define.app config', async ({ prepareDist, execCli, expect }) => { +test('should build app with define.app config', async ({ + prepareDist, + execCli, + expect, +}) => { const distPath = await prepareDist(); try { diff --git a/packages/rstack/tests/config/define-doc/index.test.ts b/packages/rstack/tests/config/define-doc/index.test.ts index 464e7580..18142fc4 100644 --- a/packages/rstack/tests/config/define-doc/index.test.ts +++ b/packages/rstack/tests/config/define-doc/index.test.ts @@ -3,7 +3,11 @@ import { test } from '#test-helpers'; const expectedText = 'define.doc works'; -test('should build docs with define.doc config', async ({ prepareDist, execCli, expect }) => { +test('should build docs with define.doc config', async ({ + prepareDist, + execCli, + expect, +}) => { const distPath = await prepareDist('doc_build'); execCli('doc build'); diff --git a/packages/rstack/tests/config/define-lib/index.test.ts b/packages/rstack/tests/config/define-lib/index.test.ts index 53435b7e..db68d6e0 100644 --- a/packages/rstack/tests/config/define-lib/index.test.ts +++ b/packages/rstack/tests/config/define-lib/index.test.ts @@ -3,7 +3,11 @@ import { test } from '#test-helpers'; const expectedText = 'define.lib works'; -test('should build lib with define.lib config', async ({ prepareDist, execCli, expect }) => { +test('should build lib with define.lib config', async ({ + prepareDist, + execCli, + expect, +}) => { const distPath = await prepareDist(); execCli('lib'); diff --git a/packages/rstack/tests/config/define-lint/index.test.ts b/packages/rstack/tests/config/define-lint/index.test.ts index 402266fc..aff80258 100644 --- a/packages/rstack/tests/config/define-lint/index.test.ts +++ b/packages/rstack/tests/config/define-lint/index.test.ts @@ -7,7 +7,11 @@ test('should run lint with define.lint config', ({ execCli }) => { execCli('lint src/index.js'); }); -test('should fail when lint reports errors', async ({ cwd, execCli, logHelper }) => { +test('should fail when lint reports errors', async ({ + cwd, + execCli, + logHelper, +}) => { const filePath = path.join(cwd, 'src/test-temp-error.js'); await writeFile(filePath, 'debugger;'); expect(() => execCli('lint src/test-temp-error.js')).toThrow(); diff --git a/packages/rstack/tests/config/define-test-projects-app/index.test.ts b/packages/rstack/tests/config/define-test-projects-app/index.test.ts index 74f00e4d..d1e41c96 100644 --- a/packages/rstack/tests/config/define-test-projects-app/index.test.ts +++ b/packages/rstack/tests/config/define-test-projects-app/index.test.ts @@ -1,5 +1,7 @@ import { test } from '#test-helpers'; -test('should apply define.app config to every inline test project', ({ execCli }) => { +test('should apply define.app config to every inline test project', ({ + execCli, +}) => { execCli('test'); }); diff --git a/packages/rstack/tests/config/define-test-projects-lib/index.test.ts b/packages/rstack/tests/config/define-test-projects-lib/index.test.ts index 62372a46..724fd167 100644 --- a/packages/rstack/tests/config/define-test-projects-lib/index.test.ts +++ b/packages/rstack/tests/config/define-test-projects-lib/index.test.ts @@ -1,5 +1,7 @@ import { test } from '#test-helpers'; -test('should apply define.lib config to every inline test project', ({ execCli }) => { +test('should apply define.lib config to every inline test project', ({ + execCli, +}) => { execCli('test'); }); diff --git a/packages/rstack/tests/config/load-config/index.test.ts b/packages/rstack/tests/config/load-config/index.test.ts index a738f80e..fa2e9c43 100644 --- a/packages/rstack/tests/config/load-config/index.test.ts +++ b/packages/rstack/tests/config/load-config/index.test.ts @@ -15,7 +15,8 @@ declare global { } const state = getConfigState(); -const configPath = (fileName: string): string => path.join(import.meta.dirname, fileName); +const configPath = (fileName: string): string => + path.join(import.meta.dirname, fileName); const loadConfigFile = (fileName: string) => loadRstackConfig({ configFilePath: configPath(fileName) }); @@ -62,7 +63,9 @@ test('should resolve a relative explicit config path from cwd', async () => { }); test('should search for the config file in cwd', async () => { - await expect(loadRstackConfig({ cwd: import.meta.dirname })).rejects.toThrow('test config error'); + await expect(loadRstackConfig({ cwd: import.meta.dirname })).rejects.toThrow( + 'test config error', + ); }); test('should isolate parallel config sessions across top-level await', async () => { diff --git a/packages/rstack/tests/config/reload-app-config/index.test.ts b/packages/rstack/tests/config/reload-app-config/index.test.ts index a7f9ab93..7fb1ea1c 100644 --- a/packages/rstack/tests/config/reload-app-config/index.test.ts +++ b/packages/rstack/tests/config/reload-app-config/index.test.ts @@ -9,7 +9,10 @@ test('should restart dev server and reload config when Rstack config changes', a }) => { const dist1 = await prepareDist(); const dist2 = await prepareDist('dist-2'); - const configFile = path.join(import.meta.dirname, 'test-temp-rstack.config.ts'); + const configFile = path.join( + import.meta.dirname, + 'test-temp-rstack.config.ts', + ); await writeFile( configFile, @@ -47,8 +50,14 @@ define.app({ await waitForFile(dist2); }); -test('should reload config when an imported file changes', async ({ execCliAsync, logHelper }) => { - const configFile = path.join(import.meta.dirname, 'test-temp-import.config.ts'); +test('should reload config when an imported file changes', async ({ + execCliAsync, + logHelper, +}) => { + const configFile = path.join( + import.meta.dirname, + 'test-temp-import.config.ts', + ); const importedFile = path.join(import.meta.dirname, 'test-temp-imported.ts'); await writeFile(importedFile, ''); @@ -69,5 +78,7 @@ define.app({ await writeFile(importedFile, '// changed\n'); - await logHelper.expectLog('restarting server as test-temp-imported.ts changed'); + await logHelper.expectLog( + 'restarting server as test-temp-imported.ts changed', + ); }); diff --git a/packages/rstack/tests/config/reload-doc-config/index.test.ts b/packages/rstack/tests/config/reload-doc-config/index.test.ts index 0b00474b..6aece32f 100644 --- a/packages/rstack/tests/config/reload-doc-config/index.test.ts +++ b/packages/rstack/tests/config/reload-doc-config/index.test.ts @@ -7,8 +7,14 @@ test('should restart doc dev server when Rstack config changes', async ({ execCliAsync, logHelper, }) => { - const configFile = path.join(import.meta.dirname, 'test-temp-rstack.config.ts'); - const userWatchFile = path.join(import.meta.dirname, 'test-temp-user-watch.txt'); + const configFile = path.join( + import.meta.dirname, + 'test-temp-rstack.config.ts', + ); + const userWatchFile = path.join( + import.meta.dirname, + 'test-temp-user-watch.txt', + ); const writeConfig = (title: string) => writeFile( @@ -33,19 +39,25 @@ define.doc({ await writeFile(userWatchFile, 'initial\n'); await writeConfig('before config change'); - execCliAsync(`doc --config test-temp-rstack.config.ts --port ${await getRandomPort()}`); + execCliAsync( + `doc --config test-temp-rstack.config.ts --port ${await getRandomPort()}`, + ); await logHelper.expectBuildEnd(); logHelper.clearLogs(); await writeConfig('after config change'); - await logHelper.expectLog('restarting server as test-temp-rstack.config.ts changed'); + await logHelper.expectLog( + 'restarting server as test-temp-rstack.config.ts changed', + ); await logHelper.expectBuildEnd(); logHelper.clearLogs(); await writeFile(userWatchFile, 'changed\n'); - await logHelper.expectLog('restarting server as test-temp-user-watch.txt changed'); + await logHelper.expectLog( + 'restarting server as test-temp-user-watch.txt changed', + ); await logHelper.expectBuildEnd(); }); @@ -53,10 +65,16 @@ test('should restart doc dev server when an imported config file changes', async execCliAsync, logHelper, }) => { - const configFile = path.join(import.meta.dirname, 'test-temp-import.config.ts'); + const configFile = path.join( + import.meta.dirname, + 'test-temp-import.config.ts', + ); const importedFile = path.join(import.meta.dirname, 'test-temp-imported.ts'); - await writeFile(importedFile, "export const title = 'before import change';\n"); + await writeFile( + importedFile, + "export const title = 'before import change';\n", + ); await writeFile( configFile, `import { define } from 'rstack'; @@ -69,12 +87,19 @@ define.doc({ `, ); - execCliAsync(`doc --config test-temp-import.config.ts --port ${await getRandomPort()}`); + execCliAsync( + `doc --config test-temp-import.config.ts --port ${await getRandomPort()}`, + ); await logHelper.expectBuildEnd(); logHelper.clearLogs(); - await writeFile(importedFile, "export const title = 'after import change';\n"); + await writeFile( + importedFile, + "export const title = 'after import change';\n", + ); - await logHelper.expectLog('restarting server as test-temp-imported.ts changed'); + await logHelper.expectLog( + 'restarting server as test-temp-imported.ts changed', + ); await logHelper.expectBuildEnd(); }); diff --git a/packages/rstack/tests/config/reload-lib-config/index.test.ts b/packages/rstack/tests/config/reload-lib-config/index.test.ts index a793c158..d2f27179 100644 --- a/packages/rstack/tests/config/reload-lib-config/index.test.ts +++ b/packages/rstack/tests/config/reload-lib-config/index.test.ts @@ -10,8 +10,14 @@ test('should restart lib watch build when Rstack config changes', async ({ }) => { const dist1 = await prepareDist(); const dist2 = await prepareDist('dist-2'); - const configFile = path.join(import.meta.dirname, 'test-temp-rstack.config.ts'); - const userWatchFile = path.join(import.meta.dirname, 'test-temp-user-watch.txt'); + const configFile = path.join( + import.meta.dirname, + 'test-temp-rstack.config.ts', + ); + const userWatchFile = path.join( + import.meta.dirname, + 'test-temp-user-watch.txt', + ); const writeConfig = (distPath: string) => writeFile( @@ -42,14 +48,18 @@ define.lib({ await writeConfig('dist-2'); - await logHelper.expectLog('restarting build as test-temp-rstack.config.ts changed'); + await logHelper.expectLog( + 'restarting build as test-temp-rstack.config.ts changed', + ); await logHelper.expectLog('build completed, watching for changes...'); await waitForFile(path.join(dist2, 'index.js')); logHelper.clearLogs(); await writeFile(userWatchFile, 'changed\n'); - await logHelper.expectLog('restarting build as test-temp-user-watch.txt changed'); + await logHelper.expectLog( + 'restarting build as test-temp-user-watch.txt changed', + ); await logHelper.expectLog('build completed, watching for changes...'); }); @@ -60,7 +70,10 @@ test('should restart lib watch build when an imported config file changes', asyn }) => { const dist1 = await prepareDist('dist-import-1'); const dist2 = await prepareDist('dist-import-2'); - const configFile = path.join(import.meta.dirname, 'test-temp-import.config.ts'); + const configFile = path.join( + import.meta.dirname, + 'test-temp-import.config.ts', + ); const importedFile = path.join(import.meta.dirname, 'test-temp-imported.ts'); await writeFile(importedFile, "export const distPath = 'dist-import-1';\n"); @@ -84,7 +97,9 @@ define.lib({ await writeFile(importedFile, "export const distPath = 'dist-import-2';\n"); - await logHelper.expectLog('restarting build as test-temp-imported.ts changed'); + await logHelper.expectLog( + 'restarting build as test-temp-imported.ts changed', + ); await logHelper.expectLog('build completed, watching for changes...'); await waitForFile(path.join(dist2, 'index.js')); }); diff --git a/packages/rstack/tests/exports/test-subpath/index.test.ts b/packages/rstack/tests/exports/test-subpath/index.test.ts index 74d693a7..d1da8169 100644 --- a/packages/rstack/tests/exports/test-subpath/index.test.ts +++ b/packages/rstack/tests/exports/test-subpath/index.test.ts @@ -1,6 +1,13 @@ import { expect, test } from 'rstack/test'; -const commonTestMethods = ['test', 'it', 'describe', 'expect', 'beforeAll', 'afterAll'] as const; +const commonTestMethods = [ + 'test', + 'it', + 'describe', + 'expect', + 'beforeAll', + 'afterAll', +] as const; test('should expose test APIs from `rstack/test`', async () => { const test = await import('rstack/test'); diff --git a/packages/rstack/tests/fmt/cacheIdentity.test.ts b/packages/rstack/tests/fmt/cacheIdentity.test.ts index 933b7229..56958b64 100644 --- a/packages/rstack/tests/fmt/cacheIdentity.test.ts +++ b/packages/rstack/tests/fmt/cacheIdentity.test.ts @@ -54,7 +54,9 @@ test('includes plugin fingerprints in option hashes', () => { const second = createOptionsHasher(new Map([[plugin, 'plugin@2']])); expect(first({ plugins: [plugin] })).toHaveLength(cacheHashLength); - expect(first({ plugins: [new URL(plugin)] })).toBe(first({ plugins: [plugin] })); + expect(first({ plugins: [new URL(plugin)] })).toBe( + first({ plugins: [plugin] }), + ); expect(first({ plugins: [plugin] })).not.toBe(second({ plugins: [plugin] })); }); @@ -71,8 +73,12 @@ test('bypasses user plugins and unserializable options', () => { ); cyclic.self = cyclic; - expect(hashOptions({ plugins: [path.resolve('plugin.mjs')] })).toBeUndefined(); - expect(hashOptions({ plugins: [pathToFileURL(path.resolve('plugin.mjs'))] })).toBeUndefined(); + expect( + hashOptions({ plugins: [path.resolve('plugin.mjs')] }), + ).toBeUndefined(); + expect( + hashOptions({ plugins: [pathToFileURL(path.resolve('plugin.mjs'))] }), + ).toBeUndefined(); expect(hashOptions(asOptions({ custom: cyclic }))).toBeUndefined(); expect(hashOptions(asOptions(unreadable))).toBeUndefined(); @@ -94,5 +100,7 @@ test('creates config-root-relative POSIX cache keys', () => { expect(resolveKey(firstPath)).toBe('src/nested/index.ts'); expect(resolveKey(secondPath)).toBe('src/other.ts'); expect(resolveKey(firstPath)).not.toBe(resolveKey(secondPath)); - expect(resolveKey(path.join(rootPath, '../shared/index.ts'))).toBe('../shared/index.ts'); + expect(resolveKey(path.join(rootPath, '../shared/index.ts'))).toBe( + '../shared/index.ts', + ); }); diff --git a/packages/rstack/tests/fmt/cacheStore.test.ts b/packages/rstack/tests/fmt/cacheStore.test.ts index e6f038b7..5c466cd7 100644 --- a/packages/rstack/tests/fmt/cacheStore.test.ts +++ b/packages/rstack/tests/fmt/cacheStore.test.ts @@ -1,4 +1,10 @@ -import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from 'node:fs'; +import { + existsSync, + mkdirSync, + readFileSync, + readdirSync, + writeFileSync, +} from 'node:fs'; import path from 'node:path'; import { expect, test } from 'rstack/test'; import { @@ -144,6 +150,8 @@ test('does not throw or leave temporary files when persistence fails', async () store.set('src/a.ts', firstEntry); await expect(store.save()).resolves.toBe(false); - expect(readdirSync(rootPath).filter((name) => name.endsWith('.tmp'))).toEqual([]); + expect( + readdirSync(rootPath).filter((name) => name.endsWith('.tmp')), + ).toEqual([]); }); }); diff --git a/packages/rstack/tests/fmt/config.test.ts b/packages/rstack/tests/fmt/config.test.ts index fe85d292..eb5a9b28 100644 --- a/packages/rstack/tests/fmt/config.test.ts +++ b/packages/rstack/tests/fmt/config.test.ts @@ -1,6 +1,9 @@ import path from 'node:path'; import { expect, test } from 'rstack/test'; -import { createOptionsResolver, normalizeFmtConfig } from '../../src/fmt/config.ts'; +import { + createOptionsResolver, + normalizeFmtConfig, +} from '../../src/fmt/config.ts'; const rootPath = path.join(import.meta.dirname, 'project'); @@ -14,7 +17,9 @@ test('reuses base options when no override matches', () => { ); const resolveOptions = createOptionsResolver(config); - expect(resolveOptions(path.join(rootPath, 'index.js'))).toBe(config.baseOptions); + expect(resolveOptions(path.join(rootPath, 'index.js'))).toBe( + config.baseOptions, + ); }); test('applies basename and path overrides in declaration order', () => { @@ -82,5 +87,7 @@ test('applies overrides outside the config root', () => { ); const resolveOptions = createOptionsResolver(config); - expect(resolveOptions(path.join(rootPath, '../shared/index.ts'))).toEqual({ semi: false }); + expect(resolveOptions(path.join(rootPath, '../shared/index.ts'))).toEqual({ + semi: false, + }); }); diff --git a/packages/rstack/tests/fmt/discoverPaths.test.ts b/packages/rstack/tests/fmt/discoverPaths.test.ts index 0fa2e6ca..6cad49f9 100644 --- a/packages/rstack/tests/fmt/discoverPaths.test.ts +++ b/packages/rstack/tests/fmt/discoverPaths.test.ts @@ -20,7 +20,10 @@ test('discovers non-binary files in stable order and skips hard-ignored paths', writeProjectFile(rootPath, '.jj/internal.js'); const files = await discoverFmtPaths({ cwd: rootPath }); - const filesWithNodeModules = await discoverFmtPaths({ cwd: rootPath, withNodeModules: true }); + const filesWithNodeModules = await discoverFmtPaths({ + cwd: rootPath, + withNodeModules: true, + }); expect(relativePaths(rootPath, files)).toEqual([ 'a.js', @@ -36,7 +39,10 @@ test('discovers non-binary files in stable order and skips hard-ignored paths', 'unknown.extension', ]); await expect( - discoverFmtPaths({ cwd: rootPath, patterns: ['node_modules/package/index.js'] }), + discoverFmtPaths({ + cwd: rootPath, + patterns: ['node_modules/package/index.js'], + }), ).resolves.toEqual([]); await expect( discoverFmtPaths({ @@ -54,7 +60,10 @@ test('keeps node_modules excluded by gitignore when built-in exclusion is disabl writeProjectFile(rootPath, 'node_modules/package/index.js'); writeProjectFile(rootPath, 'index.js'); - const files = await discoverFmtPaths({ cwd: rootPath, withNodeModules: true }); + const files = await discoverFmtPaths({ + cwd: rootPath, + withNodeModules: true, + }); expect(relativePaths(rootPath, files)).toEqual(['.gitignore', 'index.js']); }); @@ -93,7 +102,9 @@ test('combines files, directories, and globs without duplicates', async () => { path.join('src', 'a.ts'), path.join('test', 'c.ts'), ]); - expect(relativePaths(rootPath, dotFiles)).toEqual([path.join('dot', '.hidden.ts')]); + expect(relativePaths(rootPath, dotFiles)).toEqual([ + path.join('dot', '.hidden.ts'), + ]); await expect( discoverFmtPaths({ cwd: rootPath, patterns: ['missing/**/*.ts'] }), ).resolves.toEqual([]); @@ -112,13 +123,19 @@ test('applies nested gitignore rules with child negation', async () => { writeProjectFile(rootPath, 'dist/nested/keep.js'); writeProjectFile(rootPath, 'visible.ts'); - const files = await discoverFmtPaths({ cwd: rootPath, patterns: ['**/*.{js,ts}'] }); + const files = await discoverFmtPaths({ + cwd: rootPath, + patterns: ['**/*.{js,ts}'], + }); const ignoredNestedDirectory = await discoverFmtPaths({ cwd: rootPath, patterns: ['dist/nested'], }); - expect(relativePaths(rootPath, files)).toEqual([path.join('src', 'keep.js'), 'visible.ts']); + expect(relativePaths(rootPath, files)).toEqual([ + path.join('src', 'keep.js'), + 'visible.ts', + ]); expect(ignoredNestedDirectory).toEqual([]); }); }); @@ -129,7 +146,10 @@ test('does not extend a nested directory negation to its files', async () => { writeProjectFile(rootPath, 'scripts/.gitignore', '!debug\n'); writeProjectFile(rootPath, 'scripts/debug/launch.mjs'); - const files = await discoverFmtPaths({ cwd: rootPath, patterns: ['**/*.mjs'] }); + const files = await discoverFmtPaths({ + cwd: rootPath, + patterns: ['**/*.mjs'], + }); expect(files).toEqual([]); }); @@ -195,9 +215,15 @@ test('keeps valid nested gitignore rules around normalized and malformed lines', writeProjectFile(rootPath, 'src/drop.js'); writeProjectFile(rootPath, 'visible.ts'); - const files = await discoverFmtPaths({ cwd: rootPath, patterns: ['**/*.{js,ts}'] }); + const files = await discoverFmtPaths({ + cwd: rootPath, + patterns: ['**/*.{js,ts}'], + }); - expect(relativePaths(rootPath, files)).toEqual([path.join('src', 'keep.js'), 'visible.ts']); + expect(relativePaths(rootPath, files)).toEqual([ + path.join('src', 'keep.js'), + 'visible.ts', + ]); }); }); @@ -213,7 +239,9 @@ test('propagates native binding errors while loading a nested gitignore', async }); try { - await expect(discoverFmtPaths({ cwd: rootPath })).rejects.toBe(nativeError); + await expect(discoverFmtPaths({ cwd: rootPath })).rejects.toBe( + nativeError, + ); } finally { loadNativeBinding.mockRestore(); } @@ -230,10 +258,17 @@ test('lets explicit files bypass gitignore', async () => { cwd: rootPath, patterns: ['**/*.ts'], }); - const explicitFiles = await discoverFmtPaths({ cwd: rootPath, patterns: [keepPath] }); + const explicitFiles = await discoverFmtPaths({ + cwd: rootPath, + patterns: [keepPath], + }); - expect(relativePaths(rootPath, discoveredFiles)).toEqual([path.join('src', 'index.ts')]); - expect(relativePaths(rootPath, explicitFiles)).toEqual([path.join('generated', 'keep.ts')]); + expect(relativePaths(rootPath, discoveredFiles)).toEqual([ + path.join('src', 'index.ts'), + ]); + expect(relativePaths(rootPath, explicitFiles)).toEqual([ + path.join('generated', 'keep.ts'), + ]); }); }); @@ -249,7 +284,9 @@ test('applies an external ignore matcher to traversed and explicit paths', async path: path.relative(rootPath, filePath), isDirectory, }); - return isDirectory ? filePath === generatedPath : filePath === ignoredFilePath; + return isDirectory + ? filePath === generatedPath + : filePath === ignoredFilePath; }; const files = await discoverFmtPaths({ cwd: rootPath, isIgnored }); @@ -264,10 +301,15 @@ test('applies an external ignore matcher to traversed and explicit paths', async isIgnored, }); - expect(relativePaths(rootPath, files)).toEqual([path.join('src', 'index.ts')]); + expect(relativePaths(rootPath, files)).toEqual([ + path.join('src', 'index.ts'), + ]); expect(ignoredRoot).toEqual([]); expect(explicitIgnoredFile).toEqual([]); - expect(checkedPaths).toContainEqual({ path: 'generated', isDirectory: true }); + expect(checkedPaths).toContainEqual({ + path: 'generated', + isDirectory: true, + }); expect(checkedPaths).toContainEqual({ path: path.join('src', 'ignored.ts'), isDirectory: false, @@ -279,19 +321,27 @@ test('applies an external ignore matcher to traversed and explicit paths', async }); }); -test.runIf(process.platform !== 'win32')('does not follow file or directory symlinks', async () => { - await withTempProject(async (rootPath) => { - const targetPath = writeProjectFile(rootPath, 'target/index.ts'); - symlinkSync(path.join(rootPath, 'target'), path.join(rootPath, 'linked-directory')); - symlinkSync(targetPath, path.join(rootPath, 'linked-file.ts')); +test.runIf(process.platform !== 'win32')( + 'does not follow file or directory symlinks', + async () => { + await withTempProject(async (rootPath) => { + const targetPath = writeProjectFile(rootPath, 'target/index.ts'); + symlinkSync( + path.join(rootPath, 'target'), + path.join(rootPath, 'linked-directory'), + ); + symlinkSync(targetPath, path.join(rootPath, 'linked-file.ts')); + + const discoveredFiles = await discoverFmtPaths({ cwd: rootPath }); + const explicitFiles = await discoverFmtPaths({ + cwd: rootPath, + patterns: ['linked-directory', 'linked-file.ts'], + }); - const discoveredFiles = await discoverFmtPaths({ cwd: rootPath }); - const explicitFiles = await discoverFmtPaths({ - cwd: rootPath, - patterns: ['linked-directory', 'linked-file.ts'], + expect(relativePaths(rootPath, discoveredFiles)).toEqual([ + path.join('target', 'index.ts'), + ]); + expect(explicitFiles).toEqual([]); }); - - expect(relativePaths(rootPath, discoveredFiles)).toEqual([path.join('target', 'index.ts')]); - expect(explicitFiles).toEqual([]); - }); -}); + }, +); diff --git a/packages/rstack/tests/fmt/discovery.test.ts b/packages/rstack/tests/fmt/discovery.test.ts index 4dfd1937..0e062435 100644 --- a/packages/rstack/tests/fmt/discovery.test.ts +++ b/packages/rstack/tests/fmt/discovery.test.ts @@ -6,15 +6,22 @@ import { discoverFmtFiles } from '../../src/fmt/discovery.ts'; import type { FmtConfig } from '../../src/fmt/types.ts'; import { withTempProject, writeProjectFile } from './helpers.ts'; -const discover = async (cwd: string, patterns?: string[], config?: FmtConfig, configRoot = cwd) => +const discover = async ( + cwd: string, + patterns?: string[], + config?: FmtConfig, + configRoot = cwd, +) => discoverFmtFiles({ cwd, patterns, config: normalizeFmtConfig(config, configRoot), }); -const relativePaths = (rootPath: string, files: Awaited>): string[] => - files.map((file) => path.relative(rootPath, file.path)); +const relativePaths = ( + rootPath: string, + files: Awaited>, +): string[] => files.map((file) => path.relative(rootPath, file.path)); test('applies config ignore patterns to discovered and explicit files', async () => { await withTempProject(async (rootPath) => { @@ -24,13 +31,19 @@ test('applies config ignore patterns to discovered and explicit files', async () const config = { ignorePatterns: ['generated/blocked.ts'] }; const discoveredFiles = await discover(rootPath, undefined, config); - const explicitFiles = await discover(rootPath, [keepPath, blockedPath], config); + const explicitFiles = await discover( + rootPath, + [keepPath, blockedPath], + config, + ); expect(relativePaths(rootPath, discoveredFiles)).toEqual([ path.join('generated', 'keep.ts'), path.join('src', 'index.ts'), ]); - expect(relativePaths(rootPath, explicitFiles)).toEqual([path.join('generated', 'keep.ts')]); + expect(relativePaths(rootPath, explicitFiles)).toEqual([ + path.join('generated', 'keep.ts'), + ]); }); }); @@ -41,14 +54,23 @@ test('applies config ignore patterns outside the config root', async () => { mkdirSync(configRoot); await expect( - discover(configRoot, [filePath], { ignorePatterns: ['../shared/*.ts'] }, configRoot), + discover( + configRoot, + [filePath], + { ignorePatterns: ['../shared/*.ts'] }, + configRoot, + ), ).resolves.toEqual([]); }); }); test('excludes .rstack from discovery', async () => { await withTempProject(async (rootPath) => { - const cacheFile = writeProjectFile(rootPath, '.rstack/cache/fmt-v1.json', '{}'); + const cacheFile = writeProjectFile( + rootPath, + '.rstack/cache/fmt-v1.json', + '{}', + ); writeProjectFile(rootPath, 'index.ts'); const discoveredFiles = await discover(rootPath); @@ -85,7 +107,11 @@ test('excludes a custom cache directory', async () => { test('keeps files re-included by a CLI ignore file during directory traversal', async () => { await withTempProject(async (rootPath) => { - writeProjectFile(rootPath, '.prettierignore', 'generated/*\n!generated/keep.ts\n'); + writeProjectFile( + rootPath, + '.prettierignore', + 'generated/*\n!generated/keep.ts\n', + ); writeProjectFile(rootPath, 'generated/drop.ts'); writeProjectFile(rootPath, 'generated/keep.ts'); writeProjectFile(rootPath, 'src/index.ts'); @@ -112,7 +138,9 @@ test('defers parser inference to workers and preserves an explicit parser', asyn writeProjectFile(rootPath, 'unknown.extension'); const inferredFiles = await discover(rootPath); - const configuredFiles = await discover(rootPath, ['source.custom'], { parser: 'babel' }); + const configuredFiles = await discover(rootPath, ['source.custom'], { + parser: 'babel', + }); expect(relativePaths(rootPath, inferredFiles)).toEqual([ 'index.js', @@ -120,7 +148,9 @@ test('defers parser inference to workers and preserves an explicit parser', asyn 'source.custom', 'unknown.extension', ]); - expect(inferredFiles.every((file) => file.options.parser === undefined)).toBe(true); + expect( + inferredFiles.every((file) => file.options.parser === undefined), + ).toBe(true); expect(configuredFiles[0]).toEqual({ path: path.join(rootPath, 'source.custom'), options: { parser: 'babel' }, diff --git a/packages/rstack/tests/fmt/fileResolver.test.ts b/packages/rstack/tests/fmt/fileResolver.test.ts index 98e1e486..e0089095 100644 --- a/packages/rstack/tests/fmt/fileResolver.test.ts +++ b/packages/rstack/tests/fmt/fileResolver.test.ts @@ -21,7 +21,10 @@ test('applies matching overrides before resolving plugins', async () => { writeProjectFile( rootPath, 'node_modules/prettier-plugin-fixture/package.json', - JSON.stringify({ name: 'prettier-plugin-fixture', exports: './index.mjs' }), + JSON.stringify({ + name: 'prettier-plugin-fixture', + exports: './index.mjs', + }), ); const config = normalizeFmtConfig( { diff --git a/packages/rstack/tests/fmt/helpers.ts b/packages/rstack/tests/fmt/helpers.ts index 698708cb..1468b32d 100644 --- a/packages/rstack/tests/fmt/helpers.ts +++ b/packages/rstack/tests/fmt/helpers.ts @@ -1,7 +1,11 @@ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'; import path from 'node:path'; import { fmtCacheFileName } from '../../src/fmt/cacheStore.ts'; -import type { FmtCacheContext, FmtFileRequest, ResolvedFmtOptions } from '../../src/fmt/types.ts'; +import type { + FmtCacheContext, + FmtFileRequest, + ResolvedFmtOptions, +} from '../../src/fmt/types.ts'; export const createFmtRequest = ( filePath: string, @@ -19,7 +23,9 @@ export const createFmtCacheContext = (rootPath: string): FmtCacheContext => ({ export const withTempProject = async ( callback: (rootPath: string) => void | Promise, ): Promise => { - const rootPath = mkdtempSync(path.join(import.meta.dirname, 'test-temp-fmt-')); + const rootPath = mkdtempSync( + path.join(import.meta.dirname, 'test-temp-fmt-'), + ); // Prevent repository-level ignore rules from affecting the fixture. mkdirSync(path.join(rootPath, '.git')); @@ -30,7 +36,11 @@ export const withTempProject = async ( } }; -export const writeProjectFile = (rootPath: string, filePath: string, content = ''): string => { +export const writeProjectFile = ( + rootPath: string, + filePath: string, + content = '', +): string => { const absolutePath = path.join(rootPath, filePath); mkdirSync(path.dirname(absolutePath), { recursive: true }); writeFileSync(absolutePath, content); diff --git a/packages/rstack/tests/fmt/ignore.test.ts b/packages/rstack/tests/fmt/ignore.test.ts index 68220775..b8aa2126 100644 --- a/packages/rstack/tests/fmt/ignore.test.ts +++ b/packages/rstack/tests/fmt/ignore.test.ts @@ -55,7 +55,11 @@ test('does not apply negated directory patterns to files', async () => { test('applies negated patterns in declaration order', async () => { const isIgnored = await createMatcher(['*.js', '!src/keep.js']); - const isIgnoredAgain = await createMatcher(['*.js', '!src/keep.js', 'src/keep.js']); + const isIgnoredAgain = await createMatcher([ + '*.js', + '!src/keep.js', + 'src/keep.js', + ]); const isIgnoredAfterReinclude = await createMatcher(['dist', '!dist']); const filePath = path.join(rootPath, 'src/keep.js'); @@ -70,11 +74,17 @@ test('ignores common lock files by default and allows explicit negation', async const isIgnoredAfterReinclude = await createMatcher(['!pnpm-lock.yaml']); expect(isIgnored(path.join(rootPath, 'package-lock.json'))).toBe(true); - expect(isIgnored(path.join(rootPath, 'packages/app/pnpm-lock.yaml'))).toBe(true); - expect(isIgnored(path.join(rootPath, 'packages/app/PNPM-LOCK.YAML'))).toBe(false); + expect(isIgnored(path.join(rootPath, 'packages/app/pnpm-lock.yaml'))).toBe( + true, + ); + expect(isIgnored(path.join(rootPath, 'packages/app/PNPM-LOCK.YAML'))).toBe( + false, + ); expect(isIgnored(path.join(rootPath, '../shared/pnpm-lock.yaml'))).toBe(true); expect(isIgnored(path.join(rootPath, 'pnpm-lock.yaml.backup'))).toBe(false); - expect(isIgnoredAfterReinclude(path.join(rootPath, 'pnpm-lock.yaml'))).toBe(false); + expect(isIgnoredAfterReinclude(path.join(rootPath, 'pnpm-lock.yaml'))).toBe( + false, + ); }); test('does not let explicit files bypass ignore patterns', async () => { @@ -99,11 +109,18 @@ test('does not ignore other files when no patterns are configured', async () => test('loads repeated ignore paths relative to cwd and each ignore file', async () => { await withTempProject(async (projectPath) => { - writeProjectFile(projectPath, '.prettierignore', 'src/*.js\n!src/keep.js\n'); + writeProjectFile( + projectPath, + '.prettierignore', + 'src/*.js\n!src/keep.js\n', + ); writeProjectFile(projectPath, 'config/extra.ignore', '../generated/*.js\n'); const isIgnored = await createIgnoreMatcher({ - config: normalizeFmtConfig({ ignorePatterns: ['configured.js'] }, projectPath), + config: normalizeFmtConfig( + { ignorePatterns: ['configured.js'] }, + projectPath, + ), cwd: projectPath, ignorePaths: ['.prettierignore', 'config/extra.ignore'], }); diff --git a/packages/rstack/tests/fmt/lsp/minimalEdit.test.ts b/packages/rstack/tests/fmt/lsp/minimalEdit.test.ts index cf94e86f..7fc1882c 100644 --- a/packages/rstack/tests/fmt/lsp/minimalEdit.test.ts +++ b/packages/rstack/tests/fmt/lsp/minimalEdit.test.ts @@ -1,6 +1,9 @@ import { expect, test } from 'rstack/test'; import { TextDocument } from 'vscode-languageserver-textdocument'; -import { computeMinimalEdit, computeMinimalTextEdit } from '../../../src/fmt/lsp/minimalEdit.ts'; +import { + computeMinimalEdit, + computeMinimalTextEdit, +} from '../../../src/fmt/lsp/minimalEdit.ts'; /** Applies an edit the way an editor does, to prove it rewrites the document. */ const applyMinimalEdit = (source: string, formatted: string): string => { @@ -17,7 +20,10 @@ const applyMinimalEdit = (source: string, formatted: string): string => { * does: offsets become positions on the server and positions become offsets * again on the client, which moves any offset that lands inside a `\r\n`. */ -const applyMinimalEditThroughPositions = (source: string, formatted: string): string => { +const applyMinimalEditThroughPositions = ( + source: string, + formatted: string, +): string => { const edit = computeMinimalEdit(source, formatted); if (!edit) { return source; @@ -35,7 +41,9 @@ const applyMinimalEditThroughPositions = (source: string, formatted: string): st test('returns no edit for identical sources', () => { expect(computeMinimalEdit('', '')).toBeUndefined(); - expect(computeMinimalEdit('const x = 1;\n', 'const x = 1;\n')).toBeUndefined(); + expect( + computeMinimalEdit('const x = 1;\n', 'const x = 1;\n'), + ).toBeUndefined(); }); test('replaces the whole document when nothing is shared', () => { @@ -44,7 +52,11 @@ test('replaces the whole document when nothing is shared', () => { end: 0, newText: 'const x = 1;\n', }); - expect(computeMinimalEdit('a\n', '')).toEqual({ start: 0, end: 2, newText: '' }); + expect(computeMinimalEdit('a\n', '')).toEqual({ + start: 0, + end: 2, + newText: '', + }); }); test('trims a shared prefix', () => { @@ -134,8 +146,12 @@ test('survives a round trip through a real text document', () => { const formatted = 'const a = 1;\r\nconst b = 2;\r\n'; expect(applyMinimalEditThroughPositions(source, formatted)).toBe(formatted); - expect(applyMinimalEditThroughPositions('a\nb\n', 'a\r\nb\r\n')).toBe('a\r\nb\r\n'); - expect(applyMinimalEditThroughPositions('a\r\nb\r\n', 'a\nb\n')).toBe('a\nb\n'); + expect(applyMinimalEditThroughPositions('a\nb\n', 'a\r\nb\r\n')).toBe( + 'a\r\nb\r\n', + ); + expect(applyMinimalEditThroughPositions('a\r\nb\r\n', 'a\nb\n')).toBe( + 'a\nb\n', + ); }); // Line terminators are where offsets stop being interchangeable with positions, @@ -146,13 +162,20 @@ test('addresses every combination of line terminators', () => { const texts: string[] = ['']; let current = ['']; for (let length = 0; length < 5; length++) { - current = current.flatMap((text) => alphabet.map((character) => text + character)); + current = current.flatMap((text) => + alphabet.map((character) => text + character), + ); texts.push(...current); } const failures: string[] = []; for (const source of texts) { - const document = TextDocument.create('file:///a.ts', 'typescript', 1, source); + const document = TextDocument.create( + 'file:///a.ts', + 'typescript', + 1, + source, + ); for (const formatted of texts) { const edit = computeMinimalEdit(source, formatted); if (!edit) { @@ -163,7 +186,9 @@ test('addresses every combination of line terminators', () => { const end = document.offsetAt(document.positionAt(edit.end)); const applied = source.slice(0, start) + edit.newText + source.slice(end); if (applied !== formatted) { - failures.push(`${JSON.stringify(source)} -> ${JSON.stringify(formatted)}`); + failures.push( + `${JSON.stringify(source)} -> ${JSON.stringify(formatted)}`, + ); } // The hand-rolled position mapping must agree with the reference @@ -174,7 +199,9 @@ test('addresses every combination of line terminators', () => { end: document.positionAt(edit.end), }; if (JSON.stringify(range) !== JSON.stringify(expected)) { - failures.push(`positions ${JSON.stringify(source)} -> ${JSON.stringify(formatted)}`); + failures.push( + `positions ${JSON.stringify(source)} -> ${JSON.stringify(formatted)}`, + ); } } } diff --git a/packages/rstack/tests/fmt/lsp/server.test.ts b/packages/rstack/tests/fmt/lsp/server.test.ts index 597ca968..ca764b21 100644 --- a/packages/rstack/tests/fmt/lsp/server.test.ts +++ b/packages/rstack/tests/fmt/lsp/server.test.ts @@ -9,7 +9,10 @@ test('maps the edit onto the formatted document', async () => { expect(edits).toEqual([ { - range: { start: { line: 1, character: 7 }, end: { line: 1, character: 8 } }, + range: { + start: { line: 1, character: 7 }, + end: { line: 1, character: 8 }, + }, newText: ' = ', }, ]); @@ -18,8 +21,12 @@ test('maps the edit onto the formatted document', async () => { test('returns no edits for an already formatted document', async () => { const getText = () => 'const a = 1;\n'; - expect(await createDocumentEdits(getText, () => Promise.resolve('const a = 1;\n'))).toEqual([]); - expect(await createDocumentEdits(getText, () => Promise.resolve(undefined))).toEqual([]); + expect( + await createDocumentEdits(getText, () => Promise.resolve('const a = 1;\n')), + ).toEqual([]); + expect( + await createDocumentEdits(getText, () => Promise.resolve(undefined)), + ).toEqual([]); }); test('returns no edits for a document that is not open', async () => { diff --git a/packages/rstack/tests/fmt/plugins.test.ts b/packages/rstack/tests/fmt/plugins.test.ts index 842c6db4..5f25262e 100644 --- a/packages/rstack/tests/fmt/plugins.test.ts +++ b/packages/rstack/tests/fmt/plugins.test.ts @@ -1,6 +1,9 @@ import { pathToFileURL } from 'node:url'; import { expect, test } from 'rstack/test'; -import { createFingerprintResolver, createPluginResolver } from '../../src/fmt/plugins.ts'; +import { + createFingerprintResolver, + createPluginResolver, +} from '../../src/fmt/plugins.ts'; import { withTempProject, writeProjectFile } from './helpers.ts'; test('resolves plugin specifiers from the config root', async () => { @@ -65,7 +68,10 @@ test('rejects imported plugin objects', () => { test('fingerprints installed package plugins once', async () => { await withTempProject(async (rootPath) => { - const entry = writeProjectFile(rootPath, 'node_modules/prettier-plugin-fixture/dist/index.mjs'); + const entry = writeProjectFile( + rootPath, + 'node_modules/prettier-plugin-fixture/dist/index.mjs', + ); const packageJsonPath = 'node_modules/prettier-plugin-fixture/package.json'; writeProjectFile( rootPath, diff --git a/packages/rstack/tests/fmt/runner.test.ts b/packages/rstack/tests/fmt/runner.test.ts index dbcd59e6..101151af 100644 --- a/packages/rstack/tests/fmt/runner.test.ts +++ b/packages/rstack/tests/fmt/runner.test.ts @@ -1,4 +1,10 @@ -import { chmodSync, readFileSync, statSync, utimesSync, writeFileSync } from 'node:fs'; +import { + chmodSync, + readFileSync, + statSync, + utimesSync, + writeFileSync, +} from 'node:fs'; import path from 'node:path'; import { expect, test } from 'rstack/test'; import { runFmtFiles } from '../../src/fmt/runner.ts'; @@ -46,17 +52,20 @@ test('writes changed files', async () => { }); }); -test.runIf(process.platform !== 'win32')('preserves file mode when writing', async () => { - await withTempProject(async (rootPath) => { - const filePath = path.join(rootPath, 'executable.ts'); - writeFileSync(filePath, 'const value=1'); - chmodSync(filePath, 0o744); +test.runIf(process.platform !== 'win32')( + 'preserves file mode when writing', + async () => { + await withTempProject(async (rootPath) => { + const filePath = path.join(rootPath, 'executable.ts'); + writeFileSync(filePath, 'const value=1'); + chmodSync(filePath, 0o744); - await run([createFmtRequest(filePath)]); + await run([createFmtRequest(filePath)]); - expect(statSync(filePath).mode & 0o777).toBe(0o744); - }); -}); + expect(statSync(filePath).mode & 0o777).toBe(0o744); + }); + }, +); for (const mode of ['check', 'list-different'] as const) { test(`${mode} reports differences without writing`, async () => { @@ -84,7 +93,10 @@ test('continues after a file fails and gives errors exit-code precedence', async writeFileSync(invalidPath, 'const value = ;'); writeFileSync(validPath, 'const value=1'); - const result = await run([createFmtRequest(invalidPath), createFmtRequest(validPath)], 'check'); + const result = await run( + [createFmtRequest(invalidPath), createFmtRequest(validPath)], + 'check', + ); expect(result).toMatchObject({ exitCode: 2, @@ -110,7 +122,11 @@ test('omits unsupported files from the result', async () => { }, ]); - expect(result).toMatchObject({ exitCode: 2, files: [], processedFileCount: 0 }); + expect(result).toMatchObject({ + exitCode: 2, + files: [], + processedFileCount: 0, + }); expect(readFileSync(filePath, 'utf8')).toBe('plain text'); }); }); diff --git a/packages/rstack/tests/fmt/runnerCache.test.ts b/packages/rstack/tests/fmt/runnerCache.test.ts index e78a2ab0..8426d5e1 100644 --- a/packages/rstack/tests/fmt/runnerCache.test.ts +++ b/packages/rstack/tests/fmt/runnerCache.test.ts @@ -10,7 +10,11 @@ import { } from '../../src/fmt/cacheIdentity.ts'; import { loadFmtCacheStore } from '../../src/fmt/cacheStore.ts'; import { runFmtFiles } from '../../src/fmt/runner.ts'; -import type { FmtCacheContext, FmtFileRequest, FmtMode } from '../../src/fmt/types.ts'; +import type { + FmtCacheContext, + FmtFileRequest, + FmtMode, +} from '../../src/fmt/types.ts'; import { createFmtCacheContext, createFmtRequest, @@ -77,7 +81,9 @@ test('uses content hashes instead of file metadata', async () => { size: Buffer.byteLength(clean), }); - await expect(run([createFmtRequest(filePath)], 'check', cache)).resolves.toMatchObject({ + await expect( + run([createFmtRequest(filePath)], 'check', cache), + ).resolves.toMatchObject({ exitCode: 1, files: [{ path: filePath, status: 'different' }], }); @@ -99,10 +105,16 @@ test('invalidates entries when final options change', async () => { const cache = createFmtCacheContext(rootPath); writeFileSync(filePath, 'const value = "text";\n'); - const initial = createFmtRequest(filePath, { parser: 'typescript', singleQuote: false }); + const initial = createFmtRequest(filePath, { + parser: 'typescript', + singleQuote: false, + }); await run([initial], 'check', cache); - const changed = createFmtRequest(filePath, { parser: 'typescript', singleQuote: true }); + const changed = createFmtRequest(filePath, { + parser: 'typescript', + singleQuote: true, + }); await expect(run([changed], 'check', cache)).resolves.toMatchObject({ exitCode: 1, files: [{ path: filePath, status: 'different' }], @@ -119,7 +131,11 @@ test('invalidates entries when final options change', async () => { test('caches unsupported parser results until final options change', async () => { await withTempProject(async (rootPath) => { - const filePath = writeProjectFile(rootPath, 'data.unknown', '{"value":true}'); + const filePath = writeProjectFile( + rootPath, + 'data.unknown', + '{"value":true}', + ); const cache = createFmtCacheContext(rootPath); const unsupported = createFmtRequest(filePath, {}); @@ -129,11 +145,11 @@ test('caches unsupported parser results until final options change', async () => files: [], processedFileCount: 0, }); - expect((await loadFmtCacheStore(cache.filePath, cacheNamespace)).get('data.unknown')).toEqual([ - '', - createOptionsHasher()(unsupported.options), - 'unsupported', - ]); + expect( + (await loadFmtCacheStore(cache.filePath, cacheNamespace)).get( + 'data.unknown', + ), + ).toEqual(['', createOptionsHasher()(unsupported.options), 'unsupported']); await expect(run([unsupported], 'check', cache)).resolves.toEqual(first); @@ -143,7 +159,11 @@ test('caches unsupported parser results until final options change', async () => files: [{ path: filePath, status: 'different' }], processedFileCount: 1, }); - expect((await loadFmtCacheStore(cache.filePath, cacheNamespace)).get('data.unknown')).toEqual([ + expect( + (await loadFmtCacheStore(cache.filePath, cacheNamespace)).get( + 'data.unknown', + ), + ).toEqual([ createCacheHash(readFileSync(filePath)), createOptionsHasher()(supported.options), 'dirty', @@ -163,7 +183,9 @@ test('invalidates cached unsupported parser results when content changes without files: [], processedFileCount: 0, }); - expect((await loadFmtCacheStore(cache.filePath, cacheNamespace)).get('script')).toEqual([ + expect( + (await loadFmtCacheStore(cache.filePath, cacheNamespace)).get('script'), + ).toEqual([ createCacheHash(readFileSync(filePath)), createOptionsHasher()(file.options), 'unsupported', @@ -177,7 +199,9 @@ test('invalidates cached unsupported parser results when content changes without files: [{ path: filePath, status: 'different' }], processedFileCount: 1, }); - expect((await loadFmtCacheStore(cache.filePath, cacheNamespace)).get('script')).toEqual([ + expect( + (await loadFmtCacheStore(cache.filePath, cacheNamespace)).get('script'), + ).toEqual([ createCacheHash(readFileSync(filePath)), createOptionsHasher()(file.options), 'dirty', @@ -187,7 +211,11 @@ test('invalidates cached unsupported parser results when content changes without test('caches only plugins with stable fingerprints', async () => { await withTempProject(async (rootPath) => { - const filePath = writeProjectFile(rootPath, 'data.fixture', '{"value":true}'); + const filePath = writeProjectFile( + rootPath, + 'data.fixture', + '{"value":true}', + ); const pluginEntry = writeProjectFile( rootPath, 'node_modules/prettier-plugin-fixture/index.mjs', @@ -208,26 +236,30 @@ test('caches only plugins with stable fingerprints', async () => { }), ); const cache = createFmtCacheContext(rootPath); - const file = createFmtRequest(filePath, { plugins: [pathToFileURL(pluginEntry).href] }); + const file = createFmtRequest(filePath, { + plugins: [pathToFileURL(pluginEntry).href], + }); writePackageJson(); await run([file], 'check', cache); - expect((await loadFmtCacheStore(cache.filePath, cacheNamespace)).get('data.fixture')).toBe( - undefined, - ); + expect( + (await loadFmtCacheStore(cache.filePath, cacheNamespace)).get( + 'data.fixture', + ), + ).toBe(undefined); writePackageJson('1.0.0'); await run([file], 'check', cache); - const firstHash = (await loadFmtCacheStore(cache.filePath, cacheNamespace)).get( - 'data.fixture', - )?.[1]; + const firstHash = ( + await loadFmtCacheStore(cache.filePath, cacheNamespace) + ).get('data.fixture')?.[1]; expect(firstHash).toHaveLength(cacheHashLength); writePackageJson('2.0.0'); await run([file], 'check', cache); - const secondHash = (await loadFmtCacheStore(cache.filePath, cacheNamespace)).get( - 'data.fixture', - )?.[1]; + const secondHash = ( + await loadFmtCacheStore(cache.filePath, cacheNamespace) + ).get('data.fixture')?.[1]; expect(secondHash).toHaveLength(cacheHashLength); expect(secondHash).not.toBe(firstHash); }); @@ -241,7 +273,11 @@ test('preserves entries outside the formatted subset', async () => { writeFileSync(firstPath, 'const first = 1;\n'); writeFileSync(secondPath, 'const second = 2;\n'); - await run([createFmtRequest(firstPath), createFmtRequest(secondPath)], 'check', cache); + await run( + [createFmtRequest(firstPath), createFmtRequest(secondPath)], + 'check', + cache, + ); const firstStore = await loadFmtCacheStore(cache.filePath, cacheNamespace); const secondEntry = firstStore.get('second.ts'); @@ -262,7 +298,9 @@ test('does not cache formatting errors', async () => { writeFileSync(invalidPath, 'const invalid = ;'); await run([createFmtRequest(validPath)], 'check', cache); - await expect(run([createFmtRequest(invalidPath)], 'check', cache)).resolves.toMatchObject({ + await expect( + run([createFmtRequest(invalidPath)], 'check', cache), + ).resolves.toMatchObject({ exitCode: 2, files: [{ path: invalidPath, status: 'error' }], }); @@ -306,7 +344,9 @@ test('write persists clean results for misses and hits', async () => { files: [], processedFileCount: 2, }); - expect(files.map((file) => statSync(file.path).mtimeMs)).toEqual(timestamps); + expect(files.map((file) => statSync(file.path).mtimeMs)).toEqual( + timestamps, + ); }); }); diff --git a/packages/rstack/tests/fmt/runnerWorkerPreflight.test.ts b/packages/rstack/tests/fmt/runnerWorkerPreflight.test.ts index 7b9e3b87..cb3dec45 100644 --- a/packages/rstack/tests/fmt/runnerWorkerPreflight.test.ts +++ b/packages/rstack/tests/fmt/runnerWorkerPreflight.test.ts @@ -1,5 +1,8 @@ import { beforeEach, expect, rs, test } from 'rstack/test'; -import { cacheNamespace, createOptionsHasher } from '../../src/fmt/cacheIdentity.ts'; +import { + cacheNamespace, + createOptionsHasher, +} from '../../src/fmt/cacheIdentity.ts'; import { loadFmtCacheStore } from '../../src/fmt/cacheStore.ts'; import { runFmtFiles } from '../../src/fmt/runner.ts'; import { @@ -24,7 +27,10 @@ beforeEach(() => { mocks.workerPoolCalls.length = 0; }); -const createCachedUnsupportedFile = async (rootPath: string, fileName: string) => { +const createCachedUnsupportedFile = async ( + rootPath: string, + fileName: string, +) => { const filePath = writeProjectFile(rootPath, fileName, 'plain text'); const cache = createFmtCacheContext(rootPath); const file = createFmtRequest(filePath, {}); @@ -42,7 +48,10 @@ const createCachedUnsupportedFile = async (rootPath: string, fileName: string) = test('does not start the worker pool when every parser result is cached as unsupported', async () => { await withTempProject(async (rootPath) => { - const { cache, file } = await createCachedUnsupportedFile(rootPath, 'example.unknown'); + const { cache, file } = await createCachedUnsupportedFile( + rootPath, + 'example.unknown', + ); await expect( runFmtFiles({ @@ -61,7 +70,10 @@ test('does not start the worker pool when every parser result is cached as unsup test('starts the worker pool for a path-only unsupported entry without an extension', async () => { await withTempProject(async (rootPath) => { - const { cache, file } = await createCachedUnsupportedFile(rootPath, 'script'); + const { cache, file } = await createCachedUnsupportedFile( + rootPath, + 'script', + ); await expect( runFmtFiles({ diff --git a/packages/rstack/tests/fmt/worker.test.ts b/packages/rstack/tests/fmt/worker.test.ts index 3ef3d3aa..ddc35ba9 100644 --- a/packages/rstack/tests/fmt/worker.test.ts +++ b/packages/rstack/tests/fmt/worker.test.ts @@ -18,8 +18,18 @@ test('returns cached states before resolving the parser', async () => { [[contentHash, optionsHash, 'clean'], filePath, false, 'unchanged'], [[contentHash, optionsHash, 'dirty'], filePath, false, 'changed'], [[contentHash, optionsHash, 'clean'], filePath, true, 'unchanged'], - [[contentHash, optionsHash, 'unsupported'], noExtensionPath, false, 'unsupported'], - [[contentHash, optionsHash, 'unsupported'], noExtensionPath, true, 'unsupported'], + [ + [contentHash, optionsHash, 'unsupported'], + noExtensionPath, + false, + 'unsupported', + ], + [ + [contentHash, optionsHash, 'unsupported'], + noExtensionPath, + true, + 'unsupported', + ], [['', optionsHash, 'unsupported'], missingPath, false, 'unsupported'], [['', optionsHash, 'unsupported'], missingPath, true, 'unsupported'], ] as const) { @@ -44,7 +54,11 @@ test('returns cached states before resolving the parser', async () => { test('does not trust path-only unsupported entries for files without extensions', async () => { await withTempProject(async (rootPath) => { - const filePath = writeProjectFile(rootPath, 'script', '#!/usr/bin/env node\nconst value=1'); + const filePath = writeProjectFile( + rootPath, + 'script', + '#!/usr/bin/env node\nconst value=1', + ); await expect( formatFile({ diff --git a/packages/rstack/tests/fmt/yukuPlugin.test.ts b/packages/rstack/tests/fmt/yukuPlugin.test.ts index b4841ce3..b8e79457 100644 --- a/packages/rstack/tests/fmt/yukuPlugin.test.ts +++ b/packages/rstack/tests/fmt/yukuPlugin.test.ts @@ -1,4 +1,9 @@ -import { format, getFileInfo, type Options, type ParserOptions } from 'prettier'; +import { + format, + getFileInfo, + type Options, + type ParserOptions, +} from 'prettier'; import { expect, test } from 'rstack/test'; import { yukuPlugin } from '../../src/fmt/yukuPlugin.ts'; @@ -9,11 +14,14 @@ const formatWithYuku = ( format(source, { plugins: [yukuPlugin], ...options, - filepath: options.filepath ?? `example.${options.parser === 'yuku' ? 'js' : 'ts'}`, + filepath: + options.filepath ?? `example.${options.parser === 'yuku' ? 'js' : 'ts'}`, }); test('exposes the same JavaScript and TypeScript language mappings as the official plugin', async () => { - expect(yukuPlugin.languages?.map(({ name, parsers }) => ({ name, parsers }))).toEqual([ + expect( + yukuPlugin.languages?.map(({ name, parsers }) => ({ name, parsers })), + ).toEqual([ { name: 'JavaScript', parsers: ['yuku', 'yuku-ts'] }, { name: 'JSX', parsers: ['yuku', 'yuku-ts'] }, { name: 'TypeScript', parsers: ['yuku-ts'] }, @@ -63,7 +71,9 @@ test.each(['example.d.ts', 'example.d.mts', 'example.d.cts'])( filepath, parser: 'yuku-ts', }), - ).rejects.toThrow('An implementation cannot be declared in ambient contexts'); + ).rejects.toThrow( + 'An implementation cannot be declared in ambient contexts', + ); }, ); @@ -115,7 +125,8 @@ test.each([ parser: 'yuku-ts' as const, filepath: 'example.tsx', source: 'const view=({(item)})', - expected: 'const view = {item};\n', + expected: + 'const view = {item};\n', }, ])('normalizes $name for the ESTree printer', async (fixture) => { await expect( @@ -179,15 +190,18 @@ test.each([ hasPragma: false, hasIgnorePragma: false, }, -])('matches Prettier pragma detection for $source', ({ source, hasPragma, hasIgnorePragma }) => { - const parser = yukuPlugin.parsers?.yuku; - if (!parser?.hasPragma || !parser.hasIgnorePragma) { - throw new Error('The Yuku parser does not expose pragma handlers.'); - } +])( + 'matches Prettier pragma detection for $source', + ({ source, hasPragma, hasIgnorePragma }) => { + const parser = yukuPlugin.parsers?.yuku; + if (!parser?.hasPragma || !parser.hasIgnorePragma) { + throw new Error('The Yuku parser does not expose pragma handlers.'); + } - expect(parser.hasPragma(source)).toBe(hasPragma); - expect(parser.hasIgnorePragma(source)).toBe(hasIgnorePragma); -}); + expect(parser.hasPragma(source)).toBe(hasPragma); + expect(parser.hasIgnorePragma(source)).toBe(hasIgnorePragma); + }, +); test('matches Prettier JavaScript location overrides', () => { const parser = yukuPlugin.parsers?.yuku; @@ -278,10 +292,10 @@ test('matches the official hashbang AST shape', async () => { } const options = { filepath: 'example.js' } as ParserOptions; - const astWithoutHashbang = (await parser.parse('const value = 1', options)) as Record< - string, - unknown - >; + const astWithoutHashbang = (await parser.parse( + 'const value = 1', + options, + )) as Record; const astWithHashbang = (await parser.parse( '#!/usr/bin/env node\nconst value = 1', options, diff --git a/packages/rstack/tests/helpers/cli.ts b/packages/rstack/tests/helpers/cli.ts index d1d287d0..790e34f4 100644 --- a/packages/rstack/tests/helpers/cli.ts +++ b/packages/rstack/tests/helpers/cli.ts @@ -2,7 +2,10 @@ import { type ExecSyncOptions, execSync } from 'node:child_process'; import path from 'node:path'; import type { LogHelper } from '@rstackjs/test-utils'; -export const RSTACK_BIN_PATH: string = path.join(import.meta.dirname, '../../bin/rs.js'); +export const RSTACK_BIN_PATH: string = path.join( + import.meta.dirname, + '../../bin/rs.js', +); export type ExecCliOptions = ExecSyncOptions & { logHelper?: LogHelper; @@ -18,7 +21,10 @@ type ExecCliError = Error & { stderr?: Buffer | string; }; -const addLog = (logHelper: LogHelper | undefined, output: Buffer | string | undefined) => { +const addLog = ( + logHelper: LogHelper | undefined, + output: Buffer | string | undefined, +) => { if (output) { logHelper?.addLog(output.toString()); } @@ -28,14 +34,17 @@ export const execCli: ExecCli = (command, options = {}) => { const { logHelper, ...execOptions } = options; try { - const output = execSync(`"${process.execPath}" "${RSTACK_BIN_PATH}" ${command}`, { - stdio: 'pipe', - ...execOptions, - env: { - ...process.env, - ...execOptions.env, + const output = execSync( + `"${process.execPath}" "${RSTACK_BIN_PATH}" ${command}`, + { + stdio: 'pipe', + ...execOptions, + env: { + ...process.env, + ...execOptions.env, + }, }, - }); + ); addLog(logHelper, output); return output.toString(); diff --git a/packages/rstack/tests/helpers/cliTest.ts b/packages/rstack/tests/helpers/cliTest.ts index f3ff322d..895d54c8 100644 --- a/packages/rstack/tests/helpers/cliTest.ts +++ b/packages/rstack/tests/helpers/cliTest.ts @@ -1,8 +1,16 @@ -import { type ChildProcess, type SpawnOptions, spawn as nodeSpawn } from 'node:child_process'; +import { + type ChildProcess, + type SpawnOptions, + spawn as nodeSpawn, +} from 'node:child_process'; import path from 'node:path'; import { prepareDist as basePrepareDist } from '@rstackjs/test-utils'; import { test as baseTest } from 'rstack/test'; -import { execCli as baseExecCli, type ExecCli, RSTACK_BIN_PATH } from './cli.ts'; +import { + execCli as baseExecCli, + type ExecCli, + RSTACK_BIN_PATH, +} from './cli.ts'; import { type ExtendedLogHelper, proxyConsole } from './logs.ts'; type Exec = ( @@ -33,7 +41,10 @@ function makeBox(title: string) { }; } -const setupExecOptions = (options: T, cwd: string): T => { +const setupExecOptions = ( + options: T, + cwd: string, +): T => { // inherit process.env from current process const { NODE_ENV: _, ...restEnv } = process.env; options.env ||= {}; @@ -47,7 +58,9 @@ export const test: CliTest = baseTest.extend({ const { testPath } = expect.getState(); if (!testPath) { - throw new Error('Unable to resolve current test file path from expect state.'); + throw new Error( + 'Unable to resolve current test file path from expect state.', + ); } await use(path.dirname(testPath)); @@ -86,7 +99,10 @@ export const test: CliTest = baseTest.extend({ const closes: Array<() => void> = []; const exec: Exec = (command, options = {}) => { - const childProcess = nodeSpawn(command, setupExecOptions({ shell: true, ...options }, cwd)); + const childProcess = nodeSpawn( + command, + setupExecOptions({ shell: true, ...options }, cwd), + ); const onData = (data: Buffer) => { logHelper.addLog(data.toString()); diff --git a/packages/rstack/tests/helpers/logs.ts b/packages/rstack/tests/helpers/logs.ts index 2a0d19fa..12646a26 100644 --- a/packages/rstack/tests/helpers/logs.ts +++ b/packages/rstack/tests/helpers/logs.ts @@ -14,7 +14,9 @@ export type LogHelper = BaseLogHelper & ExpectBuildEnd; export type ExtendedLogHelper = BaseExtendedLogHelper & ExpectBuildEnd; -export const proxyConsole = (options?: ProxyConsoleOptions): ExtendedLogHelper => { +export const proxyConsole = ( + options?: ProxyConsoleOptions, +): ExtendedLogHelper => { const logHelper = baseProxyConsole(options); return { diff --git a/packages/rstack/tests/setup/directories.test.ts b/packages/rstack/tests/setup/directories.test.ts index dfaf62da..d27c662a 100644 --- a/packages/rstack/tests/setup/directories.test.ts +++ b/packages/rstack/tests/setup/directories.test.ts @@ -2,7 +2,13 @@ import { existsSync, mkdirSync, readFileSync } from 'node:fs'; import path from 'node:path'; import { expect, test } from 'rstack/test'; import { installHooks } from '../../src/setup/install.ts'; -import { hooksPath, runGit, runHook, withRepository, writeHook } from './helpers.ts'; +import { + hooksPath, + runGit, + runHook, + withRepository, + writeHook, +} from './helpers.ts'; test('installs a custom hooks directory from the Git root and runs its hook', () => { withRepository((cwd) => { @@ -14,11 +20,15 @@ test('installs a custom hooks directory from the Git root and runs its hook', () status: 'installed', hooksPath: customHooksPath, }); - expect(runGit(cwd, ['config', '--local', '--get', 'core.hooksPath'])).toBe(customHooksPath); + expect(runGit(cwd, ['config', '--local', '--get', 'core.hooksPath'])).toBe( + customHooksPath, + ); expect(existsSync(path.join(cwd, customHooksPath, 'runner'))).toBe(true); expect(runHook(cwd).status).toBe(0); - expect(readFileSync(path.join(cwd, 'custom-hook-ran'), 'utf8')).toBe('ran\n'); + expect(readFileSync(path.join(cwd, 'custom-hook-ran'), 'utf8')).toBe( + 'ran\n', + ); }); }); @@ -36,12 +46,18 @@ test('installs repository-level hooks from a nested project', () => { status: 'unchanged', hooksPath, }); - expect(runGit(cwd, ['config', '--local', '--get', 'core.hooksPath'])).toBe(hooksPath); + expect(runGit(cwd, ['config', '--local', '--get', 'core.hooksPath'])).toBe( + hooksPath, + ); expect(existsSync(path.join(cwd, hooksPath, 'runner'))).toBe(true); - expect(readFileSync(path.join(cwd, hooksPath, '.owner'), 'utf8')).toBe('frontend\n'); + expect(readFileSync(path.join(cwd, hooksPath, '.owner'), 'utf8')).toBe( + 'frontend\n', + ); expect(runHook(cwd).status).toBe(0); - expect(readFileSync(path.join(projectDirectory, 'nested-hook-ran'), 'utf8')).toBe('ran\n'); + expect( + readFileSync(path.join(projectDirectory, 'nested-hook-ran'), 'utf8'), + ).toBe('ran\n'); }); }); @@ -50,15 +66,23 @@ test('installs a root-relative custom hooks directory from a nested project', () const projectDirectory = path.join(cwd, 'frontend app'); mkdirSync(projectDirectory); - expect(installHooks({ cwd: projectDirectory, hooksDir: 'config\\hooks' })).toEqual({ + expect( + installHooks({ cwd: projectDirectory, hooksDir: 'config\\hooks' }), + ).toEqual({ status: 'installed', hooksPath: 'config/hooks/_', }); - expect(installHooks({ cwd: projectDirectory, hooksDir: 'config\\hooks' })).toEqual({ + expect( + installHooks({ cwd: projectDirectory, hooksDir: 'config\\hooks' }), + ).toEqual({ status: 'unchanged', hooksPath: 'config/hooks/_', }); - expect(runGit(cwd, ['config', '--local', '--get', 'core.hooksPath'])).toBe('config/hooks/_'); - expect(existsSync(path.join(cwd, 'config', 'hooks', '_', 'runner'))).toBe(true); + expect(runGit(cwd, ['config', '--local', '--get', 'core.hooksPath'])).toBe( + 'config/hooks/_', + ); + expect(existsSync(path.join(cwd, 'config', 'hooks', '_', 'runner'))).toBe( + true, + ); }); }); diff --git a/packages/rstack/tests/setup/helpers.ts b/packages/rstack/tests/setup/helpers.ts index 206e54c6..794691f2 100644 --- a/packages/rstack/tests/setup/helpers.ts +++ b/packages/rstack/tests/setup/helpers.ts @@ -10,7 +10,8 @@ export const git = ( cwd: string, args: string[], env: NodeJS.ProcessEnv = process.env, -): SpawnSyncReturns => spawnSync('git', args, { cwd, encoding: 'utf8', env }); +): SpawnSyncReturns => + spawnSync('git', args, { cwd, encoding: 'utf8', env }); export const runGit = (cwd: string, args: string[]): string => { const result = git(cwd, args); @@ -21,7 +22,9 @@ export const runGit = (cwd: string, args: string[]): string => { }; export const withDirectory = (callback: (cwd: string) => void): void => { - const cwd = mkdtempSync(path.join(import.meta.dirname, 'test-temp-rstack hooks ')); + const cwd = mkdtempSync( + path.join(import.meta.dirname, 'test-temp-rstack hooks '), + ); const gitCeilingDirectories = process.env.GIT_CEILING_DIRECTORIES; // Keep Git from treating the temporary directory as part of this repository. process.env.GIT_CEILING_DIRECTORIES = import.meta.dirname; @@ -55,7 +58,11 @@ const hookEnv = (cwd: string, value?: string): NodeJS.ProcessEnv => { return env; }; -export const writeHook = (cwd: string, content: string, directory: string = hooksDir): void => { +export const writeHook = ( + cwd: string, + content: string, + directory: string = hooksDir, +): void => { const filePath = path.join(cwd, directory, 'pre-commit'); mkdirSync(path.dirname(filePath), { recursive: true }); writeFileSync(filePath, content); @@ -67,10 +74,17 @@ export const writeInit = (cwd: string, content: string): void => { writeFileSync(filePath, content); }; -export const runHook = (cwd: string, value?: string): SpawnSyncReturns => +export const runHook = ( + cwd: string, + value?: string, +): SpawnSyncReturns => git(cwd, ['hook', 'run', 'pre-commit'], hookEnv(cwd, value)); -export const runGitHook = (cwd: string, name: string, args: string[]): SpawnSyncReturns => +export const runGitHook = ( + cwd: string, + name: string, + args: string[], +): SpawnSyncReturns => git(cwd, ['hook', 'run', name, '--', ...args], hookEnv(cwd)); export const withRepository = (callback: (cwd: string) => void): void => diff --git a/packages/rstack/tests/setup/hooks.test.ts b/packages/rstack/tests/setup/hooks.test.ts index 3baa5348..a2bd5762 100644 --- a/packages/rstack/tests/setup/hooks.test.ts +++ b/packages/rstack/tests/setup/hooks.test.ts @@ -6,7 +6,9 @@ import { createHookFiles } from '../../src/setup/hooks.ts'; import { withDirectory } from './helpers.ts'; test('generates the runner and all client-side Git hook shims', () => { - expect(Object.keys(createHookFiles()).filter((name) => name !== 'runner')).toEqual([ + expect( + Object.keys(createHookFiles()).filter((name) => name !== 'runner'), + ).toEqual([ 'pre-commit', 'pre-merge-commit', 'prepare-commit-msg', @@ -25,17 +27,24 @@ test('generates the runner and all client-side Git hook shims', () => { }); test.runIf(process.platform === 'win32')('converts Windows Node paths', () => { - const { runner } = createHookFiles(String.raw`C:\Program Files\nodejs\node.exe`); + const { runner } = createHookFiles( + String.raw`C:\Program Files\nodejs\node.exe`, + ); - expect(runner).toContain("rs_node_fallback='/c/Program Files/nodejs/node.exe'"); + expect(runner).toContain( + "rs_node_fallback='/c/Program Files/nodejs/node.exe'", + ); }); -test.runIf(process.platform !== 'win32')('preserves backslashes in POSIX Node paths', () => { - const nodeExecutable = String.raw`/opt/node\24/bin/node`; - const { runner } = createHookFiles(nodeExecutable); +test.runIf(process.platform !== 'win32')( + 'preserves backslashes in POSIX Node paths', + () => { + const nodeExecutable = String.raw`/opt/node\24/bin/node`; + const { runner } = createHookFiles(nodeExecutable); - expect(runner).toContain(`rs_node_fallback='${nodeExecutable}'`); -}); + expect(runner).toContain(`rs_node_fallback='${nodeExecutable}'`); + }, +); test.runIf(process.platform !== 'win32')('runs generated hooks', () => { withDirectory((directory) => { @@ -58,7 +67,9 @@ test.runIf(process.platform !== 'win32')('runs generated hooks', () => { writeFileSync(path.join(generatedDirectory, 'runner'), files.runner); writeFileSync(generatedHook, files['pre-commit']); - expect(spawnSync('sh', [generatedHook], { cwd: directory, env }).status).toBe(0); + expect( + spawnSync('sh', [generatedHook], { cwd: directory, env }).status, + ).toBe(0); writeFileSync( userHook, @@ -89,7 +100,9 @@ printf 'unreachable\\n' }); expect(errexitResult.status).toBe(1); - expect(errexitResult.stdout).toBe('Rstack - pre-commit hook failed (code 1)\n'); + expect(errexitResult.stdout).toBe( + 'Rstack - pre-commit hook failed (code 1)\n', + ); mkdirSync(runtimeDirectory, { recursive: true }); writeFileSync(init, `export PATH="${runtimeDirectory}"\n`); diff --git a/packages/rstack/tests/setup/install.test.ts b/packages/rstack/tests/setup/install.test.ts index a64ea7c7..f91b2b45 100644 --- a/packages/rstack/tests/setup/install.test.ts +++ b/packages/rstack/tests/setup/install.test.ts @@ -1,19 +1,38 @@ -import { chmodSync, existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from 'node:fs'; +import { + chmodSync, + existsSync, + mkdirSync, + readFileSync, + statSync, + writeFileSync, +} from 'node:fs'; import path from 'node:path'; import { expect, test } from 'rstack/test'; import { createHookFiles } from '../../src/setup/hooks.ts'; import { installHooks } from '../../src/setup/install.ts'; -import { git, hooksPath, restoreEnv, runGit, withRepository } from './helpers.ts'; +import { + git, + hooksPath, + restoreEnv, + runGit, + withRepository, +} from './helpers.ts'; test('installs generated hooks and configures the repository', () => { withRepository((cwd) => { expect(installHooks({ cwd })).toEqual({ status: 'installed', hooksPath }); - expect(runGit(cwd, ['config', '--local', '--get', 'core.hooksPath'])).toBe(hooksPath); + expect(runGit(cwd, ['config', '--local', '--get', 'core.hooksPath'])).toBe( + hooksPath, + ); const directory = path.join(cwd, hooksPath); - expect(readFileSync(path.join(directory, '.gitignore'), 'utf8')).toBe('*\n'); + expect(readFileSync(path.join(directory, '.gitignore'), 'utf8')).toBe( + '*\n', + ); expect(readFileSync(path.join(directory, '.owner'), 'utf8')).toBe('.\n'); - expect(runGit(cwd, ['status', '--short', '--untracked-files=all'])).toBe(''); + expect(runGit(cwd, ['status', '--short', '--untracked-files=all'])).toBe( + '', + ); for (const [name, content] of Object.entries(createHookFiles())) { const filePath = path.join(directory, name); @@ -40,16 +59,19 @@ test('is idempotent and preserves user hooks', () => { }); }); -test.runIf(process.platform !== 'win32')('restores executable mode on existing shims', () => { - withRepository((cwd) => { - expect(installHooks({ cwd }).status).toBe('installed'); - const shim = path.join(cwd, hooksPath, 'pre-commit'); - chmodSync(shim, 0o644); +test.runIf(process.platform !== 'win32')( + 'restores executable mode on existing shims', + () => { + withRepository((cwd) => { + expect(installHooks({ cwd }).status).toBe('installed'); + const shim = path.join(cwd, hooksPath, 'pre-commit'); + chmodSync(shim, 0o644); - expect(installHooks({ cwd }).status).toBe('installed'); - expect(statSync(shim).mode & 0o777).toBe(0o755); - }); -}); + expect(installHooks({ cwd }).status).toBe('installed'); + expect(statSync(shim).mode & 0o777).toBe(0o755); + }); + }, +); test('repairs generated files without rewriting an unchanged hooksPath', () => { withRepository((cwd) => { @@ -94,7 +116,9 @@ test('does not configure Git when writing generated files fails', () => { status: 'failed', reason: 'write-failed', }); - expect(git(cwd, ['config', '--local', '--get', 'core.hooksPath']).status).toBe(1); + expect( + git(cwd, ['config', '--local', '--get', 'core.hooksPath']).status, + ).toBe(1); }); }); @@ -106,7 +130,9 @@ test('reports Git configuration failures without changing hooksPath', () => { status: 'failed', reason: 'git-config-failed', }); - expect(git(cwd, ['config', '--local', '--get', 'core.hooksPath']).status).toBe(1); + expect( + git(cwd, ['config', '--local', '--get', 'core.hooksPath']).status, + ).toBe(1); expect(existsSync(path.join(cwd, hooksPath, 'runner'))).toBe(true); }); }); @@ -119,7 +145,9 @@ test('does not replace another Git hooks path', () => { status: 'skipped', reason: 'hooks-path-conflict', }); - expect(runGit(cwd, ['config', '--local', '--get', 'core.hooksPath'])).toBe('.husky/_'); + expect(runGit(cwd, ['config', '--local', '--get', 'core.hooksPath'])).toBe( + '.husky/_', + ); expect(existsSync(path.join(cwd, hooksPath))).toBe(false); }); }); @@ -134,7 +162,9 @@ test('does not bypass existing Git hooks', () => { reason: 'existing-git-hooks', message: 'existing Git hooks were found: pre-commit', }); - expect(git(cwd, ['config', '--local', '--get', 'core.hooksPath']).status).toBe(1); + expect( + git(cwd, ['config', '--local', '--get', 'core.hooksPath']).status, + ).toBe(1); expect(readFileSync(existingHook, 'utf8')).toBe('#!/usr/bin/env sh\n'); }); }); diff --git a/packages/rstack/tests/setup/runtime-errors.test.ts b/packages/rstack/tests/setup/runtime-errors.test.ts index ac85a13c..adcf553a 100644 --- a/packages/rstack/tests/setup/runtime-errors.test.ts +++ b/packages/rstack/tests/setup/runtime-errors.test.ts @@ -28,6 +28,8 @@ missing-command expect(missing.status).toBe(127); expect(output).toContain('Rstack - pre-commit hook failed (code 127)'); - expect(output).toContain(`Rstack - command not found in PATH=${actualPath}`); + expect(output).toContain( + `Rstack - command not found in PATH=${actualPath}`, + ); }); }); diff --git a/packages/rstack/tests/setup/runtime.test.ts b/packages/rstack/tests/setup/runtime.test.ts index 455f1a88..6fcff7c4 100644 --- a/packages/rstack/tests/setup/runtime.test.ts +++ b/packages/rstack/tests/setup/runtime.test.ts @@ -1,8 +1,20 @@ -import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'; +import { + chmodSync, + existsSync, + mkdirSync, + readFileSync, + writeFileSync, +} from 'node:fs'; import path from 'node:path'; import { expect, test } from 'rstack/test'; import { installHooks } from '../../src/setup/install.ts'; -import { runGitHook, runHook, withRepository, writeHook, writeInit } from './helpers.ts'; +import { + runGitHook, + runHook, + withRepository, + writeHook, + writeInit, +} from './helpers.ts'; test('loads user init and project binaries', () => { withRepository((cwd) => { @@ -30,8 +42,12 @@ rstack-hook-command expect(installHooks({ cwd: projectDirectory }).status).toBe('installed'); expect(runHook(cwd).status).toBe(0); - expect(readFileSync(path.join(projectDirectory, 'init-ran'), 'utf8')).toBe('loaded\n'); - expect(readFileSync(path.join(projectDirectory, 'project-bin-ran'), 'utf8')).toBe('ran\n'); + expect(readFileSync(path.join(projectDirectory, 'init-ran'), 'utf8')).toBe( + 'loaded\n', + ); + expect( + readFileSync(path.join(projectDirectory, 'project-bin-ran'), 'utf8'), + ).toBe('ran\n'); }); }); diff --git a/packages/rstack/tests/types/resolution-bundler/index.ts b/packages/rstack/tests/types/resolution-bundler/index.ts index 8853c64e..0dc37311 100644 --- a/packages/rstack/tests/types/resolution-bundler/index.ts +++ b/packages/rstack/tests/types/resolution-bundler/index.ts @@ -17,7 +17,9 @@ import { expect as importedExpect, test as importedTest } from 'rstack/test'; const appConfig = defineAppConfig({}); const libConfig = defineLibConfig({}); const lintConfig = defineLintConfig([]); -const loadOptions: LoadRstackConfigOptions = { configFilePath: 'rstack.config.ts' }; +const loadOptions: LoadRstackConfigOptions = { + configFilePath: 'rstack.config.ts', +}; const loadedConfig: Promise = loadRstackConfig(loadOptions); const configs: Configs = {}; @@ -28,7 +30,10 @@ void createRsbuild({ config: appConfig }); define.app(appConfig); define.lib(libConfig); define.lint(lintConfig); -define.lint(({ js, ts }) => [js.configs.recommended, ts.configs.recommendedTypeChecked]); +define.lint(({ js, ts }) => [ + js.configs.recommended, + ts.configs.recommendedTypeChecked, +]); define.doc({}); define.test({}); define.staged({}); diff --git a/packages/rstack/tests/types/resolution-nodenext/index.ts b/packages/rstack/tests/types/resolution-nodenext/index.ts index 8853c64e..0dc37311 100644 --- a/packages/rstack/tests/types/resolution-nodenext/index.ts +++ b/packages/rstack/tests/types/resolution-nodenext/index.ts @@ -17,7 +17,9 @@ import { expect as importedExpect, test as importedTest } from 'rstack/test'; const appConfig = defineAppConfig({}); const libConfig = defineLibConfig({}); const lintConfig = defineLintConfig([]); -const loadOptions: LoadRstackConfigOptions = { configFilePath: 'rstack.config.ts' }; +const loadOptions: LoadRstackConfigOptions = { + configFilePath: 'rstack.config.ts', +}; const loadedConfig: Promise = loadRstackConfig(loadOptions); const configs: Configs = {}; @@ -28,7 +30,10 @@ void createRsbuild({ config: appConfig }); define.app(appConfig); define.lib(libConfig); define.lint(lintConfig); -define.lint(({ js, ts }) => [js.configs.recommended, ts.configs.recommendedTypeChecked]); +define.lint(({ js, ts }) => [ + js.configs.recommended, + ts.configs.recommendedTypeChecked, +]); define.doc({}); define.test({}); define.staged({}); diff --git a/rstack.config.ts b/rstack.config.ts index 68b2ef8f..066eace0 100644 --- a/rstack.config.ts +++ b/rstack.config.ts @@ -52,16 +52,10 @@ define.lint(async ({ js, ts }) => { }); define.fmt({ - ignorePatterns: ['packages/rstack/binding.cjs', 'packages/rstack/binding.d.cts'], - overrides: [ - { - files: 'packages/create-rstack/template-*/**/*', - options: { - printWidth: 80, - }, - }, + ignorePatterns: [ + 'packages/rstack/binding.cjs', + 'packages/rstack/binding.d.cts', ], - printWidth: 100, singleQuote: true, sortPackageJson: true, }); diff --git a/scripts/benchmark-fmt-discovery.js b/scripts/benchmark-fmt-discovery.js index ecf4f457..2891d082 100644 --- a/scripts/benchmark-fmt-discovery.js +++ b/scripts/benchmark-fmt-discovery.js @@ -30,7 +30,9 @@ const readValue = (args, index, flag) => { const parseInteger = (value, flag, minimum) => { const result = Number(value); if (!Number.isSafeInteger(result) || result < minimum) { - throw new Error(`${flag} must be an integer greater than or equal to ${minimum}.`); + throw new Error( + `${flag} must be an integer greater than or equal to ${minimum}.`, + ); } return result; }; @@ -58,7 +60,11 @@ const parseArgs = (args) => { index++; break; case '--explicit-count': - options.explicitCount = parseInteger(readValue(args, index, arg), arg, 1); + options.explicitCount = parseInteger( + readValue(args, index, arg), + arg, + 1, + ); index++; break; case '--runs': diff --git a/scripts/prepare-release.js b/scripts/prepare-release.js index cab8f15b..a18ff738 100644 --- a/scripts/prepare-release.js +++ b/scripts/prepare-release.js @@ -1,6 +1,13 @@ #!/usr/bin/env node import { spawn } from 'node:child_process'; -import { copyFile, mkdir, readFile, readdir, rm, writeFile } from 'node:fs/promises'; +import { + copyFile, + mkdir, + readFile, + readdir, + rm, + writeFile, +} from 'node:fs/promises'; import path from 'node:path'; const rootDir = path.resolve(import.meta.dirname, '..'); diff --git a/website/docs/en/guide/ai.mdx b/website/docs/en/guide/ai.mdx index 80ef7217..83a9cf79 100644 --- a/website/docs/en/guide/ai.mdx +++ b/website/docs/en/guide/ai.mdx @@ -50,7 +50,10 @@ The [migrate-to-rstack-cli](https://github.com/rstackjs/rstack-cli/tree/main/.ag To migrate an existing project, install the Skill: - + For supported tools and migration instructions, see [Migrate to Rstack CLI](./migration). diff --git a/website/docs/en/guide/cli/_meta.json b/website/docs/en/guide/cli/_meta.json index acdaffbe..5357606a 100644 --- a/website/docs/en/guide/cli/_meta.json +++ b/website/docs/en/guide/cli/_meta.json @@ -1 +1,13 @@ -["dev", "build", "preview", "lib", "doc", "test", "check", "lint", "fmt", "setup", "staged"] +[ + "dev", + "build", + "preview", + "lib", + "doc", + "test", + "check", + "lint", + "fmt", + "setup", + "staged" +] diff --git a/website/docs/en/guide/cli/lint.mdx b/website/docs/en/guide/cli/lint.mdx index e007abb3..aea5fa8a 100644 --- a/website/docs/en/guide/cli/lint.mdx +++ b/website/docs/en/guide/cli/lint.mdx @@ -34,5 +34,8 @@ Configure linting through [`define.lint()`](../configuration#define-lint) in the ```ts title="rstack.config.ts" import { define } from 'rstack'; -define.lint(({ js, ts }) => [js.configs.recommended, ts.configs.recommendedTypeChecked]); +define.lint(({ js, ts }) => [ + js.configs.recommended, + ts.configs.recommendedTypeChecked, +]); ``` diff --git a/website/docs/en/guide/configuration.mdx b/website/docs/en/guide/configuration.mdx index ff057d24..d1aaa0aa 100644 --- a/website/docs/en/guide/configuration.mdx +++ b/website/docs/en/guide/configuration.mdx @@ -154,7 +154,10 @@ Defines the [Rslint configuration](https://rslint.rs/config/). Pass the configur ```ts title="rstack.config.ts" import { define } from 'rstack'; -define.lint(({ js, ts }) => [js.configs.recommended, ts.configs.recommendedTypeChecked]); +define.lint(({ js, ts }) => [ + js.configs.recommended, + ts.configs.recommendedTypeChecked, +]); ``` ### `define.fmt()` \{#define-fmt} diff --git a/website/docs/en/guide/monorepo.mdx b/website/docs/en/guide/monorepo.mdx index 88c6cfce..41282191 100644 --- a/website/docs/en/guide/monorepo.mdx +++ b/website/docs/en/guide/monorepo.mdx @@ -46,7 +46,10 @@ Use [`define.lint()`](./configuration#define-lint), [`define.fmt()`](./configura ```ts title="rstack.config.ts" import { define } from 'rstack'; -define.lint(({ js, ts }) => [js.configs.recommended, ts.configs.recommendedTypeChecked]); +define.lint(({ js, ts }) => [ + js.configs.recommended, + ts.configs.recommendedTypeChecked, +]); define.fmt({ singleQuote: true, diff --git a/website/docs/zh/guide/ai.mdx b/website/docs/zh/guide/ai.mdx index a9ab69f1..581e94d5 100644 --- a/website/docs/zh/guide/ai.mdx +++ b/website/docs/zh/guide/ai.mdx @@ -50,7 +50,10 @@ Rstack CLI 提供面向特定领域的 Agent Skills,帮助 Coding Agent 更准 迁移现有项目时,安装该 Skill: - + 支持的工具和迁移说明请参阅[迁移到 Rstack CLI](./migration)。 diff --git a/website/docs/zh/guide/cli/_meta.json b/website/docs/zh/guide/cli/_meta.json index acdaffbe..5357606a 100644 --- a/website/docs/zh/guide/cli/_meta.json +++ b/website/docs/zh/guide/cli/_meta.json @@ -1 +1,13 @@ -["dev", "build", "preview", "lib", "doc", "test", "check", "lint", "fmt", "setup", "staged"] +[ + "dev", + "build", + "preview", + "lib", + "doc", + "test", + "check", + "lint", + "fmt", + "setup", + "staged" +] diff --git a/website/docs/zh/guide/cli/lint.mdx b/website/docs/zh/guide/cli/lint.mdx index 48011c5e..0634bd38 100644 --- a/website/docs/zh/guide/cli/lint.mdx +++ b/website/docs/zh/guide/cli/lint.mdx @@ -34,5 +34,8 @@ rs lint --type-check ```ts title="rstack.config.ts" import { define } from 'rstack'; -define.lint(({ js, ts }) => [js.configs.recommended, ts.configs.recommendedTypeChecked]); +define.lint(({ js, ts }) => [ + js.configs.recommended, + ts.configs.recommendedTypeChecked, +]); ``` diff --git a/website/docs/zh/guide/configuration.mdx b/website/docs/zh/guide/configuration.mdx index 5f15b77b..06939f84 100644 --- a/website/docs/zh/guide/configuration.mdx +++ b/website/docs/zh/guide/configuration.mdx @@ -154,7 +154,10 @@ define.test({ ```ts title="rstack.config.ts" import { define } from 'rstack'; -define.lint(({ js, ts }) => [js.configs.recommended, ts.configs.recommendedTypeChecked]); +define.lint(({ js, ts }) => [ + js.configs.recommended, + ts.configs.recommendedTypeChecked, +]); ``` ### `define.fmt()` \{#define-fmt} diff --git a/website/docs/zh/guide/monorepo.mdx b/website/docs/zh/guide/monorepo.mdx index ab8671db..aa898b82 100644 --- a/website/docs/zh/guide/monorepo.mdx +++ b/website/docs/zh/guide/monorepo.mdx @@ -46,7 +46,10 @@ Rsbuild 插件、测试库等项目专属依赖,建议定义在实际使用它 ```ts title="rstack.config.ts" import { define } from 'rstack'; -define.lint(({ js, ts }) => [js.configs.recommended, ts.configs.recommendedTypeChecked]); +define.lint(({ js, ts }) => [ + js.configs.recommended, + ts.configs.recommendedTypeChecked, +]); define.fmt({ singleQuote: true, diff --git a/website/rstack.config.ts b/website/rstack.config.ts index 8e1fd234..29116243 100644 --- a/website/rstack.config.ts +++ b/website/rstack.config.ts @@ -5,14 +5,19 @@ import { define } from 'rstack'; const title = 'Rstack CLI'; const description = 'Rstack CLI brings the Rstack toolchain together with one CLI, one configuration, and one consistent workflow.'; -const descriptionZh = 'Rstack CLI 通过统一的命令行、配置和工作流整合 Rstack 工具链。'; +const descriptionZh = + 'Rstack CLI 通过统一的命令行、配置和工作流整合 Rstack 工具链。'; const injectLlmsHint = process.env.RSPRESS_INJECT_LLMS_HINT !== 'false'; define.doc(async () => { const { pluginSass } = await import('@rsbuild/plugin-sass'); - const { transformerNotationDiff, transformerNotationFocus, transformerNotationHighlight } = - await import('@shikijs/transformers'); - const { pluginClientRedirects } = await import('@rspress/plugin-client-redirects'); + const { + transformerNotationDiff, + transformerNotationFocus, + transformerNotationHighlight, + } = await import('@shikijs/transformers'); + const { pluginClientRedirects } = + await import('@rspress/plugin-client-redirects'); const { pluginSitemap } = await import('@rspress/plugin-sitemap'); const { pluginOpenGraph } = await import('rsbuild-plugin-open-graph'); const { pluginFontOpenSans } = await import('rspress-plugin-font-open-sans'); @@ -88,7 +93,8 @@ define.doc(async () => { }, ], editLink: { - docRepoBaseUrl: 'https://github.com/rstackjs/rstack-cli/tree/main/website/docs', + docRepoBaseUrl: + 'https://github.com/rstackjs/rstack-cli/tree/main/website/docs', }, }, builderConfig: { diff --git a/website/theme/components/Copyright.tsx b/website/theme/components/Copyright.tsx index 5ef14a01..75e3049a 100644 --- a/website/theme/components/Copyright.tsx +++ b/website/theme/components/Copyright.tsx @@ -5,7 +5,10 @@ export const CopyRight = () => {