diff --git a/.changeset/angry-ads-pick.md b/.changeset/angry-ads-pick.md new file mode 100644 index 000000000..fb1a094a6 --- /dev/null +++ b/.changeset/angry-ads-pick.md @@ -0,0 +1,5 @@ +--- +'@granite-js/plugin-radon': patch +--- + +add radon plugin diff --git a/eslint.config.cjs b/eslint.config.cjs index d17543c95..51b2ead60 100644 --- a/eslint.config.cjs +++ b/eslint.config.cjs @@ -42,6 +42,7 @@ module.exports = tseslint.config( '.pnp.*', '.yarn/', '**/.granite/', + 'packages/plugin-radon/src/lib/vendor/**/*', ], }, eslint.configs.recommended, diff --git a/packages/create-granite-app/package.json b/packages/create-granite-app/package.json index 3baeebd41..15988e234 100644 --- a/packages/create-granite-app/package.json +++ b/packages/create-granite-app/package.json @@ -29,13 +29,13 @@ "test:no-parallel": "vitest --no-watch --coverage" }, "devDependencies": { - "@types/kill-port": "^2.0.1", + "@types/kill-port": "2.0.1", "@types/node": "^22.10.2", "@types/yargs": "^17.0.33", "@vitest/coverage-v8": "^4.0.12", "es-toolkit": "^1.39.8", "execa": "^9.5.2", - "kill-port": "^2.0.1", + "kill-port": "2.0.1", "tsup": "^8.5.0", "typescript": "5.8.3", "vitest": "^4.0.12", diff --git a/packages/mpack/src/metro/enhancedResolver.ts b/packages/mpack/src/metro/enhancedResolver.ts index 4a8cff03c..59597aacb 100644 --- a/packages/mpack/src/metro/enhancedResolver.ts +++ b/packages/mpack/src/metro/enhancedResolver.ts @@ -24,6 +24,8 @@ const resolvers = new Map(); interface CreateResolverOptions { conditionNames?: string[]; + extraNodeModules?: Record; + monorepoRoot?: string; } export function createResolver(rootPath: string, options?: CreateResolverOptions) { @@ -45,11 +47,12 @@ export function createResolver(rootPath: string, options?: CreateResolverOptions conditionNames: options?.conditionNames ?? [...RESOLVER_EXPORTS_MAP_CONDITIONS, 'require', 'node', 'default'], mainFiles: ['index'], modules: ['node_modules', path.join(rootPath, 'src')], + alias: options?.extraNodeModules ?? {}, }); function resolve(context: MetroResolutionContext, request: string) { for (const nativeModule of NATIVE_MODULES) { - if (request === nativeModule) { + if (request === nativeModule || request.startsWith(nativeModule + '/')) { return { type: 'sourceFile', filePath: resolver({}, rootPath, request), @@ -78,6 +81,19 @@ export function createResolver(rootPath: string, options?: CreateResolverOptions request = `${request}/`; } + const isPackageImport = !(request.startsWith('.') || request.startsWith('/')); + if (isPackageImport) { + try { + const resolveResult = resolver({}, rootPath, request); + return { + type: 'sourceFile', + filePath: resolveResult, + }; + } catch { + // noop: If package resolution fails from rootPath, fall through to try resolving from originModulePath below + } + } + try { const resolveResult = resolver({}, path.dirname(context.originModulePath), request); diff --git a/packages/mpack/src/metro/getMetroConfig.ts b/packages/mpack/src/metro/getMetroConfig.ts index 38a544f36..3a8a5378c 100644 --- a/packages/mpack/src/metro/getMetroConfig.ts +++ b/packages/mpack/src/metro/getMetroConfig.ts @@ -42,6 +42,7 @@ export async function getMetroConfig({ rootPath }: GetMetroConfig, additionalCon additionalConfig?.resolver?.resolveRequest ?? createResolver(rootPath, { conditionNames: additionalConfig?.resolver?.conditionNames, + extraNodeModules: additionalConfig?.resolver?.extraNodeModules, }); return mergeConfig(defaultConfig, { @@ -58,7 +59,8 @@ export async function getMetroConfig({ rootPath }: GetMetroConfig, additionalCon inlineRequires: false, }, }), - babelTransformerPath: require.resolve('metro-react-native-babel-transformer'), + babelTransformerPath: + additionalConfig?.transformer?.babelTransformerPath || require.resolve('metro-react-native-babel-transformer'), asyncRequireModulePath: require.resolve('metro-runtime/src/modules/asyncRequire'), unstable_collectDependenciesPath: resolveVendors('metro/src/ModuleGraph/worker/collectDependencies'), unstable_allowRequireContext: true, @@ -87,11 +89,15 @@ export async function getMetroConfig({ rootPath }: GetMetroConfig, additionalCon resolverMainFields: additionalConfig?.resolver?.resolverMainFields ?? RESOLVER_MAIN_FIELDS, }, serializer: { - getModulesRunBeforeMainModule: () => [resolveFromRoot('react-native/Libraries/Core/InitializeCore', rootPath)], + getModulesRunBeforeMainModule: () => [ + resolveFromRoot('react-native/Libraries/Core/InitializeCore', rootPath), + ...(additionalConfig?.serializer?.getModulesRunBeforeMainModule?.() ?? []), + ], getPolyfills: () => [ ...require(path.join(reactNativePath, 'rn-get-polyfills'))(), ...(additionalConfig?.serializer?.getPolyfills?.() ?? []), ], + processModuleFilter: additionalConfig?.serializer?.processModuleFilter, }, symbolicator: { customizeFrame: (frame: { file: string }) => { @@ -103,6 +109,7 @@ export async function getMetroConfig({ rootPath }: GetMetroConfig, additionalCon port: DEV_SERVER_DEFAULT_PORT, }, reporter: additionalConfig?.reporter, + cacheVersion: additionalConfig?.cacheVersion, ...(process.env.METRO_RESET_CACHE !== 'false' ? { resetCache: true } : {}), }); } diff --git a/packages/mpack/src/operations/serve.ts b/packages/mpack/src/operations/serve.ts index f8300f7c3..4037e072e 100644 --- a/packages/mpack/src/operations/serve.ts +++ b/packages/mpack/src/operations/serve.ts @@ -72,6 +72,7 @@ export async function runServer({ const resolvedConfig = await resolveConfig(config); const { middlewares = [], inspectorProxy, ...additionalMetroConfig } = resolvedConfig?.metro ?? {}; const baseConfig = await getMetroConfig({ rootPath: config.cwd }, additionalMetroConfig); + const metroConfig = mergeConfig(baseConfig, { server: { port }, reporter, diff --git a/packages/plugin-core/src/types/MetroConfig.ts b/packages/plugin-core/src/types/MetroConfig.ts index 053de237e..137af28ff 100644 --- a/packages/plugin-core/src/types/MetroConfig.ts +++ b/packages/plugin-core/src/types/MetroConfig.ts @@ -1,3 +1,4 @@ +import type Module from 'node:module'; import * as babel from '@babel/core'; import type { MetroConfig } from './vendors/metro'; @@ -6,8 +7,18 @@ export interface AdditionalMetroConfig extends MetroConfig { * Partial support for some options only * * - `getPolyfills` + * - `getModulesRunBeforeMainModule` + * - `processModuleFilter` */ - serializer?: MetroConfig['serializer']; + serializer?: MetroConfig['serializer'] & { + /** + * Filter function to determine which modules should be included in the bundle + * @param module - The module to filter + * @returns true if the module should be included, false otherwise + */ + processModuleFilter?: (module: Module) => boolean; + getModulesRunBeforeMainModule?: () => string[]; + }; /** * Partial support for some options only * diff --git a/packages/plugin-core/src/types/vendors/metro.ts b/packages/plugin-core/src/types/vendors/metro.ts index 8a5d03849..a96b1e146 100644 --- a/packages/plugin-core/src/types/vendors/metro.ts +++ b/packages/plugin-core/src/types/vendors/metro.ts @@ -224,4 +224,5 @@ export interface MetroConfig { readonly reporter?: { update: (event: ReportableEvent) => void; }; + readonly cacheVersion?: string; } diff --git a/packages/plugin-radon/LICENSE b/packages/plugin-radon/LICENSE new file mode 100644 index 000000000..f5f123df8 --- /dev/null +++ b/packages/plugin-radon/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2025 Viva Republica, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/plugin-radon/NOTICE b/packages/plugin-radon/NOTICE new file mode 100644 index 000000000..6fe271a1e --- /dev/null +++ b/packages/plugin-radon/NOTICE @@ -0,0 +1,69 @@ +NOTICE + +This project makes use of third-party libraries that are licensed under their respective open-source licenses. Below is a list of these libraries, their licenses, and their links for further reference. + +================================================================================ +Project Name: @granite-js/plugin-radon +Copyright 2025 Viva Republica, Inc + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +================================================================================ +Third-Party Libraries: + +1. **@vitest/coverage-v8** + + - License: MIT + - License Text: https://opensource.org/licenses/MIT + - Repository: git+https://github.com/vitest-dev/vitest.git + +2. **es-toolkit** + + - License: MIT + - License Text: https://opensource.org/licenses/MIT + - Repository: https://github.com/toss/es-toolkit.git + +3. **execa** + + - License: MIT + - License Text: https://opensource.org/licenses/MIT + - Repository: git+https://github.com/sindresorhus/execa.git + +4. **tsdown** + + - License: MIT + - License Text: https://opensource.org/licenses/MIT + - Repository: git+https://github.com/rolldown/tsdown.git + +5. **vitest** + + - License: MIT + - License Text: https://opensource.org/licenses/MIT + - Repository: git+https://github.com/vitest-dev/vitest.git + +6. **source-map** + + - License: BSD-3-Clause + - License Text: https://opensource.org/licenses/BSD-3-Clause + - Repository: http://github.com/mozilla/source-map.git + +7. **typescript** + + - License: Apache-2.0 + - License Text: https://www.apache.org/licenses/LICENSE-2.0 + - Repository: https://github.com/microsoft/TypeScript.git + + +================================================================================ + +For further details about each license, please refer to the provided links. If there are updates to these dependencies, this file should also be updated. \ No newline at end of file diff --git a/packages/plugin-radon/package.json b/packages/plugin-radon/package.json new file mode 100644 index 000000000..8e84c0f50 --- /dev/null +++ b/packages/plugin-radon/package.json @@ -0,0 +1,46 @@ +{ + "name": "@granite-js/plugin-radon", + "type": "module", + "version": "0.1.20", + "description": "Radon compilation plugin for Granite", + "scripts": { + "prepack": "yarn build", + "typecheck": "tsc --noEmit", + "test": "vitest --run --coverage --passWithNoTests", + "build": "tsdown", + "lint": "eslint . --ext .js,.jsx,.ts,.tsx" + }, + "types": "./dist/index.d.ts", + "exports": { + ".": { + "import": "./dist/index.js", + "require": "./dist/index.cjs" + }, + "./dist/*": "./dist/*", + "./package.json": "./package.json" + }, + "files": [ + "dist" + ], + "dependencies": { + "@granite-js/utils": "workspace:*", + "metro-react-native-babel-transformer": "0.76.8" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-native": ">=0.60.0" + }, + "devDependencies": { + "@babel/core": "7.23.9", + "@babel/template": "^7.27.2", + "@granite-js/plugin-core": "workspace:*", + "@types/babel__core": "^7.20.5", + "@types/babel__template": "^7", + "@types/node": "^22.10.2", + "@vitest/coverage-v8": "^3.1.3", + "tsdown": "^0.11.13", + "typescript": "^5.8.3", + "vitest": "^3.1.3" + }, + "sideEffects": false +} diff --git a/packages/plugin-radon/src/index.ts b/packages/plugin-radon/src/index.ts new file mode 100644 index 000000000..7e8414bec --- /dev/null +++ b/packages/plugin-radon/src/index.ts @@ -0,0 +1,5 @@ +export { radon } from './radonPlugin'; + +export { radonCorePlugin } from './radonCorePlugin'; + +export { radonGraniteRouter } from './radonGraniteRouterPlugin'; diff --git a/packages/plugin-radon/src/lib/granite_router/global_injector.js b/packages/plugin-radon/src/lib/granite_router/global_injector.js new file mode 100644 index 000000000..7c75e340b --- /dev/null +++ b/packages/plugin-radon/src/lib/granite_router/global_injector.js @@ -0,0 +1,38 @@ +/** + * Generate code to inject Granite Router detection and routes into global scope + * @param {Array} routes - Array of route objects from parseRouterGenFile + * @returns {string} - Code string to inject + */ +const generateGraniteInjectionCode = (routes) => { + const routesJson = JSON.stringify(routes, null, 2); + + return ` +// Mark that Granite Router is being used +globalThis.__GRANITE_ROUTER_DETECTED__ = true; + +// Inject auto-scanned routes +globalThis.__GRANITE_ROUTES = ${routesJson}; +`; +}; + +/** + * Inject Granite Router global variables into the program + * @param {Function} injectCode - Babel inject function + * @param {Object} programPath - Babel program path + * @param {Array} routes - Array of route objects + */ +const injectGraniteGlobals = (injectCode, programPath, routes) => { + try { + const graniteDetectionCode = generateGraniteInjectionCode(routes); + injectCode(programPath, graniteDetectionCode, false); + return true; + } catch (error) { + console.error('πŸ”₯ RADON BABEL PLUGIN: Failed to inject Granite detection code:', error); + return false; + } +}; + +module.exports = { + generateGraniteInjectionCode, + injectGraniteGlobals, +}; diff --git a/packages/plugin-radon/src/lib/granite_router/granite_navigation_plugin.js b/packages/plugin-radon/src/lib/granite_router/granite_navigation_plugin.js new file mode 100644 index 000000000..61b108570 --- /dev/null +++ b/packages/plugin-radon/src/lib/granite_router/granite_navigation_plugin.js @@ -0,0 +1,316 @@ +import { useEffect, useRef, useState } from 'react'; +import { computeRouteIdentifier, extractGraniteRouteList, sendNavigationChange } from './granite_router_helpers.js'; + +const graniteStore = { + currentRoute: { pathname: '/', params: {} }, + routes: [], + listeners: [], + + subscribeToStateChange: (callback) => { + graniteStore.listeners.push(callback); + return () => { + const index = graniteStore.listeners.indexOf(callback); + if (index > -1) { + graniteStore.listeners.splice(index, 1); + } + }; + }, + + routeInfoSnapshot: () => { + return graniteStore.currentRoute; + }, + + notifyStateChange: () => { + graniteStore.listeners.forEach((listener) => { + try { + listener(); + } catch (error) { + console.error('πŸ”₯ Radon Runtime: Error in state change listener:', error); + } + }); + }, + + // Update route + updateRoute: (newRoute) => { + graniteStore.currentRoute = newRoute; + graniteStore.notifyStateChange(); + }, +}; + +const getNavigationObject = () => { + return globalThis.__granite_real_navigation; +}; + +const connectToGraniteRouter = () => { + try { + const navigation = getNavigationObject(); + + if (navigation) { + return { + navigate: (pathname, params) => { + try { + navigation.navigate(pathname, params); + } catch (error) { + console.error('πŸ”₯ Radon Runtime: Navigation error:', error); + try { + navigation.dispatch({ + type: 'NAVIGATE', + payload: { name: pathname, params }, + }); + } catch (dispatchError) { + console.error('πŸ”₯ Radon Runtime: Dispatch navigation error:', dispatchError); + } + } + }, + back: () => { + try { + if (navigation.canGoBack()) { + navigation.goBack(); + } else { + console.warn('πŸ”₯ Radon Runtime: Cannot go back'); + } + } catch (error) { + console.error('πŸ”₯ Radon Runtime: Back navigation error:', error); + } + }, + canGoBack: () => { + try { + return navigation.canGoBack(); + } catch { + return false; + } + }, + }; + } + } catch (error) { + console.log('πŸ”₯ Radon Runtime: Real navigation not found, using fallback', error); + } + + return null; +}; + +if (!globalThis.__granite) { + globalThis.__granite = {}; +} + +if (!globalThis.__granite.router) { + globalThis.__granite.router = { + current: graniteStore.currentRoute, + navigate: (pathname, params) => { + const newRoute = { + pathname: pathname.startsWith('/') ? pathname : `/${pathname}`, + params: params || {}, + }; + + const realRouter = connectToGraniteRouter(); + if (realRouter) { + realRouter.navigate(pathname, params); + } else { + console.log('πŸ”₯ Radon Runtime: Real navigation not available, updating internal state only'); + } + + graniteStore.updateRoute(newRoute); + globalThis.__granite.router.current = newRoute; + }, + back: () => { + const realRouter = connectToGraniteRouter(); + if (realRouter) { + realRouter.back(); + } else { + console.log('πŸ”₯ Radon Runtime: Real navigation not available for back action'); + } + }, + canGoBack: () => { + const realRouter = connectToGraniteRouter(); + if (realRouter) { + return realRouter.canGoBack(); + } + return true; // fallback + }, + setParams: (params) => { + const newRoute = { + ...graniteStore.currentRoute, + params: { ...graniteStore.currentRoute.params, ...params }, + }; + graniteStore.updateRoute(newRoute); + globalThis.__granite.router.current = newRoute; + }, + + // Manual route registration function for RadonIDE (fallback) + registerRoute: (route) => { + if (!globalThis.__GRANITE_MANUAL_ROUTES) { + globalThis.__GRANITE_MANUAL_ROUTES = []; + } + + // Remove duplicates + const existingIndex = globalThis.__GRANITE_MANUAL_ROUTES.findIndex((r) => r.path === route.path); + if (existingIndex >= 0) { + globalThis.__GRANITE_MANUAL_ROUTES[existingIndex] = route; + } else { + globalThis.__GRANITE_MANUAL_ROUTES.push(route); + } + }, + + // Get registered route list + getRoutes: () => { + return globalThis.__GRANITE_ROUTES || globalThis.__GRANITE_MANUAL_ROUTES || []; + }, + }; +} + +// useRouter hook simulation for Granite Router +const useGraniteRouter = () => { + return { + navigate: globalThis.__granite.router.navigate, + back: globalThis.__granite.router.back, + canGoBack: globalThis.__granite.router.canGoBack, + setParams: globalThis.__granite.router.setParams, + }; +}; + +// Helper to register actual navigation object globally +globalThis.__granite_register_navigation = (navigation) => { + globalThis.__granite_real_navigation = navigation; + + // Sync current state to Granite store immediately upon registration + try { + const state = navigation.getState(); + if (state && state.routes && state.routes.length > 0) { + const currentRoute = state.routes[state.index]; + const routeInfo = { + pathname: currentRoute.name, + params: currentRoute.params || {}, + }; + + graniteStore.updateRoute(routeInfo); + } + } catch (error) { + console.log('πŸ”₯ Radon Runtime: Could not sync initial state:', error.message); + } +}; + +// useSyncExternalStore simulation for Granite Router +const useGraniteRouteInfo = () => { + const [routeInfo, setRouteInfo] = useState(graniteStore.routeInfoSnapshot()); + + useEffect(() => { + const unsubscribe = graniteStore.subscribeToStateChange(() => { + const newRouteInfo = graniteStore.routeInfoSnapshot(); + setRouteInfo(newRouteInfo); + }); + return unsubscribe; + }, []); + + return routeInfo; +}; + +// Actual React Navigation state change detection system +const useReactNavigationStateListener = (onNavigationChange) => { + useEffect(() => { + let isListenerAdded = false; + + const addNavigationListener = () => { + const navigation = globalThis.__granite_real_navigation; + if (navigation && navigation.addListener && !isListenerAdded) { + const unsubscribe = navigation.addListener('state', () => { + const state = navigation.getState(); + + if (state && state.routes && state.routes.length > 0) { + const currentRoute = state.routes[state.index]; + const routeInfo = { + pathname: currentRoute.name, + params: currentRoute.params || {}, + }; + + graniteStore.updateRoute(routeInfo); + } + }); + + isListenerAdded = true; + return unsubscribe; + } + return null; + }; + + // Try immediately + let unsubscribe = addNavigationListener(); + + // Retry periodically since navigation might be registered later + const interval = setInterval(() => { + if (!isListenerAdded) { + unsubscribe = addNavigationListener(); + } + }, 1000); + + return () => { + if (unsubscribe) { + unsubscribe(); + } + clearInterval(interval); + }; + }, [onNavigationChange]); +}; + +// Main hook identical to Expo Router structure +function useGraniteRouterPluginMainHook({ onNavigationChange, onRouteListChange }) { + const router = useGraniteRouter(); + const routeInfo = useGraniteRouteInfo(); + const previousRouteInfo = useRef(); + + // React Navigation state change detection (App β†’ RadonIDE sync) + useReactNavigationStateListener(onNavigationChange); + + const pathname = routeInfo?.pathname; + const params = routeInfo?.params; + + // Send route list (Granite Router auto-detection) + useEffect(() => { + const routes = globalThis.__GRANITE_ROUTES || []; + const routeList = extractGraniteRouteList(routes); + onRouteListChange(routeList); + }, [onRouteListChange]); + + // Navigation change detection (same method as Expo Router) + useEffect(() => { + sendNavigationChange(previousRouteInfo, routeInfo, onNavigationChange); + }, [pathname, params, onNavigationChange]); + + // Navigation request function (same signature as Expo Router) + function requestNavigationChange({ pathname, params }) { + if (pathname === '__BACK__') { + if (router.canGoBack()) { + router.back(); + } + return; + } + + router.navigate(pathname); + if (params && Object.keys(params).length > 0) { + router.setParams(params); + } + } + + // Same return format as Expo Router + return { + getCurrentNavigationDescriptor: () => { + const snapshot = graniteStore.routeInfoSnapshot(); + return { + name: snapshot.pathname, + pathname: snapshot.pathname, + params: snapshot.params, + id: computeRouteIdentifier(snapshot.pathname, snapshot.params), + }; + }, + requestNavigationChange: (navigationDescriptor) => { + requestNavigationChange(navigationDescriptor); + }, + }; +} + +// Same plugin registration method as Expo Router +// eslint-disable-next-line @typescript-eslint/no-unused-expressions +global.__RNIDE_register_navigation_plugin && + global.__RNIDE_register_navigation_plugin('granite-router', { mainHook: useGraniteRouterPluginMainHook }); + +// Export the hook for wrapper to use +export { useGraniteRouterPluginMainHook }; diff --git a/packages/plugin-radon/src/lib/granite_router/granite_router_helpers.js b/packages/plugin-radon/src/lib/granite_router/granite_router_helpers.js new file mode 100644 index 000000000..ba24e7894 --- /dev/null +++ b/packages/plugin-radon/src/lib/granite_router/granite_router_helpers.js @@ -0,0 +1,119 @@ +// Compute a unique identifier for a route based on pathname and params +export function computeRouteIdentifier(pathname, params) { + if (!params || Object.keys(params).length === 0) { + return pathname; + } + const query = new URLSearchParams(params).toString(); + return query ? `${pathname}?${query}` : pathname; +} + +export function checkNavigationDescriptorsEqual(a, b) { + if (!a || !b) { + return false; + } + if (a.pathname !== b.pathname) { + return false; + } + if (Object.keys(a.params || {}).length !== Object.keys(b.params || {}).length) { + return false; + } + return Object.keys(a).every((key) => deepEqual(a[key], b[key])); +} + +// Send navigation change event if the route has actually changed +export function sendNavigationChange(previousRouteInfo, routeInfo, onNavigationChange) { + const pathname = routeInfo?.pathname || routeInfo?.name; + const params = routeInfo?.params || {}; + + // Create display name with query params + const displayParams = new URLSearchParams(params).toString(); + const displayName = `${pathname}${displayParams ? `?${displayParams}` : ''}`; + + const hasChanged = + pathname && (!previousRouteInfo.current || !checkNavigationDescriptorsEqual(previousRouteInfo.current, routeInfo)); + + if (hasChanged) { + const navigationDescriptor = { + name: displayName, + pathname, + params, + id: computeRouteIdentifier(pathname, params), + }; + onNavigationChange(navigationDescriptor); + } + previousRouteInfo.current = routeInfo; +} + +// Extract route list from Granite Router's routes array (Expo Router style) +export function extractGraniteRouteList(routes) { + if (!routes || !Array.isArray(routes)) { + return []; + } + + const routeList = routes.map((route) => { + return { + path: route.path, + filePath: route.filePath || route.path, + children: route.children || [], + dynamic: route.dynamic || null, + type: route.type || 'route', + }; + }); + + // Same sorting method as Expo Router + const sortedRoutes = routeList.sort((a, b) => { + const aPath = a.path.split('/'); + const bPath = b.path.split('/'); + if (aPath.length === bPath.length) { + return a.path.localeCompare(b.path); + } + return aPath.length - bPath.length; + }); + + return sortedRoutes; +} + +// Parse route information from React Navigation state +export function parseNavigationState(state) { + if (!state || !state.routes || state.routes.length === 0) { + return null; + } + + const currentRoute = state.routes[state.index]; + return { + name: currentRoute.name, + pathname: currentRoute.name, // Granite Router uses paths like '/', '/about', '/page' + params: currentRoute.params || {}, + key: currentRoute.key, + routeNames: state.routeNames || [], // Available route names + canGoBack: state.index > 0, // Can go back if not at the first route + }; +} + +// Deep equality check for comparing navigation descriptors +function deepEqual(x, y) { + if (x === y) { + return true; + } + if (typeof x !== typeof y) { + return false; + } + if (x && y && typeof x === 'object') { + if (Array.isArray(x) && Array.isArray(y)) { + if (x.length !== y.length) { + return false; + } + return x.every((item, i) => deepEqual(item, y[i])); + } + if (Array.isArray(x) !== Array.isArray(y)) { + return false; + } + const keysX = Object.keys(x); + const keysY = Object.keys(y); + if (keysX.length !== keysY.length) { + return false; + } + return keysX.every((key) => deepEqual(x[key], y[key])); + } + return false; +} diff --git a/packages/plugin-radon/src/lib/granite_router/navigation_injector.js b/packages/plugin-radon/src/lib/granite_router/navigation_injector.js new file mode 100644 index 000000000..f638072b3 --- /dev/null +++ b/packages/plugin-radon/src/lib/granite_router/navigation_injector.js @@ -0,0 +1,148 @@ +/** + * Generate navigation registration code + * @param {string} navigationVariableName - Name of the navigation variable + * @returns {string} - Registration code to inject + */ +const generateNavigationRegistrationCode = (navigationVariableName) => { + return ` + // πŸ”₯ RadonIDE: Auto-register navigation object + React.useEffect(() => { + try { + if (globalThis.__granite_register_navigation && ${navigationVariableName}) { + globalThis.__granite_register_navigation(${navigationVariableName}); + } + } catch (error) { + console.log("πŸ”₯ Radon Runtime: Could not auto-register navigation:", error.message); + } + }, [${navigationVariableName}]); +`; +}; + +/** + * Check if a page file uses navigation-related imports + * @param {Object} programPath - Babel program path + * @returns {Object} - { usesNavigation: boolean, hasReactDefaultImport: boolean } + */ +const analyzePageImports = (programPath) => { + let usesNavigation = false; + let hasReactDefaultImport = false; + + programPath.traverse({ + ImportDeclaration(importPath) { + const source = importPath.node.source.value; + + if (source === 'react') { + importPath.node.specifiers.forEach((spec) => { + if (spec.type === 'ImportDefaultSpecifier') { + hasReactDefaultImport = true; + } + }); + } + + // Check for createRoute import (to prepare for Route.useNavigation pattern) + if (source === '@granite-js/react-native') { + importPath.node.specifiers.forEach((spec) => { + if (spec.type === 'ImportSpecifier' && spec.imported.name === 'useNavigation') { + usesNavigation = true; + } + if (spec.type === 'ImportSpecifier' && spec.imported.name === 'createRoute') { + usesNavigation = true; // If createRoute exists, likely to use Route.useNavigation + } + }); + } + }, + }); + + return { usesNavigation, hasReactDefaultImport }; +}; + +/** + * Process navigation variables and inject registration code + * @param {Object} programPath - Babel program path + * @param {Function} parse - Babel parse function + * @param {Object} t - Babel types + */ +const processNavigationVariables = (programPath, parse) => { + programPath.traverse({ + VariableDeclarator(variablePath) { + let isNavigationVariable = false; + let variableName = null; + + if (variablePath.node.init && variablePath.node.id.type === 'Identifier') { + variableName = variablePath.node.id.name; + + // Pattern 1: const navigation = useNavigation() + if ( + variablePath.node.init.type === 'CallExpression' && + variablePath.node.init.callee.name === 'useNavigation' + ) { + isNavigationVariable = true; + } + + // Pattern 2: const navigation = Route.useNavigation() + else if ( + variablePath.node.init.type === 'CallExpression' && + variablePath.node.init.callee.type === 'MemberExpression' && + variablePath.node.init.callee.property.name === 'useNavigation' + ) { + isNavigationVariable = true; + } + } + + if (isNavigationVariable && variableName) { + const parentFunction = variablePath.getFunctionParent(); + if (parentFunction) { + const registrationCode = generateNavigationRegistrationCode(variableName); + + const registrationAST = parse(registrationCode, { + sourceType: 'module', + filename: 'navigation-registration.js', + parserOpts: { allowReturnOutsideFunction: true }, + }); + + const statement = variablePath.getStatementParent(); + statement.insertAfter(registrationAST.program.body); + } + } + }, + }); +}; + +const processPageFile = (filename, programPath, parse, t, state) => { + const isPageFile = filename.includes('/pages/') && /\.(tsx|ts|jsx|js)$/.test(filename); + + if (!isPageFile || state.file.metadata.radonPageInjected) { + return false; + } + + try { + const { usesNavigation, hasReactDefaultImport } = analyzePageImports(programPath); + + if (usesNavigation) { + if (!hasReactDefaultImport) { + const reactImport = t.importDeclaration( + [t.importDefaultSpecifier(t.identifier('React'))], + t.stringLiteral('react') + ); + programPath.unshiftContainer('body', reactImport); + } + + processNavigationVariables(programPath, parse, t); + + state.file.metadata.radonPageInjected = true; + return true; + } + + return false; + } catch (error) { + console.error('πŸ”₯ RADON BABEL PLUGIN: Failed to process page file:', error); + return false; + } +}; + +module.exports = { + generateNavigationRegistrationCode, + analyzePageImports, + processNavigationVariables, + processPageFile, +}; diff --git a/packages/plugin-radon/src/lib/granite_router/router_parser.js b/packages/plugin-radon/src/lib/granite_router/router_parser.js new file mode 100644 index 000000000..6876872db --- /dev/null +++ b/packages/plugin-radon/src/lib/granite_router/router_parser.js @@ -0,0 +1,103 @@ +const fs = require('fs'); + +const parseRouterGenFile = (parse, routerGenPath) => { + try { + const content = fs.readFileSync(routerGenPath, 'utf8'); + const routes = []; + const routeTypeMap = new Map(); // path -> param types + + const ast = parse(content, { + sourceType: 'module', + filename: routerGenPath, + parserOpts: { + plugins: ['typescript', 'jsx'], + }, + }); + + const traverse = (node) => { + if (node.type === 'ImportDeclaration') { + const source = node.source.value; + if (source && source.startsWith('../pages/')) { + const pagePath = source.replace('../pages/', ''); + + const routeSpecifier = node.specifiers.find( + (spec) => + spec.type === 'ImportSpecifier' && spec.imported.name === 'Route' && spec.local.name.endsWith('Route') + ); + + if (routeSpecifier) { + const componentName = routeSpecifier.local.name.replace(/^_(.*)Route$/, '$1'); + const routePath = convertPagePathToRoute(pagePath); + + routes.push({ + path: routePath, + filePath: `./pages/${pagePath}.tsx`, + componentName: componentName, + type: 'route', + }); + } + } + } + + if ( + node.type === 'TSModuleDeclaration' && + node.id.type === 'StringLiteral' && + node.id.value === '@granite-js/react-native' + ) { + if (node.body && node.body.type === 'TSModuleBlock') { + node.body.body.forEach((stmt) => { + if (stmt.type === 'TSInterfaceDeclaration' && stmt.id.name === 'RegisterScreen') { + stmt.body.body.forEach((member) => { + if (member.type === 'TSPropertySignature' && member.key) { + const routePath = member.key.type === 'StringLiteral' ? member.key.value : member.key.name; + + if (member.typeAnnotation && member.typeAnnotation.typeAnnotation) { + routeTypeMap.set(routePath, { hasTypes: true }); + } + } + }); + } + }); + } + } + + for (const key in node) { + const child = node[key]; + if (Array.isArray(child)) { + child.forEach(traverse); + } else if (child && typeof child === 'object' && child.type) { + traverse(child); + } + } + }; + + traverse(ast); + + return routes; + } catch (error) { + console.error('πŸ”₯ RADON BABEL PLUGIN: Failed to parse router.gen.ts:', error); + return []; + } +}; + +const convertPagePathToRoute = (pagePath) => { + // index β†’ / + // about β†’ /about + // user/profile β†’ /user/profile + // user/[id] β†’ /user/:id + + let routePath = pagePath.replace(/\/index$/, '').replace(/\[([^\]]+)\]/g, ':$1'); + + if (!routePath || routePath === '' || routePath === 'index') { + routePath = '/'; + } else if (!routePath.startsWith('/')) { + routePath = '/' + routePath; + } + + return routePath; +}; + +module.exports = { + parseRouterGenFile, + convertPagePathToRoute, +}; diff --git a/packages/plugin-radon/src/radonCorePlugin.ts b/packages/plugin-radon/src/radonCorePlugin.ts new file mode 100644 index 000000000..8c21148ee --- /dev/null +++ b/packages/plugin-radon/src/radonCorePlugin.ts @@ -0,0 +1,38 @@ +import path from 'node:path'; +import type { GranitePluginCore } from '@granite-js/plugin-core'; +import { getPackageRoot } from '@granite-js/utils'; +import { detectRadonIdeExtensionPath } from './utils/detectRadonIdeExtensionPath'; +import { loadRadonMetroConfig } from './utils/loadRadonMetroConfig'; + +function ensureRadonIdeEnv() { + const appRoot = getPackageRoot(); + const radonIdePath = detectRadonIdeExtensionPath(); + + if (!radonIdePath) { + console.warn('[Radon] Extension not found, Radon IDE features will not be available'); + return; + } + const radonIdeLibPath = path.join(radonIdePath, 'lib'); + + const metroConfigPath = path.join(radonIdeLibPath, 'metro_config.js'); + + process.env.RN_IDE_METRO_CONFIG_PATH = metroConfigPath; + //TODO: μ–΄λ””μ„œ μ“°μ΄λŠ”μ§€ ν™•μΈν•˜κΈ° + process.env.NODE_PATH = path.join(appRoot, 'node_modules'); + process.env.RCT_METRO_PORT = '8081'; + process.env.RADON_IDE_LIB_PATH = radonIdeLibPath; + process.env.RADON_IDE_VERSION = '1.14.0'; + process.env.RADON_IDE_ORIG_BABEL_TRANSFORMER_PATH = require.resolve('metro-react-native-babel-transformer'); +} + +// import와 λ™μ‹œμ— λ„£μ–΄μ£ΌκΈ° +ensureRadonIdeEnv(); + +export const radonCorePlugin = (): GranitePluginCore => { + return { + name: 'radon-core-plugin', + config: { + metro: loadRadonMetroConfig(), + }, + }; +}; diff --git a/packages/plugin-radon/src/radonGraniteRouterPlugin.ts b/packages/plugin-radon/src/radonGraniteRouterPlugin.ts new file mode 100644 index 000000000..6dd1a5481 --- /dev/null +++ b/packages/plugin-radon/src/radonGraniteRouterPlugin.ts @@ -0,0 +1,28 @@ +import type { GranitePluginCore } from '@granite-js/plugin-core'; + +export interface RadonGraniteRouterPluginOptions { + enableRouteScanning?: boolean; +} + +const DEFAULT_OPTIONS: Required = { + enableRouteScanning: true, +}; +export const radonGraniteRouter = (options: RadonGraniteRouterPluginOptions = DEFAULT_OPTIONS): GranitePluginCore => { + const mergedOptions = { ...DEFAULT_OPTIONS, ...options }; + + return { + name: 'radon-metro-reporter', + config: { + babel: { + plugins: [ + [ + require.resolve('@granite-js/plugin-radon/dist/routerBabel.js'), + { + ...mergedOptions, + }, + ], + ], + }, + }, + }; +}; diff --git a/packages/plugin-radon/src/radonPlugin.ts b/packages/plugin-radon/src/radonPlugin.ts new file mode 100644 index 000000000..58ce64559 --- /dev/null +++ b/packages/plugin-radon/src/radonPlugin.ts @@ -0,0 +1,12 @@ +import type { GranitePlugin } from '@granite-js/plugin-core'; +import { radonCorePlugin } from './radonCorePlugin.js'; +import { radonGraniteRouter } from './radonGraniteRouterPlugin.js'; + +export const radon = (): GranitePlugin[] => { + const plugins: GranitePlugin[] = []; + + plugins.push(radonCorePlugin()); + plugins.push(radonGraniteRouter()); + + return plugins; +}; diff --git a/packages/plugin-radon/src/routerBabel.js b/packages/plugin-radon/src/routerBabel.js new file mode 100644 index 000000000..f5033c710 --- /dev/null +++ b/packages/plugin-radon/src/routerBabel.js @@ -0,0 +1,86 @@ +const fs = require('node:fs'); +const path = require('node:path'); +const { getPackageRoot } = require('@granite-js/utils'); +const { injectGraniteGlobals } = require('./lib/granite_router/global_injector'); +const { processPageFile } = require('./lib/granite_router/navigation_injector'); +const { parseRouterGenFile } = require('./lib/granite_router/router_parser'); + +module.exports = (api) => { + api.assertVersion(7); + + const { parse, types: t } = api; + + const appRoot = getPackageRoot(); + + const scanGraniteRoutes = () => { + try { + const routerGenPath = path.join(appRoot, 'src', 'router.gen.ts'); + + if (fs.existsSync(routerGenPath)) { + return parseRouterGenFile(parse, routerGenPath); + } + } catch (error) { + console.error('πŸ”₯ RADON BABEL PLUGIN: Route scanning failed:', error); + return [ + { + path: '/', + filePath: './pages/index.tsx', + type: 'route', + }, + ]; + } + }; + + // Helper to check if we're transforming a file from a specific package + const isTransforming = (packageName, filename) => { + if (!filename) { + return false; + } + // Check if filename includes the package name (could be in node_modules or package path) + return filename.includes(packageName); + }; + + // Helper to inject code into the program + const injectCode = (programPath, codeString, _prepend = false) => { + try { + const ast = parse(codeString, { + sourceType: 'module', + filename: 'injected-code.js', + }); + if (_prepend) { + programPath.unshiftContainer('body', ast.program.body); + } else { + programPath.pushContainer('body', ast.program.body); + } + } catch (error) { + console.error('πŸ”₯ RADON BABEL PLUGIN: Failed to parse injected code:', error); + throw error; + } + }; + + return { + name: 'radon-injector-plugin', + visitor: { + Program: { + enter(programPath, state) { + const filename = state.file.opts.filename || state.filename || ''; + + if (isTransforming('@granite-js/react-native', filename)) { + try { + const scannedRoutes = scanGraniteRoutes(); + const injected = injectGraniteGlobals(injectCode, programPath, scannedRoutes); + + if (injected) { + state.file.metadata.radonInjected = true; + } + } catch (e) { + console.error('πŸ”₯ RADON BABEL PLUGIN: Failed to inject Granite detection code:', e); + } + } + + processPageFile(filename, programPath, parse, t, state); + }, + }, + }, + }; +}; diff --git a/packages/plugin-radon/src/utils/detectRadonIdeExtensionPath.ts b/packages/plugin-radon/src/utils/detectRadonIdeExtensionPath.ts new file mode 100644 index 000000000..d8e9258e8 --- /dev/null +++ b/packages/plugin-radon/src/utils/detectRadonIdeExtensionPath.ts @@ -0,0 +1,33 @@ +import fs from 'node:fs'; +import path from 'node:path'; + +export function detectRadonIdeExtensionPath(): string | undefined { + const homeDir = process.env.HOME || process.env.USERPROFILE; + if (!homeDir) { + return undefined; + } + + // Check VSCode extensions + const vscodeExtPath = path.join(homeDir, '.vscode', 'extensions'); + + // Check Cursor extensions + const cursorExtPaths = path.join(homeDir, '.cursor', 'extensions'); + + const searchPaths = [vscodeExtPath, cursorExtPaths]; + + for (const searchPath of searchPaths) { + if (fs.existsSync(searchPath)) { + const entries = fs.readdirSync(searchPath); + // Match exact version: swmansion.react-native-ide-1.14.2-{platform} + const radonFolder = entries.find((entry) => /^swmansion\.react-native-ide-1\.14\.2-.+$/.test(entry)); + if (radonFolder) { + const fullPath = path.join(searchPath, radonFolder); + console.log(`[Radon] Found extension at: ${fullPath}`); + return fullPath; + } + } + } + + console.warn('[Radon] Extension not found'); + return undefined; +} diff --git a/packages/plugin-radon/src/utils/loadRadonMetroConfig.ts b/packages/plugin-radon/src/utils/loadRadonMetroConfig.ts new file mode 100644 index 000000000..cca40514b --- /dev/null +++ b/packages/plugin-radon/src/utils/loadRadonMetroConfig.ts @@ -0,0 +1,113 @@ +import fs from 'node:fs'; +import path from 'node:path'; +import vm from 'node:vm'; +import type { AdditionalMetroConfig } from '@granite-js/plugin-core'; + +type MetroHelpers = { + adaptMetroConfig: (config: AdditionalMetroConfig) => AdditionalMetroConfig; +}; + +export const loadRadonMetroConfig = (): AdditionalMetroConfig => { + const nodeRequire = require; + const requireCache = nodeRequire.cache; + const requireResolve = nodeRequire.resolve; + + const radonIdeLibPath = process.env.RADON_IDE_LIB_PATH; + if (!radonIdeLibPath) { + throw new Error('RADON_IDE_LIB_PATH not set'); + } + + const metroHelpersPath = path.join(radonIdeLibPath, 'metro_helpers.js'); + + const loadCjsFile = (filePath: string): MetroHelpers => { + const resolvedFilePath = path.isAbsolute(filePath) ? filePath : path.resolve(filePath); + const cached = requireCache[resolvedFilePath]; + if (cached) { + return cached.exports; + } + + const code = fs.readFileSync(resolvedFilePath, 'utf8'); + // biome-ignore lint/suspicious/noExplicitAny: NodeRequire module is deprecated + const module: any = { exports: {}, filename: resolvedFilePath }; + requireCache[resolvedFilePath] = module; + + const localRequire = ((specifier: string) => { + if (specifier.startsWith('.')) { + const basePath = path.resolve(path.dirname(resolvedFilePath), specifier); + const withExtension = fs.existsSync(basePath) + ? basePath + : ['.js', '.cjs', '.json'].map((ext) => `${basePath}${ext}`).find((candidate) => fs.existsSync(candidate)); + + if (!withExtension) { + return nodeRequire(specifier); + } + + if (withExtension.endsWith('.json')) { + return JSON.parse(fs.readFileSync(withExtension, 'utf8')); + } + + return loadCjsFile(withExtension); + } + + return nodeRequire(specifier); + }) as typeof require; + + localRequire.cache = requireCache; + localRequire.resolve = requireResolve; + + const wrapper = `(function (exports, require, module, __filename, __dirname) { ${code}\n})`; + const compiledWrapper = vm.runInThisContext(wrapper, { filename: resolvedFilePath }); + compiledWrapper(module.exports, localRequire, module, resolvedFilePath, path.dirname(resolvedFilePath)); + + return module.exports; + }; + + const metroHelpers = loadCjsFile(metroHelpersPath); + + // Radon's `adaptMetroConfig` expects a Metro config shape that includes `projectRoot` + // and an initial `transformer.babelTransformerPath`. It then moves that value to + // `process.env.RADON_IDE_ORIG_BABEL_TRANSFORMER_PATH` and replaces `babelTransformerPath` + // with its wrapper transformer. + const appRoot = process.cwd(); + const originalBabelTransformerPath = + process.env.RADON_IDE_ORIG_BABEL_TRANSFORMER_PATH ?? requireResolve('metro-react-native-babel-transformer'); + + const baseConfig: AdditionalMetroConfig = { + projectRoot: appRoot, + serializer: { + processModuleFilter: () => true, + }, + resolver: { + blockList: [], + extraNodeModules: {}, + nodeModulesPaths: [], + }, + transformer: { + babelTransformerPath: originalBabelTransformerPath, + }, + watchFolders: [], + cacheVersion: 'granite', + }; + + const adaptedConfig = metroHelpers.adaptMetroConfig(baseConfig); + + return { + serializer: { + processModuleFilter: adaptedConfig.serializer?.processModuleFilter, + }, + watchFolders: adaptedConfig.watchFolders, + resolver: { + resolveRequest: adaptedConfig.resolver?.resolveRequest, + blockList: adaptedConfig.resolver?.blockList, + extraNodeModules: { + ...adaptedConfig.resolver?.extraNodeModules, + }, + nodeModulesPaths: adaptedConfig.resolver?.nodeModulesPaths, + }, + transformer: { + babelTransformerPath: adaptedConfig.transformer?.babelTransformerPath, + }, + reporter: adaptedConfig.reporter, + cacheVersion: adaptedConfig.cacheVersion, + }; +}; diff --git a/packages/plugin-radon/tsconfig.json b/packages/plugin-radon/tsconfig.json new file mode 100644 index 000000000..6fd1da508 --- /dev/null +++ b/packages/plugin-radon/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "types": ["node"] + }, + "include": ["src"] +} diff --git a/packages/plugin-radon/tsdown.config.ts b/packages/plugin-radon/tsdown.config.ts new file mode 100644 index 000000000..48ca58535 --- /dev/null +++ b/packages/plugin-radon/tsdown.config.ts @@ -0,0 +1,17 @@ +import { defineConfig } from 'tsdown'; + +export default defineConfig([ + { + entry: ['src/index.ts'], + format: ['cjs', 'esm'], + dts: true, + minify: true, + }, + { + entry: 'src/routerBabel.js', + outDir: 'dist', + format: ['esm', 'cjs'], + dts: false, + minify: true, + }, +]); diff --git a/yarn.lock b/yarn.lock index 2bd9c369e..8fd175014 100644 --- a/yarn.lock +++ b/yarn.lock @@ -243,7 +243,7 @@ __metadata: languageName: node linkType: hard -"@ampproject/remapping@npm:^2.2.0": +"@ampproject/remapping@npm:^2.2.0, @ampproject/remapping@npm:^2.3.0": version: 2.3.0 resolution: "@ampproject/remapping@npm:2.3.0" dependencies: @@ -1150,7 +1150,7 @@ __metadata: languageName: node linkType: hard -"@babel/code-frame@npm:7.27.1, @babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.24.7, @babel/code-frame@npm:^7.27.1": +"@babel/code-frame@npm:7.27.1, @babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.23.5, @babel/code-frame@npm:^7.24.7, @babel/code-frame@npm:^7.27.1": version: 7.27.1 resolution: "@babel/code-frame@npm:7.27.1" dependencies: @@ -1175,6 +1175,29 @@ __metadata: languageName: node linkType: hard +"@babel/core@npm:7.23.9": + version: 7.23.9 + resolution: "@babel/core@npm:7.23.9" + dependencies: + "@ampproject/remapping": "npm:^2.2.0" + "@babel/code-frame": "npm:^7.23.5" + "@babel/generator": "npm:^7.23.6" + "@babel/helper-compilation-targets": "npm:^7.23.6" + "@babel/helper-module-transforms": "npm:^7.23.3" + "@babel/helpers": "npm:^7.23.9" + "@babel/parser": "npm:^7.23.9" + "@babel/template": "npm:^7.23.9" + "@babel/traverse": "npm:^7.23.9" + "@babel/types": "npm:^7.23.9" + convert-source-map: "npm:^2.0.0" + debug: "npm:^4.1.0" + gensync: "npm:^1.0.0-beta.2" + json5: "npm:^2.2.3" + semver: "npm:^6.3.1" + checksum: 10c0/03883300bf1252ab4c9ba5b52f161232dd52873dbe5cde9289bb2bb26e935c42682493acbac9194a59a3b6cbd17f4c4c84030db8d6d482588afe64531532ff9b + languageName: node + linkType: hard + "@babel/core@npm:7.28.5": version: 7.28.5 resolution: "@babel/core@npm:7.28.5" @@ -1244,7 +1267,7 @@ __metadata: languageName: node linkType: hard -"@babel/generator@npm:7.28.5, @babel/generator@npm:^7.28.5": +"@babel/generator@npm:7.28.5, @babel/generator@npm:^7.23.6, @babel/generator@npm:^7.28.0, @babel/generator@npm:^7.28.5": version: 7.28.5 resolution: "@babel/generator@npm:7.28.5" dependencies: @@ -1301,7 +1324,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-compilation-targets@npm:^7.20.7, @babel/helper-compilation-targets@npm:^7.22.6, @babel/helper-compilation-targets@npm:^7.27.1, @babel/helper-compilation-targets@npm:^7.27.2": +"@babel/helper-compilation-targets@npm:^7.20.7, @babel/helper-compilation-targets@npm:^7.22.6, @babel/helper-compilation-targets@npm:^7.23.6, @babel/helper-compilation-targets@npm:^7.27.1, @babel/helper-compilation-targets@npm:^7.27.2": version: 7.27.2 resolution: "@babel/helper-compilation-targets@npm:7.27.2" dependencies: @@ -1437,6 +1460,19 @@ __metadata: languageName: node linkType: hard +"@babel/helper-module-transforms@npm:^7.23.3, @babel/helper-module-transforms@npm:^7.28.3": + version: 7.28.3 + resolution: "@babel/helper-module-transforms@npm:7.28.3" + dependencies: + "@babel/helper-module-imports": "npm:^7.27.1" + "@babel/helper-validator-identifier": "npm:^7.27.1" + "@babel/traverse": "npm:^7.28.3" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10c0/549be62515a6d50cd4cfefcab1b005c47f89bd9135a22d602ee6a5e3a01f27571868ada10b75b033569f24dc4a2bb8d04bfa05ee75c16da7ade2d0db1437fcdb + languageName: node + linkType: hard + "@babel/helper-module-transforms@npm:^7.27.1": version: 7.27.1 resolution: "@babel/helper-module-transforms@npm:7.27.1" @@ -1463,19 +1499,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-module-transforms@npm:^7.28.3": - version: 7.28.3 - resolution: "@babel/helper-module-transforms@npm:7.28.3" - dependencies: - "@babel/helper-module-imports": "npm:^7.27.1" - "@babel/helper-validator-identifier": "npm:^7.27.1" - "@babel/traverse": "npm:^7.28.3" - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 10c0/549be62515a6d50cd4cfefcab1b005c47f89bd9135a22d602ee6a5e3a01f27571868ada10b75b033569f24dc4a2bb8d04bfa05ee75c16da7ade2d0db1437fcdb - languageName: node - linkType: hard - "@babel/helper-optimise-call-expression@npm:^7.27.1": version: 7.27.1 resolution: "@babel/helper-optimise-call-expression@npm:7.27.1" @@ -1567,6 +1590,16 @@ __metadata: languageName: node linkType: hard +"@babel/helpers@npm:^7.23.9, @babel/helpers@npm:^7.28.4": + version: 7.28.4 + resolution: "@babel/helpers@npm:7.28.4" + dependencies: + "@babel/template": "npm:^7.27.2" + "@babel/types": "npm:^7.28.4" + checksum: 10c0/aaa5fb8098926dfed5f223adf2c5e4c7fbba4b911b73dfec2d7d3083f8ba694d201a206db673da2d9b3ae8c01793e795767654558c450c8c14b4c2175b4fcb44 + languageName: node + linkType: hard + "@babel/helpers@npm:^7.27.1": version: 7.27.1 resolution: "@babel/helpers@npm:7.27.1" @@ -1587,17 +1620,7 @@ __metadata: languageName: node linkType: hard -"@babel/helpers@npm:^7.28.4": - version: 7.28.4 - resolution: "@babel/helpers@npm:7.28.4" - dependencies: - "@babel/template": "npm:^7.27.2" - "@babel/types": "npm:^7.28.4" - checksum: 10c0/aaa5fb8098926dfed5f223adf2c5e4c7fbba4b911b73dfec2d7d3083f8ba694d201a206db673da2d9b3ae8c01793e795767654558c450c8c14b4c2175b4fcb44 - languageName: node - linkType: hard - -"@babel/parser@npm:7.28.5, @babel/parser@npm:^7.28.5": +"@babel/parser@npm:7.28.5, @babel/parser@npm:^7.25.4, @babel/parser@npm:^7.28.0, @babel/parser@npm:^7.28.5": version: 7.28.5 resolution: "@babel/parser@npm:7.28.5" dependencies: @@ -3280,7 +3303,7 @@ __metadata: languageName: node linkType: hard -"@babel/template@npm:7.27.2, @babel/template@npm:^7.0.0, @babel/template@npm:^7.25.0, @babel/template@npm:^7.27.1, @babel/template@npm:^7.27.2, @babel/template@npm:^7.3.3": +"@babel/template@npm:7.27.2, @babel/template@npm:^7.0.0, @babel/template@npm:^7.23.9, @babel/template@npm:^7.25.0, @babel/template@npm:^7.27.1, @babel/template@npm:^7.27.2, @babel/template@npm:^7.3.3": version: 7.27.2 resolution: "@babel/template@npm:7.27.2" dependencies: @@ -3306,7 +3329,7 @@ __metadata: languageName: node linkType: hard -"@babel/traverse@npm:7.28.5, @babel/traverse@npm:^7.28.0, @babel/traverse@npm:^7.28.3, @babel/traverse@npm:^7.28.4, @babel/traverse@npm:^7.28.5": +"@babel/traverse@npm:7.28.5, @babel/traverse@npm:^7.23.9, @babel/traverse@npm:^7.28.0, @babel/traverse@npm:^7.28.3, @babel/traverse@npm:^7.28.4, @babel/traverse@npm:^7.28.5": version: 7.28.5 resolution: "@babel/traverse@npm:7.28.5" dependencies: @@ -3336,7 +3359,7 @@ __metadata: languageName: node linkType: hard -"@babel/types@npm:7.28.5, @babel/types@npm:^7.28.4, @babel/types@npm:^7.28.5": +"@babel/types@npm:7.28.5, @babel/types@npm:^7.23.9, @babel/types@npm:^7.25.4, @babel/types@npm:^7.28.1, @babel/types@npm:^7.28.4, @babel/types@npm:^7.28.5": version: 7.28.5 resolution: "@babel/types@npm:7.28.5" dependencies: @@ -4014,6 +4037,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/aix-ppc64@npm:0.27.1": + version: 0.27.1 + resolution: "@esbuild/aix-ppc64@npm:0.27.1" + conditions: os=aix & cpu=ppc64 + languageName: node + linkType: hard + "@esbuild/android-arm64@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/android-arm64@npm:0.17.19" @@ -4049,6 +4079,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/android-arm64@npm:0.27.1": + version: 0.27.1 + resolution: "@esbuild/android-arm64@npm:0.27.1" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/android-arm@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/android-arm@npm:0.17.19" @@ -4084,6 +4121,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/android-arm@npm:0.27.1": + version: 0.27.1 + resolution: "@esbuild/android-arm@npm:0.27.1" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + "@esbuild/android-x64@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/android-x64@npm:0.17.19" @@ -4119,6 +4163,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/android-x64@npm:0.27.1": + version: 0.27.1 + resolution: "@esbuild/android-x64@npm:0.27.1" + conditions: os=android & cpu=x64 + languageName: node + linkType: hard + "@esbuild/darwin-arm64@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/darwin-arm64@npm:0.17.19" @@ -4154,6 +4205,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/darwin-arm64@npm:0.27.1": + version: 0.27.1 + resolution: "@esbuild/darwin-arm64@npm:0.27.1" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/darwin-x64@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/darwin-x64@npm:0.17.19" @@ -4189,6 +4247,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/darwin-x64@npm:0.27.1": + version: 0.27.1 + resolution: "@esbuild/darwin-x64@npm:0.27.1" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + "@esbuild/freebsd-arm64@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/freebsd-arm64@npm:0.17.19" @@ -4224,6 +4289,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/freebsd-arm64@npm:0.27.1": + version: 0.27.1 + resolution: "@esbuild/freebsd-arm64@npm:0.27.1" + conditions: os=freebsd & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/freebsd-x64@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/freebsd-x64@npm:0.17.19" @@ -4259,6 +4331,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/freebsd-x64@npm:0.27.1": + version: 0.27.1 + resolution: "@esbuild/freebsd-x64@npm:0.27.1" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + "@esbuild/linux-arm64@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/linux-arm64@npm:0.17.19" @@ -4294,6 +4373,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-arm64@npm:0.27.1": + version: 0.27.1 + resolution: "@esbuild/linux-arm64@npm:0.27.1" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/linux-arm@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/linux-arm@npm:0.17.19" @@ -4329,6 +4415,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-arm@npm:0.27.1": + version: 0.27.1 + resolution: "@esbuild/linux-arm@npm:0.27.1" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + "@esbuild/linux-ia32@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/linux-ia32@npm:0.17.19" @@ -4364,6 +4457,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-ia32@npm:0.27.1": + version: 0.27.1 + resolution: "@esbuild/linux-ia32@npm:0.27.1" + conditions: os=linux & cpu=ia32 + languageName: node + linkType: hard + "@esbuild/linux-loong64@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/linux-loong64@npm:0.17.19" @@ -4399,6 +4499,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-loong64@npm:0.27.1": + version: 0.27.1 + resolution: "@esbuild/linux-loong64@npm:0.27.1" + conditions: os=linux & cpu=loong64 + languageName: node + linkType: hard + "@esbuild/linux-mips64el@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/linux-mips64el@npm:0.17.19" @@ -4434,6 +4541,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-mips64el@npm:0.27.1": + version: 0.27.1 + resolution: "@esbuild/linux-mips64el@npm:0.27.1" + conditions: os=linux & cpu=mips64el + languageName: node + linkType: hard + "@esbuild/linux-ppc64@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/linux-ppc64@npm:0.17.19" @@ -4469,6 +4583,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-ppc64@npm:0.27.1": + version: 0.27.1 + resolution: "@esbuild/linux-ppc64@npm:0.27.1" + conditions: os=linux & cpu=ppc64 + languageName: node + linkType: hard + "@esbuild/linux-riscv64@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/linux-riscv64@npm:0.17.19" @@ -4504,6 +4625,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-riscv64@npm:0.27.1": + version: 0.27.1 + resolution: "@esbuild/linux-riscv64@npm:0.27.1" + conditions: os=linux & cpu=riscv64 + languageName: node + linkType: hard + "@esbuild/linux-s390x@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/linux-s390x@npm:0.17.19" @@ -4539,6 +4667,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-s390x@npm:0.27.1": + version: 0.27.1 + resolution: "@esbuild/linux-s390x@npm:0.27.1" + conditions: os=linux & cpu=s390x + languageName: node + linkType: hard + "@esbuild/linux-x64@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/linux-x64@npm:0.17.19" @@ -4574,6 +4709,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-x64@npm:0.27.1": + version: 0.27.1 + resolution: "@esbuild/linux-x64@npm:0.27.1" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + "@esbuild/netbsd-arm64@npm:0.25.4": version: 0.25.4 resolution: "@esbuild/netbsd-arm64@npm:0.25.4" @@ -4588,6 +4730,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/netbsd-arm64@npm:0.27.1": + version: 0.27.1 + resolution: "@esbuild/netbsd-arm64@npm:0.27.1" + conditions: os=netbsd & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/netbsd-x64@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/netbsd-x64@npm:0.17.19" @@ -4623,6 +4772,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/netbsd-x64@npm:0.27.1": + version: 0.27.1 + resolution: "@esbuild/netbsd-x64@npm:0.27.1" + conditions: os=netbsd & cpu=x64 + languageName: node + linkType: hard + "@esbuild/openbsd-arm64@npm:0.25.4": version: 0.25.4 resolution: "@esbuild/openbsd-arm64@npm:0.25.4" @@ -4637,6 +4793,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/openbsd-arm64@npm:0.27.1": + version: 0.27.1 + resolution: "@esbuild/openbsd-arm64@npm:0.27.1" + conditions: os=openbsd & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/openbsd-x64@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/openbsd-x64@npm:0.17.19" @@ -4672,6 +4835,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/openbsd-x64@npm:0.27.1": + version: 0.27.1 + resolution: "@esbuild/openbsd-x64@npm:0.27.1" + conditions: os=openbsd & cpu=x64 + languageName: node + linkType: hard + "@esbuild/openharmony-arm64@npm:0.25.8": version: 0.25.8 resolution: "@esbuild/openharmony-arm64@npm:0.25.8" @@ -4679,6 +4849,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/openharmony-arm64@npm:0.27.1": + version: 0.27.1 + resolution: "@esbuild/openharmony-arm64@npm:0.27.1" + conditions: os=openharmony & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/sunos-x64@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/sunos-x64@npm:0.17.19" @@ -4714,6 +4891,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/sunos-x64@npm:0.27.1": + version: 0.27.1 + resolution: "@esbuild/sunos-x64@npm:0.27.1" + conditions: os=sunos & cpu=x64 + languageName: node + linkType: hard + "@esbuild/win32-arm64@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/win32-arm64@npm:0.17.19" @@ -4749,6 +4933,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/win32-arm64@npm:0.27.1": + version: 0.27.1 + resolution: "@esbuild/win32-arm64@npm:0.27.1" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/win32-ia32@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/win32-ia32@npm:0.17.19" @@ -4784,6 +4975,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/win32-ia32@npm:0.27.1": + version: 0.27.1 + resolution: "@esbuild/win32-ia32@npm:0.27.1" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + "@esbuild/win32-x64@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/win32-x64@npm:0.17.19" @@ -4819,6 +5017,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/win32-x64@npm:0.27.1": + version: 0.27.1 + resolution: "@esbuild/win32-x64@npm:0.27.1" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@eslint-community/eslint-utils@npm:^4.2.0, @eslint-community/eslint-utils@npm:^4.4.0, @eslint-community/eslint-utils@npm:^4.7.0": version: 4.7.0 resolution: "@eslint-community/eslint-utils@npm:4.7.0" @@ -5512,6 +5717,28 @@ __metadata: languageName: unknown linkType: soft +"@granite-js/plugin-radon@workspace:packages/plugin-radon": + version: 0.0.0-use.local + resolution: "@granite-js/plugin-radon@workspace:packages/plugin-radon" + dependencies: + "@babel/core": "npm:7.23.9" + "@babel/template": "npm:^7.27.2" + "@granite-js/plugin-core": "workspace:*" + "@granite-js/utils": "workspace:*" + "@types/babel__core": "npm:^7.20.5" + "@types/babel__template": "npm:^7" + "@types/node": "npm:^22.10.2" + "@vitest/coverage-v8": "npm:^3.1.3" + metro-react-native-babel-transformer: "npm:0.76.8" + tsdown: "npm:^0.11.13" + typescript: "npm:^5.8.3" + vitest: "npm:^3.1.3" + peerDependencies: + react: ">=16.8.0" + react-native: ">=0.60.0" + languageName: unknown + linkType: soft + "@granite-js/plugin-router@workspace:*, @granite-js/plugin-router@workspace:packages/plugin-router": version: 0.0.0-use.local resolution: "@granite-js/plugin-router@workspace:packages/plugin-router" @@ -6488,6 +6715,17 @@ __metadata: languageName: node linkType: hard +"@napi-rs/wasm-runtime@npm:^0.2.4": + version: 0.2.12 + resolution: "@napi-rs/wasm-runtime@npm:0.2.12" + dependencies: + "@emnapi/core": "npm:^1.4.3" + "@emnapi/runtime": "npm:^1.4.3" + "@tybys/wasm-util": "npm:^0.10.0" + checksum: 10c0/6d07922c0613aab30c6a497f4df297ca7c54e5b480e00035e0209b872d5c6aab7162fc49477267556109c2c7ed1eb9c65a174e27e9b87568106a87b0a6e3ca7d + languageName: node + linkType: hard + "@napi-rs/wasm-runtime@npm:^1.0.7": version: 1.0.7 resolution: "@napi-rs/wasm-runtime@npm:1.0.7" @@ -7045,6 +7283,13 @@ __metadata: languageName: node linkType: hard +"@oxc-project/types@npm:0.70.0": + version: 0.70.0 + resolution: "@oxc-project/types@npm:0.70.0" + checksum: 10c0/c293ccdb194c1b7045d2076ac67bc686e0e28c35b484627885c41eb50bd7acd81338e6777b8433149628a3b06b6afef27ded166998530db08a432ba9dff78b7c + languageName: node + linkType: hard + "@oxc-project/types@npm:=0.97.0": version: 0.97.0 resolution: "@oxc-project/types@npm:0.97.0" @@ -7337,6 +7582,15 @@ __metadata: languageName: node linkType: hard +"@quansync/fs@npm:^1.0.0": + version: 1.0.0 + resolution: "@quansync/fs@npm:1.0.0" + dependencies: + quansync: "npm:^1.0.0" + checksum: 10c0/41a7e145d4fc349eaeac20ee7ffe0c876a7c26b2268d5704b462b3e7379091221336e315b2b346d5b07a531502a41cad15c9f374800cc60b6339d074ef99aa16 + languageName: node + linkType: hard + "@react-native-async-storage/async-storage@npm:1.18.2": version: 1.18.2 resolution: "@react-native-async-storage/async-storage@npm:1.18.2" @@ -7846,6 +8100,13 @@ __metadata: languageName: node linkType: hard +"@rolldown/binding-darwin-arm64@npm:1.0.0-beta.9": + version: 1.0.0-beta.9 + resolution: "@rolldown/binding-darwin-arm64@npm:1.0.0-beta.9" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + "@rolldown/binding-darwin-x64@npm:1.0.0-beta.50": version: 1.0.0-beta.50 resolution: "@rolldown/binding-darwin-x64@npm:1.0.0-beta.50" @@ -7853,6 +8114,13 @@ __metadata: languageName: node linkType: hard +"@rolldown/binding-darwin-x64@npm:1.0.0-beta.9": + version: 1.0.0-beta.9 + resolution: "@rolldown/binding-darwin-x64@npm:1.0.0-beta.9" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + "@rolldown/binding-freebsd-x64@npm:1.0.0-beta.50": version: 1.0.0-beta.50 resolution: "@rolldown/binding-freebsd-x64@npm:1.0.0-beta.50" @@ -7860,6 +8128,13 @@ __metadata: languageName: node linkType: hard +"@rolldown/binding-freebsd-x64@npm:1.0.0-beta.9": + version: 1.0.0-beta.9 + resolution: "@rolldown/binding-freebsd-x64@npm:1.0.0-beta.9" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + "@rolldown/binding-linux-arm-gnueabihf@npm:1.0.0-beta.50": version: 1.0.0-beta.50 resolution: "@rolldown/binding-linux-arm-gnueabihf@npm:1.0.0-beta.50" @@ -7867,6 +8142,13 @@ __metadata: languageName: node linkType: hard +"@rolldown/binding-linux-arm-gnueabihf@npm:1.0.0-beta.9": + version: 1.0.0-beta.9 + resolution: "@rolldown/binding-linux-arm-gnueabihf@npm:1.0.0-beta.9" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + "@rolldown/binding-linux-arm64-gnu@npm:1.0.0-beta.50": version: 1.0.0-beta.50 resolution: "@rolldown/binding-linux-arm64-gnu@npm:1.0.0-beta.50" @@ -7874,6 +8156,13 @@ __metadata: languageName: node linkType: hard +"@rolldown/binding-linux-arm64-gnu@npm:1.0.0-beta.9": + version: 1.0.0-beta.9 + resolution: "@rolldown/binding-linux-arm64-gnu@npm:1.0.0-beta.9" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + "@rolldown/binding-linux-arm64-musl@npm:1.0.0-beta.50": version: 1.0.0-beta.50 resolution: "@rolldown/binding-linux-arm64-musl@npm:1.0.0-beta.50" @@ -7881,6 +8170,13 @@ __metadata: languageName: node linkType: hard +"@rolldown/binding-linux-arm64-musl@npm:1.0.0-beta.9": + version: 1.0.0-beta.9 + resolution: "@rolldown/binding-linux-arm64-musl@npm:1.0.0-beta.9" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + "@rolldown/binding-linux-x64-gnu@npm:1.0.0-beta.50": version: 1.0.0-beta.50 resolution: "@rolldown/binding-linux-x64-gnu@npm:1.0.0-beta.50" @@ -7888,6 +8184,13 @@ __metadata: languageName: node linkType: hard +"@rolldown/binding-linux-x64-gnu@npm:1.0.0-beta.9": + version: 1.0.0-beta.9 + resolution: "@rolldown/binding-linux-x64-gnu@npm:1.0.0-beta.9" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + "@rolldown/binding-linux-x64-musl@npm:1.0.0-beta.50": version: 1.0.0-beta.50 resolution: "@rolldown/binding-linux-x64-musl@npm:1.0.0-beta.50" @@ -7895,6 +8198,13 @@ __metadata: languageName: node linkType: hard +"@rolldown/binding-linux-x64-musl@npm:1.0.0-beta.9": + version: 1.0.0-beta.9 + resolution: "@rolldown/binding-linux-x64-musl@npm:1.0.0-beta.9" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + "@rolldown/binding-openharmony-arm64@npm:1.0.0-beta.50": version: 1.0.0-beta.50 resolution: "@rolldown/binding-openharmony-arm64@npm:1.0.0-beta.50" @@ -7911,6 +8221,15 @@ __metadata: languageName: node linkType: hard +"@rolldown/binding-wasm32-wasi@npm:1.0.0-beta.9": + version: 1.0.0-beta.9 + resolution: "@rolldown/binding-wasm32-wasi@npm:1.0.0-beta.9" + dependencies: + "@napi-rs/wasm-runtime": "npm:^0.2.4" + conditions: cpu=wasm32 + languageName: node + linkType: hard + "@rolldown/binding-win32-arm64-msvc@npm:1.0.0-beta.50": version: 1.0.0-beta.50 resolution: "@rolldown/binding-win32-arm64-msvc@npm:1.0.0-beta.50" @@ -7918,6 +8237,13 @@ __metadata: languageName: node linkType: hard +"@rolldown/binding-win32-arm64-msvc@npm:1.0.0-beta.9": + version: 1.0.0-beta.9 + resolution: "@rolldown/binding-win32-arm64-msvc@npm:1.0.0-beta.9" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + "@rolldown/binding-win32-ia32-msvc@npm:1.0.0-beta.50": version: 1.0.0-beta.50 resolution: "@rolldown/binding-win32-ia32-msvc@npm:1.0.0-beta.50" @@ -7925,6 +8251,13 @@ __metadata: languageName: node linkType: hard +"@rolldown/binding-win32-ia32-msvc@npm:1.0.0-beta.9": + version: 1.0.0-beta.9 + resolution: "@rolldown/binding-win32-ia32-msvc@npm:1.0.0-beta.9" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + "@rolldown/binding-win32-x64-msvc@npm:1.0.0-beta.50": version: 1.0.0-beta.50 resolution: "@rolldown/binding-win32-x64-msvc@npm:1.0.0-beta.50" @@ -7932,6 +8265,13 @@ __metadata: languageName: node linkType: hard +"@rolldown/binding-win32-x64-msvc@npm:1.0.0-beta.9": + version: 1.0.0-beta.9 + resolution: "@rolldown/binding-win32-x64-msvc@npm:1.0.0-beta.9" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@rolldown/pluginutils@npm:1.0.0-beta.50": version: 1.0.0-beta.50 resolution: "@rolldown/pluginutils@npm:1.0.0-beta.50" @@ -7939,6 +8279,13 @@ __metadata: languageName: node linkType: hard +"@rolldown/pluginutils@npm:1.0.0-beta.9": + version: 1.0.0-beta.9 + resolution: "@rolldown/pluginutils@npm:1.0.0-beta.9" + checksum: 10c0/21aebb7ebd093282efd96f63ddd465f76746b1d70282366d6ccc7fff6eb4da5c2f8f4bfaaaeb4283c2432600e5609e39e9897864575e593efc11d376ca1a6fa1 + languageName: node + linkType: hard + "@rollup/rollup-android-arm-eabi@npm:4.41.1": version: 4.41.1 resolution: "@rollup/rollup-android-arm-eabi@npm:4.41.1" @@ -9589,7 +9936,7 @@ __metadata: languageName: node linkType: hard -"@tybys/wasm-util@npm:^0.10.1": +"@tybys/wasm-util@npm:^0.10.0, @tybys/wasm-util@npm:^0.10.1": version: 0.10.1 resolution: "@tybys/wasm-util@npm:0.10.1" dependencies: @@ -9914,13 +10261,13 @@ __metadata: languageName: node linkType: hard -"@types/kill-port@npm:^2.0.1": - version: 2.0.3 - resolution: "@types/kill-port@npm:2.0.3" +"@types/kill-port@npm:2.0.1": + version: 2.0.1 + resolution: "@types/kill-port@npm:2.0.1" dependencies: "@types/node": "npm:*" shell-exec: "npm:^1" - checksum: 10c0/e48aa96134f01770ec729e0cc0da6388a0fbbf659e69a3e993fad9d12c48a258b3a70741699b51e5b35f664fa065ebde5a2fe25fea98dcc5eed2abdeb2b76c47 + checksum: 10c0/809f049be96ea839dcde8daebf69ca72421807eec6b48cc14321f439fb7bf6495104d30051f0d84aa09f6ccd5e5fcf6f4d7aac31b89ea210e77827afd10f742d languageName: node linkType: hard @@ -10450,6 +10797,33 @@ __metadata: languageName: node linkType: hard +"@vitest/coverage-v8@npm:^3.1.3": + version: 3.2.4 + resolution: "@vitest/coverage-v8@npm:3.2.4" + dependencies: + "@ampproject/remapping": "npm:^2.3.0" + "@bcoe/v8-coverage": "npm:^1.0.2" + ast-v8-to-istanbul: "npm:^0.3.3" + debug: "npm:^4.4.1" + istanbul-lib-coverage: "npm:^3.2.2" + istanbul-lib-report: "npm:^3.0.1" + istanbul-lib-source-maps: "npm:^5.0.6" + istanbul-reports: "npm:^3.1.7" + magic-string: "npm:^0.30.17" + magicast: "npm:^0.3.5" + std-env: "npm:^3.9.0" + test-exclude: "npm:^7.0.1" + tinyrainbow: "npm:^2.0.0" + peerDependencies: + "@vitest/browser": 3.2.4 + vitest: 3.2.4 + peerDependenciesMeta: + "@vitest/browser": + optional: true + checksum: 10c0/cae3e58d81d56e7e1cdecd7b5baab7edd0ad9dee8dec9353c52796e390e452377d3f04174d40b6986b17c73241a5e773e422931eaa8102dcba0605ff24b25193 + languageName: node + linkType: hard + "@vitest/coverage-v8@npm:^4.0.12": version: 4.0.12 resolution: "@vitest/coverage-v8@npm:4.0.12" @@ -10475,6 +10849,19 @@ __metadata: languageName: node linkType: hard +"@vitest/expect@npm:3.2.4": + version: 3.2.4 + resolution: "@vitest/expect@npm:3.2.4" + dependencies: + "@types/chai": "npm:^5.2.2" + "@vitest/spy": "npm:3.2.4" + "@vitest/utils": "npm:3.2.4" + chai: "npm:^5.2.0" + tinyrainbow: "npm:^2.0.0" + checksum: 10c0/7586104e3fd31dbe1e6ecaafb9a70131e4197dce2940f727b6a84131eee3decac7b10f9c7c72fa5edbdb68b6f854353bd4c0fa84779e274207fb7379563b10db + languageName: node + linkType: hard + "@vitest/expect@npm:4.0.12": version: 4.0.12 resolution: "@vitest/expect@npm:4.0.12" @@ -10489,6 +10876,25 @@ __metadata: languageName: node linkType: hard +"@vitest/mocker@npm:3.2.4": + version: 3.2.4 + resolution: "@vitest/mocker@npm:3.2.4" + dependencies: + "@vitest/spy": "npm:3.2.4" + estree-walker: "npm:^3.0.3" + magic-string: "npm:^0.30.17" + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + checksum: 10c0/f7a4aea19bbbf8f15905847ee9143b6298b2c110f8b64789224cb0ffdc2e96f9802876aa2ca83f1ec1b6e1ff45e822abb34f0054c24d57b29ab18add06536ccd + languageName: node + linkType: hard + "@vitest/mocker@npm:4.0.12": version: 4.0.12 resolution: "@vitest/mocker@npm:4.0.12" @@ -10508,6 +10914,15 @@ __metadata: languageName: node linkType: hard +"@vitest/pretty-format@npm:3.2.4, @vitest/pretty-format@npm:^3.2.4": + version: 3.2.4 + resolution: "@vitest/pretty-format@npm:3.2.4" + dependencies: + tinyrainbow: "npm:^2.0.0" + checksum: 10c0/5ad7d4278e067390d7d633e307fee8103958806a419ca380aec0e33fae71b44a64415f7a9b4bc11635d3c13d4a9186111c581d3cef9c65cc317e68f077456887 + languageName: node + linkType: hard + "@vitest/pretty-format@npm:4.0.12": version: 4.0.12 resolution: "@vitest/pretty-format@npm:4.0.12" @@ -10517,6 +10932,17 @@ __metadata: languageName: node linkType: hard +"@vitest/runner@npm:3.2.4": + version: 3.2.4 + resolution: "@vitest/runner@npm:3.2.4" + dependencies: + "@vitest/utils": "npm:3.2.4" + pathe: "npm:^2.0.3" + strip-literal: "npm:^3.0.0" + checksum: 10c0/e8be51666c72b3668ae3ea348b0196656a4a5adb836cb5e270720885d9517421815b0d6c98bfdf1795ed02b994b7bfb2b21566ee356a40021f5bf4f6ed4e418a + languageName: node + linkType: hard + "@vitest/runner@npm:4.0.12": version: 4.0.12 resolution: "@vitest/runner@npm:4.0.12" @@ -10527,6 +10953,17 @@ __metadata: languageName: node linkType: hard +"@vitest/snapshot@npm:3.2.4": + version: 3.2.4 + resolution: "@vitest/snapshot@npm:3.2.4" + dependencies: + "@vitest/pretty-format": "npm:3.2.4" + magic-string: "npm:^0.30.17" + pathe: "npm:^2.0.3" + checksum: 10c0/f8301a3d7d1559fd3d59ed51176dd52e1ed5c2d23aa6d8d6aa18787ef46e295056bc726a021698d8454c16ed825ecba163362f42fa90258bb4a98cfd2c9424fc + languageName: node + linkType: hard + "@vitest/snapshot@npm:4.0.12": version: 4.0.12 resolution: "@vitest/snapshot@npm:4.0.12" @@ -10538,6 +10975,15 @@ __metadata: languageName: node linkType: hard +"@vitest/spy@npm:3.2.4": + version: 3.2.4 + resolution: "@vitest/spy@npm:3.2.4" + dependencies: + tinyspy: "npm:^4.0.3" + checksum: 10c0/6ebf0b4697dc238476d6b6a60c76ba9eb1dd8167a307e30f08f64149612fd50227682b876420e4c2e09a76334e73f72e3ebf0e350714dc22474258292e202024 + languageName: node + linkType: hard + "@vitest/spy@npm:4.0.12": version: 4.0.12 resolution: "@vitest/spy@npm:4.0.12" @@ -10545,6 +10991,17 @@ __metadata: languageName: node linkType: hard +"@vitest/utils@npm:3.2.4": + version: 3.2.4 + resolution: "@vitest/utils@npm:3.2.4" + dependencies: + "@vitest/pretty-format": "npm:3.2.4" + loupe: "npm:^3.1.4" + tinyrainbow: "npm:^2.0.0" + checksum: 10c0/024a9b8c8bcc12cf40183c246c244b52ecff861c6deb3477cbf487ac8781ad44c68a9c5fd69f8c1361878e55b97c10d99d511f2597f1f7244b5e5101d028ba64 + languageName: node + linkType: hard + "@vitest/utils@npm:4.0.12": version: 4.0.12 resolution: "@vitest/utils@npm:4.0.12" @@ -11231,7 +11688,7 @@ __metadata: languageName: node linkType: hard -"ansis@npm:^4.2.0": +"ansis@npm:^4.0.0, ansis@npm:^4.2.0": version: 4.2.0 resolution: "ansis@npm:4.2.0" checksum: 10c0/cd6a7a681ecd36e72e0d79c1e34f1f3bcb1b15bcbb6f0f8969b4228062d3bfebbef468e09771b00d93b2294370b34f707599d4a113542a876de26823b795b5d2 @@ -11442,7 +11899,14 @@ __metadata: languageName: node linkType: hard -"ast-kit@npm:^2.2.0": +"assertion-error@npm:^2.0.1": + version: 2.0.1 + resolution: "assertion-error@npm:2.0.1" + checksum: 10c0/bbbcb117ac6480138f8c93cf7f535614282dea9dc828f540cdece85e3c665e8f78958b96afac52f29ff883c72638e6a87d469ecc9fe5bc902df03ed24a55dba8 + languageName: node + linkType: hard + +"ast-kit@npm:^2.1.1, ast-kit@npm:^2.2.0": version: 2.2.0 resolution: "ast-kit@npm:2.2.0" dependencies: @@ -11461,7 +11925,7 @@ __metadata: languageName: node linkType: hard -"ast-v8-to-istanbul@npm:^0.3.8": +"ast-v8-to-istanbul@npm:^0.3.3, ast-v8-to-istanbul@npm:^0.3.8": version: 0.3.8 resolution: "ast-v8-to-istanbul@npm:0.3.8" dependencies: @@ -11962,6 +12426,13 @@ __metadata: languageName: node linkType: hard +"birpc@npm:^2.5.0": + version: 2.9.0 + resolution: "birpc@npm:2.9.0" + checksum: 10c0/2462d0d67061f95bae213b0b9b323a6643ff749f7457a25242897c99e31355f1bd522c17f83ecf57506351e3e28b4e38c12a39b8beddee2dd0cbf78f9b9876ce + languageName: node + linkType: hard + "birpc@npm:^2.8.0": version: 2.8.0 resolution: "birpc@npm:2.8.0" @@ -12324,6 +12795,19 @@ __metadata: languageName: node linkType: hard +"chai@npm:^5.2.0": + version: 5.3.3 + resolution: "chai@npm:5.3.3" + dependencies: + assertion-error: "npm:^2.0.1" + check-error: "npm:^2.1.1" + deep-eql: "npm:^5.0.1" + loupe: "npm:^3.1.0" + pathval: "npm:^2.0.0" + checksum: 10c0/b360fd4d38861622e5010c2f709736988b05c7f31042305fa3f4e9911f6adb80ccfb4e302068bf8ed10e835c2e2520cba0f5edc13d878b886987e5aa62483f53 + languageName: node + linkType: hard + "chai@npm:^6.2.1": version: 6.2.1 resolution: "chai@npm:6.2.1" @@ -12419,6 +12903,13 @@ __metadata: languageName: node linkType: hard +"check-error@npm:^2.1.1": + version: 2.1.1 + resolution: "check-error@npm:2.1.1" + checksum: 10c0/979f13eccab306cf1785fa10941a590b4e7ea9916ea2a4f8c87f0316fc3eab07eabefb6e587424ef0f88cbcd3805791f172ea739863ca3d7ce2afc54641c7f0e + languageName: node + linkType: hard + "chokidar@npm:4.0.1": version: 4.0.1 resolution: "chokidar@npm:4.0.1" @@ -13051,13 +13542,13 @@ __metadata: resolution: "create-granite-app@workspace:packages/create-granite-app" dependencies: "@clack/prompts": "npm:^0.8.2" - "@types/kill-port": "npm:^2.0.1" + "@types/kill-port": "npm:2.0.1" "@types/node": "npm:^22.10.2" "@types/yargs": "npm:^17.0.33" "@vitest/coverage-v8": "npm:^4.0.12" es-toolkit: "npm:^1.39.8" execa: "npm:^9.5.2" - kill-port: "npm:^2.0.1" + kill-port: "npm:2.0.1" tsup: "npm:^8.5.0" typescript: "npm:5.8.3" vitest: "npm:^4.0.12" @@ -13358,6 +13849,13 @@ __metadata: languageName: node linkType: hard +"deep-eql@npm:^5.0.1": + version: 5.0.2 + resolution: "deep-eql@npm:5.0.2" + checksum: 10c0/7102cf3b7bb719c6b9c0db2e19bf0aa9318d141581befe8c7ce8ccd39af9eaa4346e5e05adef7f9bd7015da0f13a3a25dcfe306ef79dc8668aedbecb658dd247 + languageName: node + linkType: hard + "deep-freeze@npm:0.0.1": version: 0.0.1 resolution: "deep-freeze@npm:0.0.1" @@ -13424,6 +13922,13 @@ __metadata: languageName: node linkType: hard +"defu@npm:^6.1.4": + version: 6.1.4 + resolution: "defu@npm:6.1.4" + checksum: 10c0/2d6cc366262dc0cb8096e429368e44052fdf43ed48e53ad84cc7c9407f890301aa5fcb80d0995abaaf842b3949f154d060be4160f7a46cb2bc2f7726c81526f5 + languageName: node + linkType: hard + "degit@npm:^2.8.4": version: 2.8.4 resolution: "degit@npm:2.8.4" @@ -13547,7 +14052,7 @@ __metadata: languageName: node linkType: hard -"diff@npm:^8.0.2": +"diff@npm:^8.0.1, diff@npm:^8.0.2": version: 8.0.2 resolution: "diff@npm:8.0.2" checksum: 10c0/abfb387f033e089df3ec3be960205d17b54df8abf0924d982a7ced3a94c557a4e6cbff2e78b121f216b85f466b3d8d041673a386177c311aaea41459286cc9bc @@ -13668,7 +14173,7 @@ __metadata: languageName: node linkType: hard -"dts-resolver@npm:^2.1.3": +"dts-resolver@npm:^2.1.1, dts-resolver@npm:^2.1.3": version: 2.1.3 resolution: "dts-resolver@npm:2.1.3" peerDependencies: @@ -13778,6 +14283,13 @@ __metadata: languageName: node linkType: hard +"empathic@npm:^1.1.0": + version: 1.1.0 + resolution: "empathic@npm:1.1.0" + checksum: 10c0/ed906c4ad6dabe1477ed00d6420f79eff8ac72e2eb580aab42406f50160fd34d66e8381e92b405e96d75a826a840706af261fd397c3e7db4d1a293d23e2e72f7 + languageName: node + linkType: hard + "empathic@npm:^2.0.0": version: 2.0.0 resolution: "empathic@npm:2.0.0" @@ -14426,7 +14938,96 @@ __metadata: optional: true bin: esbuild: bin/esbuild - checksum: 10c0/db9f51248f0560bc46ab219461d338047617f6caf373c95f643b204760bdfa10c95b48cfde948949f7e509599ae4ab61c3f112092a3534936c6abfb800c565b0 + checksum: 10c0/db9f51248f0560bc46ab219461d338047617f6caf373c95f643b204760bdfa10c95b48cfde948949f7e509599ae4ab61c3f112092a3534936c6abfb800c565b0 + languageName: node + linkType: hard + +"esbuild@npm:^0.27.0": + version: 0.27.1 + resolution: "esbuild@npm:0.27.1" + dependencies: + "@esbuild/aix-ppc64": "npm:0.27.1" + "@esbuild/android-arm": "npm:0.27.1" + "@esbuild/android-arm64": "npm:0.27.1" + "@esbuild/android-x64": "npm:0.27.1" + "@esbuild/darwin-arm64": "npm:0.27.1" + "@esbuild/darwin-x64": "npm:0.27.1" + "@esbuild/freebsd-arm64": "npm:0.27.1" + "@esbuild/freebsd-x64": "npm:0.27.1" + "@esbuild/linux-arm": "npm:0.27.1" + "@esbuild/linux-arm64": "npm:0.27.1" + "@esbuild/linux-ia32": "npm:0.27.1" + "@esbuild/linux-loong64": "npm:0.27.1" + "@esbuild/linux-mips64el": "npm:0.27.1" + "@esbuild/linux-ppc64": "npm:0.27.1" + "@esbuild/linux-riscv64": "npm:0.27.1" + "@esbuild/linux-s390x": "npm:0.27.1" + "@esbuild/linux-x64": "npm:0.27.1" + "@esbuild/netbsd-arm64": "npm:0.27.1" + "@esbuild/netbsd-x64": "npm:0.27.1" + "@esbuild/openbsd-arm64": "npm:0.27.1" + "@esbuild/openbsd-x64": "npm:0.27.1" + "@esbuild/openharmony-arm64": "npm:0.27.1" + "@esbuild/sunos-x64": "npm:0.27.1" + "@esbuild/win32-arm64": "npm:0.27.1" + "@esbuild/win32-ia32": "npm:0.27.1" + "@esbuild/win32-x64": "npm:0.27.1" + dependenciesMeta: + "@esbuild/aix-ppc64": + optional: true + "@esbuild/android-arm": + optional: true + "@esbuild/android-arm64": + optional: true + "@esbuild/android-x64": + optional: true + "@esbuild/darwin-arm64": + optional: true + "@esbuild/darwin-x64": + optional: true + "@esbuild/freebsd-arm64": + optional: true + "@esbuild/freebsd-x64": + optional: true + "@esbuild/linux-arm": + optional: true + "@esbuild/linux-arm64": + optional: true + "@esbuild/linux-ia32": + optional: true + "@esbuild/linux-loong64": + optional: true + "@esbuild/linux-mips64el": + optional: true + "@esbuild/linux-ppc64": + optional: true + "@esbuild/linux-riscv64": + optional: true + "@esbuild/linux-s390x": + optional: true + "@esbuild/linux-x64": + optional: true + "@esbuild/netbsd-arm64": + optional: true + "@esbuild/netbsd-x64": + optional: true + "@esbuild/openbsd-arm64": + optional: true + "@esbuild/openbsd-x64": + optional: true + "@esbuild/openharmony-arm64": + optional: true + "@esbuild/sunos-x64": + optional: true + "@esbuild/win32-arm64": + optional: true + "@esbuild/win32-ia32": + optional: true + "@esbuild/win32-x64": + optional: true + bin: + esbuild: bin/esbuild + checksum: 10c0/8bfcf13a499a9e7b7da4b68273e12b453c7d7a5e39c944c2e5a4c64a0594d6df1391fc168a5353c22bc94eeae38dd9897199ddbbc4973525b0aae18186e996bd languageName: node linkType: hard @@ -14978,6 +15579,13 @@ __metadata: languageName: node linkType: hard +"expect-type@npm:^1.2.1": + version: 1.3.0 + resolution: "expect-type@npm:1.3.0" + checksum: 10c0/8412b3fe4f392c420ab41dae220b09700e4e47c639a29ba7ba2e83cc6cffd2b4926f7ac9e47d7e277e8f4f02acda76fd6931cb81fd2b382fa9477ef9ada953fd + languageName: node + linkType: hard + "expect-type@npm:^1.2.2": version: 1.2.2 resolution: "expect-type@npm:1.2.2" @@ -15755,7 +16363,7 @@ __metadata: languageName: node linkType: hard -"get-tsconfig@npm:^4.13.0": +"get-tsconfig@npm:^4.10.1, get-tsconfig@npm:^4.13.0": version: 4.13.0 resolution: "get-tsconfig@npm:4.13.0" dependencies: @@ -15833,6 +16441,22 @@ __metadata: languageName: node linkType: hard +"glob@npm:^10.4.1": + version: 10.5.0 + resolution: "glob@npm:10.5.0" + dependencies: + foreground-child: "npm:^3.1.0" + jackspeak: "npm:^3.1.2" + minimatch: "npm:^9.0.4" + minipass: "npm:^7.1.2" + package-json-from-dist: "npm:^1.0.0" + path-scurry: "npm:^1.11.1" + bin: + glob: dist/esm/bin.mjs + checksum: 10c0/100705eddbde6323e7b35e1d1ac28bcb58322095bd8e63a7d0bef1a2cdafe0d0f7922a981b2b48369a4f8c1b077be5c171804534c3509dfe950dde15fbe6d828 + languageName: node + linkType: hard + "glob@npm:^11.0.0": version: 11.0.2 resolution: "glob@npm:11.0.2" @@ -17225,7 +17849,7 @@ __metadata: languageName: node linkType: hard -"istanbul-reports@npm:^3.2.0": +"istanbul-reports@npm:^3.1.7, istanbul-reports@npm:^3.2.0": version: 3.2.0 resolution: "istanbul-reports@npm:3.2.0" dependencies: @@ -17833,6 +18457,15 @@ __metadata: languageName: node linkType: hard +"jiti@npm:^2.6.1": + version: 2.6.1 + resolution: "jiti@npm:2.6.1" + bin: + jiti: lib/jiti-cli.mjs + checksum: 10c0/79b2e96a8e623f66c1b703b98ec1b8be4500e1d217e09b09e343471bbb9c105381b83edbb979d01cef18318cc45ce6e153571b6c83122170eefa531c64b6789b + languageName: node + linkType: hard + "jju@npm:^1.4.0": version: 1.4.0 resolution: "jju@npm:1.4.0" @@ -18241,7 +18874,7 @@ __metadata: languageName: node linkType: hard -"kill-port@npm:^2.0.1": +"kill-port@npm:2.0.1": version: 2.0.1 resolution: "kill-port@npm:2.0.1" dependencies: @@ -18540,6 +19173,13 @@ __metadata: languageName: node linkType: hard +"loupe@npm:^3.1.0, loupe@npm:^3.1.4": + version: 3.2.1 + resolution: "loupe@npm:3.2.1" + checksum: 10c0/910c872cba291309664c2d094368d31a68907b6f5913e989d301b5c25f30e97d76d77f23ab3bf3b46d0f601ff0b6af8810c10c31b91d2c6b2f132809ca2cc705 + languageName: node + linkType: hard + "lower-case-first@npm:^1.0.0": version: 1.0.2 resolution: "lower-case-first@npm:1.0.2" @@ -18622,6 +19262,17 @@ __metadata: languageName: node linkType: hard +"magicast@npm:^0.3.5": + version: 0.3.5 + resolution: "magicast@npm:0.3.5" + dependencies: + "@babel/parser": "npm:^7.25.4" + "@babel/types": "npm:^7.25.4" + source-map-js: "npm:^1.2.0" + checksum: 10c0/a6cacc0a848af84f03e3f5bda7b0de75e4d0aa9ddce5517fd23ed0f31b5ddd51b2d0ff0b7e09b51f7de0f4053c7a1107117edda6b0732dca3e9e39e6c5a68c64 + languageName: node + linkType: hard + "magicast@npm:^0.5.1": version: 0.5.1 resolution: "magicast@npm:0.5.1" @@ -21237,6 +21888,13 @@ __metadata: languageName: node linkType: hard +"pathval@npm:^2.0.0": + version: 2.0.1 + resolution: "pathval@npm:2.0.1" + checksum: 10c0/460f4709479fbf2c45903a65655fc8f0a5f6d808f989173aeef5fdea4ff4f303dc13f7870303999add60ec49d4c14733895c0a869392e9866f1091fa64fd7581 + languageName: node + linkType: hard + "pend@npm:~1.2.0": version: 1.2.0 resolution: "pend@npm:1.2.0" @@ -21790,6 +22448,13 @@ __metadata: languageName: node linkType: hard +"quansync@npm:^1.0.0": + version: 1.0.0 + resolution: "quansync@npm:1.0.0" + checksum: 10c0/076542634399a0cc46078baab6b31acee7a88c5a435234345f645aedaa42bc6a63836e655fb39b1b21a83c98ec86a4b73ec5e2b2d6f3fdc22711eeeff9463253 + languageName: node + linkType: hard + "query-string@npm:^7.1.3": version: 7.1.3 resolution: "query-string@npm:7.1.3" @@ -22781,6 +23446,34 @@ __metadata: languageName: node linkType: hard +"rolldown-plugin-dts@npm:^0.13.3": + version: 0.13.14 + resolution: "rolldown-plugin-dts@npm:0.13.14" + dependencies: + "@babel/generator": "npm:^7.28.0" + "@babel/parser": "npm:^7.28.0" + "@babel/types": "npm:^7.28.1" + ast-kit: "npm:^2.1.1" + birpc: "npm:^2.5.0" + debug: "npm:^4.4.1" + dts-resolver: "npm:^2.1.1" + get-tsconfig: "npm:^4.10.1" + peerDependencies: + "@typescript/native-preview": ">=7.0.0-dev.20250601.1" + rolldown: ^1.0.0-beta.9 + typescript: ^5.0.0 + vue-tsc: ^2.2.0 || ^3.0.0 + peerDependenciesMeta: + "@typescript/native-preview": + optional: true + typescript: + optional: true + vue-tsc: + optional: true + checksum: 10c0/f09da3990a6be11aed07db121439db907251578cd51bff69479186a056524f07a7a4d5b4056ff6bf884c1fdbacc655fcb0c956753f9bf8a73f2c885731bc2e77 + languageName: node + linkType: hard + "rolldown-plugin-dts@npm:^0.17.7": version: 0.17.8 resolution: "rolldown-plugin-dts@npm:0.17.8" @@ -22868,6 +23561,61 @@ __metadata: languageName: node linkType: hard +"rolldown@npm:1.0.0-beta.9": + version: 1.0.0-beta.9 + resolution: "rolldown@npm:1.0.0-beta.9" + dependencies: + "@oxc-project/types": "npm:0.70.0" + "@rolldown/binding-darwin-arm64": "npm:1.0.0-beta.9" + "@rolldown/binding-darwin-x64": "npm:1.0.0-beta.9" + "@rolldown/binding-freebsd-x64": "npm:1.0.0-beta.9" + "@rolldown/binding-linux-arm-gnueabihf": "npm:1.0.0-beta.9" + "@rolldown/binding-linux-arm64-gnu": "npm:1.0.0-beta.9" + "@rolldown/binding-linux-arm64-musl": "npm:1.0.0-beta.9" + "@rolldown/binding-linux-x64-gnu": "npm:1.0.0-beta.9" + "@rolldown/binding-linux-x64-musl": "npm:1.0.0-beta.9" + "@rolldown/binding-wasm32-wasi": "npm:1.0.0-beta.9" + "@rolldown/binding-win32-arm64-msvc": "npm:1.0.0-beta.9" + "@rolldown/binding-win32-ia32-msvc": "npm:1.0.0-beta.9" + "@rolldown/binding-win32-x64-msvc": "npm:1.0.0-beta.9" + "@rolldown/pluginutils": "npm:1.0.0-beta.9" + ansis: "npm:^4.0.0" + peerDependencies: + "@oxc-project/runtime": 0.70.0 + dependenciesMeta: + "@rolldown/binding-darwin-arm64": + optional: true + "@rolldown/binding-darwin-x64": + optional: true + "@rolldown/binding-freebsd-x64": + optional: true + "@rolldown/binding-linux-arm-gnueabihf": + optional: true + "@rolldown/binding-linux-arm64-gnu": + optional: true + "@rolldown/binding-linux-arm64-musl": + optional: true + "@rolldown/binding-linux-x64-gnu": + optional: true + "@rolldown/binding-linux-x64-musl": + optional: true + "@rolldown/binding-wasm32-wasi": + optional: true + "@rolldown/binding-win32-arm64-msvc": + optional: true + "@rolldown/binding-win32-ia32-msvc": + optional: true + "@rolldown/binding-win32-x64-msvc": + optional: true + peerDependenciesMeta: + "@oxc-project/runtime": + optional: true + bin: + rolldown: bin/cli.mjs + checksum: 10c0/063f9e0c7153cbba04307dd919734c3bc72d25f7afeae1a495f585cf3c0709b75468d6b732721ae6fd6d30ae302a70a1eb9d4ac207bc986fdbb214419fc90941 + languageName: node + linkType: hard + "rollup@npm:^4.20.0, rollup@npm:^4.34.8": version: 4.41.1 resolution: "rollup@npm:4.41.1" @@ -23210,7 +23958,7 @@ __metadata: languageName: node linkType: hard -"semver@npm:^7.7.3": +"semver@npm:^7.7.2, semver@npm:^7.7.3": version: 7.7.3 resolution: "semver@npm:7.7.3" bin: @@ -23617,7 +24365,7 @@ __metadata: languageName: node linkType: hard -"source-map-js@npm:^1.2.1": +"source-map-js@npm:^1.2.0, source-map-js@npm:^1.2.1": version: 1.2.1 resolution: "source-map-js@npm:1.2.1" checksum: 10c0/7bda1fc4c197e3c6ff17de1b8b2c20e60af81b63a52cb32ec5a5d67a20a7d42651e2cb34ebe93833c5a2a084377e17455854fee3e21e7925c64a51b6a52b0faf @@ -23841,7 +24589,7 @@ __metadata: languageName: node linkType: hard -"std-env@npm:^3.10.0": +"std-env@npm:^3.10.0, std-env@npm:^3.9.0": version: 3.10.0 resolution: "std-env@npm:3.10.0" checksum: 10c0/1814927a45004d36dde6707eaf17552a546769bc79a6421be2c16ce77d238158dfe5de30910b78ec30d95135cc1c59ea73ee22d2ca170f8b9753f84da34c427f @@ -24091,6 +24839,15 @@ __metadata: languageName: node linkType: hard +"strip-literal@npm:^3.0.0": + version: 3.1.0 + resolution: "strip-literal@npm:3.1.0" + dependencies: + js-tokens: "npm:^9.0.1" + checksum: 10c0/50918f669915d9ad0fe4b7599902b735f853f2201c97791ead00104a654259c0c61bc2bc8fa3db05109339b61f4cf09e47b94ecc874ffbd0e013965223893af8 + languageName: node + linkType: hard + "strnum@npm:^1.0.5, strnum@npm:^1.1.1": version: 1.1.2 resolution: "strnum@npm:1.1.2" @@ -24313,6 +25070,17 @@ __metadata: languageName: node linkType: hard +"test-exclude@npm:^7.0.1": + version: 7.0.1 + resolution: "test-exclude@npm:7.0.1" + dependencies: + "@istanbuljs/schema": "npm:^0.1.2" + glob: "npm:^10.4.1" + minimatch: "npm:^9.0.4" + checksum: 10c0/6d67b9af4336a2e12b26a68c83308c7863534c65f27ed4ff7068a56f5a58f7ac703e8fc80f698a19bb154fd8f705cdf7ec347d9512b2c522c737269507e7b263 + languageName: node + linkType: hard + "text-table@npm:^0.2.0": version: 0.2.0 resolution: "text-table@npm:0.2.0" @@ -24395,7 +25163,7 @@ __metadata: languageName: node linkType: hard -"tinyexec@npm:^1.0.2": +"tinyexec@npm:^1.0.1, tinyexec@npm:^1.0.2": version: 1.0.2 resolution: "tinyexec@npm:1.0.2" checksum: 10c0/1261a8e34c9b539a9aae3b7f0bb5372045ff28ee1eba035a2a059e532198fe1a182ec61ac60fa0b4a4129f0c4c4b1d2d57355b5cb9aa2d17ac9454ecace502ee @@ -24412,7 +25180,7 @@ __metadata: languageName: node linkType: hard -"tinyglobby@npm:^0.2.15": +"tinyglobby@npm:^0.2.13, tinyglobby@npm:^0.2.14, tinyglobby@npm:^0.2.15": version: 0.2.15 resolution: "tinyglobby@npm:0.2.15" dependencies: @@ -24429,6 +25197,20 @@ __metadata: languageName: node linkType: hard +"tinypool@npm:^1.1.1": + version: 1.1.1 + resolution: "tinypool@npm:1.1.1" + checksum: 10c0/bf26727d01443061b04fa863f571016950888ea994ba0cd8cba3a1c51e2458d84574341ab8dbc3664f1c3ab20885c8cf9ff1cc4b18201f04c2cde7d317fff69b + languageName: node + linkType: hard + +"tinyrainbow@npm:^2.0.0": + version: 2.0.0 + resolution: "tinyrainbow@npm:2.0.0" + checksum: 10c0/c83c52bef4e0ae7fb8ec6a722f70b5b6fa8d8be1c85792e829f56c0e1be94ab70b293c032dc5048d4d37cfe678f1f5babb04bdc65fd123098800148ca989184f + languageName: node + linkType: hard + "tinyrainbow@npm:^3.0.3": version: 3.0.3 resolution: "tinyrainbow@npm:3.0.3" @@ -24436,6 +25218,13 @@ __metadata: languageName: node linkType: hard +"tinyspy@npm:^4.0.3": + version: 4.0.4 + resolution: "tinyspy@npm:4.0.4" + checksum: 10c0/a8020fc17799251e06a8398dcc352601d2770aa91c556b9531ecd7a12581161fd1c14e81cbdaff0c1306c93bfdde8ff6d1c1a3f9bbe6d91604f0fd4e01e2f1eb + languageName: node + linkType: hard + "title-case@npm:^2.1.0": version: 2.1.1 resolution: "title-case@npm:2.1.1" @@ -24758,6 +25547,43 @@ __metadata: languageName: node linkType: hard +"tsdown@npm:^0.11.13": + version: 0.11.13 + resolution: "tsdown@npm:0.11.13" + dependencies: + ansis: "npm:^4.0.0" + cac: "npm:^6.7.14" + chokidar: "npm:^4.0.3" + debug: "npm:^4.4.1" + diff: "npm:^8.0.1" + empathic: "npm:^1.1.0" + hookable: "npm:^5.5.3" + rolldown: "npm:1.0.0-beta.9" + rolldown-plugin-dts: "npm:^0.13.3" + semver: "npm:^7.7.2" + tinyexec: "npm:^1.0.1" + tinyglobby: "npm:^0.2.13" + unconfig: "npm:^7.3.2" + peerDependencies: + publint: ^0.3.0 + typescript: ^5.0.0 + unplugin-lightningcss: ^0.4.0 + unplugin-unused: ^0.5.0 + peerDependenciesMeta: + publint: + optional: true + typescript: + optional: true + unplugin-lightningcss: + optional: true + unplugin-unused: + optional: true + bin: + tsdown: dist/run.js + checksum: 10c0/37a97471971b9ca7e3c6c5d642b97c0fa3f0ffc31a140487a41bd5f30a19218e12e1c98ad3a60030814652724705b7807dc68cd48e799f79442cc82451da83a0 + languageName: node + linkType: hard + "tsdown@npm:^0.16.5": version: 0.16.5 resolution: "tsdown@npm:0.16.5" @@ -25085,6 +25911,16 @@ __metadata: languageName: node linkType: hard +"unconfig-core@npm:7.4.2": + version: 7.4.2 + resolution: "unconfig-core@npm:7.4.2" + dependencies: + "@quansync/fs": "npm:^1.0.0" + quansync: "npm:^1.0.0" + checksum: 10c0/12aa85c78114a505fb49adc5fd6c2ce58b1661c517caea7f8943b9f56912634bfd085443a84d7675a0b245598e6220daaff0a69e3dd712819e0d05195fcfb75b + languageName: node + linkType: hard + "unconfig-core@npm:^7.4.1": version: 7.4.1 resolution: "unconfig-core@npm:7.4.1" @@ -25095,6 +25931,19 @@ __metadata: languageName: node linkType: hard +"unconfig@npm:^7.3.2": + version: 7.4.2 + resolution: "unconfig@npm:7.4.2" + dependencies: + "@quansync/fs": "npm:^1.0.0" + defu: "npm:^6.1.4" + jiti: "npm:^2.6.1" + quansync: "npm:^1.0.0" + unconfig-core: "npm:7.4.2" + checksum: 10c0/8423963303297e1e4213323b87bfa265fb893806d10bc8f7b38d40dab17fcb5f6173683b8400b275687a2c78839d61215679fb41895f5465713f700205464687 + languageName: node + linkType: hard + "undici-types@npm:~5.26.4": version: 5.26.5 resolution: "undici-types@npm:5.26.5" @@ -25535,6 +26384,76 @@ __metadata: languageName: node linkType: hard +"vite-node@npm:3.2.4": + version: 3.2.4 + resolution: "vite-node@npm:3.2.4" + dependencies: + cac: "npm:^6.7.14" + debug: "npm:^4.4.1" + es-module-lexer: "npm:^1.7.0" + pathe: "npm:^2.0.3" + vite: "npm:^5.0.0 || ^6.0.0 || ^7.0.0-0" + bin: + vite-node: vite-node.mjs + checksum: 10c0/6ceca67c002f8ef6397d58b9539f80f2b5d79e103a18367288b3f00a8ab55affa3d711d86d9112fce5a7fa658a212a087a005a045eb8f4758947dd99af2a6c6b + languageName: node + linkType: hard + +"vite@npm:^5.0.0 || ^6.0.0 || ^7.0.0-0": + version: 7.3.0 + resolution: "vite@npm:7.3.0" + dependencies: + esbuild: "npm:^0.27.0" + fdir: "npm:^6.5.0" + fsevents: "npm:~2.3.3" + picomatch: "npm:^4.0.3" + postcss: "npm:^8.5.6" + rollup: "npm:^4.43.0" + tinyglobby: "npm:^0.2.15" + peerDependencies: + "@types/node": ^20.19.0 || >=22.12.0 + jiti: ">=1.21.0" + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: ">=0.54.8" + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + dependenciesMeta: + fsevents: + optional: true + peerDependenciesMeta: + "@types/node": + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + bin: + vite: bin/vite.js + checksum: 10c0/0457c196cdd5761ec351c0f353945430fbad330e615b9eeab729c8ae163334f18acdc1d9cd7d9d673dbf111f07f6e4f0b25d4ac32360e65b4a6df9991046f3ff + languageName: node + linkType: hard + "vite@npm:^5.4.14": version: 5.4.19 resolution: "vite@npm:5.4.19" @@ -25669,6 +26588,62 @@ __metadata: languageName: node linkType: hard +"vitest@npm:^3.1.3": + version: 3.2.4 + resolution: "vitest@npm:3.2.4" + dependencies: + "@types/chai": "npm:^5.2.2" + "@vitest/expect": "npm:3.2.4" + "@vitest/mocker": "npm:3.2.4" + "@vitest/pretty-format": "npm:^3.2.4" + "@vitest/runner": "npm:3.2.4" + "@vitest/snapshot": "npm:3.2.4" + "@vitest/spy": "npm:3.2.4" + "@vitest/utils": "npm:3.2.4" + chai: "npm:^5.2.0" + debug: "npm:^4.4.1" + expect-type: "npm:^1.2.1" + magic-string: "npm:^0.30.17" + pathe: "npm:^2.0.3" + picomatch: "npm:^4.0.2" + std-env: "npm:^3.9.0" + tinybench: "npm:^2.9.0" + tinyexec: "npm:^0.3.2" + tinyglobby: "npm:^0.2.14" + tinypool: "npm:^1.1.1" + tinyrainbow: "npm:^2.0.0" + vite: "npm:^5.0.0 || ^6.0.0 || ^7.0.0-0" + vite-node: "npm:3.2.4" + why-is-node-running: "npm:^2.3.0" + peerDependencies: + "@edge-runtime/vm": "*" + "@types/debug": ^4.1.12 + "@types/node": ^18.0.0 || ^20.0.0 || >=22.0.0 + "@vitest/browser": 3.2.4 + "@vitest/ui": 3.2.4 + happy-dom: "*" + jsdom: "*" + peerDependenciesMeta: + "@edge-runtime/vm": + optional: true + "@types/debug": + optional: true + "@types/node": + optional: true + "@vitest/browser": + optional: true + "@vitest/ui": + optional: true + happy-dom: + optional: true + jsdom: + optional: true + bin: + vitest: vitest.mjs + checksum: 10c0/5bf53ede3ae6a0e08956d72dab279ae90503f6b5a05298a6a5e6ef47d2fd1ab386aaf48fafa61ed07a0ebfe9e371772f1ccbe5c258dd765206a8218bf2eb79eb + languageName: node + linkType: hard + "vitest@npm:^4.0.12": version: 4.0.12 resolution: "vitest@npm:4.0.12"