@elench/testkit 0.1.64 → 0.1.65
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/coverage/evidence.mjs +15 -3
- package/lib/coverage/evidence.test.mjs +13 -4
- package/lib/coverage/graph-builder.mjs +23 -24
- package/lib/coverage/next-ir-to-graph.mjs +240 -0
- package/node_modules/@elench/next-analysis/package.json +14 -0
- package/node_modules/@elench/next-analysis/src/api-routes.mjs +81 -0
- package/node_modules/@elench/next-analysis/src/api-routes.test.mjs +22 -0
- package/node_modules/@elench/next-analysis/src/app-root.mjs +7 -0
- package/node_modules/@elench/next-analysis/src/backend-links.mjs +31 -0
- package/node_modules/@elench/next-analysis/src/index.mjs +21 -0
- package/node_modules/@elench/next-analysis/src/pages.mjs +68 -0
- package/node_modules/@elench/next-analysis/src/project.mjs +94 -0
- package/node_modules/@elench/next-analysis/src/project.test.mjs +35 -0
- package/node_modules/@elench/next-analysis/src/route-tree.mjs +621 -0
- package/node_modules/@elench/next-analysis/src/routes.mjs +41 -0
- package/node_modules/@elench/next-analysis/src/routes.test.mjs +25 -0
- package/node_modules/@elench/next-analysis/src/server-actions.mjs +53 -0
- package/node_modules/@elench/next-analysis/src/server-actions.test.mjs +37 -0
- package/node_modules/@elench/next-analysis/src/shared.mjs +209 -0
- package/node_modules/@elench/next-analysis/src/swc.mjs +388 -0
- package/node_modules/@elench/testkit-bridge/package.json +2 -2
- package/node_modules/@elench/testkit-protocol/package.json +1 -1
- package/node_modules/@elench/ts-analysis/package.json +1 -1
- package/node_modules/@next/routing/README.md +91 -0
- package/node_modules/@next/routing/dist/__tests__/captures.test.d.ts +1 -0
- package/node_modules/@next/routing/dist/__tests__/conditions.test.d.ts +1 -0
- package/node_modules/@next/routing/dist/__tests__/dynamic-after-rewrites.test.d.ts +1 -0
- package/node_modules/@next/routing/dist/__tests__/i18n-resolve-routes.test.d.ts +1 -0
- package/node_modules/@next/routing/dist/__tests__/i18n.test.d.ts +1 -0
- package/node_modules/@next/routing/dist/__tests__/middleware.test.d.ts +1 -0
- package/node_modules/@next/routing/dist/__tests__/normalize-next-data.test.d.ts +1 -0
- package/node_modules/@next/routing/dist/__tests__/redirects.test.d.ts +1 -0
- package/node_modules/@next/routing/dist/__tests__/resolve-routes.test.d.ts +1 -0
- package/node_modules/@next/routing/dist/__tests__/rewrites.test.d.ts +1 -0
- package/node_modules/@next/routing/dist/destination.d.ts +22 -0
- package/node_modules/@next/routing/dist/i18n.d.ts +48 -0
- package/node_modules/@next/routing/dist/index.d.ts +5 -0
- package/node_modules/@next/routing/dist/index.js +1 -0
- package/node_modules/@next/routing/dist/matchers.d.ts +12 -0
- package/node_modules/@next/routing/dist/middleware.d.ts +12 -0
- package/node_modules/@next/routing/dist/next-data.d.ts +10 -0
- package/node_modules/@next/routing/dist/resolve-routes.d.ts +2 -0
- package/node_modules/@next/routing/dist/types.d.ts +97 -0
- package/node_modules/@next/routing/package.json +39 -0
- package/node_modules/@swc/core/README.md +100 -0
- package/node_modules/@swc/core/Visitor.d.ts +218 -0
- package/node_modules/@swc/core/Visitor.js +1399 -0
- package/node_modules/@swc/core/binding.d.ts +59 -0
- package/node_modules/@swc/core/binding.js +368 -0
- package/node_modules/@swc/core/index.d.ts +120 -0
- package/node_modules/@swc/core/index.js +443 -0
- package/node_modules/@swc/core/package.json +120 -0
- package/node_modules/@swc/core/postinstall.js +148 -0
- package/node_modules/@swc/core/spack.d.ts +51 -0
- package/node_modules/@swc/core/spack.js +87 -0
- package/node_modules/@swc/core/util.d.ts +1 -0
- package/node_modules/@swc/core/util.js +104 -0
- package/node_modules/@swc/core-linux-x64-gnu/README.md +3 -0
- package/node_modules/@swc/core-linux-x64-gnu/package.json +46 -0
- package/node_modules/@swc/core-linux-x64-gnu/swc.linux-x64-gnu.node +0 -0
- package/node_modules/@swc/counter/CHANGELOG.md +7 -0
- package/node_modules/@swc/counter/README.md +7 -0
- package/node_modules/@swc/counter/index.js +1 -0
- package/node_modules/@swc/counter/package.json +27 -0
- package/node_modules/@swc/types/LICENSE +201 -0
- package/node_modules/@swc/types/README.md +4 -0
- package/node_modules/@swc/types/assumptions.d.ts +92 -0
- package/node_modules/@swc/types/assumptions.js +2 -0
- package/node_modules/@swc/types/index.d.ts +2049 -0
- package/node_modules/@swc/types/index.js +2 -0
- package/node_modules/@swc/types/package.json +40 -0
- package/package.json +6 -4
- package/lib/coverage/next-discovery.mjs +0 -205
- package/lib/coverage/next-static-analysis.mjs +0 -1045
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# @next/routing
|
|
2
|
+
|
|
3
|
+
Shared route resolving package for Next.js.
|
|
4
|
+
|
|
5
|
+
**NOTE: This package is experimental and will become stable along with adapters API**
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
This package provides a comprehensive route resolution system that handles rewrites, redirects, middleware invocation, and dynamic route matching with support for conditional routing based on headers, cookies, queries, and host.
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install @next/routing
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { resolveRoutes } from '@next/routing'
|
|
21
|
+
|
|
22
|
+
const result = await resolveRoutes({
|
|
23
|
+
url: new URL('https://example.com/api/users'),
|
|
24
|
+
basePath: '',
|
|
25
|
+
requestBody: readableStream,
|
|
26
|
+
headers: new Headers(),
|
|
27
|
+
pathnames: ['/api/users', '/api/posts'],
|
|
28
|
+
routes: {
|
|
29
|
+
beforeMiddleware: [],
|
|
30
|
+
beforeFiles: [],
|
|
31
|
+
afterFiles: [],
|
|
32
|
+
dynamicRoutes: [],
|
|
33
|
+
onMatch: [],
|
|
34
|
+
fallback: [],
|
|
35
|
+
},
|
|
36
|
+
invokeMiddleware: async (ctx) => {
|
|
37
|
+
// Your middleware logic
|
|
38
|
+
return {}
|
|
39
|
+
},
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
if (result.resolvedPathname) {
|
|
43
|
+
console.log('Resolved pathname:', result.resolvedPathname)
|
|
44
|
+
console.log('Resolved query:', result.resolvedQuery)
|
|
45
|
+
console.log('Invocation target:', result.invocationTarget)
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Route Resolution Flow
|
|
50
|
+
|
|
51
|
+
1. **beforeMiddleware routes** - Applied before middleware execution
|
|
52
|
+
2. **invokeMiddleware** - Custom middleware logic
|
|
53
|
+
3. **beforeFiles routes** - Applied before checking filesystem
|
|
54
|
+
4. **Static pathname matching** - Check against provided pathnames
|
|
55
|
+
5. **afterFiles routes** - Applied after filesystem checks
|
|
56
|
+
6. **dynamicRoutes** - Dynamic route matching with parameter extraction
|
|
57
|
+
7. **fallback routes** - Final fallback routes
|
|
58
|
+
|
|
59
|
+
## Route Configuration
|
|
60
|
+
|
|
61
|
+
Each route can have:
|
|
62
|
+
|
|
63
|
+
- `sourceRegex` - Regular expression to match against pathname
|
|
64
|
+
- `destination` - Destination path with support for replacements ($1, $name)
|
|
65
|
+
- `headers` - Headers to apply on match
|
|
66
|
+
- `has` - Conditions that must match
|
|
67
|
+
- `missing` - Conditions that must not match
|
|
68
|
+
- `status` - HTTP status code (3xx for redirects)
|
|
69
|
+
|
|
70
|
+
### Redirects
|
|
71
|
+
|
|
72
|
+
When a route has:
|
|
73
|
+
- A redirect status code (300-399)
|
|
74
|
+
- Headers containing `Location` or `Refresh`
|
|
75
|
+
|
|
76
|
+
The routing will end immediately and return a `redirect` result with the destination URL and status code.
|
|
77
|
+
|
|
78
|
+
### Has/Missing Conditions
|
|
79
|
+
|
|
80
|
+
Conditions support:
|
|
81
|
+
|
|
82
|
+
- `header` - Match HTTP headers
|
|
83
|
+
- `cookie` - Match cookies
|
|
84
|
+
- `query` - Match query parameters
|
|
85
|
+
- `host` - Match hostname
|
|
86
|
+
|
|
87
|
+
Values can be:
|
|
88
|
+
|
|
89
|
+
- `undefined` - Match if key exists
|
|
90
|
+
- String - Direct string match
|
|
91
|
+
- Regex string - Match against regex pattern
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Replaces $1, $2, etc. and $name placeholders in the destination string
|
|
3
|
+
* with matches from the regex and has conditions
|
|
4
|
+
*/
|
|
5
|
+
export declare function replaceDestination(destination: string, regexMatches: RegExpMatchArray | null, hasCaptures: Record<string, string>): string;
|
|
6
|
+
/**
|
|
7
|
+
* Checks if a destination is an external rewrite (starts with http/https)
|
|
8
|
+
*/
|
|
9
|
+
export declare function isExternalDestination(destination: string): boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Applies a destination to a URL, updating the pathname or creating a new URL
|
|
12
|
+
* if it's external
|
|
13
|
+
*/
|
|
14
|
+
export declare function applyDestination(currentUrl: URL, destination: string): URL;
|
|
15
|
+
/**
|
|
16
|
+
* Checks if a status code is a redirect status code
|
|
17
|
+
*/
|
|
18
|
+
export declare function isRedirectStatus(status: number | undefined): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Checks if headers contain redirect headers (Location or Refresh)
|
|
21
|
+
*/
|
|
22
|
+
export declare function hasRedirectHeaders(headers: Record<string, string>): boolean;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* i18n utilities for locale detection and handling
|
|
3
|
+
*/
|
|
4
|
+
export interface I18nDomain {
|
|
5
|
+
defaultLocale: string;
|
|
6
|
+
domain: string;
|
|
7
|
+
http?: true;
|
|
8
|
+
locales?: string[];
|
|
9
|
+
}
|
|
10
|
+
export interface I18nConfig {
|
|
11
|
+
defaultLocale: string;
|
|
12
|
+
domains?: I18nDomain[];
|
|
13
|
+
localeDetection?: false;
|
|
14
|
+
locales: string[];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Detects the domain locale based on hostname or detected locale
|
|
18
|
+
*/
|
|
19
|
+
export declare function detectDomainLocale(domains: I18nDomain[] | undefined, hostname: string | undefined, detectedLocale?: string): I18nDomain | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* Normalizes a pathname by removing the locale prefix if present
|
|
22
|
+
*/
|
|
23
|
+
export declare function normalizeLocalePath(pathname: string, locales: string[]): {
|
|
24
|
+
pathname: string;
|
|
25
|
+
detectedLocale?: string;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Parses the Accept-Language header and returns the best matching locale
|
|
29
|
+
*/
|
|
30
|
+
export declare function getAcceptLanguageLocale(acceptLanguageHeader: string, locales: string[]): string | undefined;
|
|
31
|
+
/**
|
|
32
|
+
* Gets the locale from the NEXT_LOCALE cookie
|
|
33
|
+
*/
|
|
34
|
+
export declare function getCookieLocale(cookieHeader: string | undefined, locales: string[]): string | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* Detects the appropriate locale based on path, domain, cookie, and accept-language
|
|
37
|
+
*/
|
|
38
|
+
export declare function detectLocale(params: {
|
|
39
|
+
pathname: string;
|
|
40
|
+
hostname: string | undefined;
|
|
41
|
+
cookieHeader: string | undefined;
|
|
42
|
+
acceptLanguageHeader: string | undefined;
|
|
43
|
+
i18n: I18nConfig;
|
|
44
|
+
}): {
|
|
45
|
+
locale: string;
|
|
46
|
+
pathnameWithoutLocale: string;
|
|
47
|
+
localeInPath: boolean;
|
|
48
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { resolveRoutes } from './resolve-routes';
|
|
2
|
+
export type { RouteHas, Route, MiddlewareContext, MiddlewareResult, ResolveRoutesParams, ResolveRoutesResult, ResolveRoutesQuery, ResolveRoutesQueryValue, RouteInvocationTarget, } from './types';
|
|
3
|
+
export type { I18nConfig, I18nDomain } from './i18n';
|
|
4
|
+
export { detectLocale, detectDomainLocale, normalizeLocalePath, getAcceptLanguageLocale, getCookieLocale, } from './i18n';
|
|
5
|
+
export { responseToMiddlewareResult } from './middleware';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(()=>{"use strict";var e={};(()=>{e.d=(t,n)=>{for(var a in n){if(e.o(n,a)&&!e.o(t,a)){Object.defineProperty(t,a,{enumerable:true,get:n[a]})}}}})();(()=>{e.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t)})();(()=>{e.r=e=>{if(typeof Symbol!=="undefined"&&Symbol.toStringTag){Object.defineProperty(e,Symbol.toStringTag,{value:"Module"})}Object.defineProperty(e,"__esModule",{value:true})}})();if(typeof e!=="undefined")e.ab=__dirname+"/";var t={};e.r(t);e.d(t,{detectDomainLocale:()=>detectDomainLocale,detectLocale:()=>detectLocale,getAcceptLanguageLocale:()=>getAcceptLanguageLocale,getCookieLocale:()=>getCookieLocale,normalizeLocalePath:()=>normalizeLocalePath,resolveRoutes:()=>resolveRoutes,responseToMiddlewareResult:()=>responseToMiddlewareResult});function matchesCondition(e,t){if(e===undefined){return{matched:false}}if(t===undefined){return{matched:true,capturedValue:e}}try{const n=new RegExp(t);const a=e.match(n);if(a){return{matched:true,capturedValue:a[0]}}}catch(e){}if(e===t){return{matched:true,capturedValue:e}}return{matched:false}}function getConditionValue(e,t,n){switch(e.type){case"header":return n.get(e.key)||undefined;case"cookie":{const t=n.get("cookie");if(!t)return undefined;const a=t.split(";").reduce(((e,t)=>{const[n,...a]=t.trim().split("=");if(n){e[n]=a.join("=")}return e}),{});return a[e.key]}case"query":return t.searchParams.get(e.key)||undefined;case"host":return t.hostname;default:return""}}function normalizeCaptureKey(e){return e.replace(/[^a-zA-Z]/g,"")}function checkHasConditions(e,t,n){if(!e||e.length===0){return{matched:true,captures:{}}}const a={};for(const r of e){const e=getConditionValue(r,t,n);const s=matchesCondition(e,r.value);if(!s.matched){return{matched:false,captures:{}}}if(s.capturedValue!==undefined&&r.type!=="host"){const e=normalizeCaptureKey(r.key);a[e]=s.capturedValue}}return{matched:true,captures:a}}function checkMissingConditions(e,t,n){if(!e||e.length===0){return true}for(const a of e){const e=getConditionValue(a,t,n);const r=matchesCondition(e,a.value);if(r.matched){return false}}return true}function replaceDestination(e,t,n){let a=e;if(t){for(let e=1;e<t.length;e++){const n=t[e];if(n!==undefined){a=a.replace(new RegExp(`\\$${e}`,"g"),n)}}if(t.groups){for(const[e,n]of Object.entries(t.groups)){if(n!==undefined){a=a.replace(new RegExp(`\\$${e}`,"g"),n)}}}}for(const[e,t]of Object.entries(n)){a=a.replace(new RegExp(`\\$${e}`,"g"),t)}return a}function isExternalDestination(e){return e.startsWith("http://")||e.startsWith("https://")}function applyDestination(e,t){if(isExternalDestination(t)){return new URL(t)}const n=new URL(e.toString());const[a,r]=t.split("?");n.pathname=a;if(r){const e=new URLSearchParams(r);for(const[t,a]of e.entries()){n.searchParams.set(t,a)}}return n}function isRedirectStatus(e){if(!e)return false;return e>=300&&e<400}function hasRedirectHeaders(e){const t=Object.keys(e).map((e=>e.toLowerCase()));return t.includes("location")||t.includes("refresh")}function normalizeNextDataUrl(e,t,n){const a=new URL(e.toString());let r=a.pathname;const s=`${t}/_next/data/${n}/`;if(r.startsWith(s)){let e=r.slice(s.length);if(e.endsWith(".json")){e=e.slice(0,-5)}r=t?`${t}/${e}`:`/${e}`;a.pathname=r}return a}function denormalizeNextDataUrl(e,t,n){const a=new URL(e.toString());let r=a.pathname;const s=`${t}/_next/data/${n}/`;if(!r.startsWith(s)){let e=r;if(t&&r.startsWith(t)){e=r.slice(t.length)}r=`${t}/_next/data/${n}${e}.json`;a.pathname=r}return a}function detectDomainLocale(e,t,n){if(!e)return undefined;const a=t?.toLowerCase();const r=n?.toLowerCase();for(const t of e){const e=t.domain.split(":",1)[0].toLowerCase();if(a===e||r===t.defaultLocale.toLowerCase()||t.locales?.some((e=>e.toLowerCase()===r))){return t}}return undefined}function normalizeLocalePath(e,t){if(!t||t.length===0){return{pathname:e}}const n=e.split("/",2);if(!n[1]){return{pathname:e}}const a=n[1].toLowerCase();const r=t.map((e=>e.toLowerCase()));const s=r.indexOf(a);if(s<0){return{pathname:e}}const o=t[s];const i=e.slice(o.length+1)||"/";return{pathname:i,detectedLocale:o}}function getAcceptLanguageLocale(e,t){if(!e||!t.length){return undefined}try{const n=e.split(",").map((e=>{const t=e.trim().split(";");const n=t[0];let a=1;if(t[1]){const e=t[1].match(/q=([0-9.]+)/);if(e&&e[1]){a=parseFloat(e[1])}}return{locale:n,quality:a}})).filter((e=>e.quality>0)).sort(((e,t)=>t.quality-e.quality));const a=new Map;for(const e of t){a.set(e.toLowerCase(),e)}for(const{locale:e}of n){const t=e.toLowerCase();if(a.has(t)){return a.get(t)}}for(const{locale:e}of n){const t=e.toLowerCase().split("-")[0];if(a.has(t)){return a.get(t)}for(const[e,n]of a){if(e.startsWith(t+"-")){return n}}}return undefined}catch(e){return undefined}}function getCookieLocale(e,t){if(!e||!t.length){return undefined}try{const n=e.split(";").reduce(((e,t)=>{const[n,...a]=t.trim().split("=");if(n&&a.length>0){e[n]=decodeURIComponent(a.join("="))}return e}),{});const a=n.NEXT_LOCALE?.toLowerCase();if(!a){return undefined}return t.find((e=>e.toLowerCase()===a))}catch(e){return undefined}}function detectLocale(e){const{pathname:t,hostname:n,cookieHeader:a,acceptLanguageHeader:r,i18n:s}=e;const o=normalizeLocalePath(t,s.locales);if(o.detectedLocale){return{locale:o.detectedLocale,pathnameWithoutLocale:o.pathname,localeInPath:true}}if(s.localeDetection===false){const e=detectDomainLocale(s.domains,n);return{locale:e?.defaultLocale||s.defaultLocale,pathnameWithoutLocale:t,localeInPath:false}}const i=getCookieLocale(a,s.locales);if(i){return{locale:i,pathnameWithoutLocale:t,localeInPath:false}}const c=getAcceptLanguageLocale(r||"",s.locales);if(c){return{locale:c,pathnameWithoutLocale:t,localeInPath:false}}const l=detectDomainLocale(s.domains,n);if(l){return{locale:l.defaultLocale,pathnameWithoutLocale:t,localeInPath:false}}return{locale:s.defaultLocale,pathnameWithoutLocale:t,localeInPath:false}}function matchRoute(e,t,n){const a=new RegExp(e.sourceRegex);const r=t.pathname.match(a);if(!r){return{matched:false}}const s=checkHasConditions(e.has,t,n);if(!s.matched){return{matched:false}}const o=checkMissingConditions(e.missing,t,n);if(!o){return{matched:false}}const i=e.destination?replaceDestination(e.destination,r,s.captures):undefined;const c=e.headers?Object.fromEntries(Object.entries(e.headers).map((([e,t])=>[replaceDestination(e,r,s.captures),replaceDestination(t,r,s.captures)]))):undefined;return{matched:true,destination:i,headers:c,regexMatches:r,hasCaptures:s.captures}}function processRoutes(e,t,n,a,r){let s=t;let o;for(const t of e){const e=matchRoute(t,s,n);if(e.matched){if(e.headers){for(const[t,n]of Object.entries(e.headers)){a.set(t,n)}}if(t.status){o=t.status}if(e.destination){if(isRedirectStatus(t.status)&&e.headers&&hasRedirectHeaders(e.headers)){const n=isExternalDestination(e.destination)?new URL(e.destination):applyDestination(s,e.destination);return{url:s,redirect:{url:n,status:t.status},stopped:true,status:o}}if(isExternalDestination(e.destination)){return{url:s,externalRewrite:new URL(e.destination),stopped:true,status:o}}s=applyDestination(s,e.destination);if(s.origin!==r){return{url:s,externalRewrite:s,stopped:true,status:o}}}}}return{url:s,stopped:false,status:o}}function matchesPathname(e,t){for(const n of t){if(e===n){return n}}return undefined}function toResolvedQuery(e){const t={};for(const[n,a]of e.searchParams.entries()){const e=t[n];if(e===undefined){t[n]=a;continue}t[n]=Array.isArray(e)?[...e,a]:[e,a]}return t}function mergeDestinationQueryIntoUrl(e,t){const n=new URL(e.toString());const a=t.split("?")[1];if(!a){return n}const r=new URLSearchParams(a);for(const[e,t]of r.entries()){n.searchParams.set(e,t)}return n}function withResolvedInvocationTarget({result:e,url:t,resolvedPathname:n,invocationPathname:a}){const r=toResolvedQuery(t);return{...e,resolvedPathname:n,resolvedQuery:r,invocationTarget:{pathname:a,query:r}}}function matchDynamicRoute(e,t){const n=new RegExp(t.sourceRegex);const a=e.match(n);if(!a){return{matched:false}}const r={};for(let e=1;e<a.length;e++){if(a[e]!==undefined){r[String(e)]=a[e]}}if(a.groups){Object.assign(r,a.groups)}return{matched:true,params:r,regexMatches:a}}function applyOnMatchHeaders(e,t,n,a){const r=new Headers(a);for(const a of e){const e=matchRoute(a,t,n);if(e.matched&&e.headers){for(const[t,n]of Object.entries(e.headers)){r.set(t,n)}}}return r}function checkDynamicRoutes(e,t,n,a,r,s,o,i,c,l){let d=t;if(l&&c){d=denormalizeNextDataUrl(t,o,i)}for(const t of e){const e=matchDynamicRoute(d.pathname,t);if(e.matched){const o=checkHasConditions(t.has,d,a);const i=checkMissingConditions(t.missing,d,a);if(o.matched&&i){const i=t.destination?replaceDestination(t.destination,e.regexMatches||null,o.captures):undefined;const c=i?i.split("?")[0]:d.pathname;const l=matchesPathname(c,n);if(l){const t=i?mergeDestinationQueryIntoUrl(d,i):d;const n=applyOnMatchHeaders(s,t,a,r);const o=withResolvedInvocationTarget({result:{routeMatches:e.params,resolvedHeaders:n},url:t,resolvedPathname:l,invocationPathname:d.pathname});return{matched:true,result:o,resetUrl:d}}}}}return{matched:false}}async function resolveRoutes(e){const{url:t,basePath:n,requestBody:a,headers:r,pathnames:s,routes:o,invokeMiddleware:i,buildId:c,i18n:l}=e;const{shouldNormalizeNextData:d}=o;let u=new URL(t.toString());let f=new Headers(r);let h=new Headers;let m;const p=t.origin;let g=false;if(d){const e=`${n}/_next/data/${c}/`;g=t.pathname.startsWith(e);if(g){u=normalizeNextDataUrl(u,n,c)}}if(l&&!g){const e=u.pathname.startsWith(n)?u.pathname.slice(n.length)||"/":u.pathname;if(!e.startsWith("/_next/")&&!e.startsWith("/api/")){const t=u.hostname;const a=f.get("cookie")||undefined;const r=f.get("accept-language")||undefined;const s=normalizeLocalePath(e,l.locales);const o=!!s.detectedLocale;const i=detectDomainLocale(l.domains,t);const c=i?.defaultLocale||l.defaultLocale;let d=s.detectedLocale||c;if(l.localeDetection!==false&&!o){const s=detectLocale({pathname:e,hostname:t,cookieHeader:a,acceptLanguageHeader:r,i18n:l});d=s.locale;if(d!==c){const a=detectDomainLocale(l.domains,undefined,d);if(a&&a.domain!==t){const t=a.http?"http":"https";const r=d===a.defaultLocale?"":`/${d}`;const s=new URL(`${t}://${a.domain}${n}${r}${e}${u.search}`);return{redirect:{url:s,status:307},resolvedHeaders:h}}if(!a||a&&a.domain===t){const t=new URL(u.toString());t.pathname=`${n}/${d}${e}`;return{redirect:{url:t,status:307},resolvedHeaders:h}}}}if(!o){const t=d||i?.defaultLocale||l.defaultLocale;u.pathname=`${n}/${t}${e}`}}}const w=processRoutes(o.beforeMiddleware,u,f,h,p);if(w.status){m=w.status}if(w.redirect){return{redirect:w.redirect,resolvedHeaders:h,status:m}}if(w.externalRewrite){return{externalRewrite:w.externalRewrite,resolvedHeaders:h,status:m}}u=w.url;if(g&&d){u=denormalizeNextDataUrl(u,n,c)}const L=await i({url:u,headers:f,requestBody:a});if(L.bodySent){return{middlewareResponded:true}}if(L.requestHeaders){f=new Headers(L.requestHeaders)}if(L.responseHeaders){L.responseHeaders.forEach(((e,t)=>{if(t.toLowerCase()==="set-cookie"){h.append(t,e)}else{h.set(t,e)}}))}if(L.redirect){if(!h.has("location")){h.set("Location",L.redirect.url.toString())}return{resolvedHeaders:h,status:L.redirect.status}}if(L.rewrite){u=L.rewrite;if(u.origin!==p){return{externalRewrite:u,resolvedHeaders:h,status:m}}}if(g&&d){u=normalizeNextDataUrl(u,n,c)}const R=processRoutes(o.beforeFiles,u,f,h,p);if(R.status){m=R.status}if(R.redirect){return{redirect:R.redirect,resolvedHeaders:h,status:m}}if(R.externalRewrite){return{externalRewrite:R.externalRewrite,resolvedHeaders:h,status:m}}u=R.url;if(g&&d){u=denormalizeNextDataUrl(u,n,c)}let y=matchesPathname(u.pathname,s);if(y){for(const e of o.dynamicRoutes){const t=matchDynamicRoute(u.pathname,e);if(t.matched){const n=checkHasConditions(e.has,u,f);const a=checkMissingConditions(e.missing,u,f);if(n.matched&&a){const a=e.destination?replaceDestination(e.destination,t.regexMatches||null,n.captures):undefined;const r=a?mergeDestinationQueryIntoUrl(u,a):u;const s=applyOnMatchHeaders(o.onMatch,r,f,h);return withResolvedInvocationTarget({result:{routeMatches:t.params,resolvedHeaders:s,status:m},url:r,resolvedPathname:y,invocationPathname:u.pathname})}}}const e=applyOnMatchHeaders(o.onMatch,u,f,h);return withResolvedInvocationTarget({result:{resolvedHeaders:e,status:m},url:u,resolvedPathname:y,invocationPathname:u.pathname})}if(g&&d){u=normalizeNextDataUrl(u,n,c)}for(const e of o.afterFiles){const t=matchRoute(e,u,f);if(t.matched){if(t.headers){for(const[e,n]of Object.entries(t.headers)){h.set(e,n)}}if(e.status){m=e.status}if(t.destination){if(isRedirectStatus(e.status)&&t.headers&&hasRedirectHeaders(t.headers)){const n=isExternalDestination(t.destination)?new URL(t.destination):applyDestination(u,t.destination);return{redirect:{url:n,status:e.status},resolvedHeaders:h,status:m}}if(isExternalDestination(t.destination)){return{externalRewrite:new URL(t.destination),resolvedHeaders:h,status:m}}u=applyDestination(u,t.destination);if(u.origin!==p){return{externalRewrite:u,resolvedHeaders:h,status:m}}const a=checkDynamicRoutes(o.dynamicRoutes,u,s,f,h,o.onMatch,n,c,d,g);if(a.matched&&a.result){if(a.resetUrl){u=a.resetUrl}return{...a.result,status:m}}let r=u;if(g&&d){r=denormalizeNextDataUrl(u,n,c)}y=matchesPathname(r.pathname,s);if(y){const e=applyOnMatchHeaders(o.onMatch,r,f,h);return withResolvedInvocationTarget({result:{resolvedHeaders:e,status:m},url:r,resolvedPathname:y,invocationPathname:r.pathname})}}}}for(const e of o.dynamicRoutes){const t=matchDynamicRoute(u.pathname,e);if(t.matched){const n=checkHasConditions(e.has,u,f);const a=checkMissingConditions(e.missing,u,f);if(n.matched&&a){const a=e.destination?replaceDestination(e.destination,t.regexMatches||null,n.captures):undefined;const r=a?a.split("?")[0]:u.pathname;y=matchesPathname(r,s);if(y){const e=a?mergeDestinationQueryIntoUrl(u,a):u;const n=applyOnMatchHeaders(o.onMatch,e,f,h);return withResolvedInvocationTarget({result:{routeMatches:t.params,resolvedHeaders:n,status:m},url:e,resolvedPathname:y,invocationPathname:u.pathname})}}}}for(const e of o.fallback){const t=matchRoute(e,u,f);if(t.matched){if(t.headers){for(const[e,n]of Object.entries(t.headers)){h.set(e,n)}}if(e.status){m=e.status}if(t.destination){if(isRedirectStatus(e.status)&&t.headers&&hasRedirectHeaders(t.headers)){const n=isExternalDestination(t.destination)?new URL(t.destination):applyDestination(u,t.destination);return{redirect:{url:n,status:e.status},resolvedHeaders:h,status:m}}if(isExternalDestination(t.destination)){return{externalRewrite:new URL(t.destination),resolvedHeaders:h,status:m}}u=applyDestination(u,t.destination);if(u.origin!==p){return{externalRewrite:u,resolvedHeaders:h,status:m}}const a=checkDynamicRoutes(o.dynamicRoutes,u,s,f,h,o.onMatch,n,c,d,g);if(a.matched&&a.result){if(a.resetUrl){u=a.resetUrl}return{...a.result,status:m}}let r=u;if(g&&d){r=denormalizeNextDataUrl(u,n,c)}y=matchesPathname(r.pathname,s);if(y){const e=applyOnMatchHeaders(o.onMatch,r,f,h);return withResolvedInvocationTarget({result:{resolvedHeaders:e,status:m},url:r,resolvedPathname:y,invocationPathname:r.pathname})}}}}return{resolvedHeaders:h,status:m}}function responseToMiddlewareResult(e,t,a){const r={};const s={};e.headers.forEach(((e,t)=>{if(s[t]){const n=s[t];if(Array.isArray(n)){n.push(e)}else{s[t]=[n,e]}}else{s[t]=e}}));if(s["x-middleware-override-headers"]){const e=new Set;let n=s["x-middleware-override-headers"];if(typeof n==="string"){n=n.split(",")}for(const t of n){e.add(t.trim())}delete s["x-middleware-override-headers"];const a=[];t.forEach(((t,n)=>{if(!e.has(n)){a.push(n)}}));for(const e of a){t.delete(e)}for(const n of e.keys()){const e="x-middleware-request-"+n;const a=s[e];if(a===undefined||a===null){t.delete(n)}else if(Array.isArray(a)){t.set(n,a[0]);for(let e=1;e<a.length;e++){t.append(n,a[e])}}else{t.set(n,a)}delete s[e]}}if(!s["x-middleware-rewrite"]&&!s["x-middleware-next"]&&!s["location"]){s["x-middleware-refresh"]="1"}delete s["x-middleware-next"];const o=new Headers;for(const[e,n]of Object.entries(s)){if(["content-length","x-middleware-rewrite","x-middleware-redirect","x-middleware-refresh"].includes(e)){continue}if(e==="x-middleware-set-cookie"){if(n!==undefined){if(Array.isArray(n)){for(const a of n){t.append(e,a)}}else{t.set(e,n)}}continue}if(n!==undefined){if(Array.isArray(n)){for(const a of n){o.append(e,a);t.append(e,a)}}else{o.set(e,n);t.set(e,n)}}}r.responseHeaders=o;r.requestHeaders=t;if(s["x-middleware-rewrite"]){const e=s["x-middleware-rewrite"];const t=getRelativeURL(e,a.toString());o.set("x-middleware-rewrite",t);try{const e=new URL(t,a);if(e.origin!==a.origin){r.rewrite=e;return r}r.rewrite=e}catch{r.rewrite=new URL(t,a)}}if(s["location"]){const t=s["location"];const i=n.has(e.status);if(i){const n=getRelativeURL(t,a.toString());o.set("location",n);try{const t=new URL(n,a);r.redirect={url:t,status:e.status};return r}catch{r.redirect={url:new URL(n,a),status:e.status};return r}}else{o.set("location",t);return r}}if(s["x-middleware-refresh"]){r.bodySent=true;return r}return r}function getRelativeURL(e,t){try{const n=new URL(e,t);const a=new URL(t);if(n.origin===a.origin){return n.pathname+n.search+n.hash}return n.toString()}catch{return e}}const n=new Set([301,302,303,307,308]);module.exports=t})();
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { RouteHas } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Checks if all "has" conditions are satisfied
|
|
4
|
+
*/
|
|
5
|
+
export declare function checkHasConditions(has: RouteHas[] | undefined, url: URL, headers: Headers): {
|
|
6
|
+
matched: boolean;
|
|
7
|
+
captures: Record<string, string>;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Checks if all "missing" conditions are satisfied (i.e., none of them match)
|
|
11
|
+
*/
|
|
12
|
+
export declare function checkMissingConditions(missing: RouteHas[] | undefined, url: URL, headers: Headers): boolean;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { MiddlewareResult } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Converts a middleware Response object to a MiddlewareResult.
|
|
4
|
+
* This function processes middleware response headers and applies transformations
|
|
5
|
+
* such as header overrides, rewrites, redirects, and refresh signals.
|
|
6
|
+
*
|
|
7
|
+
* @param response - The Response object returned from middleware
|
|
8
|
+
* @param requestHeaders - The request Headers object to be mutated
|
|
9
|
+
* @param url - The original request URL
|
|
10
|
+
* @returns A MiddlewareResult object with processed headers and routing information
|
|
11
|
+
*/
|
|
12
|
+
export declare function responseToMiddlewareResult(response: Response, requestHeaders: Headers, url: URL): MiddlewareResult;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalizes Next.js data URL by removing /_next/data/{buildId}/ prefix and .json extension
|
|
3
|
+
* ${basePath}/_next/data/$buildId/$path.json -> ${basePath}/$path
|
|
4
|
+
*/
|
|
5
|
+
export declare function normalizeNextDataUrl(url: URL, basePath: string, buildId: string): URL;
|
|
6
|
+
/**
|
|
7
|
+
* Denormalizes URL by adding /_next/data/{buildId}/ prefix and .json extension
|
|
8
|
+
* ${basePath}/$path -> ${basePath}/_next/data/$buildId/$path.json
|
|
9
|
+
*/
|
|
10
|
+
export declare function denormalizeNextDataUrl(url: URL, basePath: string, buildId: string): URL;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
export type RouteHas = {
|
|
2
|
+
type: 'header' | 'cookie' | 'query';
|
|
3
|
+
key: string;
|
|
4
|
+
value?: string;
|
|
5
|
+
} | {
|
|
6
|
+
type: 'host';
|
|
7
|
+
key?: undefined;
|
|
8
|
+
value: string;
|
|
9
|
+
};
|
|
10
|
+
export type Route = {
|
|
11
|
+
sourceRegex: string;
|
|
12
|
+
destination?: string;
|
|
13
|
+
headers?: Record<string, string>;
|
|
14
|
+
has?: RouteHas[];
|
|
15
|
+
missing?: RouteHas[];
|
|
16
|
+
status?: number;
|
|
17
|
+
};
|
|
18
|
+
export type MiddlewareContext = {
|
|
19
|
+
url: URL;
|
|
20
|
+
headers: Headers;
|
|
21
|
+
requestBody: ReadableStream;
|
|
22
|
+
};
|
|
23
|
+
export type MiddlewareResult = {
|
|
24
|
+
bodySent?: boolean;
|
|
25
|
+
requestHeaders?: Headers;
|
|
26
|
+
responseHeaders?: Headers;
|
|
27
|
+
redirect?: {
|
|
28
|
+
url: URL;
|
|
29
|
+
status: number;
|
|
30
|
+
};
|
|
31
|
+
rewrite?: URL;
|
|
32
|
+
};
|
|
33
|
+
export type ResolveRoutesParams = {
|
|
34
|
+
url: URL;
|
|
35
|
+
buildId: string;
|
|
36
|
+
basePath: string;
|
|
37
|
+
requestBody: ReadableStream;
|
|
38
|
+
headers: Headers;
|
|
39
|
+
pathnames: string[];
|
|
40
|
+
i18n?: {
|
|
41
|
+
defaultLocale: string;
|
|
42
|
+
domains?: Array<{
|
|
43
|
+
defaultLocale: string;
|
|
44
|
+
domain: string;
|
|
45
|
+
http?: true;
|
|
46
|
+
locales?: string[];
|
|
47
|
+
}>;
|
|
48
|
+
localeDetection?: false;
|
|
49
|
+
locales: string[];
|
|
50
|
+
};
|
|
51
|
+
routes: {
|
|
52
|
+
beforeMiddleware: Array<Route>;
|
|
53
|
+
beforeFiles: Array<Route>;
|
|
54
|
+
afterFiles: Array<Route>;
|
|
55
|
+
dynamicRoutes: Array<Route>;
|
|
56
|
+
onMatch: Array<Route>;
|
|
57
|
+
fallback: Array<Route>;
|
|
58
|
+
shouldNormalizeNextData?: boolean;
|
|
59
|
+
};
|
|
60
|
+
invokeMiddleware: (ctx: MiddlewareContext) => Promise<MiddlewareResult>;
|
|
61
|
+
};
|
|
62
|
+
export type ResolveRoutesQueryValue = string | string[];
|
|
63
|
+
export type ResolveRoutesQuery = Record<string, ResolveRoutesQueryValue>;
|
|
64
|
+
export type RouteInvocationTarget = {
|
|
65
|
+
/**
|
|
66
|
+
* Concrete pathname that should be invoked after routing resolution.
|
|
67
|
+
*/
|
|
68
|
+
pathname: string;
|
|
69
|
+
/**
|
|
70
|
+
* Concrete query that should be invoked after routing resolution.
|
|
71
|
+
*/
|
|
72
|
+
query: ResolveRoutesQuery;
|
|
73
|
+
};
|
|
74
|
+
export type ResolveRoutesResult = {
|
|
75
|
+
middlewareResponded?: boolean;
|
|
76
|
+
externalRewrite?: URL;
|
|
77
|
+
redirect?: {
|
|
78
|
+
url: URL;
|
|
79
|
+
status: number;
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* Resolved pathname selected by route matching. For dynamic routes this is
|
|
83
|
+
* the matched template pathname.
|
|
84
|
+
*/
|
|
85
|
+
resolvedPathname?: string;
|
|
86
|
+
/**
|
|
87
|
+
* Merged query produced by rewrite/middleware routing.
|
|
88
|
+
*/
|
|
89
|
+
resolvedQuery?: ResolveRoutesQuery;
|
|
90
|
+
/**
|
|
91
|
+
* Concrete invocation target to use when invoking the resolved route/module.
|
|
92
|
+
*/
|
|
93
|
+
invocationTarget?: RouteInvocationTarget;
|
|
94
|
+
resolvedHeaders?: Headers;
|
|
95
|
+
status?: number;
|
|
96
|
+
routeMatches?: Record<string, string>;
|
|
97
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@next/routing",
|
|
3
|
+
"version": "16.2.4",
|
|
4
|
+
"keywords": [
|
|
5
|
+
"react",
|
|
6
|
+
"next",
|
|
7
|
+
"next.js",
|
|
8
|
+
"routing"
|
|
9
|
+
],
|
|
10
|
+
"description": "Next.js shared route resolving",
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "https://github.com/vercel/next.js",
|
|
14
|
+
"directory": "packages/next-routing"
|
|
15
|
+
},
|
|
16
|
+
"author": "Next.js Team <support@vercel.com>",
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"main": "dist/index.js",
|
|
19
|
+
"types": "dist/index.d.ts",
|
|
20
|
+
"files": [
|
|
21
|
+
"dist"
|
|
22
|
+
],
|
|
23
|
+
"scripts": {
|
|
24
|
+
"dev": "ncc build ./src/index.ts -w -o dist/",
|
|
25
|
+
"prerelease": "node ../../scripts/rm.mjs dist",
|
|
26
|
+
"types": "tsc --declaration --emitDeclarationOnly --declarationDir dist",
|
|
27
|
+
"release": "ncc build ./src/index.ts -o ./dist/ --minify --no-cache --no-source-map-register",
|
|
28
|
+
"build": "pnpm release && pnpm types",
|
|
29
|
+
"test": "jest",
|
|
30
|
+
"test:watch": "jest --watch",
|
|
31
|
+
"prepublishOnly": "cd ../../ && turbo run build"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/jest": "^29.5.0",
|
|
35
|
+
"@vercel/ncc": "0.34.0",
|
|
36
|
+
"jest": "^29.5.0",
|
|
37
|
+
"ts-jest": "^29.1.0"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://swc.rs/">
|
|
3
|
+
<img alt="swc" src="https://raw.githubusercontent.com/swc-project/logo/master/swc.png" width="546">
|
|
4
|
+
</a>
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
Make the web (development) faster.
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
<a href="https://www.npmjs.com/package/@swc/core"><img alt="downloads (@swc/core)" src="https://img.shields.io/npm/dm/@swc/core?label=downloads%20%28%40swc%2Fcore%29"></a>
|
|
13
|
+
<a href="https://www.npmjs.com/package/@swc/counter?activeTab=dependents"><img alt="downloads (3rd party)" src="https://img.shields.io/npm/dm/@swc/counter?label=downloads%20%283rd%20party%29"></a>
|
|
14
|
+
</p>
|
|
15
|
+
<p align="center">
|
|
16
|
+
<a href="https://crates.io/crates/swc_ecma_parser"><img alt="undefined" src="https://img.shields.io/crates/d/swc_ecma_parser.svg?label=crates.io%20downloads"></a>
|
|
17
|
+
<a href="https://github.com/swc-project/swc/releases/latest"><img alt="GitHub release (latest SemVer)" src="https://img.shields.io/github/v/release/swc-project/swc"></a>
|
|
18
|
+
</p>
|
|
19
|
+
<p align="center">
|
|
20
|
+
<img alt="GitHub code size in bytes" src="https://img.shields.io/github/languages/code-size/swc-project/swc">
|
|
21
|
+
<a href="https://github.com/swc-project/swc/blob/main/package.json#L22"><img alt="node-current (scoped)" src="https://img.shields.io/node/v/@swc/core"></a>
|
|
22
|
+
</p>
|
|
23
|
+
<p align="center">
|
|
24
|
+
<a href="https://discord.com/invite/GnHbXTdZz6"><img alt="Discord" src="https://img.shields.io/discord/889779439272075314"></a>
|
|
25
|
+
</p>
|
|
26
|
+
|
|
27
|
+
SWC (stands for `Speedy Web Compiler`) is a super-fast TypeScript / JavaScript compiler written in Rust. It's a library for Rust and JavaScript at the same time. If you are using SWC from Rust, see [rustdoc](https://rustdoc.swc.rs/swc/) and for most users, your entry point for using the library will be [parser](https://rustdoc.swc.rs/swc_ecma_parser/).
|
|
28
|
+
|
|
29
|
+
Also, SWC tries to ensure that
|
|
30
|
+
|
|
31
|
+
> If you select the latest version of each crates, it will work
|
|
32
|
+
|
|
33
|
+
for rust users.
|
|
34
|
+
|
|
35
|
+
MSRV of crates is currently `1.73`.
|
|
36
|
+
|
|
37
|
+
To update all SWC crates you use, you can run `curl https://raw.githubusercontent.com/swc-project/swc/main/scripts/update-all-swc-crates.sh | bash -s`. This script will update all dependencies to the latest version and run `cargo build` to ensure that everything works.
|
|
38
|
+
Note that you need
|
|
39
|
+
|
|
40
|
+
- `jq`
|
|
41
|
+
- `cargo upgrade`
|
|
42
|
+
|
|
43
|
+
command to run the script.
|
|
44
|
+
|
|
45
|
+
Supported Node Versions:
|
|
46
|
+
|
|
47
|
+
- Node v10+ for usage
|
|
48
|
+
- Node v20+ for development
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
If you are using SWC from JavaScript, please refer to [docs on the website](https://swc.rs/docs/installation/).
|
|
53
|
+
|
|
54
|
+
# Documentation
|
|
55
|
+
|
|
56
|
+
Check out the documentation [in the website](https://swc.rs/docs/installation/).
|
|
57
|
+
|
|
58
|
+
# Features
|
|
59
|
+
|
|
60
|
+
Please see [comparison with babel](https://swc.rs/docs/migrating-from-babel).
|
|
61
|
+
|
|
62
|
+
# Performance
|
|
63
|
+
|
|
64
|
+
Please see [benchmark results](https://swc.rs/docs/benchmark-transform) on the website.
|
|
65
|
+
|
|
66
|
+
# Supporting development
|
|
67
|
+
|
|
68
|
+
<h2 align="center">Supporting swc</h2>
|
|
69
|
+
|
|
70
|
+
## Star History
|
|
71
|
+
|
|
72
|
+
[](https://www.star-history.com/#swc-project/swc&Timeline)
|
|
73
|
+
|
|
74
|
+
## Powered by
|
|
75
|
+
|
|
76
|
+
[](https://jb.gg/OpenSourceSupport)
|
|
77
|
+
|
|
78
|
+
## Sponsors
|
|
79
|
+
|
|
80
|
+
<p align="center">
|
|
81
|
+
<a href="https://opencollective.com/swc">
|
|
82
|
+
<img src="https://raw.githubusercontent.com/swc-project/swc-sponsor-images/main/sponsors.svg" alt="Sponsors">
|
|
83
|
+
</a>
|
|
84
|
+
</p>
|
|
85
|
+
|
|
86
|
+
SWC is a community-driven project, and is maintained by a group of [volunteers](https://swc.rs/docs/team). If you'd like to help support the future of the project, please consider:
|
|
87
|
+
|
|
88
|
+
- Giving developer time on the project. (Message us on [Discord](https://discord.gg/GnHbXTdZz6) (preferred) or [Github discussions](https://github.com/swc-project/swc/discussions) for guidance!)
|
|
89
|
+
- Giving funds by becoming a sponsor (see https://opencollective.com/swc)!
|
|
90
|
+
|
|
91
|
+
## Contributing
|
|
92
|
+
|
|
93
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md). You may also find the architecture
|
|
94
|
+
documentation useful ([ARCHITECTURE.md](ARCHITECTURE.md)).
|
|
95
|
+
|
|
96
|
+
## License
|
|
97
|
+
|
|
98
|
+
SWC is primarily distributed under the terms of the Apache License (Version 2.0).
|
|
99
|
+
|
|
100
|
+
See [LICENSE](LICENSE) for details.
|