├── .eslintignore ├── .gitattributes ├── .npmignore ├── example ├── page-router │ ├── src │ │ ├── pages │ │ │ ├── a │ │ │ │ └── b.tsx │ │ │ ├── 404.tsx │ │ │ ├── _app.tsx │ │ │ ├── api │ │ │ │ └── hello.ts │ │ │ ├── second.tsx │ │ │ └── index.tsx │ │ ├── constants.ts │ │ ├── components │ │ │ ├── sharedComponent.tsx │ │ │ ├── injectDescription.tsx │ │ │ └── header.tsx │ │ └── styles │ │ │ ├── globals.css │ │ │ └── Home.module.css │ ├── public │ │ ├── favicon.ico │ │ └── vercel.svg │ ├── README.md │ ├── .gitignore │ ├── next.config.js │ ├── package.json │ ├── tsconfig.json │ └── obfuscator-options.js └── app-router │ ├── .yarnrc.yml │ ├── .vscode │ ├── extensions.json │ └── settings.json │ ├── src │ └── app │ │ ├── favicon.ico │ │ ├── layout.tsx │ │ ├── client.tsx │ │ ├── globals.css │ │ ├── page.tsx │ │ └── page.module.css │ ├── .yarn │ └── sdks │ │ ├── integrations.yml │ │ └── typescript │ │ ├── package.json │ │ ├── lib │ │ ├── typescript.js │ │ ├── tsc.js │ │ ├── tsserver.js │ │ └── tsserverlibrary.js │ │ └── bin │ │ ├── tsc │ │ └── tsserver │ ├── package.json │ ├── public │ ├── vercel.svg │ └── next.svg │ ├── next.config.js │ ├── .gitignore │ ├── tsconfig.json │ ├── README.md │ ├── yarn.lock │ └── .pnp.loader.mjs ├── .eslintrc.json ├── .gitignore ├── tsconfig.json ├── .swcrc ├── src ├── debug.ts ├── type.ts ├── loader.ts └── index.ts ├── LICENSE ├── package.json └── README.md /.eslintignore: -------------------------------------------------------------------------------- 1 | example 2 | *.js 3 | *.d.ts 4 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | example/* linguist-documentation 2 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | example 2 | src 3 | tsconfig.json 4 | .swcrc 5 | .git* 6 | .eslint* 7 | -------------------------------------------------------------------------------- /example/page-router/src/pages/a/b.tsx: -------------------------------------------------------------------------------- 1 | export default function(){ 2 | return

a

3 | } -------------------------------------------------------------------------------- /example/app-router/.yarnrc.yml: -------------------------------------------------------------------------------- 1 | yarnPath: .yarn/releases/yarn-3.6.0.cjs 2 | nodeLinker: pnp 3 | -------------------------------------------------------------------------------- /example/page-router/src/pages/404.tsx: -------------------------------------------------------------------------------- 1 | export default function C404(){ 2 | return

404

3 | } 4 | -------------------------------------------------------------------------------- /example/app-router/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "arcanis.vscode-zipfs" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /example/page-router/src/constants.ts: -------------------------------------------------------------------------------- 1 | export const GitHubPageUrl = "https://github.com/mtripg6666tdr/nextjs-obfuscator"; 2 | -------------------------------------------------------------------------------- /example/app-router/src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mtripg6666tdr/nextjs-obfuscator/HEAD/example/app-router/src/app/favicon.ico -------------------------------------------------------------------------------- /example/page-router/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mtripg6666tdr/nextjs-obfuscator/HEAD/example/page-router/public/favicon.ico -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "@mtripg6666tdr/eslint-config/nodejs-typescript" 4 | ], 5 | "parserOptions": { 6 | "project": "./tsconfig.json" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /example/app-router/.yarn/sdks/integrations.yml: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by @yarnpkg/sdks. 2 | # Manual changes might be lost! 3 | 4 | integrations: 5 | - vscode 6 | -------------------------------------------------------------------------------- /example/page-router/README.md: -------------------------------------------------------------------------------- 1 | This directory contains an example app that have been obfuscated by nextjs-obfuscator. 2 | Almost all of These files were generated by `create-next-app`. 3 | -------------------------------------------------------------------------------- /example/app-router/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "search.exclude": { 3 | "**/.yarn": true, 4 | "**/.pnp.*": true 5 | }, 6 | "typescript.tsdk": ".yarn/sdks/typescript/lib", 7 | "typescript.enablePromptUseWorkspaceTsdk": true 8 | } 9 | -------------------------------------------------------------------------------- /example/page-router/src/components/sharedComponent.tsx: -------------------------------------------------------------------------------- 1 | import { AnimatePresence } from "framer-motion"; 2 | 3 | export default function SharedComponent(){ 4 | return ( 5 | 6 |

あいうえお

7 |
8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /example/app-router/.yarn/sdks/typescript/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "typescript", 3 | "version": "5.2.2-sdk", 4 | "main": "./lib/typescript.js", 5 | "type": "commonjs", 6 | "bin": { 7 | "tsc": "./bin/tsc", 8 | "tsserver": "./bin/tsserver" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /example/page-router/src/pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import '../styles/globals.css' 2 | import type { AppProps } from 'next/app' 3 | import ExampleHeader from '../components/header' 4 | 5 | function MyApp({ Component, pageProps }: AppProps) { 6 | return ( 7 | <> 8 | 9 | 10 | 11 | ) 12 | } 13 | 14 | export default MyApp 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *node_modules 2 | index.js 3 | loader.js 4 | loader.d.ts 5 | type.js 6 | type.d.ts 7 | index.d.ts 8 | debug.js 9 | debug.d.ts 10 | *.temp.* 11 | *.tmp.* 12 | *.temp 13 | *.tmp 14 | *.log 15 | 16 | # VSCode 17 | **/.vscode/* 18 | !**/.vscode/settings.json 19 | !**/.vscode/tasks.json 20 | !**/.vscode/launch.json 21 | !**/.vscode/extensions.json 22 | !**/.vscode/*.code-snippets 23 | -------------------------------------------------------------------------------- /example/page-router/src/pages/api/hello.ts: -------------------------------------------------------------------------------- 1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction 2 | import type { NextApiRequest, NextApiResponse } from 'next' 3 | 4 | type Data = { 5 | name: string 6 | } 7 | 8 | export default function handler( 9 | req: NextApiRequest, 10 | res: NextApiResponse 11 | ) { 12 | res.status(200).json({ name: 'John Doe' }) 13 | } 14 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "@tsconfig/node16/tsconfig.json" 4 | ], 5 | "compilerOptions": { 6 | "allowSyntheticDefaultImports": true, 7 | "esModuleInterop": true, 8 | "strict": true, 9 | "outDir": "./", 10 | "declaration": true, 11 | "declarationDir": ".", 12 | "emitDeclarationOnly": true, 13 | "skipLibCheck": true 14 | }, 15 | "include": [ 16 | "./src/**/*.ts" 17 | ], 18 | "exclude": [ 19 | "**/node_modules" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /example/app-router/src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import './globals.css' 2 | import { Inter } from 'next/font/google' 3 | 4 | const inter = Inter({ subsets: ['latin'] }) 5 | 6 | export const metadata = { 7 | title: 'Create Next App', 8 | description: 'Generated by create next app', 9 | } 10 | 11 | export default function RootLayout({ 12 | children, 13 | }: { 14 | children: React.ReactNode 15 | }) { 16 | return ( 17 | 18 | {children} 19 | 20 | ) 21 | } 22 | -------------------------------------------------------------------------------- /example/app-router/src/app/client.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { useEffect } from "react"; 4 | 5 | export default function Alerter(){ 6 | useEffect(() => { 7 | let timeout: any = setTimeout(() => { 8 | window.alert("a"); 9 | timeout = null; 10 | }, 5e3); 11 | return () => timeout && clearTimeout(timeout); 12 | }, []); 13 | 14 | return ( 15 | <> 16 | client component 17 | (env: NEXT_PUBLIC_FOOBAR: {process.env.NEXT_PUBLIC_FOOBAR}) 18 | 19 | ) 20 | } 21 | -------------------------------------------------------------------------------- /example/page-router/src/components/injectDescription.tsx: -------------------------------------------------------------------------------- 1 | import Link from "next/link"; 2 | import { GitHubPageUrl } from "../constants"; 3 | 4 | export default function InjectDescription(){ 5 | return ( 6 | <> 7 |

*This website is obfuscated by nextjs-obfuscator powered by javascript-obfuscator.

11 | 12 | Go to 2nd page. 13 | 14 | 15 | ) 16 | } 17 | -------------------------------------------------------------------------------- /.swcrc: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/swcrc", 3 | "jsc": { 4 | "parser": { 5 | "syntax": "typescript", 6 | "tsx": false, 7 | "decorators": false, 8 | "dynamicImport": false 9 | }, 10 | "transform": {}, 11 | "target": "es2021", 12 | "loose": false, 13 | "externalHelpers": false, 14 | // Requires v1.2.50 or upper and requires target to be es2016 or upper. 15 | "keepClassNames": false 16 | }, 17 | "minify": false, 18 | "module": { 19 | "type": "commonjs" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /example/page-router/src/styles/globals.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | padding: 0; 4 | margin: 0; 5 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, 6 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; 7 | } 8 | 9 | a { 10 | color: inherit; 11 | text-decoration: none; 12 | } 13 | 14 | * { 15 | box-sizing: border-box; 16 | } 17 | 18 | @media (prefers-color-scheme: dark) { 19 | html { 20 | color-scheme: dark; 21 | } 22 | body { 23 | color: white; 24 | background: black; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /example/page-router/src/pages/second.tsx: -------------------------------------------------------------------------------- 1 | import Link from "next/link"; 2 | import SharedComponent from "../components/sharedComponent"; 3 | 4 | export default function SecondPage(){ 5 | const style = { 6 | textAlign: "center" as const, 7 | fontSize: "1.4rem", 8 | }; 9 | 10 | return ( 11 |
12 |

This is the 2nd test page!

13 |

14 | 15 | 16 | Return to top 17 | 18 |

19 |
20 | ) 21 | } 22 | -------------------------------------------------------------------------------- /example/page-router/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | .pnpm-debug.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | -------------------------------------------------------------------------------- /src/debug.ts: -------------------------------------------------------------------------------- 1 | import fs from "fs"; 2 | 3 | export function writeDownWebpackConfig(config: any){ 4 | const stringified = JSON.stringify(config, jsonStringifyReplacer, " "); 5 | 6 | fs.writeFileSync(`./webpack-config-${Date.now()}.temp.json`, stringified); 7 | } 8 | 9 | function jsonStringifyReplacer(_key: string, value: any){ 10 | if(value instanceof RegExp){ 11 | return { "[__type]": "RegExp", value: value.toString() }; 12 | }else if(typeof value === "bigint"){ 13 | return { "[__type": "BigInt", value: value.toString() }; 14 | } 15 | 16 | return value; 17 | } 18 | -------------------------------------------------------------------------------- /example/page-router/next.config.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | const obfuscatorOptions = require("./obfuscator-options"); 3 | const withNextJSObfuscatorPlugin = require("../..")(obfuscatorOptions, { 4 | log: true, 5 | obfuscateFiles: { 6 | buildManifest: true, 7 | ssgManifest: true, 8 | webpack: true, 9 | additionalModules: ["es6-object-assign"], 10 | }, 11 | }); 12 | 13 | /** @type {import('next').NextConfig} */ 14 | module.exports = withNextJSObfuscatorPlugin({ 15 | productionBrowserSourceMaps: true, 16 | eslint: { 17 | ignoreDuringBuilds: true, 18 | } 19 | }); 20 | -------------------------------------------------------------------------------- /example/app-router/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example-nextjs-obfuscated-app-with-app-router", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "next": "15.0.2", 13 | "react": "18.3.1", 14 | "react-dom": "18.3.1", 15 | "typescript": "5.6.3" 16 | }, 17 | "devDependencies": { 18 | "@types/node": "22.8.7", 19 | "@types/react": "18.3.12", 20 | "@types/react-dom": "^18.3.1" 21 | }, 22 | "packageManager": "yarn@3.6.0" 23 | } 24 | -------------------------------------------------------------------------------- /example/app-router/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/app-router/next.config.js: -------------------------------------------------------------------------------- 1 | const withNextjsObfuscator = require("../..")( 2 | require("../page-router/obfuscator-options"), 3 | { 4 | log: true, 5 | // writeConfig: true, 6 | obfuscateFiles: { 7 | buildManifest: true, 8 | ssgManifest: true, 9 | webpack: true, 10 | additionalModules: ["es6-object-assign"], 11 | }, 12 | } 13 | ); 14 | 15 | /** @type {import('next').NextConfig} */ 16 | const nextConfig = { 17 | eslint: { 18 | ignoreDuringBuilds: true, 19 | }, 20 | env: { 21 | NEXT_PUBLIC_FOOBAR: "foobar", 22 | }, 23 | }; 24 | 25 | module.exports = withNextjsObfuscator(nextConfig); 26 | -------------------------------------------------------------------------------- /example/page-router/src/components/header.tsx: -------------------------------------------------------------------------------- 1 | import { GitHubPageUrl } from "../constants"; 2 | 3 | export default function ExampleHeader(){ 4 | return ( 5 |
11 | An example obfuscated Next.js app 12 |
15 | 16 | GitHub 17 | 18 |
19 |
20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /example/app-router/.yarn/sdks/typescript/lib/typescript.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire} = require(`module`); 5 | const {resolve} = require(`path`); 6 | 7 | const relPnpApiPath = "../../../../.pnp.cjs"; 8 | 9 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 10 | const absRequire = createRequire(absPnpApiPath); 11 | 12 | if (existsSync(absPnpApiPath)) { 13 | if (!process.versions.pnp) { 14 | // Setup the environment to be able to require typescript 15 | require(absPnpApiPath).setup(); 16 | } 17 | } 18 | 19 | // Defer to the real typescript your application uses 20 | module.exports = absRequire(`typescript`); 21 | -------------------------------------------------------------------------------- /example/app-router/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env*.local 29 | 30 | # vercel 31 | .vercel 32 | 33 | # typescript 34 | *.tsbuildinfo 35 | next-env.d.ts 36 | 37 | # Yarn (without zero-install) 38 | .yarn/* 39 | !.yarn/releases 40 | !.yarn/patches 41 | !.yarn/plugins 42 | !.yarn/sdks 43 | !.yarn/versions 44 | -------------------------------------------------------------------------------- /example/app-router/.yarn/sdks/typescript/bin/tsc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire} = require(`module`); 5 | const {resolve} = require(`path`); 6 | 7 | const relPnpApiPath = "../../../../.pnp.cjs"; 8 | 9 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 10 | const absRequire = createRequire(absPnpApiPath); 11 | 12 | if (existsSync(absPnpApiPath)) { 13 | if (!process.versions.pnp) { 14 | // Setup the environment to be able to require typescript/bin/tsc 15 | require(absPnpApiPath).setup(); 16 | } 17 | } 18 | 19 | // Defer to the real typescript/bin/tsc your application uses 20 | module.exports = absRequire(`typescript/bin/tsc`); 21 | -------------------------------------------------------------------------------- /example/app-router/.yarn/sdks/typescript/lib/tsc.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire} = require(`module`); 5 | const {resolve} = require(`path`); 6 | 7 | const relPnpApiPath = "../../../../.pnp.cjs"; 8 | 9 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 10 | const absRequire = createRequire(absPnpApiPath); 11 | 12 | if (existsSync(absPnpApiPath)) { 13 | if (!process.versions.pnp) { 14 | // Setup the environment to be able to require typescript/lib/tsc.js 15 | require(absPnpApiPath).setup(); 16 | } 17 | } 18 | 19 | // Defer to the real typescript/lib/tsc.js your application uses 20 | module.exports = absRequire(`typescript/lib/tsc.js`); 21 | -------------------------------------------------------------------------------- /example/app-router/.yarn/sdks/typescript/bin/tsserver: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire} = require(`module`); 5 | const {resolve} = require(`path`); 6 | 7 | const relPnpApiPath = "../../../../.pnp.cjs"; 8 | 9 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 10 | const absRequire = createRequire(absPnpApiPath); 11 | 12 | if (existsSync(absPnpApiPath)) { 13 | if (!process.versions.pnp) { 14 | // Setup the environment to be able to require typescript/bin/tsserver 15 | require(absPnpApiPath).setup(); 16 | } 17 | } 18 | 19 | // Defer to the real typescript/bin/tsserver your application uses 20 | module.exports = absRequire(`typescript/bin/tsserver`); 21 | -------------------------------------------------------------------------------- /example/page-router/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example-nextjs-obfuscated-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "cross-env NODE_OPTIONS='--inspect' next dev", 7 | "build": "next build", 8 | "start": "cross-env NODE_OPTIONS='--inspect' next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "cross-env": "^7.0.3", 13 | "framer-motion": "^11.11.11", 14 | "next": "^15.0.2", 15 | "react": "^18.3.1", 16 | "react-dom": "^18.3.1" 17 | }, 18 | "devDependencies": { 19 | "@types/node": "22.8.7", 20 | "@types/react": "18.3.12", 21 | "@types/react-dom": "18.3.1", 22 | "javascript-obfuscator": "^4.1.1", 23 | "typescript": "5.6.3" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /example/page-router/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": false, 6 | "skipLibCheck": true, 7 | "strict": false, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "noImplicitAny": true, 11 | "noImplicitReturns": true, 12 | "noImplicitThis": true, 13 | "esModuleInterop": true, 14 | "allowSyntheticDefaultImports": true, 15 | "module": "esnext", 16 | "moduleResolution": "node", 17 | "resolveJsonModule": true, 18 | "isolatedModules": true, 19 | "jsx": "preserve", 20 | "incremental": true 21 | }, 22 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], 23 | "exclude": ["node_modules"] 24 | } 25 | -------------------------------------------------------------------------------- /example/page-router/obfuscator-options.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | compact: true, 3 | controlFlowFlattening: false, 4 | controlFlowFlatteningThreshold: 0.75, 5 | disableConsoleOutput: false, 6 | domainLock: [ 7 | ".usamyon.moe", 8 | "localhost", 9 | ], 10 | domainLockRedirectUrl: "about:blank", 11 | identifierNamesCache: null, 12 | identifierNamesGenerator: "mangled", 13 | optionsPreset: "low-obfuscation", 14 | rotateStringArray: true, 15 | seed: 0, 16 | selfDefending: true, 17 | shuffleStringArray: true, 18 | simplify: true, 19 | splitStrings: true, 20 | splitStringsChunkLength: 10, 21 | stringArray: true, 22 | stringArrayIndexesType: [ 23 | "hexadecimal-number" 24 | ], 25 | target: "browser", 26 | sourceMap: true, 27 | } 28 | -------------------------------------------------------------------------------- /example/app-router/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true, 17 | "plugins": [ 18 | { 19 | "name": "next" 20 | } 21 | ], 22 | "paths": { 23 | "@/*": ["./src/*"] 24 | } 25 | }, 26 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 27 | "exclude": ["node_modules"] 28 | } 29 | -------------------------------------------------------------------------------- /example/page-router/public/vercel.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Redistribution and use in source and binary forms, with or without 2 | modification, are permitted provided that the following conditions are met: 3 | 4 | * Redistributions of source code must retain the above copyright 5 | notice, this list of conditions and the following disclaimer. 6 | * Redistributions in binary form must reproduce the above copyright 7 | notice, this list of conditions and the following disclaimer in the 8 | documentation and/or other materials provided with the distribution. 9 | 10 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 11 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 12 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 13 | ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 14 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 15 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 16 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 17 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 18 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 19 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /example/app-router/public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/app-router/README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | # or 12 | pnpm dev 13 | ``` 14 | 15 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 16 | 17 | You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. 18 | 19 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. 20 | 21 | ## Learn More 22 | 23 | To learn more about Next.js, take a look at the following resources: 24 | 25 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 26 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 27 | 28 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 29 | 30 | ## Deploy on Vercel 31 | 32 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 33 | 34 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 35 | -------------------------------------------------------------------------------- /src/type.ts: -------------------------------------------------------------------------------- 1 | import type { ObfuscatorOptions } from "javascript-obfuscator"; 2 | 3 | type OmitKeys = T & { [key in U]: never }; 4 | 5 | export type PluginOptions = { 6 | enabled: boolean | "detect", 7 | /** 8 | * determines which files to be obfuscated 9 | */ 10 | patterns: string[], 11 | /** 12 | * Additional files to be obfuscated 13 | */ 14 | obfuscateFiles: Partial<{ 15 | buildManifest: boolean, 16 | ssgManifest: boolean, 17 | webpack: boolean, 18 | additionalModules: string[], 19 | }>, 20 | /** 21 | * indicates whether the plugin logs to console 22 | */ 23 | log: boolean, 24 | }; 25 | 26 | export type ObjectWithUnconstantString> = { 27 | [key in keyof T]: Required[key] extends string 28 | ? string 29 | : Required[key] extends number 30 | ? number 31 | : Required[key] extends string[] 32 | ? string[] 33 | : Required[key] extends number[] 34 | ? number[] 35 | : Required[key] extends Record 36 | ? Partial> 37 | : T[key] 38 | }; 39 | 40 | export type NextjsObfuscatorOptions = OmitKeys< 41 | ObfuscatorOptions, 42 | | "inputFileName" 43 | | "sourceMapBaseUrl" 44 | | "sourceMapFileName" 45 | | "sourceMapMode" 46 | | "sourceMapSourcesMode" 47 | >; 48 | 49 | export const LoggerSymbol = Symbol("NextJsObfuscatorLogger"); 50 | export const PublicEnvVariablesSymbol = Symbol("NextJsObfuscatorPublicEnvVariables"); 51 | 52 | export type InternalNextjsObfuscatorOptions = NextjsObfuscatorOptions & { 53 | [LoggerSymbol]: (...messages: any[]) => void, 54 | [PublicEnvVariablesSymbol]: Map, 55 | }; 56 | -------------------------------------------------------------------------------- /src/loader.ts: -------------------------------------------------------------------------------- 1 | import type { InternalNextjsObfuscatorOptions } from "./type"; 2 | import type { RawSourceMap } from "source-map"; 3 | import type webpack from "webpack"; 4 | 5 | import * as path from "path"; 6 | // import fs from "fs"; 7 | 8 | import { obfuscate } from "javascript-obfuscator"; 9 | import { transfer as transferSourceMap } from "multi-stage-sourcemap"; 10 | 11 | import { LoggerSymbol, PublicEnvVariablesSymbol } from "./type"; 12 | 13 | function loader(this: webpack.LoaderContext, source: string, map: RawSourceMap){ 14 | const moduleRelativePath = path.relative(this.rootContext, this.resourcePath); 15 | const options = this.getOptions(); 16 | const logger = options[LoggerSymbol]; 17 | const publicEnvVariables = options[PublicEnvVariablesSymbol]; 18 | const sourceMapRequired = options.sourceMap; 19 | 20 | const sortedEntries = Array.from(publicEnvVariables.entries()) 21 | .sort(([keyA], [keyB]) => keyB.length - keyA.length); 22 | 23 | for (const [key, value] of sortedEntries){ 24 | source = source.replaceAll(key, value); 25 | } 26 | 27 | const finalOptions = Object.assign(options, { 28 | ignoreRequireImports: true, 29 | inputFileName: moduleRelativePath, 30 | sourceMapMode: "separate", 31 | }); 32 | 33 | // obfuscation 34 | const obfuscationResult = obfuscate(source, finalOptions); 35 | const obfuscated = obfuscationResult.getObfuscatedCode(); 36 | 37 | logger("Obfuscated:", moduleRelativePath, source.length, "->", obfuscated.length); 38 | 39 | // eslint-disable-next-line @typescript-eslint/init-declarations 40 | let sourceMap: string | undefined; 41 | if(map && sourceMapRequired){ 42 | sourceMap = transferSourceMap({ 43 | fromSourceMap: obfuscationResult.getSourceMap(), 44 | toSourceMap: map, 45 | }); 46 | } 47 | 48 | this.callback(null, obfuscated, sourceMap); 49 | } 50 | 51 | export = loader; 52 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nextjs-obfuscator", 3 | "version": "3.1.0", 4 | "description": "javascript obfuscator plugin for next.js", 5 | "main": "./index.js", 6 | "types": "./index.d.ts", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1", 9 | "build": "swc -d . ./src --strip-leading-paths && tsc", 10 | "watch": "swc -w -d . ./src --strip-leading-paths", 11 | "cleanup": "rimraf index.js index.d.ts loader.js loader.d.ts type.js type.d.ts debug.js debug.d.ts", 12 | "lint": "eslint ." 13 | }, 14 | "keywords": [ 15 | "obfuscator", 16 | "obfuscation", 17 | "code protection", 18 | "javascript obfuscator", 19 | "js obfuscator", 20 | "next obfuscator", 21 | "next.js obfuscator", 22 | "nextjs", 23 | "next", 24 | "obfuscation", 25 | "plugin", 26 | "obfuscate" 27 | ], 28 | "author": "mtripg6666tdr", 29 | "license": "BSD-2-Clause", 30 | "dependencies": { 31 | "minimatch": "^9", 32 | "multi-stage-sourcemap": "^0.3.1", 33 | "safe-traverse": "^0.2.1", 34 | "source-map": "^0.7.4" 35 | }, 36 | "devDependencies": { 37 | "@mtripg6666tdr/eslint-config": "^3.0.19", 38 | "@swc/cli": "^0.5.0", 39 | "@swc/core": "^1.8.0", 40 | "@tsconfig/node16": "^16.1.3", 41 | "@types/loader-utils": "^2.0.6", 42 | "@types/multi-stage-sourcemap": "^0.3.4", 43 | "@types/react": "^18.3.12", 44 | "@types/react-dom": "^18.3.1", 45 | "chokidar": "^3.6.0", 46 | "eslint": "^8.54.0", 47 | "javascript-obfuscator": "*", 48 | "next": "*", 49 | "rimraf": "^6.0.1", 50 | "typescript": "^5.6.3", 51 | "webpack": "^5.96.1" 52 | }, 53 | "peerDependencies": { 54 | "javascript-obfuscator": "^4.0.0", 55 | "next": "^13.0.0 || ^14.0.0 || ^15.0.0" 56 | }, 57 | "engines": { 58 | "node": ">=16.14.0" 59 | }, 60 | "repository": { 61 | "type": "git", 62 | "url": "git+https://github.com/mtripg6666tdr/nextjs-obfuscator.git" 63 | }, 64 | "bugs": { 65 | "url": "https://github.com/mtripg6666tdr/nextjs-obfuscator/issues" 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /example/page-router/src/styles/Home.module.css: -------------------------------------------------------------------------------- 1 | .container { 2 | padding: 0 2rem; 3 | } 4 | 5 | .main { 6 | min-height: 100vh; 7 | padding: 4rem 0; 8 | flex: 1; 9 | display: flex; 10 | flex-direction: column; 11 | justify-content: center; 12 | align-items: center; 13 | } 14 | 15 | .footer { 16 | display: flex; 17 | flex: 1; 18 | padding: 2rem 0; 19 | border-top: 1px solid #eaeaea; 20 | justify-content: center; 21 | align-items: center; 22 | } 23 | 24 | .footer a { 25 | display: flex; 26 | justify-content: center; 27 | align-items: center; 28 | flex-grow: 1; 29 | } 30 | 31 | .title a { 32 | color: #0070f3; 33 | text-decoration: none; 34 | } 35 | 36 | .title a:hover, 37 | .title a:focus, 38 | .title a:active { 39 | text-decoration: underline; 40 | } 41 | 42 | .title { 43 | margin: 0; 44 | line-height: 1.15; 45 | font-size: 4rem; 46 | } 47 | 48 | .title, 49 | .description { 50 | text-align: center; 51 | } 52 | 53 | .description { 54 | margin: 4rem 0; 55 | line-height: 1.5; 56 | font-size: 1.5rem; 57 | } 58 | 59 | .code { 60 | background: #fafafa; 61 | border-radius: 5px; 62 | padding: 0.75rem; 63 | font-size: 1.1rem; 64 | font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, 65 | Bitstream Vera Sans Mono, Courier New, monospace; 66 | } 67 | 68 | .grid { 69 | display: flex; 70 | align-items: center; 71 | justify-content: center; 72 | flex-wrap: wrap; 73 | max-width: 800px; 74 | } 75 | 76 | .card { 77 | margin: 1rem; 78 | padding: 1.5rem; 79 | text-align: left; 80 | color: inherit; 81 | text-decoration: none; 82 | border: 1px solid #eaeaea; 83 | border-radius: 10px; 84 | transition: color 0.15s ease, border-color 0.15s ease; 85 | max-width: 300px; 86 | } 87 | 88 | .card:hover, 89 | .card:focus, 90 | .card:active { 91 | color: #0070f3; 92 | border-color: #0070f3; 93 | } 94 | 95 | .card h2 { 96 | margin: 0 0 1rem 0; 97 | font-size: 1.5rem; 98 | } 99 | 100 | .card p { 101 | margin: 0; 102 | font-size: 1.25rem; 103 | line-height: 1.5; 104 | } 105 | 106 | .logo { 107 | height: 1em; 108 | margin-left: 0.5rem; 109 | } 110 | 111 | @media (max-width: 600px) { 112 | .grid { 113 | width: 100%; 114 | flex-direction: column; 115 | } 116 | } 117 | 118 | @media (prefers-color-scheme: dark) { 119 | .card, 120 | .footer { 121 | border-color: #222; 122 | } 123 | .code { 124 | background: #111; 125 | } 126 | .logo img { 127 | filter: invert(1); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /example/app-router/src/app/globals.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --max-width: 1100px; 3 | --border-radius: 12px; 4 | --font-mono: ui-monospace, Menlo, Monaco, 'Cascadia Mono', 'Segoe UI Mono', 5 | 'Roboto Mono', 'Oxygen Mono', 'Ubuntu Monospace', 'Source Code Pro', 6 | 'Fira Mono', 'Droid Sans Mono', 'Courier New', monospace; 7 | 8 | --foreground-rgb: 0, 0, 0; 9 | --background-start-rgb: 214, 219, 220; 10 | --background-end-rgb: 255, 255, 255; 11 | 12 | --primary-glow: conic-gradient( 13 | from 180deg at 50% 50%, 14 | #16abff33 0deg, 15 | #0885ff33 55deg, 16 | #54d6ff33 120deg, 17 | #0071ff33 160deg, 18 | transparent 360deg 19 | ); 20 | --secondary-glow: radial-gradient( 21 | rgba(255, 255, 255, 1), 22 | rgba(255, 255, 255, 0) 23 | ); 24 | 25 | --tile-start-rgb: 239, 245, 249; 26 | --tile-end-rgb: 228, 232, 233; 27 | --tile-border: conic-gradient( 28 | #00000080, 29 | #00000040, 30 | #00000030, 31 | #00000020, 32 | #00000010, 33 | #00000010, 34 | #00000080 35 | ); 36 | 37 | --callout-rgb: 238, 240, 241; 38 | --callout-border-rgb: 172, 175, 176; 39 | --card-rgb: 180, 185, 188; 40 | --card-border-rgb: 131, 134, 135; 41 | } 42 | 43 | @media (prefers-color-scheme: dark) { 44 | :root { 45 | --foreground-rgb: 255, 255, 255; 46 | --background-start-rgb: 0, 0, 0; 47 | --background-end-rgb: 0, 0, 0; 48 | 49 | --primary-glow: radial-gradient(rgba(1, 65, 255, 0.4), rgba(1, 65, 255, 0)); 50 | --secondary-glow: linear-gradient( 51 | to bottom right, 52 | rgba(1, 65, 255, 0), 53 | rgba(1, 65, 255, 0), 54 | rgba(1, 65, 255, 0.3) 55 | ); 56 | 57 | --tile-start-rgb: 2, 13, 46; 58 | --tile-end-rgb: 2, 5, 19; 59 | --tile-border: conic-gradient( 60 | #ffffff80, 61 | #ffffff40, 62 | #ffffff30, 63 | #ffffff20, 64 | #ffffff10, 65 | #ffffff10, 66 | #ffffff80 67 | ); 68 | 69 | --callout-rgb: 20, 20, 20; 70 | --callout-border-rgb: 108, 108, 108; 71 | --card-rgb: 100, 100, 100; 72 | --card-border-rgb: 200, 200, 200; 73 | } 74 | } 75 | 76 | * { 77 | box-sizing: border-box; 78 | padding: 0; 79 | margin: 0; 80 | } 81 | 82 | html, 83 | body { 84 | max-width: 100vw; 85 | overflow-x: hidden; 86 | } 87 | 88 | body { 89 | color: rgb(var(--foreground-rgb)); 90 | background: linear-gradient( 91 | to bottom, 92 | transparent, 93 | rgb(var(--background-end-rgb)) 94 | ) 95 | rgb(var(--background-start-rgb)); 96 | } 97 | 98 | a { 99 | color: inherit; 100 | text-decoration: none; 101 | } 102 | 103 | @media (prefers-color-scheme: dark) { 104 | html { 105 | color-scheme: dark; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /example/page-router/src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import type { NextPage } from 'next' 2 | import Head from 'next/head' 3 | import Image from 'next/image' 4 | import InjectDescription from '../components/injectDescription' 5 | import styles from '../styles/Home.module.css' 6 | import Shared from "../components/sharedComponent"; 7 | // this is just a test for module obfuscation 8 | // @ts-ignore 9 | import object from "es6-object-assign"; 10 | console.log(object); 11 | 12 | const Home: NextPage = () => { 13 | return ( 14 | 79 | ) 80 | } 81 | 82 | export default Home 83 | -------------------------------------------------------------------------------- /example/app-router/src/app/page.tsx: -------------------------------------------------------------------------------- 1 | import Image from 'next/image' 2 | import styles from './page.module.css' 3 | import Alerter from './client' 4 | 5 | export default function Home() { 6 | return ( 7 |
8 |
9 |

10 | Get started by editing  11 | src/app/page.tsx 12 |

13 | 14 | 31 |
32 | 33 |
34 | Next.js Logo 42 |
43 | 44 | 95 |
96 | ) 97 | } 98 | -------------------------------------------------------------------------------- /example/app-router/src/app/page.module.css: -------------------------------------------------------------------------------- 1 | .main { 2 | display: flex; 3 | flex-direction: column; 4 | justify-content: space-between; 5 | align-items: center; 6 | padding: 6rem; 7 | min-height: 100vh; 8 | } 9 | 10 | .description { 11 | display: inherit; 12 | justify-content: inherit; 13 | align-items: inherit; 14 | font-size: 0.85rem; 15 | max-width: var(--max-width); 16 | width: 100%; 17 | z-index: 2; 18 | font-family: var(--font-mono); 19 | } 20 | 21 | .description a { 22 | display: flex; 23 | justify-content: center; 24 | align-items: center; 25 | gap: 0.5rem; 26 | } 27 | 28 | .description p { 29 | position: relative; 30 | margin: 0; 31 | padding: 1rem; 32 | background-color: rgba(var(--callout-rgb), 0.5); 33 | border: 1px solid rgba(var(--callout-border-rgb), 0.3); 34 | border-radius: var(--border-radius); 35 | } 36 | 37 | .code { 38 | font-weight: 700; 39 | font-family: var(--font-mono); 40 | } 41 | 42 | .grid { 43 | display: grid; 44 | grid-template-columns: repeat(4, minmax(25%, auto)); 45 | width: var(--max-width); 46 | max-width: 100%; 47 | } 48 | 49 | .card { 50 | padding: 1rem 1.2rem; 51 | border-radius: var(--border-radius); 52 | background: rgba(var(--card-rgb), 0); 53 | border: 1px solid rgba(var(--card-border-rgb), 0); 54 | transition: background 200ms, border 200ms; 55 | } 56 | 57 | .card span { 58 | display: inline-block; 59 | transition: transform 200ms; 60 | } 61 | 62 | .card h2 { 63 | font-weight: 600; 64 | margin-bottom: 0.7rem; 65 | } 66 | 67 | .card p { 68 | margin: 0; 69 | opacity: 0.6; 70 | font-size: 0.9rem; 71 | line-height: 1.5; 72 | max-width: 30ch; 73 | } 74 | 75 | .center { 76 | display: flex; 77 | justify-content: center; 78 | align-items: center; 79 | position: relative; 80 | padding: 4rem 0; 81 | } 82 | 83 | .center::before { 84 | background: var(--secondary-glow); 85 | border-radius: 50%; 86 | width: 480px; 87 | height: 360px; 88 | margin-left: -400px; 89 | } 90 | 91 | .center::after { 92 | background: var(--primary-glow); 93 | width: 240px; 94 | height: 180px; 95 | z-index: -1; 96 | } 97 | 98 | .center::before, 99 | .center::after { 100 | content: ''; 101 | left: 50%; 102 | position: absolute; 103 | filter: blur(45px); 104 | transform: translateZ(0); 105 | } 106 | 107 | .logo { 108 | position: relative; 109 | } 110 | /* Enable hover only on non-touch devices */ 111 | @media (hover: hover) and (pointer: fine) { 112 | .card:hover { 113 | background: rgba(var(--card-rgb), 0.1); 114 | border: 1px solid rgba(var(--card-border-rgb), 0.15); 115 | } 116 | 117 | .card:hover span { 118 | transform: translateX(4px); 119 | } 120 | } 121 | 122 | @media (prefers-reduced-motion) { 123 | .card:hover span { 124 | transform: none; 125 | } 126 | } 127 | 128 | /* Mobile */ 129 | @media (max-width: 700px) { 130 | .content { 131 | padding: 4rem; 132 | } 133 | 134 | .grid { 135 | grid-template-columns: 1fr; 136 | margin-bottom: 120px; 137 | max-width: 320px; 138 | text-align: center; 139 | } 140 | 141 | .card { 142 | padding: 1rem 2.5rem; 143 | } 144 | 145 | .card h2 { 146 | margin-bottom: 0.5rem; 147 | } 148 | 149 | .center { 150 | padding: 8rem 0 6rem; 151 | } 152 | 153 | .center::before { 154 | transform: none; 155 | height: 300px; 156 | } 157 | 158 | .description { 159 | font-size: 0.8rem; 160 | } 161 | 162 | .description a { 163 | padding: 1rem; 164 | } 165 | 166 | .description p, 167 | .description div { 168 | display: flex; 169 | justify-content: center; 170 | position: fixed; 171 | width: 100%; 172 | } 173 | 174 | .description p { 175 | align-items: center; 176 | inset: 0 0 auto; 177 | padding: 2rem 1rem 1.4rem; 178 | border-radius: 0; 179 | border: none; 180 | border-bottom: 1px solid rgba(var(--callout-border-rgb), 0.25); 181 | background: linear-gradient( 182 | to bottom, 183 | rgba(var(--background-start-rgb), 1), 184 | rgba(var(--callout-rgb), 0.5) 185 | ); 186 | background-clip: padding-box; 187 | backdrop-filter: blur(24px); 188 | } 189 | 190 | .description div { 191 | align-items: flex-end; 192 | pointer-events: none; 193 | inset: auto 0 0; 194 | padding: 2rem; 195 | height: 200px; 196 | background: linear-gradient( 197 | to bottom, 198 | transparent 0%, 199 | rgb(var(--background-end-rgb)) 40% 200 | ); 201 | z-index: 1; 202 | } 203 | } 204 | 205 | /* Tablet and Smaller Desktop */ 206 | @media (min-width: 701px) and (max-width: 1120px) { 207 | .grid { 208 | grid-template-columns: repeat(2, 50%); 209 | } 210 | } 211 | 212 | @media (prefers-color-scheme: dark) { 213 | .vercelLogo { 214 | filter: invert(1); 215 | } 216 | 217 | .logo { 218 | filter: invert(1) drop-shadow(0 0 0.3rem #ffffff70); 219 | } 220 | } 221 | 222 | @keyframes rotate { 223 | from { 224 | transform: rotate(360deg); 225 | } 226 | to { 227 | transform: rotate(0deg); 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # javascript-obfuscator plugin for Next.js 2 | [![npm](https://img.shields.io/npm/v/nextjs-obfuscator)](https://www.npmjs.com/package/nextjs-obfuscator) 3 | 4 | The `nextjs-obfuscator` enables you to make your Next.js app difficult to be reverse-engineered, using [javascript-obfuscator](https://github.com/javascript-obfuscator/javascript-obfuscator). 5 | 6 | ### ℹ️ If you are looking for README for v1, see [here](https://github.com/mtripg6666tdr/nextjs-obfuscator/tree/v1#readme). 7 | 8 | There are some useful notes: 9 | - The app router is supported. 10 | - Building by turbopack is currently NOT supported. 11 | - Minimum supported Next.js version is v13. 12 | 13 | ## Installation 14 | You have to install javascript-obfuscator separately. 15 | 16 | On npm: 17 | ``` 18 | npm i -D javascript-obfuscator nextjs-obfuscator 19 | ``` 20 | On yarn: 21 | ``` 22 | yarn add -D javascript-obfuscator nextjs-obfuscator 23 | ``` 24 | 25 | ## Usage 26 | Wrap your configuration in your `next.config.js` to use this plugin, for example: 27 | ```js 28 | const withNextJsObfuscator = require("nextjs-obfuscator")(obfuscatorOptions, pluginOptions); 29 | 30 | /** @type {import("next").NextConfig} */ 31 | const nextConfig = withNextJsObfuscator({ 32 | // ... your next.js configuration 33 | }); 34 | 35 | module.exports = nextConfig; 36 | ``` 37 | Or if you use `next.config.mjs`: 38 | ```js 39 | import createNextJsObfuscator from "nextjs-obfuscator"; 40 | 41 | const withNextJsObfuscator = createNextJsObfuscator(obfuscatorOptions, pluginOptions); 42 | 43 | /** @type {import("next").NextConfig} */ 44 | const nextConfig = withNextJsObfuscator({ 45 | // ... your next.js configuration 46 | }); 47 | 48 | export default nextConfig; 49 | ``` 50 | 51 | ## API 52 |
 53 | require("nextjs-obfuscator")(obfuscatorOptions, pluginOptions)
 54 | 
55 | ### `obfuscatorOptions` 56 | Type: `Object` (required) 57 | This is [the options](https://github.com/javascript-obfuscator/javascript-obfuscator#javascript-obfuscator-options) of [javascript-obfuscator](https://github.com/javascript-obfuscator/javascript-obfuscator), but there are some important notes: 58 | * [`disableConsoleOutput`](https://github.com/javascript-obfuscator/javascript-obfuscator#disableconsoleoutput) should be set to `false` and you can easily notice the error logging by React on console. If they are present, they indicate your app has been broken. 59 | * There are some options that MUST NOT be set: 60 | * [`inputFileName`](https://github.com/javascript-obfuscator/javascript-obfuscator#inputfilename) 61 | * [`sourceMapBaseUrl`](https://github.com/javascript-obfuscator/javascript-obfuscator#sourcemapbaseurl) 62 | * [`sourceMapFileName`](https://github.com/javascript-obfuscator/javascript-obfuscator#sourcemapfilename) 63 | * [`sourceMapMode`](https://github.com/javascript-obfuscator/javascript-obfuscator#sourcemapmode) 64 | * [`sourceMapSourcesMode`](https://github.com/javascript-obfuscator/javascript-obfuscator#sourcemapsourcesmode) 65 | 66 | These options will be set by the nextjs-obfuscator plugin internally if necessary. 67 | 68 | ### `pluginOptions` 69 | Type: `Object` (optional) 70 | More options for this plugin. All properties are optional. 71 | ```ts 72 | { 73 | enabled: boolean | "detect", 74 | patterns: string[], 75 | obfuscateFiles: Partial<{ 76 | buildManifest: boolean, 77 | ssgManifest: boolean, 78 | webpack: boolean, 79 | additionalModules: string[], 80 | }>, 81 | log: boolean, 82 | }; 83 | ``` 84 | 85 | |Option |Type |Default Value|Description| 86 | |---------|------------------------------------|-------------|-----------| 87 | |`enabled`|boolean | "detect"|`"detect"`|Indicates if the plugin is enabled or not.
If `"detect"` specified, the plugin will be enabled only when building for production.| 88 | |`patterns`|`string[]`|["./**/*.(js|jsx|ts|tsx)"]|Glob patterns to determine which files to be obfuscated. They must be relative paths from the directory where `next.config.js` is placed.| 89 | |`obfuscateFiles`|`object`||Additional files to be obfuscated.| 90 | |`obfuscateFiles.buildManifest`|`boolean`|`false`|If set to true, the plugin will obfuscate `_buildManifest.js`| 91 | |`obfuscateFiles.ssgManifest`|`boolean`|`false`|If set to true, the plugin will obfuscate `_ssgManifest.js`| 92 | |`obfuscateFiles.webpack`|`boolean`|`false`|If set to true, the plugin will obfuscate `webpack.js`, which is an entry point.| 93 | |`obfuscateFiles.additionalModules`|`string[]`|`[]`|Names of additional external modules to be obfuscated. Convenient if you are using custom npm package, for instance. Use like `["module-a", "module-b", ...]`.| 94 | |`log`|`boolean`|`false`|If set to true, the plugin will use `console.log` as logger. Otherwise, it uses webpack's standard logger.| 95 | 96 | ## How it works 97 | * This plugin inserts a custom loader to obfuscate project files and external modules. 98 | * This plugin inserts a custom plugin to obfuscate `buildManifest`, `ssgManifest`, `webpack` assets. 99 | 100 | ## Disclaimer 101 | Using this plugin can break your next.js app, so you have to check carefully your app works fine. 102 | 103 | ## License 104 | [LICENSE](LICENSE) 105 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import type { ObjectWithUnconstantString, PluginOptions } from "./type"; 2 | import type { NextConfig } from "next"; 3 | 4 | import * as path from "path"; 5 | 6 | import { obfuscate } from "javascript-obfuscator"; 7 | import { Minimatch } from "minimatch"; 8 | import { safeTraverse } from "safe-traverse"; 9 | import webpack, { sources } from "webpack"; 10 | 11 | import { writeDownWebpackConfig } from "./debug"; 12 | import { LoggerSymbol, PublicEnvVariablesSymbol, type NextjsObfuscatorOptions } from "./type"; 13 | 14 | const craeteError = (message = "An error occurred.") => 15 | new Error(`${message} If you think this is a bug of nextjs-obfuscator, please file an issue at https://github.com/mtripg6666tdr/nextjs-obfuscator/issues`); 16 | 17 | function main( 18 | obfuscatorOptions: NextjsObfuscatorOptions | Partial>, 19 | pluginOptions?: Partial 20 | ) { 21 | // initialize options 22 | pluginOptions = Object.assign({ 23 | enabled: "detect", 24 | patterns: [ 25 | "./**/*.js", 26 | "./**/*.jsx", 27 | "./**/*.ts", 28 | "./**/*.tsx", 29 | ], 30 | log: false, 31 | }, pluginOptions); 32 | pluginOptions.obfuscateFiles = Object.assign({ 33 | buildManifest: false, 34 | ssgManifest: false, 35 | webpack: false, 36 | additionalModules: [], 37 | }, pluginOptions.obfuscateFiles); 38 | 39 | const logger: ((...message: string[]) => void) = pluginOptions.log ? console.log.bind(console, "\n") : () => {}; 40 | const matchers = pluginOptions.patterns!.map(pattern => new Minimatch(pattern)); 41 | 42 | return function(nextConfig: NextConfig) { 43 | if(!nextConfig || typeof nextConfig !== "object"){ 44 | throw new TypeError("Invalid configuration object passed."); 45 | } 46 | 47 | const moduleRegEx = /\.(tsx|ts|js|cjs|mjs|jsx)$/; 48 | 49 | const originalWebpackFn = nextConfig.webpack; 50 | nextConfig.webpack = function(config: webpack.Configuration, context){ 51 | if("writeConfig" in pluginOptions && pluginOptions.writeConfig){ 52 | writeDownWebpackConfig(config); 53 | } 54 | 55 | const basePath = config.context!; 56 | 57 | if(!basePath){ 58 | throw craeteError("No context detected."); 59 | } 60 | 61 | // extract public environment variables 62 | const publicEnvVariables = new Map(); 63 | config.plugins?.forEach(plugin => { 64 | const entries = safeTraverse(plugin) 65 | .get("definitions") 66 | .entries() 67 | .value || []; 68 | for(const kv of entries){ 69 | const key = kv?.[0]; 70 | const value = kv?.[1]; 71 | if(typeof key === "string" && key.startsWith("process.env.") && typeof value === "string"){ 72 | publicEnvVariables.set(key, value); 73 | } 74 | } 75 | }); 76 | 77 | const moduleMatcher = (value: string) => { 78 | if(moduleRegEx.test(value)){ 79 | if(!value.includes("node_modules")){ 80 | const relativePath = `.${path.sep}${path.relative(basePath, value)}`; 81 | logger("Detected:", relativePath); 82 | 83 | if( 84 | matchers.some(matcher => { 85 | const matched = matcher.match(relativePath); 86 | if(matched){ 87 | logger("Matched:", relativePath, `(pattern: ${matcher.pattern})`); 88 | } 89 | return matched; 90 | }) 91 | ){ 92 | return true; 93 | } 94 | }else{ 95 | const matched = pluginOptions.obfuscateFiles!.additionalModules!.some(mod => value.includes(`${path.sep}node_modules${path.sep}${mod}`)); 96 | if(matched){ 97 | logger("Matched:", value); 98 | } 99 | return matched; 100 | } 101 | } 102 | return false; 103 | }; 104 | 105 | // obfuscate only if the chunk is for browser 106 | if( 107 | pluginOptions.enabled === true || (pluginOptions.enabled === "detect" && !context.dev) 108 | ){ 109 | if( 110 | !context.isServer 111 | && !context.nextRuntime 112 | && config.module?.rules 113 | ){ 114 | config.module.rules.unshift({ 115 | test: moduleMatcher, 116 | enforce: "post" as const, 117 | use: { 118 | loader: require.resolve("./loader"), 119 | options: Object.assign({ 120 | [LoggerSymbol]: logger, 121 | [PublicEnvVariablesSymbol]: publicEnvVariables, 122 | }, obfuscatorOptions), 123 | }, 124 | }); 125 | 126 | const buildId = context.buildId; 127 | 128 | if(!buildId){ 129 | throw craeteError("No buildId found."); 130 | } 131 | 132 | if(Object.values(pluginOptions.obfuscateFiles!).some(val => val)){ 133 | config.plugins!.push( 134 | new NextJSObfuscatorPlugin( 135 | obfuscatorOptions as NextjsObfuscatorOptions, 136 | buildId, 137 | pluginOptions.obfuscateFiles!, 138 | logger, 139 | ) 140 | ); 141 | } 142 | } 143 | } 144 | 145 | // by using below code we can obfuscator server components but at most cases it is not necessary 146 | // const appDirEnabled = ( 147 | // config.plugins?.find(p => p && typeof p === "object" && "appDirEnabled" in p) as ({ appDirEnabled: boolean } | undefined) 148 | // )?.appDirEnabled; 149 | 150 | // if(appDirEnabled && context.isServer && context.nextRuntime === "nodejs"){ 151 | // config.module!.rules!.unshift({ 152 | // test: moduleMatcher, 153 | // enforce: "post", 154 | // use: { 155 | // loader: require.resolve("./loader"), 156 | // options: Object.assign({ 157 | // [LoggerSymbol]: logger, 158 | // }, obfuscatorOptions, { 159 | // target: "node", 160 | // domainLock: [], 161 | // }), 162 | // }, 163 | // }); 164 | // } 165 | 166 | if(originalWebpackFn){ 167 | return originalWebpackFn(config, context); 168 | } 169 | return config; 170 | }; 171 | 172 | return nextConfig; 173 | }; 174 | } 175 | 176 | export = main; 177 | 178 | class NextJSObfuscatorPlugin { 179 | protected logger: ((...messages: any[]) => void); 180 | protected obfuscatorOptions: NextjsObfuscatorOptions; 181 | 182 | constructor( 183 | obfuscatorOptions: NextjsObfuscatorOptions, 184 | protected buildId: string, 185 | protected target: PluginOptions["obfuscateFiles"], 186 | logger: (...messages: any[]) => void, 187 | ) { 188 | this.logger = (...messages: any[]) => logger("(Plugin)", ...messages); 189 | this.obfuscatorOptions = Object.assign(obfuscatorOptions, { 190 | splitStrings: false, 191 | }); 192 | } 193 | 194 | apply(compiler: webpack.Compiler) { 195 | const PluginName = this.constructor.name; 196 | 197 | compiler.hooks.compilation.tap( 198 | PluginName, 199 | (compilation) => { 200 | compilation.hooks.processAssets.tap({ 201 | name: PluginName.slice(0, -6), 202 | stage: webpack.Compilation.PROCESS_ASSETS_STAGE_DEV_TOOLING, 203 | }, (assets) => { 204 | this.logger("Initialized"); 205 | const assetNames = Object.keys(assets); 206 | this.logger(assetNames); 207 | 208 | for(let i = 0; i < assetNames.length; i++){ 209 | const assetName = assetNames[i]; 210 | 211 | if( 212 | (this.target.webpack && assetName.match(/^static\/chunks\/webpack-[abcdef\d]+\.js$/)) 213 | || (this.target.buildManifest && assetName === `static/${this.buildId}/_buildManifest.js`) 214 | || (this.target.ssgManifest && assetName === `static/${this.buildId}/_ssgManifest.js`) 215 | ){ 216 | const asset = assets[assetName]; 217 | if(!asset) return; 218 | const source = asset.source() as string; 219 | const obfuscatedCode = obfuscate(source, this.obfuscatorOptions).getObfuscatedCode(); 220 | assets[assetName] = new sources.RawSource(`!function(){${obfuscatedCode}}()`, false); 221 | this.logger("Obfuscated:", assetName, source.length, "->", obfuscatedCode.length); 222 | } 223 | } 224 | }); 225 | } 226 | ); 227 | } 228 | } 229 | -------------------------------------------------------------------------------- /example/app-router/.yarn/sdks/typescript/lib/tsserver.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire} = require(`module`); 5 | const {resolve} = require(`path`); 6 | 7 | const relPnpApiPath = "../../../../.pnp.cjs"; 8 | 9 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 10 | const absRequire = createRequire(absPnpApiPath); 11 | 12 | const moduleWrapper = tsserver => { 13 | if (!process.versions.pnp) { 14 | return tsserver; 15 | } 16 | 17 | const {isAbsolute} = require(`path`); 18 | const pnpApi = require(`pnpapi`); 19 | 20 | const isVirtual = str => str.match(/\/(\$\$virtual|__virtual__)\//); 21 | const isPortal = str => str.startsWith("portal:/"); 22 | const normalize = str => str.replace(/\\/g, `/`).replace(/^\/?/, `/`); 23 | 24 | const dependencyTreeRoots = new Set(pnpApi.getDependencyTreeRoots().map(locator => { 25 | return `${locator.name}@${locator.reference}`; 26 | })); 27 | 28 | // VSCode sends the zip paths to TS using the "zip://" prefix, that TS 29 | // doesn't understand. This layer makes sure to remove the protocol 30 | // before forwarding it to TS, and to add it back on all returned paths. 31 | 32 | function toEditorPath(str) { 33 | // We add the `zip:` prefix to both `.zip/` paths and virtual paths 34 | if (isAbsolute(str) && !str.match(/^\^?(zip:|\/zip\/)/) && (str.match(/\.zip\//) || isVirtual(str))) { 35 | // We also take the opportunity to turn virtual paths into physical ones; 36 | // this makes it much easier to work with workspaces that list peer 37 | // dependencies, since otherwise Ctrl+Click would bring us to the virtual 38 | // file instances instead of the real ones. 39 | // 40 | // We only do this to modules owned by the the dependency tree roots. 41 | // This avoids breaking the resolution when jumping inside a vendor 42 | // with peer dep (otherwise jumping into react-dom would show resolution 43 | // errors on react). 44 | // 45 | const resolved = isVirtual(str) ? pnpApi.resolveVirtual(str) : str; 46 | if (resolved) { 47 | const locator = pnpApi.findPackageLocator(resolved); 48 | if (locator && (dependencyTreeRoots.has(`${locator.name}@${locator.reference}`) || isPortal(locator.reference))) { 49 | str = resolved; 50 | } 51 | } 52 | 53 | str = normalize(str); 54 | 55 | if (str.match(/\.zip\//)) { 56 | switch (hostInfo) { 57 | // Absolute VSCode `Uri.fsPath`s need to start with a slash. 58 | // VSCode only adds it automatically for supported schemes, 59 | // so we have to do it manually for the `zip` scheme. 60 | // The path needs to start with a caret otherwise VSCode doesn't handle the protocol 61 | // 62 | // Ref: https://github.com/microsoft/vscode/issues/105014#issuecomment-686760910 63 | // 64 | // 2021-10-08: VSCode changed the format in 1.61. 65 | // Before | ^zip:/c:/foo/bar.zip/package.json 66 | // After | ^/zip//c:/foo/bar.zip/package.json 67 | // 68 | // 2022-04-06: VSCode changed the format in 1.66. 69 | // Before | ^/zip//c:/foo/bar.zip/package.json 70 | // After | ^/zip/c:/foo/bar.zip/package.json 71 | // 72 | // 2022-05-06: VSCode changed the format in 1.68 73 | // Before | ^/zip/c:/foo/bar.zip/package.json 74 | // After | ^/zip//c:/foo/bar.zip/package.json 75 | // 76 | case `vscode <1.61`: { 77 | str = `^zip:${str}`; 78 | } break; 79 | 80 | case `vscode <1.66`: { 81 | str = `^/zip/${str}`; 82 | } break; 83 | 84 | case `vscode <1.68`: { 85 | str = `^/zip${str}`; 86 | } break; 87 | 88 | case `vscode`: { 89 | str = `^/zip/${str}`; 90 | } break; 91 | 92 | // To make "go to definition" work, 93 | // We have to resolve the actual file system path from virtual path 94 | // and convert scheme to supported by [vim-rzip](https://github.com/lbrayner/vim-rzip) 95 | case `coc-nvim`: { 96 | str = normalize(resolved).replace(/\.zip\//, `.zip::`); 97 | str = resolve(`zipfile:${str}`); 98 | } break; 99 | 100 | // Support neovim native LSP and [typescript-language-server](https://github.com/theia-ide/typescript-language-server) 101 | // We have to resolve the actual file system path from virtual path, 102 | // everything else is up to neovim 103 | case `neovim`: { 104 | str = normalize(resolved).replace(/\.zip\//, `.zip::`); 105 | str = `zipfile://${str}`; 106 | } break; 107 | 108 | default: { 109 | str = `zip:${str}`; 110 | } break; 111 | } 112 | } else { 113 | str = str.replace(/^\/?/, process.platform === `win32` ? `` : `/`); 114 | } 115 | } 116 | 117 | return str; 118 | } 119 | 120 | function fromEditorPath(str) { 121 | switch (hostInfo) { 122 | case `coc-nvim`: { 123 | str = str.replace(/\.zip::/, `.zip/`); 124 | // The path for coc-nvim is in format of //zipfile://.yarn/... 125 | // So in order to convert it back, we use .* to match all the thing 126 | // before `zipfile:` 127 | return process.platform === `win32` 128 | ? str.replace(/^.*zipfile:\//, ``) 129 | : str.replace(/^.*zipfile:/, ``); 130 | } break; 131 | 132 | case `neovim`: { 133 | str = str.replace(/\.zip::/, `.zip/`); 134 | // The path for neovim is in format of zipfile:////.yarn/... 135 | return str.replace(/^zipfile:\/\//, ``); 136 | } break; 137 | 138 | case `vscode`: 139 | default: { 140 | return str.replace(/^\^?(zip:|\/zip(\/ts-nul-authority)?)\/+/, process.platform === `win32` ? `` : `/`) 141 | } break; 142 | } 143 | } 144 | 145 | // Force enable 'allowLocalPluginLoads' 146 | // TypeScript tries to resolve plugins using a path relative to itself 147 | // which doesn't work when using the global cache 148 | // https://github.com/microsoft/TypeScript/blob/1b57a0395e0bff191581c9606aab92832001de62/src/server/project.ts#L2238 149 | // VSCode doesn't want to enable 'allowLocalPluginLoads' due to security concerns but 150 | // TypeScript already does local loads and if this code is running the user trusts the workspace 151 | // https://github.com/microsoft/vscode/issues/45856 152 | const ConfiguredProject = tsserver.server.ConfiguredProject; 153 | const {enablePluginsWithOptions: originalEnablePluginsWithOptions} = ConfiguredProject.prototype; 154 | ConfiguredProject.prototype.enablePluginsWithOptions = function() { 155 | this.projectService.allowLocalPluginLoads = true; 156 | return originalEnablePluginsWithOptions.apply(this, arguments); 157 | }; 158 | 159 | // And here is the point where we hijack the VSCode <-> TS communications 160 | // by adding ourselves in the middle. We locate everything that looks 161 | // like an absolute path of ours and normalize it. 162 | 163 | const Session = tsserver.server.Session; 164 | const {onMessage: originalOnMessage, send: originalSend} = Session.prototype; 165 | let hostInfo = `unknown`; 166 | 167 | Object.assign(Session.prototype, { 168 | onMessage(/** @type {string | object} */ message) { 169 | const isStringMessage = typeof message === 'string'; 170 | const parsedMessage = isStringMessage ? JSON.parse(message) : message; 171 | 172 | if ( 173 | parsedMessage != null && 174 | typeof parsedMessage === `object` && 175 | parsedMessage.arguments && 176 | typeof parsedMessage.arguments.hostInfo === `string` 177 | ) { 178 | hostInfo = parsedMessage.arguments.hostInfo; 179 | if (hostInfo === `vscode` && process.env.VSCODE_IPC_HOOK) { 180 | const [, major, minor] = (process.env.VSCODE_IPC_HOOK.match( 181 | // The RegExp from https://semver.org/ but without the caret at the start 182 | /(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/ 183 | ) ?? []).map(Number) 184 | 185 | if (major === 1) { 186 | if (minor < 61) { 187 | hostInfo += ` <1.61`; 188 | } else if (minor < 66) { 189 | hostInfo += ` <1.66`; 190 | } else if (minor < 68) { 191 | hostInfo += ` <1.68`; 192 | } 193 | } 194 | } 195 | } 196 | 197 | const processedMessageJSON = JSON.stringify(parsedMessage, (key, value) => { 198 | return typeof value === 'string' ? fromEditorPath(value) : value; 199 | }); 200 | 201 | return originalOnMessage.call( 202 | this, 203 | isStringMessage ? processedMessageJSON : JSON.parse(processedMessageJSON) 204 | ); 205 | }, 206 | 207 | send(/** @type {any} */ msg) { 208 | return originalSend.call(this, JSON.parse(JSON.stringify(msg, (key, value) => { 209 | return typeof value === `string` ? toEditorPath(value) : value; 210 | }))); 211 | } 212 | }); 213 | 214 | return tsserver; 215 | }; 216 | 217 | if (existsSync(absPnpApiPath)) { 218 | if (!process.versions.pnp) { 219 | // Setup the environment to be able to require typescript/lib/tsserver.js 220 | require(absPnpApiPath).setup(); 221 | } 222 | } 223 | 224 | // Defer to the real typescript/lib/tsserver.js your application uses 225 | module.exports = moduleWrapper(absRequire(`typescript/lib/tsserver.js`)); 226 | -------------------------------------------------------------------------------- /example/app-router/.yarn/sdks/typescript/lib/tsserverlibrary.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire} = require(`module`); 5 | const {resolve} = require(`path`); 6 | 7 | const relPnpApiPath = "../../../../.pnp.cjs"; 8 | 9 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 10 | const absRequire = createRequire(absPnpApiPath); 11 | 12 | const moduleWrapper = tsserver => { 13 | if (!process.versions.pnp) { 14 | return tsserver; 15 | } 16 | 17 | const {isAbsolute} = require(`path`); 18 | const pnpApi = require(`pnpapi`); 19 | 20 | const isVirtual = str => str.match(/\/(\$\$virtual|__virtual__)\//); 21 | const isPortal = str => str.startsWith("portal:/"); 22 | const normalize = str => str.replace(/\\/g, `/`).replace(/^\/?/, `/`); 23 | 24 | const dependencyTreeRoots = new Set(pnpApi.getDependencyTreeRoots().map(locator => { 25 | return `${locator.name}@${locator.reference}`; 26 | })); 27 | 28 | // VSCode sends the zip paths to TS using the "zip://" prefix, that TS 29 | // doesn't understand. This layer makes sure to remove the protocol 30 | // before forwarding it to TS, and to add it back on all returned paths. 31 | 32 | function toEditorPath(str) { 33 | // We add the `zip:` prefix to both `.zip/` paths and virtual paths 34 | if (isAbsolute(str) && !str.match(/^\^?(zip:|\/zip\/)/) && (str.match(/\.zip\//) || isVirtual(str))) { 35 | // We also take the opportunity to turn virtual paths into physical ones; 36 | // this makes it much easier to work with workspaces that list peer 37 | // dependencies, since otherwise Ctrl+Click would bring us to the virtual 38 | // file instances instead of the real ones. 39 | // 40 | // We only do this to modules owned by the the dependency tree roots. 41 | // This avoids breaking the resolution when jumping inside a vendor 42 | // with peer dep (otherwise jumping into react-dom would show resolution 43 | // errors on react). 44 | // 45 | const resolved = isVirtual(str) ? pnpApi.resolveVirtual(str) : str; 46 | if (resolved) { 47 | const locator = pnpApi.findPackageLocator(resolved); 48 | if (locator && (dependencyTreeRoots.has(`${locator.name}@${locator.reference}`) || isPortal(locator.reference))) { 49 | str = resolved; 50 | } 51 | } 52 | 53 | str = normalize(str); 54 | 55 | if (str.match(/\.zip\//)) { 56 | switch (hostInfo) { 57 | // Absolute VSCode `Uri.fsPath`s need to start with a slash. 58 | // VSCode only adds it automatically for supported schemes, 59 | // so we have to do it manually for the `zip` scheme. 60 | // The path needs to start with a caret otherwise VSCode doesn't handle the protocol 61 | // 62 | // Ref: https://github.com/microsoft/vscode/issues/105014#issuecomment-686760910 63 | // 64 | // 2021-10-08: VSCode changed the format in 1.61. 65 | // Before | ^zip:/c:/foo/bar.zip/package.json 66 | // After | ^/zip//c:/foo/bar.zip/package.json 67 | // 68 | // 2022-04-06: VSCode changed the format in 1.66. 69 | // Before | ^/zip//c:/foo/bar.zip/package.json 70 | // After | ^/zip/c:/foo/bar.zip/package.json 71 | // 72 | // 2022-05-06: VSCode changed the format in 1.68 73 | // Before | ^/zip/c:/foo/bar.zip/package.json 74 | // After | ^/zip//c:/foo/bar.zip/package.json 75 | // 76 | case `vscode <1.61`: { 77 | str = `^zip:${str}`; 78 | } break; 79 | 80 | case `vscode <1.66`: { 81 | str = `^/zip/${str}`; 82 | } break; 83 | 84 | case `vscode <1.68`: { 85 | str = `^/zip${str}`; 86 | } break; 87 | 88 | case `vscode`: { 89 | str = `^/zip/${str}`; 90 | } break; 91 | 92 | // To make "go to definition" work, 93 | // We have to resolve the actual file system path from virtual path 94 | // and convert scheme to supported by [vim-rzip](https://github.com/lbrayner/vim-rzip) 95 | case `coc-nvim`: { 96 | str = normalize(resolved).replace(/\.zip\//, `.zip::`); 97 | str = resolve(`zipfile:${str}`); 98 | } break; 99 | 100 | // Support neovim native LSP and [typescript-language-server](https://github.com/theia-ide/typescript-language-server) 101 | // We have to resolve the actual file system path from virtual path, 102 | // everything else is up to neovim 103 | case `neovim`: { 104 | str = normalize(resolved).replace(/\.zip\//, `.zip::`); 105 | str = `zipfile://${str}`; 106 | } break; 107 | 108 | default: { 109 | str = `zip:${str}`; 110 | } break; 111 | } 112 | } else { 113 | str = str.replace(/^\/?/, process.platform === `win32` ? `` : `/`); 114 | } 115 | } 116 | 117 | return str; 118 | } 119 | 120 | function fromEditorPath(str) { 121 | switch (hostInfo) { 122 | case `coc-nvim`: { 123 | str = str.replace(/\.zip::/, `.zip/`); 124 | // The path for coc-nvim is in format of //zipfile://.yarn/... 125 | // So in order to convert it back, we use .* to match all the thing 126 | // before `zipfile:` 127 | return process.platform === `win32` 128 | ? str.replace(/^.*zipfile:\//, ``) 129 | : str.replace(/^.*zipfile:/, ``); 130 | } break; 131 | 132 | case `neovim`: { 133 | str = str.replace(/\.zip::/, `.zip/`); 134 | // The path for neovim is in format of zipfile:////.yarn/... 135 | return str.replace(/^zipfile:\/\//, ``); 136 | } break; 137 | 138 | case `vscode`: 139 | default: { 140 | return str.replace(/^\^?(zip:|\/zip(\/ts-nul-authority)?)\/+/, process.platform === `win32` ? `` : `/`) 141 | } break; 142 | } 143 | } 144 | 145 | // Force enable 'allowLocalPluginLoads' 146 | // TypeScript tries to resolve plugins using a path relative to itself 147 | // which doesn't work when using the global cache 148 | // https://github.com/microsoft/TypeScript/blob/1b57a0395e0bff191581c9606aab92832001de62/src/server/project.ts#L2238 149 | // VSCode doesn't want to enable 'allowLocalPluginLoads' due to security concerns but 150 | // TypeScript already does local loads and if this code is running the user trusts the workspace 151 | // https://github.com/microsoft/vscode/issues/45856 152 | const ConfiguredProject = tsserver.server.ConfiguredProject; 153 | const {enablePluginsWithOptions: originalEnablePluginsWithOptions} = ConfiguredProject.prototype; 154 | ConfiguredProject.prototype.enablePluginsWithOptions = function() { 155 | this.projectService.allowLocalPluginLoads = true; 156 | return originalEnablePluginsWithOptions.apply(this, arguments); 157 | }; 158 | 159 | // And here is the point where we hijack the VSCode <-> TS communications 160 | // by adding ourselves in the middle. We locate everything that looks 161 | // like an absolute path of ours and normalize it. 162 | 163 | const Session = tsserver.server.Session; 164 | const {onMessage: originalOnMessage, send: originalSend} = Session.prototype; 165 | let hostInfo = `unknown`; 166 | 167 | Object.assign(Session.prototype, { 168 | onMessage(/** @type {string | object} */ message) { 169 | const isStringMessage = typeof message === 'string'; 170 | const parsedMessage = isStringMessage ? JSON.parse(message) : message; 171 | 172 | if ( 173 | parsedMessage != null && 174 | typeof parsedMessage === `object` && 175 | parsedMessage.arguments && 176 | typeof parsedMessage.arguments.hostInfo === `string` 177 | ) { 178 | hostInfo = parsedMessage.arguments.hostInfo; 179 | if (hostInfo === `vscode` && process.env.VSCODE_IPC_HOOK) { 180 | const [, major, minor] = (process.env.VSCODE_IPC_HOOK.match( 181 | // The RegExp from https://semver.org/ but without the caret at the start 182 | /(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/ 183 | ) ?? []).map(Number) 184 | 185 | if (major === 1) { 186 | if (minor < 61) { 187 | hostInfo += ` <1.61`; 188 | } else if (minor < 66) { 189 | hostInfo += ` <1.66`; 190 | } else if (minor < 68) { 191 | hostInfo += ` <1.68`; 192 | } 193 | } 194 | } 195 | } 196 | 197 | const processedMessageJSON = JSON.stringify(parsedMessage, (key, value) => { 198 | return typeof value === 'string' ? fromEditorPath(value) : value; 199 | }); 200 | 201 | return originalOnMessage.call( 202 | this, 203 | isStringMessage ? processedMessageJSON : JSON.parse(processedMessageJSON) 204 | ); 205 | }, 206 | 207 | send(/** @type {any} */ msg) { 208 | return originalSend.call(this, JSON.parse(JSON.stringify(msg, (key, value) => { 209 | return typeof value === `string` ? toEditorPath(value) : value; 210 | }))); 211 | } 212 | }); 213 | 214 | return tsserver; 215 | }; 216 | 217 | if (existsSync(absPnpApiPath)) { 218 | if (!process.versions.pnp) { 219 | // Setup the environment to be able to require typescript/lib/tsserverlibrary.js 220 | require(absPnpApiPath).setup(); 221 | } 222 | } 223 | 224 | // Defer to the real typescript/lib/tsserverlibrary.js your application uses 225 | module.exports = moduleWrapper(absRequire(`typescript/lib/tsserverlibrary.js`)); 226 | -------------------------------------------------------------------------------- /example/app-router/yarn.lock: -------------------------------------------------------------------------------- 1 | # This file is generated by running "yarn install" inside your project. 2 | # Manual changes might be lost - proceed with caution! 3 | 4 | __metadata: 5 | version: 6 6 | cacheKey: 8 7 | 8 | "@emnapi/runtime@npm:^1.2.0": 9 | version: 1.3.1 10 | resolution: "@emnapi/runtime@npm:1.3.1" 11 | dependencies: 12 | tslib: ^2.4.0 13 | checksum: 9a16ae7905a9c0e8956cf1854ef74e5087fbf36739abdba7aa6b308485aafdc993da07c19d7af104cd5f8e425121120852851bb3a0f78e2160e420a36d47f42f 14 | languageName: node 15 | linkType: hard 16 | 17 | "@img/sharp-darwin-arm64@npm:0.33.5": 18 | version: 0.33.5 19 | resolution: "@img/sharp-darwin-arm64@npm:0.33.5" 20 | dependencies: 21 | "@img/sharp-libvips-darwin-arm64": 1.0.4 22 | dependenciesMeta: 23 | "@img/sharp-libvips-darwin-arm64": 24 | optional: true 25 | conditions: os=darwin & cpu=arm64 26 | languageName: node 27 | linkType: hard 28 | 29 | "@img/sharp-darwin-x64@npm:0.33.5": 30 | version: 0.33.5 31 | resolution: "@img/sharp-darwin-x64@npm:0.33.5" 32 | dependencies: 33 | "@img/sharp-libvips-darwin-x64": 1.0.4 34 | dependenciesMeta: 35 | "@img/sharp-libvips-darwin-x64": 36 | optional: true 37 | conditions: os=darwin & cpu=x64 38 | languageName: node 39 | linkType: hard 40 | 41 | "@img/sharp-libvips-darwin-arm64@npm:1.0.4": 42 | version: 1.0.4 43 | resolution: "@img/sharp-libvips-darwin-arm64@npm:1.0.4" 44 | conditions: os=darwin & cpu=arm64 45 | languageName: node 46 | linkType: hard 47 | 48 | "@img/sharp-libvips-darwin-x64@npm:1.0.4": 49 | version: 1.0.4 50 | resolution: "@img/sharp-libvips-darwin-x64@npm:1.0.4" 51 | conditions: os=darwin & cpu=x64 52 | languageName: node 53 | linkType: hard 54 | 55 | "@img/sharp-libvips-linux-arm64@npm:1.0.4": 56 | version: 1.0.4 57 | resolution: "@img/sharp-libvips-linux-arm64@npm:1.0.4" 58 | conditions: os=linux & cpu=arm64 & libc=glibc 59 | languageName: node 60 | linkType: hard 61 | 62 | "@img/sharp-libvips-linux-arm@npm:1.0.5": 63 | version: 1.0.5 64 | resolution: "@img/sharp-libvips-linux-arm@npm:1.0.5" 65 | conditions: os=linux & cpu=arm & libc=glibc 66 | languageName: node 67 | linkType: hard 68 | 69 | "@img/sharp-libvips-linux-s390x@npm:1.0.4": 70 | version: 1.0.4 71 | resolution: "@img/sharp-libvips-linux-s390x@npm:1.0.4" 72 | conditions: os=linux & cpu=s390x & libc=glibc 73 | languageName: node 74 | linkType: hard 75 | 76 | "@img/sharp-libvips-linux-x64@npm:1.0.4": 77 | version: 1.0.4 78 | resolution: "@img/sharp-libvips-linux-x64@npm:1.0.4" 79 | conditions: os=linux & cpu=x64 & libc=glibc 80 | languageName: node 81 | linkType: hard 82 | 83 | "@img/sharp-libvips-linuxmusl-arm64@npm:1.0.4": 84 | version: 1.0.4 85 | resolution: "@img/sharp-libvips-linuxmusl-arm64@npm:1.0.4" 86 | conditions: os=linux & cpu=arm64 & libc=musl 87 | languageName: node 88 | linkType: hard 89 | 90 | "@img/sharp-libvips-linuxmusl-x64@npm:1.0.4": 91 | version: 1.0.4 92 | resolution: "@img/sharp-libvips-linuxmusl-x64@npm:1.0.4" 93 | conditions: os=linux & cpu=x64 & libc=musl 94 | languageName: node 95 | linkType: hard 96 | 97 | "@img/sharp-linux-arm64@npm:0.33.5": 98 | version: 0.33.5 99 | resolution: "@img/sharp-linux-arm64@npm:0.33.5" 100 | dependencies: 101 | "@img/sharp-libvips-linux-arm64": 1.0.4 102 | dependenciesMeta: 103 | "@img/sharp-libvips-linux-arm64": 104 | optional: true 105 | conditions: os=linux & cpu=arm64 & libc=glibc 106 | languageName: node 107 | linkType: hard 108 | 109 | "@img/sharp-linux-arm@npm:0.33.5": 110 | version: 0.33.5 111 | resolution: "@img/sharp-linux-arm@npm:0.33.5" 112 | dependencies: 113 | "@img/sharp-libvips-linux-arm": 1.0.5 114 | dependenciesMeta: 115 | "@img/sharp-libvips-linux-arm": 116 | optional: true 117 | conditions: os=linux & cpu=arm & libc=glibc 118 | languageName: node 119 | linkType: hard 120 | 121 | "@img/sharp-linux-s390x@npm:0.33.5": 122 | version: 0.33.5 123 | resolution: "@img/sharp-linux-s390x@npm:0.33.5" 124 | dependencies: 125 | "@img/sharp-libvips-linux-s390x": 1.0.4 126 | dependenciesMeta: 127 | "@img/sharp-libvips-linux-s390x": 128 | optional: true 129 | conditions: os=linux & cpu=s390x & libc=glibc 130 | languageName: node 131 | linkType: hard 132 | 133 | "@img/sharp-linux-x64@npm:0.33.5": 134 | version: 0.33.5 135 | resolution: "@img/sharp-linux-x64@npm:0.33.5" 136 | dependencies: 137 | "@img/sharp-libvips-linux-x64": 1.0.4 138 | dependenciesMeta: 139 | "@img/sharp-libvips-linux-x64": 140 | optional: true 141 | conditions: os=linux & cpu=x64 & libc=glibc 142 | languageName: node 143 | linkType: hard 144 | 145 | "@img/sharp-linuxmusl-arm64@npm:0.33.5": 146 | version: 0.33.5 147 | resolution: "@img/sharp-linuxmusl-arm64@npm:0.33.5" 148 | dependencies: 149 | "@img/sharp-libvips-linuxmusl-arm64": 1.0.4 150 | dependenciesMeta: 151 | "@img/sharp-libvips-linuxmusl-arm64": 152 | optional: true 153 | conditions: os=linux & cpu=arm64 & libc=musl 154 | languageName: node 155 | linkType: hard 156 | 157 | "@img/sharp-linuxmusl-x64@npm:0.33.5": 158 | version: 0.33.5 159 | resolution: "@img/sharp-linuxmusl-x64@npm:0.33.5" 160 | dependencies: 161 | "@img/sharp-libvips-linuxmusl-x64": 1.0.4 162 | dependenciesMeta: 163 | "@img/sharp-libvips-linuxmusl-x64": 164 | optional: true 165 | conditions: os=linux & cpu=x64 & libc=musl 166 | languageName: node 167 | linkType: hard 168 | 169 | "@img/sharp-wasm32@npm:0.33.5": 170 | version: 0.33.5 171 | resolution: "@img/sharp-wasm32@npm:0.33.5" 172 | dependencies: 173 | "@emnapi/runtime": ^1.2.0 174 | conditions: cpu=wasm32 175 | languageName: node 176 | linkType: hard 177 | 178 | "@img/sharp-win32-ia32@npm:0.33.5": 179 | version: 0.33.5 180 | resolution: "@img/sharp-win32-ia32@npm:0.33.5" 181 | conditions: os=win32 & cpu=ia32 182 | languageName: node 183 | linkType: hard 184 | 185 | "@img/sharp-win32-x64@npm:0.33.5": 186 | version: 0.33.5 187 | resolution: "@img/sharp-win32-x64@npm:0.33.5" 188 | conditions: os=win32 & cpu=x64 189 | languageName: node 190 | linkType: hard 191 | 192 | "@next/env@npm:15.0.2": 193 | version: 15.0.2 194 | resolution: "@next/env@npm:15.0.2" 195 | checksum: 6a347035e72f30c64547b01bdea2f0da53e3bdbc892ca62220bd03633db0a2484be6ce67f6e441f457b9c3b92ea09eb05fb339b529228e7d1540524c79b9c010 196 | languageName: node 197 | linkType: hard 198 | 199 | "@next/swc-darwin-arm64@npm:15.0.2": 200 | version: 15.0.2 201 | resolution: "@next/swc-darwin-arm64@npm:15.0.2" 202 | conditions: os=darwin & cpu=arm64 203 | languageName: node 204 | linkType: hard 205 | 206 | "@next/swc-darwin-x64@npm:15.0.2": 207 | version: 15.0.2 208 | resolution: "@next/swc-darwin-x64@npm:15.0.2" 209 | conditions: os=darwin & cpu=x64 210 | languageName: node 211 | linkType: hard 212 | 213 | "@next/swc-linux-arm64-gnu@npm:15.0.2": 214 | version: 15.0.2 215 | resolution: "@next/swc-linux-arm64-gnu@npm:15.0.2" 216 | conditions: os=linux & cpu=arm64 & libc=glibc 217 | languageName: node 218 | linkType: hard 219 | 220 | "@next/swc-linux-arm64-musl@npm:15.0.2": 221 | version: 15.0.2 222 | resolution: "@next/swc-linux-arm64-musl@npm:15.0.2" 223 | conditions: os=linux & cpu=arm64 & libc=musl 224 | languageName: node 225 | linkType: hard 226 | 227 | "@next/swc-linux-x64-gnu@npm:15.0.2": 228 | version: 15.0.2 229 | resolution: "@next/swc-linux-x64-gnu@npm:15.0.2" 230 | conditions: os=linux & cpu=x64 & libc=glibc 231 | languageName: node 232 | linkType: hard 233 | 234 | "@next/swc-linux-x64-musl@npm:15.0.2": 235 | version: 15.0.2 236 | resolution: "@next/swc-linux-x64-musl@npm:15.0.2" 237 | conditions: os=linux & cpu=x64 & libc=musl 238 | languageName: node 239 | linkType: hard 240 | 241 | "@next/swc-win32-arm64-msvc@npm:15.0.2": 242 | version: 15.0.2 243 | resolution: "@next/swc-win32-arm64-msvc@npm:15.0.2" 244 | conditions: os=win32 & cpu=arm64 245 | languageName: node 246 | linkType: hard 247 | 248 | "@next/swc-win32-x64-msvc@npm:15.0.2": 249 | version: 15.0.2 250 | resolution: "@next/swc-win32-x64-msvc@npm:15.0.2" 251 | conditions: os=win32 & cpu=x64 252 | languageName: node 253 | linkType: hard 254 | 255 | "@swc/counter@npm:0.1.3": 256 | version: 0.1.3 257 | resolution: "@swc/counter@npm:0.1.3" 258 | checksum: df8f9cfba9904d3d60f511664c70d23bb323b3a0803ec9890f60133954173047ba9bdeabce28cd70ba89ccd3fd6c71c7b0bd58be85f611e1ffbe5d5c18616598 259 | languageName: node 260 | linkType: hard 261 | 262 | "@swc/helpers@npm:0.5.13": 263 | version: 0.5.13 264 | resolution: "@swc/helpers@npm:0.5.13" 265 | dependencies: 266 | tslib: ^2.4.0 267 | checksum: d50c2c10da6ef940af423c6b03ad9c3c94cf9de59314b1e921a7d1bcc081a6074481c9d67b655fc8fe66a73288f98b25950743792a63882bfb5793b362494fc0 268 | languageName: node 269 | linkType: hard 270 | 271 | "@types/node@npm:22.8.7": 272 | version: 22.8.7 273 | resolution: "@types/node@npm:22.8.7" 274 | dependencies: 275 | undici-types: ~6.19.8 276 | checksum: c7b200d06da97a4d4f46528ae962c028bb06b6ef9ab7f7949639420f3b3d236f041756ca1945dcaec0fcefbafd07b8ca47bbc1b47b77d33a4173211425641426 277 | languageName: node 278 | linkType: hard 279 | 280 | "@types/prop-types@npm:*": 281 | version: 15.7.12 282 | resolution: "@types/prop-types@npm:15.7.12" 283 | checksum: ac16cc3d0a84431ffa5cfdf89579ad1e2269549f32ce0c769321fdd078f84db4fbe1b461ed5a1a496caf09e637c0e367d600c541435716a55b1d9713f5035dfe 284 | languageName: node 285 | linkType: hard 286 | 287 | "@types/react-dom@npm:^18.3.1": 288 | version: 18.3.1 289 | resolution: "@types/react-dom@npm:18.3.1" 290 | dependencies: 291 | "@types/react": "*" 292 | checksum: ad28ecce3915d30dc76adc2a1373fda1745ba429cea290e16c6628df9a05fd80b6403c8e87d78b45e6c60e51df7a67add389ab62b90070fbfdc9bda8307d9953 293 | languageName: node 294 | linkType: hard 295 | 296 | "@types/react@npm:*, @types/react@npm:18.3.12": 297 | version: 18.3.12 298 | resolution: "@types/react@npm:18.3.12" 299 | dependencies: 300 | "@types/prop-types": "*" 301 | csstype: ^3.0.2 302 | checksum: 4ab1577a8c2105a5e316536f724117c90eee5f4bd5c137fc82a2253d8c1fd299dedaa07e8dfc95d6e2f04a4be3cb8b0e1b06098c6233ebd55c508d88099395b7 303 | languageName: node 304 | linkType: hard 305 | 306 | "busboy@npm:1.6.0": 307 | version: 1.6.0 308 | resolution: "busboy@npm:1.6.0" 309 | dependencies: 310 | streamsearch: ^1.1.0 311 | checksum: 32801e2c0164e12106bf236291a00795c3c4e4b709ae02132883fe8478ba2ae23743b11c5735a0aae8afe65ac4b6ca4568b91f0d9fed1fdbc32ede824a73746e 312 | languageName: node 313 | linkType: hard 314 | 315 | "caniuse-lite@npm:^1.0.30001579": 316 | version: 1.0.30001649 317 | resolution: "caniuse-lite@npm:1.0.30001649" 318 | checksum: 7952512a243f22c942e0e99249def19d781ad1900db101f2d8de9d83de37db000a7dc7f226c9c99134001975e22852becf1677539c24c7ecae53467b681c400f 319 | languageName: node 320 | linkType: hard 321 | 322 | "client-only@npm:0.0.1": 323 | version: 0.0.1 324 | resolution: "client-only@npm:0.0.1" 325 | checksum: 0c16bf660dadb90610553c1d8946a7fdfb81d624adea073b8440b7d795d5b5b08beb3c950c6a2cf16279365a3265158a236876d92bce16423c485c322d7dfaf8 326 | languageName: node 327 | linkType: hard 328 | 329 | "color-convert@npm:^2.0.1": 330 | version: 2.0.1 331 | resolution: "color-convert@npm:2.0.1" 332 | dependencies: 333 | color-name: ~1.1.4 334 | checksum: 79e6bdb9fd479a205c71d89574fccfb22bd9053bd98c6c4d870d65c132e5e904e6034978e55b43d69fcaa7433af2016ee203ce76eeba9cfa554b373e7f7db336 335 | languageName: node 336 | linkType: hard 337 | 338 | "color-name@npm:^1.0.0, color-name@npm:~1.1.4": 339 | version: 1.1.4 340 | resolution: "color-name@npm:1.1.4" 341 | checksum: b0445859521eb4021cd0fb0cc1a75cecf67fceecae89b63f62b201cca8d345baf8b952c966862a9d9a2632987d4f6581f0ec8d957dfacece86f0a7919316f610 342 | languageName: node 343 | linkType: hard 344 | 345 | "color-string@npm:^1.9.0": 346 | version: 1.9.1 347 | resolution: "color-string@npm:1.9.1" 348 | dependencies: 349 | color-name: ^1.0.0 350 | simple-swizzle: ^0.2.2 351 | checksum: c13fe7cff7885f603f49105827d621ce87f4571d78ba28ef4a3f1a104304748f620615e6bf065ecd2145d0d9dad83a3553f52bb25ede7239d18e9f81622f1cc5 352 | languageName: node 353 | linkType: hard 354 | 355 | "color@npm:^4.2.3": 356 | version: 4.2.3 357 | resolution: "color@npm:4.2.3" 358 | dependencies: 359 | color-convert: ^2.0.1 360 | color-string: ^1.9.0 361 | checksum: 0579629c02c631b426780038da929cca8e8d80a40158b09811a0112a107c62e10e4aad719843b791b1e658ab4e800558f2e87ca4522c8b32349d497ecb6adeb4 362 | languageName: node 363 | linkType: hard 364 | 365 | "csstype@npm:^3.0.2": 366 | version: 3.1.3 367 | resolution: "csstype@npm:3.1.3" 368 | checksum: 8db785cc92d259102725b3c694ec0c823f5619a84741b5c7991b8ad135dfaa66093038a1cc63e03361a6cd28d122be48f2106ae72334e067dd619a51f49eddf7 369 | languageName: node 370 | linkType: hard 371 | 372 | "detect-libc@npm:^2.0.3": 373 | version: 2.0.3 374 | resolution: "detect-libc@npm:2.0.3" 375 | checksum: 2ba6a939ae55f189aea996ac67afceb650413c7a34726ee92c40fb0deb2400d57ef94631a8a3f052055eea7efb0f99a9b5e6ce923415daa3e68221f963cfc27d 376 | languageName: node 377 | linkType: hard 378 | 379 | "example-nextjs-obfuscated-app-with-app-router@workspace:.": 380 | version: 0.0.0-use.local 381 | resolution: "example-nextjs-obfuscated-app-with-app-router@workspace:." 382 | dependencies: 383 | "@types/node": 22.8.7 384 | "@types/react": 18.3.12 385 | "@types/react-dom": ^18.3.1 386 | next: 15.0.2 387 | react: 18.3.1 388 | react-dom: 18.3.1 389 | typescript: 5.6.3 390 | languageName: unknown 391 | linkType: soft 392 | 393 | "is-arrayish@npm:^0.3.1": 394 | version: 0.3.2 395 | resolution: "is-arrayish@npm:0.3.2" 396 | checksum: 977e64f54d91c8f169b59afcd80ff19227e9f5c791fa28fa2e5bce355cbaf6c2c356711b734656e80c9dd4a854dd7efcf7894402f1031dfc5de5d620775b4d5f 397 | languageName: node 398 | linkType: hard 399 | 400 | "js-tokens@npm:^3.0.0 || ^4.0.0": 401 | version: 4.0.0 402 | resolution: "js-tokens@npm:4.0.0" 403 | checksum: 8a95213a5a77deb6cbe94d86340e8d9ace2b93bc367790b260101d2f36a2eaf4e4e22d9fa9cf459b38af3a32fb4190e638024cf82ec95ef708680e405ea7cc78 404 | languageName: node 405 | linkType: hard 406 | 407 | "loose-envify@npm:^1.1.0": 408 | version: 1.4.0 409 | resolution: "loose-envify@npm:1.4.0" 410 | dependencies: 411 | js-tokens: ^3.0.0 || ^4.0.0 412 | bin: 413 | loose-envify: cli.js 414 | checksum: 6517e24e0cad87ec9888f500c5b5947032cdfe6ef65e1c1936a0c48a524b81e65542c9c3edc91c97d5bddc806ee2a985dbc79be89215d613b1de5db6d1cfe6f4 415 | languageName: node 416 | linkType: hard 417 | 418 | "nanoid@npm:^3.3.6": 419 | version: 3.3.7 420 | resolution: "nanoid@npm:3.3.7" 421 | bin: 422 | nanoid: bin/nanoid.cjs 423 | checksum: d36c427e530713e4ac6567d488b489a36582ef89da1d6d4e3b87eded11eb10d7042a877958c6f104929809b2ab0bafa17652b076cdf84324aa75b30b722204f2 424 | languageName: node 425 | linkType: hard 426 | 427 | "next@npm:15.0.2": 428 | version: 15.0.2 429 | resolution: "next@npm:15.0.2" 430 | dependencies: 431 | "@next/env": 15.0.2 432 | "@next/swc-darwin-arm64": 15.0.2 433 | "@next/swc-darwin-x64": 15.0.2 434 | "@next/swc-linux-arm64-gnu": 15.0.2 435 | "@next/swc-linux-arm64-musl": 15.0.2 436 | "@next/swc-linux-x64-gnu": 15.0.2 437 | "@next/swc-linux-x64-musl": 15.0.2 438 | "@next/swc-win32-arm64-msvc": 15.0.2 439 | "@next/swc-win32-x64-msvc": 15.0.2 440 | "@swc/counter": 0.1.3 441 | "@swc/helpers": 0.5.13 442 | busboy: 1.6.0 443 | caniuse-lite: ^1.0.30001579 444 | postcss: 8.4.31 445 | sharp: ^0.33.5 446 | styled-jsx: 5.1.6 447 | peerDependencies: 448 | "@opentelemetry/api": ^1.1.0 449 | "@playwright/test": ^1.41.2 450 | babel-plugin-react-compiler: "*" 451 | react: ^18.2.0 || 19.0.0-rc-02c0e824-20241028 452 | react-dom: ^18.2.0 || 19.0.0-rc-02c0e824-20241028 453 | sass: ^1.3.0 454 | dependenciesMeta: 455 | "@next/swc-darwin-arm64": 456 | optional: true 457 | "@next/swc-darwin-x64": 458 | optional: true 459 | "@next/swc-linux-arm64-gnu": 460 | optional: true 461 | "@next/swc-linux-arm64-musl": 462 | optional: true 463 | "@next/swc-linux-x64-gnu": 464 | optional: true 465 | "@next/swc-linux-x64-musl": 466 | optional: true 467 | "@next/swc-win32-arm64-msvc": 468 | optional: true 469 | "@next/swc-win32-x64-msvc": 470 | optional: true 471 | sharp: 472 | optional: true 473 | peerDependenciesMeta: 474 | "@opentelemetry/api": 475 | optional: true 476 | "@playwright/test": 477 | optional: true 478 | babel-plugin-react-compiler: 479 | optional: true 480 | sass: 481 | optional: true 482 | bin: 483 | next: dist/bin/next 484 | checksum: e2430ee430033aa651319453e6194aa13d3fe217a9d8126d3e286ab1c74f13f529f9a0067e0b68ed3f84be4d6383b831db61f9a14673fb3f49789f1dd81c4de6 485 | languageName: node 486 | linkType: hard 487 | 488 | "picocolors@npm:^1.0.0": 489 | version: 1.0.1 490 | resolution: "picocolors@npm:1.0.1" 491 | checksum: fa68166d1f56009fc02a34cdfd112b0dd3cf1ef57667ac57281f714065558c01828cdf4f18600ad6851cbe0093952ed0660b1e0156bddf2184b6aaf5817553a5 492 | languageName: node 493 | linkType: hard 494 | 495 | "postcss@npm:8.4.31": 496 | version: 8.4.31 497 | resolution: "postcss@npm:8.4.31" 498 | dependencies: 499 | nanoid: ^3.3.6 500 | picocolors: ^1.0.0 501 | source-map-js: ^1.0.2 502 | checksum: 1d8611341b073143ad90486fcdfeab49edd243377b1f51834dc4f6d028e82ce5190e4f11bb2633276864503654fb7cab28e67abdc0fbf9d1f88cad4a0ff0beea 503 | languageName: node 504 | linkType: hard 505 | 506 | "react-dom@npm:18.3.1": 507 | version: 18.3.1 508 | resolution: "react-dom@npm:18.3.1" 509 | dependencies: 510 | loose-envify: ^1.1.0 511 | scheduler: ^0.23.2 512 | peerDependencies: 513 | react: ^18.3.1 514 | checksum: 298954ecd8f78288dcaece05e88b570014d8f6dce5db6f66e6ee91448debeb59dcd31561dddb354eee47e6c1bb234669459060deb238ed0213497146e555a0b9 515 | languageName: node 516 | linkType: hard 517 | 518 | "react@npm:18.3.1": 519 | version: 18.3.1 520 | resolution: "react@npm:18.3.1" 521 | dependencies: 522 | loose-envify: ^1.1.0 523 | checksum: a27bcfa8ff7c15a1e50244ad0d0c1cb2ad4375eeffefd266a64889beea6f6b64c4966c9b37d14ee32d6c9fcd5aa6ba183b6988167ab4d127d13e7cb5b386a376 524 | languageName: node 525 | linkType: hard 526 | 527 | "scheduler@npm:^0.23.2": 528 | version: 0.23.2 529 | resolution: "scheduler@npm:0.23.2" 530 | dependencies: 531 | loose-envify: ^1.1.0 532 | checksum: 3e82d1f419e240ef6219d794ff29c7ee415fbdc19e038f680a10c067108e06284f1847450a210b29bbaf97b9d8a97ced5f624c31c681248ac84c80d56ad5a2c4 533 | languageName: node 534 | linkType: hard 535 | 536 | "semver@npm:^7.6.3": 537 | version: 7.6.3 538 | resolution: "semver@npm:7.6.3" 539 | bin: 540 | semver: bin/semver.js 541 | checksum: 4110ec5d015c9438f322257b1c51fe30276e5f766a3f64c09edd1d7ea7118ecbc3f379f3b69032bacf13116dc7abc4ad8ce0d7e2bd642e26b0d271b56b61a7d8 542 | languageName: node 543 | linkType: hard 544 | 545 | "sharp@npm:^0.33.5": 546 | version: 0.33.5 547 | resolution: "sharp@npm:0.33.5" 548 | dependencies: 549 | "@img/sharp-darwin-arm64": 0.33.5 550 | "@img/sharp-darwin-x64": 0.33.5 551 | "@img/sharp-libvips-darwin-arm64": 1.0.4 552 | "@img/sharp-libvips-darwin-x64": 1.0.4 553 | "@img/sharp-libvips-linux-arm": 1.0.5 554 | "@img/sharp-libvips-linux-arm64": 1.0.4 555 | "@img/sharp-libvips-linux-s390x": 1.0.4 556 | "@img/sharp-libvips-linux-x64": 1.0.4 557 | "@img/sharp-libvips-linuxmusl-arm64": 1.0.4 558 | "@img/sharp-libvips-linuxmusl-x64": 1.0.4 559 | "@img/sharp-linux-arm": 0.33.5 560 | "@img/sharp-linux-arm64": 0.33.5 561 | "@img/sharp-linux-s390x": 0.33.5 562 | "@img/sharp-linux-x64": 0.33.5 563 | "@img/sharp-linuxmusl-arm64": 0.33.5 564 | "@img/sharp-linuxmusl-x64": 0.33.5 565 | "@img/sharp-wasm32": 0.33.5 566 | "@img/sharp-win32-ia32": 0.33.5 567 | "@img/sharp-win32-x64": 0.33.5 568 | color: ^4.2.3 569 | detect-libc: ^2.0.3 570 | semver: ^7.6.3 571 | dependenciesMeta: 572 | "@img/sharp-darwin-arm64": 573 | optional: true 574 | "@img/sharp-darwin-x64": 575 | optional: true 576 | "@img/sharp-libvips-darwin-arm64": 577 | optional: true 578 | "@img/sharp-libvips-darwin-x64": 579 | optional: true 580 | "@img/sharp-libvips-linux-arm": 581 | optional: true 582 | "@img/sharp-libvips-linux-arm64": 583 | optional: true 584 | "@img/sharp-libvips-linux-s390x": 585 | optional: true 586 | "@img/sharp-libvips-linux-x64": 587 | optional: true 588 | "@img/sharp-libvips-linuxmusl-arm64": 589 | optional: true 590 | "@img/sharp-libvips-linuxmusl-x64": 591 | optional: true 592 | "@img/sharp-linux-arm": 593 | optional: true 594 | "@img/sharp-linux-arm64": 595 | optional: true 596 | "@img/sharp-linux-s390x": 597 | optional: true 598 | "@img/sharp-linux-x64": 599 | optional: true 600 | "@img/sharp-linuxmusl-arm64": 601 | optional: true 602 | "@img/sharp-linuxmusl-x64": 603 | optional: true 604 | "@img/sharp-wasm32": 605 | optional: true 606 | "@img/sharp-win32-ia32": 607 | optional: true 608 | "@img/sharp-win32-x64": 609 | optional: true 610 | checksum: 04beae89910ac65c5f145f88de162e8466bec67705f497ace128de849c24d168993e016f33a343a1f3c30b25d2a90c3e62b017a9a0d25452371556f6cd2471e4 611 | languageName: node 612 | linkType: hard 613 | 614 | "simple-swizzle@npm:^0.2.2": 615 | version: 0.2.2 616 | resolution: "simple-swizzle@npm:0.2.2" 617 | dependencies: 618 | is-arrayish: ^0.3.1 619 | checksum: a7f3f2ab5c76c4472d5c578df892e857323e452d9f392e1b5cf74b74db66e6294a1e1b8b390b519fa1b96b5b613f2a37db6cffef52c3f1f8f3c5ea64eb2d54c0 620 | languageName: node 621 | linkType: hard 622 | 623 | "source-map-js@npm:^1.0.2": 624 | version: 1.2.0 625 | resolution: "source-map-js@npm:1.2.0" 626 | checksum: 791a43306d9223792e84293b00458bf102a8946e7188f3db0e4e22d8d530b5f80a4ce468eb5ec0bf585443ad55ebbd630bf379c98db0b1f317fd902500217f97 627 | languageName: node 628 | linkType: hard 629 | 630 | "streamsearch@npm:^1.1.0": 631 | version: 1.1.0 632 | resolution: "streamsearch@npm:1.1.0" 633 | checksum: 1cce16cea8405d7a233d32ca5e00a00169cc0e19fbc02aa839959985f267335d435c07f96e5e0edd0eadc6d39c98d5435fb5bbbdefc62c41834eadc5622ad942 634 | languageName: node 635 | linkType: hard 636 | 637 | "styled-jsx@npm:5.1.6": 638 | version: 5.1.6 639 | resolution: "styled-jsx@npm:5.1.6" 640 | dependencies: 641 | client-only: 0.0.1 642 | peerDependencies: 643 | react: ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" 644 | peerDependenciesMeta: 645 | "@babel/core": 646 | optional: true 647 | babel-plugin-macros: 648 | optional: true 649 | checksum: 879ad68e3e81adcf4373038aaafe55f968294955593660e173fbf679204aff158c59966716a60b29af72dc88795cfb2c479b6d2c3c87b2b2d282f3e27cc66461 650 | languageName: node 651 | linkType: hard 652 | 653 | "tslib@npm:^2.4.0": 654 | version: 2.8.1 655 | resolution: "tslib@npm:2.8.1" 656 | checksum: e4aba30e632b8c8902b47587fd13345e2827fa639e7c3121074d5ee0880723282411a8838f830b55100cbe4517672f84a2472667d355b81e8af165a55dc6203a 657 | languageName: node 658 | linkType: hard 659 | 660 | "typescript@npm:5.6.3": 661 | version: 5.6.3 662 | resolution: "typescript@npm:5.6.3" 663 | bin: 664 | tsc: bin/tsc 665 | tsserver: bin/tsserver 666 | checksum: ba302f8822777ebefb28b554105f3e074466b671e7444ec6b75dadc008a62f46f373d9e57ceced1c433756d06c8b7dc569a7eefdf3a9573122a49205ff99021a 667 | languageName: node 668 | linkType: hard 669 | 670 | "typescript@patch:typescript@5.6.3#~builtin": 671 | version: 5.6.3 672 | resolution: "typescript@patch:typescript@npm%3A5.6.3#~builtin::version=5.6.3&hash=5da071" 673 | bin: 674 | tsc: bin/tsc 675 | tsserver: bin/tsserver 676 | checksum: ade87bce2363ee963eed0e4ca8a312ea02c81873ebd53609bc3f6dc0a57f6e61ad7e3fb8cbb7f7ab8b5081cbee801b023f7c4823ee70b1c447eae050e6c7622b 677 | languageName: node 678 | linkType: hard 679 | 680 | "undici-types@npm:~6.19.8": 681 | version: 6.19.8 682 | resolution: "undici-types@npm:6.19.8" 683 | checksum: de51f1b447d22571cf155dfe14ff6d12c5bdaec237c765085b439c38ca8518fc360e88c70f99469162bf2e14188a7b0bcb06e1ed2dc031042b984b0bb9544017 684 | languageName: node 685 | linkType: hard 686 | -------------------------------------------------------------------------------- /example/app-router/.pnp.loader.mjs: -------------------------------------------------------------------------------- 1 | import { URL as URL$1, fileURLToPath, pathToFileURL } from 'url'; 2 | import fs from 'fs'; 3 | import path from 'path'; 4 | import moduleExports, { Module } from 'module'; 5 | import { EOL } from 'os'; 6 | import assert from 'assert'; 7 | 8 | const SAFE_TIME = 456789e3; 9 | 10 | const PortablePath = { 11 | root: `/`, 12 | dot: `.`, 13 | parent: `..` 14 | }; 15 | const npath = Object.create(path); 16 | const ppath = Object.create(path.posix); 17 | npath.cwd = () => process.cwd(); 18 | ppath.cwd = () => toPortablePath(process.cwd()); 19 | ppath.resolve = (...segments) => { 20 | if (segments.length > 0 && ppath.isAbsolute(segments[0])) { 21 | return path.posix.resolve(...segments); 22 | } else { 23 | return path.posix.resolve(ppath.cwd(), ...segments); 24 | } 25 | }; 26 | const contains = function(pathUtils, from, to) { 27 | from = pathUtils.normalize(from); 28 | to = pathUtils.normalize(to); 29 | if (from === to) 30 | return `.`; 31 | if (!from.endsWith(pathUtils.sep)) 32 | from = from + pathUtils.sep; 33 | if (to.startsWith(from)) { 34 | return to.slice(from.length); 35 | } else { 36 | return null; 37 | } 38 | }; 39 | npath.fromPortablePath = fromPortablePath; 40 | npath.toPortablePath = toPortablePath; 41 | npath.contains = (from, to) => contains(npath, from, to); 42 | ppath.contains = (from, to) => contains(ppath, from, to); 43 | const WINDOWS_PATH_REGEXP = /^([a-zA-Z]:.*)$/; 44 | const UNC_WINDOWS_PATH_REGEXP = /^\/\/(\.\/)?(.*)$/; 45 | const PORTABLE_PATH_REGEXP = /^\/([a-zA-Z]:.*)$/; 46 | const UNC_PORTABLE_PATH_REGEXP = /^\/unc\/(\.dot\/)?(.*)$/; 47 | function fromPortablePath(p) { 48 | if (process.platform !== `win32`) 49 | return p; 50 | let portablePathMatch, uncPortablePathMatch; 51 | if (portablePathMatch = p.match(PORTABLE_PATH_REGEXP)) 52 | p = portablePathMatch[1]; 53 | else if (uncPortablePathMatch = p.match(UNC_PORTABLE_PATH_REGEXP)) 54 | p = `\\\\${uncPortablePathMatch[1] ? `.\\` : ``}${uncPortablePathMatch[2]}`; 55 | else 56 | return p; 57 | return p.replace(/\//g, `\\`); 58 | } 59 | function toPortablePath(p) { 60 | if (process.platform !== `win32`) 61 | return p; 62 | p = p.replace(/\\/g, `/`); 63 | let windowsPathMatch, uncWindowsPathMatch; 64 | if (windowsPathMatch = p.match(WINDOWS_PATH_REGEXP)) 65 | p = `/${windowsPathMatch[1]}`; 66 | else if (uncWindowsPathMatch = p.match(UNC_WINDOWS_PATH_REGEXP)) 67 | p = `/unc/${uncWindowsPathMatch[1] ? `.dot/` : ``}${uncWindowsPathMatch[2]}`; 68 | return p; 69 | } 70 | function convertPath(targetPathUtils, sourcePath) { 71 | return targetPathUtils === npath ? fromPortablePath(sourcePath) : toPortablePath(sourcePath); 72 | } 73 | 74 | const defaultTime = new Date(SAFE_TIME * 1e3); 75 | async function copyPromise(destinationFs, destination, sourceFs, source, opts) { 76 | const normalizedDestination = destinationFs.pathUtils.normalize(destination); 77 | const normalizedSource = sourceFs.pathUtils.normalize(source); 78 | const prelayout = []; 79 | const postlayout = []; 80 | const { atime, mtime } = opts.stableTime ? { atime: defaultTime, mtime: defaultTime } : await sourceFs.lstatPromise(normalizedSource); 81 | await destinationFs.mkdirpPromise(destinationFs.pathUtils.dirname(destination), { utimes: [atime, mtime] }); 82 | const updateTime = typeof destinationFs.lutimesPromise === `function` ? destinationFs.lutimesPromise.bind(destinationFs) : destinationFs.utimesPromise.bind(destinationFs); 83 | await copyImpl(prelayout, postlayout, updateTime, destinationFs, normalizedDestination, sourceFs, normalizedSource, { ...opts, didParentExist: true }); 84 | for (const operation of prelayout) 85 | await operation(); 86 | await Promise.all(postlayout.map((operation) => { 87 | return operation(); 88 | })); 89 | } 90 | async function copyImpl(prelayout, postlayout, updateTime, destinationFs, destination, sourceFs, source, opts) { 91 | var _a, _b; 92 | const destinationStat = opts.didParentExist ? await maybeLStat(destinationFs, destination) : null; 93 | const sourceStat = await sourceFs.lstatPromise(source); 94 | const { atime, mtime } = opts.stableTime ? { atime: defaultTime, mtime: defaultTime } : sourceStat; 95 | let updated; 96 | switch (true) { 97 | case sourceStat.isDirectory(): 98 | { 99 | updated = await copyFolder(prelayout, postlayout, updateTime, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts); 100 | } 101 | break; 102 | case sourceStat.isFile(): 103 | { 104 | updated = await copyFile(prelayout, postlayout, updateTime, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts); 105 | } 106 | break; 107 | case sourceStat.isSymbolicLink(): 108 | { 109 | updated = await copySymlink(prelayout, postlayout, updateTime, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts); 110 | } 111 | break; 112 | default: 113 | { 114 | throw new Error(`Unsupported file type (${sourceStat.mode})`); 115 | } 116 | } 117 | if (updated || ((_a = destinationStat == null ? void 0 : destinationStat.mtime) == null ? void 0 : _a.getTime()) !== mtime.getTime() || ((_b = destinationStat == null ? void 0 : destinationStat.atime) == null ? void 0 : _b.getTime()) !== atime.getTime()) { 118 | postlayout.push(() => updateTime(destination, atime, mtime)); 119 | updated = true; 120 | } 121 | if (destinationStat === null || (destinationStat.mode & 511) !== (sourceStat.mode & 511)) { 122 | postlayout.push(() => destinationFs.chmodPromise(destination, sourceStat.mode & 511)); 123 | updated = true; 124 | } 125 | return updated; 126 | } 127 | async function maybeLStat(baseFs, p) { 128 | try { 129 | return await baseFs.lstatPromise(p); 130 | } catch (e) { 131 | return null; 132 | } 133 | } 134 | async function copyFolder(prelayout, postlayout, updateTime, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts) { 135 | if (destinationStat !== null && !destinationStat.isDirectory()) { 136 | if (opts.overwrite) { 137 | prelayout.push(async () => destinationFs.removePromise(destination)); 138 | destinationStat = null; 139 | } else { 140 | return false; 141 | } 142 | } 143 | let updated = false; 144 | if (destinationStat === null) { 145 | prelayout.push(async () => { 146 | try { 147 | await destinationFs.mkdirPromise(destination, { mode: sourceStat.mode }); 148 | } catch (err) { 149 | if (err.code !== `EEXIST`) { 150 | throw err; 151 | } 152 | } 153 | }); 154 | updated = true; 155 | } 156 | const entries = await sourceFs.readdirPromise(source); 157 | const nextOpts = opts.didParentExist && !destinationStat ? { ...opts, didParentExist: false } : opts; 158 | if (opts.stableSort) { 159 | for (const entry of entries.sort()) { 160 | if (await copyImpl(prelayout, postlayout, updateTime, destinationFs, destinationFs.pathUtils.join(destination, entry), sourceFs, sourceFs.pathUtils.join(source, entry), nextOpts)) { 161 | updated = true; 162 | } 163 | } 164 | } else { 165 | const entriesUpdateStatus = await Promise.all(entries.map(async (entry) => { 166 | await copyImpl(prelayout, postlayout, updateTime, destinationFs, destinationFs.pathUtils.join(destination, entry), sourceFs, sourceFs.pathUtils.join(source, entry), nextOpts); 167 | })); 168 | if (entriesUpdateStatus.some((status) => status)) { 169 | updated = true; 170 | } 171 | } 172 | return updated; 173 | } 174 | const isCloneSupportedCache = /* @__PURE__ */ new WeakMap(); 175 | function makeLinkOperation(opFs, destination, source, sourceStat, linkStrategy) { 176 | return async () => { 177 | await opFs.linkPromise(source, destination); 178 | if (linkStrategy === "readOnly" /* ReadOnly */) { 179 | sourceStat.mode &= ~146; 180 | await opFs.chmodPromise(destination, sourceStat.mode); 181 | } 182 | }; 183 | } 184 | function makeCloneLinkOperation(opFs, destination, source, sourceStat, linkStrategy) { 185 | const isCloneSupported = isCloneSupportedCache.get(opFs); 186 | if (typeof isCloneSupported === `undefined`) { 187 | return async () => { 188 | try { 189 | await opFs.copyFilePromise(source, destination, fs.constants.COPYFILE_FICLONE_FORCE); 190 | isCloneSupportedCache.set(opFs, true); 191 | } catch (err) { 192 | if (err.code === `ENOSYS` || err.code === `ENOTSUP`) { 193 | isCloneSupportedCache.set(opFs, false); 194 | await makeLinkOperation(opFs, destination, source, sourceStat, linkStrategy)(); 195 | } else { 196 | throw err; 197 | } 198 | } 199 | }; 200 | } else { 201 | if (isCloneSupported) { 202 | return async () => opFs.copyFilePromise(source, destination, fs.constants.COPYFILE_FICLONE_FORCE); 203 | } else { 204 | return makeLinkOperation(opFs, destination, source, sourceStat, linkStrategy); 205 | } 206 | } 207 | } 208 | async function copyFile(prelayout, postlayout, updateTime, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts) { 209 | var _a; 210 | if (destinationStat !== null) { 211 | if (opts.overwrite) { 212 | prelayout.push(async () => destinationFs.removePromise(destination)); 213 | destinationStat = null; 214 | } else { 215 | return false; 216 | } 217 | } 218 | const linkStrategy = (_a = opts.linkStrategy) != null ? _a : null; 219 | const op = destinationFs === sourceFs ? linkStrategy !== null ? makeCloneLinkOperation(destinationFs, destination, source, sourceStat, linkStrategy) : async () => destinationFs.copyFilePromise(source, destination, fs.constants.COPYFILE_FICLONE) : linkStrategy !== null ? makeLinkOperation(destinationFs, destination, source, sourceStat, linkStrategy) : async () => destinationFs.writeFilePromise(destination, await sourceFs.readFilePromise(source)); 220 | prelayout.push(async () => op()); 221 | return true; 222 | } 223 | async function copySymlink(prelayout, postlayout, updateTime, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts) { 224 | if (destinationStat !== null) { 225 | if (opts.overwrite) { 226 | prelayout.push(async () => destinationFs.removePromise(destination)); 227 | destinationStat = null; 228 | } else { 229 | return false; 230 | } 231 | } 232 | prelayout.push(async () => { 233 | await destinationFs.symlinkPromise(convertPath(destinationFs.pathUtils, await sourceFs.readlinkPromise(source)), destination); 234 | }); 235 | return true; 236 | } 237 | 238 | function makeError(code, message) { 239 | return Object.assign(new Error(`${code}: ${message}`), { code }); 240 | } 241 | function ENOSYS(message, reason) { 242 | return makeError(`ENOSYS`, `${message}, ${reason}`); 243 | } 244 | 245 | class FakeFS { 246 | constructor(pathUtils) { 247 | this.pathUtils = pathUtils; 248 | } 249 | async *genTraversePromise(init, { stableSort = false } = {}) { 250 | const stack = [init]; 251 | while (stack.length > 0) { 252 | const p = stack.shift(); 253 | const entry = await this.lstatPromise(p); 254 | if (entry.isDirectory()) { 255 | const entries = await this.readdirPromise(p); 256 | if (stableSort) { 257 | for (const entry2 of entries.sort()) { 258 | stack.push(this.pathUtils.join(p, entry2)); 259 | } 260 | } else { 261 | throw new Error(`Not supported`); 262 | } 263 | } else { 264 | yield p; 265 | } 266 | } 267 | } 268 | async removePromise(p, { recursive = true, maxRetries = 5 } = {}) { 269 | let stat; 270 | try { 271 | stat = await this.lstatPromise(p); 272 | } catch (error) { 273 | if (error.code === `ENOENT`) { 274 | return; 275 | } else { 276 | throw error; 277 | } 278 | } 279 | if (stat.isDirectory()) { 280 | if (recursive) { 281 | const entries = await this.readdirPromise(p); 282 | await Promise.all(entries.map((entry) => { 283 | return this.removePromise(this.pathUtils.resolve(p, entry)); 284 | })); 285 | } 286 | for (let t = 0; t <= maxRetries; t++) { 287 | try { 288 | await this.rmdirPromise(p); 289 | break; 290 | } catch (error) { 291 | if (error.code !== `EBUSY` && error.code !== `ENOTEMPTY`) { 292 | throw error; 293 | } else if (t < maxRetries) { 294 | await new Promise((resolve) => setTimeout(resolve, t * 100)); 295 | } 296 | } 297 | } 298 | } else { 299 | await this.unlinkPromise(p); 300 | } 301 | } 302 | removeSync(p, { recursive = true } = {}) { 303 | let stat; 304 | try { 305 | stat = this.lstatSync(p); 306 | } catch (error) { 307 | if (error.code === `ENOENT`) { 308 | return; 309 | } else { 310 | throw error; 311 | } 312 | } 313 | if (stat.isDirectory()) { 314 | if (recursive) 315 | for (const entry of this.readdirSync(p)) 316 | this.removeSync(this.pathUtils.resolve(p, entry)); 317 | this.rmdirSync(p); 318 | } else { 319 | this.unlinkSync(p); 320 | } 321 | } 322 | async mkdirpPromise(p, { chmod, utimes } = {}) { 323 | p = this.resolve(p); 324 | if (p === this.pathUtils.dirname(p)) 325 | return void 0; 326 | const parts = p.split(this.pathUtils.sep); 327 | let createdDirectory; 328 | for (let u = 2; u <= parts.length; ++u) { 329 | const subPath = parts.slice(0, u).join(this.pathUtils.sep); 330 | if (!this.existsSync(subPath)) { 331 | try { 332 | await this.mkdirPromise(subPath); 333 | } catch (error) { 334 | if (error.code === `EEXIST`) { 335 | continue; 336 | } else { 337 | throw error; 338 | } 339 | } 340 | createdDirectory != null ? createdDirectory : createdDirectory = subPath; 341 | if (chmod != null) 342 | await this.chmodPromise(subPath, chmod); 343 | if (utimes != null) { 344 | await this.utimesPromise(subPath, utimes[0], utimes[1]); 345 | } else { 346 | const parentStat = await this.statPromise(this.pathUtils.dirname(subPath)); 347 | await this.utimesPromise(subPath, parentStat.atime, parentStat.mtime); 348 | } 349 | } 350 | } 351 | return createdDirectory; 352 | } 353 | mkdirpSync(p, { chmod, utimes } = {}) { 354 | p = this.resolve(p); 355 | if (p === this.pathUtils.dirname(p)) 356 | return void 0; 357 | const parts = p.split(this.pathUtils.sep); 358 | let createdDirectory; 359 | for (let u = 2; u <= parts.length; ++u) { 360 | const subPath = parts.slice(0, u).join(this.pathUtils.sep); 361 | if (!this.existsSync(subPath)) { 362 | try { 363 | this.mkdirSync(subPath); 364 | } catch (error) { 365 | if (error.code === `EEXIST`) { 366 | continue; 367 | } else { 368 | throw error; 369 | } 370 | } 371 | createdDirectory != null ? createdDirectory : createdDirectory = subPath; 372 | if (chmod != null) 373 | this.chmodSync(subPath, chmod); 374 | if (utimes != null) { 375 | this.utimesSync(subPath, utimes[0], utimes[1]); 376 | } else { 377 | const parentStat = this.statSync(this.pathUtils.dirname(subPath)); 378 | this.utimesSync(subPath, parentStat.atime, parentStat.mtime); 379 | } 380 | } 381 | } 382 | return createdDirectory; 383 | } 384 | async copyPromise(destination, source, { baseFs = this, overwrite = true, stableSort = false, stableTime = false, linkStrategy = null } = {}) { 385 | return await copyPromise(this, destination, baseFs, source, { overwrite, stableSort, stableTime, linkStrategy }); 386 | } 387 | copySync(destination, source, { baseFs = this, overwrite = true } = {}) { 388 | const stat = baseFs.lstatSync(source); 389 | const exists = this.existsSync(destination); 390 | if (stat.isDirectory()) { 391 | this.mkdirpSync(destination); 392 | const directoryListing = baseFs.readdirSync(source); 393 | for (const entry of directoryListing) { 394 | this.copySync(this.pathUtils.join(destination, entry), baseFs.pathUtils.join(source, entry), { baseFs, overwrite }); 395 | } 396 | } else if (stat.isFile()) { 397 | if (!exists || overwrite) { 398 | if (exists) 399 | this.removeSync(destination); 400 | const content = baseFs.readFileSync(source); 401 | this.writeFileSync(destination, content); 402 | } 403 | } else if (stat.isSymbolicLink()) { 404 | if (!exists || overwrite) { 405 | if (exists) 406 | this.removeSync(destination); 407 | const target = baseFs.readlinkSync(source); 408 | this.symlinkSync(convertPath(this.pathUtils, target), destination); 409 | } 410 | } else { 411 | throw new Error(`Unsupported file type (file: ${source}, mode: 0o${stat.mode.toString(8).padStart(6, `0`)})`); 412 | } 413 | const mode = stat.mode & 511; 414 | this.chmodSync(destination, mode); 415 | } 416 | async changeFilePromise(p, content, opts = {}) { 417 | if (Buffer.isBuffer(content)) { 418 | return this.changeFileBufferPromise(p, content, opts); 419 | } else { 420 | return this.changeFileTextPromise(p, content, opts); 421 | } 422 | } 423 | async changeFileBufferPromise(p, content, { mode } = {}) { 424 | let current = Buffer.alloc(0); 425 | try { 426 | current = await this.readFilePromise(p); 427 | } catch (error) { 428 | } 429 | if (Buffer.compare(current, content) === 0) 430 | return; 431 | await this.writeFilePromise(p, content, { mode }); 432 | } 433 | async changeFileTextPromise(p, content, { automaticNewlines, mode } = {}) { 434 | let current = ``; 435 | try { 436 | current = await this.readFilePromise(p, `utf8`); 437 | } catch (error) { 438 | } 439 | const normalizedContent = automaticNewlines ? normalizeLineEndings(current, content) : content; 440 | if (current === normalizedContent) 441 | return; 442 | await this.writeFilePromise(p, normalizedContent, { mode }); 443 | } 444 | changeFileSync(p, content, opts = {}) { 445 | if (Buffer.isBuffer(content)) { 446 | return this.changeFileBufferSync(p, content, opts); 447 | } else { 448 | return this.changeFileTextSync(p, content, opts); 449 | } 450 | } 451 | changeFileBufferSync(p, content, { mode } = {}) { 452 | let current = Buffer.alloc(0); 453 | try { 454 | current = this.readFileSync(p); 455 | } catch (error) { 456 | } 457 | if (Buffer.compare(current, content) === 0) 458 | return; 459 | this.writeFileSync(p, content, { mode }); 460 | } 461 | changeFileTextSync(p, content, { automaticNewlines = false, mode } = {}) { 462 | let current = ``; 463 | try { 464 | current = this.readFileSync(p, `utf8`); 465 | } catch (error) { 466 | } 467 | const normalizedContent = automaticNewlines ? normalizeLineEndings(current, content) : content; 468 | if (current === normalizedContent) 469 | return; 470 | this.writeFileSync(p, normalizedContent, { mode }); 471 | } 472 | async movePromise(fromP, toP) { 473 | try { 474 | await this.renamePromise(fromP, toP); 475 | } catch (error) { 476 | if (error.code === `EXDEV`) { 477 | await this.copyPromise(toP, fromP); 478 | await this.removePromise(fromP); 479 | } else { 480 | throw error; 481 | } 482 | } 483 | } 484 | moveSync(fromP, toP) { 485 | try { 486 | this.renameSync(fromP, toP); 487 | } catch (error) { 488 | if (error.code === `EXDEV`) { 489 | this.copySync(toP, fromP); 490 | this.removeSync(fromP); 491 | } else { 492 | throw error; 493 | } 494 | } 495 | } 496 | async lockPromise(affectedPath, callback) { 497 | const lockPath = `${affectedPath}.flock`; 498 | const interval = 1e3 / 60; 499 | const startTime = Date.now(); 500 | let fd = null; 501 | const isAlive = async () => { 502 | let pid; 503 | try { 504 | [pid] = await this.readJsonPromise(lockPath); 505 | } catch (error) { 506 | return Date.now() - startTime < 500; 507 | } 508 | try { 509 | process.kill(pid, 0); 510 | return true; 511 | } catch (error) { 512 | return false; 513 | } 514 | }; 515 | while (fd === null) { 516 | try { 517 | fd = await this.openPromise(lockPath, `wx`); 518 | } catch (error) { 519 | if (error.code === `EEXIST`) { 520 | if (!await isAlive()) { 521 | try { 522 | await this.unlinkPromise(lockPath); 523 | continue; 524 | } catch (error2) { 525 | } 526 | } 527 | if (Date.now() - startTime < 60 * 1e3) { 528 | await new Promise((resolve) => setTimeout(resolve, interval)); 529 | } else { 530 | throw new Error(`Couldn't acquire a lock in a reasonable time (via ${lockPath})`); 531 | } 532 | } else { 533 | throw error; 534 | } 535 | } 536 | } 537 | await this.writePromise(fd, JSON.stringify([process.pid])); 538 | try { 539 | return await callback(); 540 | } finally { 541 | try { 542 | await this.closePromise(fd); 543 | await this.unlinkPromise(lockPath); 544 | } catch (error) { 545 | } 546 | } 547 | } 548 | async readJsonPromise(p) { 549 | const content = await this.readFilePromise(p, `utf8`); 550 | try { 551 | return JSON.parse(content); 552 | } catch (error) { 553 | error.message += ` (in ${p})`; 554 | throw error; 555 | } 556 | } 557 | readJsonSync(p) { 558 | const content = this.readFileSync(p, `utf8`); 559 | try { 560 | return JSON.parse(content); 561 | } catch (error) { 562 | error.message += ` (in ${p})`; 563 | throw error; 564 | } 565 | } 566 | async writeJsonPromise(p, data) { 567 | return await this.writeFilePromise(p, `${JSON.stringify(data, null, 2)} 568 | `); 569 | } 570 | writeJsonSync(p, data) { 571 | return this.writeFileSync(p, `${JSON.stringify(data, null, 2)} 572 | `); 573 | } 574 | async preserveTimePromise(p, cb) { 575 | const stat = await this.lstatPromise(p); 576 | const result = await cb(); 577 | if (typeof result !== `undefined`) 578 | p = result; 579 | if (this.lutimesPromise) { 580 | await this.lutimesPromise(p, stat.atime, stat.mtime); 581 | } else if (!stat.isSymbolicLink()) { 582 | await this.utimesPromise(p, stat.atime, stat.mtime); 583 | } 584 | } 585 | async preserveTimeSync(p, cb) { 586 | const stat = this.lstatSync(p); 587 | const result = cb(); 588 | if (typeof result !== `undefined`) 589 | p = result; 590 | if (this.lutimesSync) { 591 | this.lutimesSync(p, stat.atime, stat.mtime); 592 | } else if (!stat.isSymbolicLink()) { 593 | this.utimesSync(p, stat.atime, stat.mtime); 594 | } 595 | } 596 | } 597 | class BasePortableFakeFS extends FakeFS { 598 | constructor() { 599 | super(ppath); 600 | } 601 | } 602 | function getEndOfLine(content) { 603 | const matches = content.match(/\r?\n/g); 604 | if (matches === null) 605 | return EOL; 606 | const crlf = matches.filter((nl) => nl === `\r 607 | `).length; 608 | const lf = matches.length - crlf; 609 | return crlf > lf ? `\r 610 | ` : ` 611 | `; 612 | } 613 | function normalizeLineEndings(originalContent, newContent) { 614 | return newContent.replace(/\r?\n/g, getEndOfLine(originalContent)); 615 | } 616 | 617 | class NodeFS extends BasePortableFakeFS { 618 | constructor(realFs = fs) { 619 | super(); 620 | this.realFs = realFs; 621 | if (typeof this.realFs.lutimes !== `undefined`) { 622 | this.lutimesPromise = this.lutimesPromiseImpl; 623 | this.lutimesSync = this.lutimesSyncImpl; 624 | } 625 | } 626 | getExtractHint() { 627 | return false; 628 | } 629 | getRealPath() { 630 | return PortablePath.root; 631 | } 632 | resolve(p) { 633 | return ppath.resolve(p); 634 | } 635 | async openPromise(p, flags, mode) { 636 | return await new Promise((resolve, reject) => { 637 | this.realFs.open(npath.fromPortablePath(p), flags, mode, this.makeCallback(resolve, reject)); 638 | }); 639 | } 640 | openSync(p, flags, mode) { 641 | return this.realFs.openSync(npath.fromPortablePath(p), flags, mode); 642 | } 643 | async opendirPromise(p, opts) { 644 | return await new Promise((resolve, reject) => { 645 | if (typeof opts !== `undefined`) { 646 | this.realFs.opendir(npath.fromPortablePath(p), opts, this.makeCallback(resolve, reject)); 647 | } else { 648 | this.realFs.opendir(npath.fromPortablePath(p), this.makeCallback(resolve, reject)); 649 | } 650 | }).then((dir) => { 651 | return Object.defineProperty(dir, `path`, { value: p, configurable: true, writable: true }); 652 | }); 653 | } 654 | opendirSync(p, opts) { 655 | const dir = typeof opts !== `undefined` ? this.realFs.opendirSync(npath.fromPortablePath(p), opts) : this.realFs.opendirSync(npath.fromPortablePath(p)); 656 | return Object.defineProperty(dir, `path`, { value: p, configurable: true, writable: true }); 657 | } 658 | async readPromise(fd, buffer, offset = 0, length = 0, position = -1) { 659 | return await new Promise((resolve, reject) => { 660 | this.realFs.read(fd, buffer, offset, length, position, (error, bytesRead) => { 661 | if (error) { 662 | reject(error); 663 | } else { 664 | resolve(bytesRead); 665 | } 666 | }); 667 | }); 668 | } 669 | readSync(fd, buffer, offset, length, position) { 670 | return this.realFs.readSync(fd, buffer, offset, length, position); 671 | } 672 | async writePromise(fd, buffer, offset, length, position) { 673 | return await new Promise((resolve, reject) => { 674 | if (typeof buffer === `string`) { 675 | return this.realFs.write(fd, buffer, offset, this.makeCallback(resolve, reject)); 676 | } else { 677 | return this.realFs.write(fd, buffer, offset, length, position, this.makeCallback(resolve, reject)); 678 | } 679 | }); 680 | } 681 | writeSync(fd, buffer, offset, length, position) { 682 | if (typeof buffer === `string`) { 683 | return this.realFs.writeSync(fd, buffer, offset); 684 | } else { 685 | return this.realFs.writeSync(fd, buffer, offset, length, position); 686 | } 687 | } 688 | async closePromise(fd) { 689 | await new Promise((resolve, reject) => { 690 | this.realFs.close(fd, this.makeCallback(resolve, reject)); 691 | }); 692 | } 693 | closeSync(fd) { 694 | this.realFs.closeSync(fd); 695 | } 696 | createReadStream(p, opts) { 697 | const realPath = p !== null ? npath.fromPortablePath(p) : p; 698 | return this.realFs.createReadStream(realPath, opts); 699 | } 700 | createWriteStream(p, opts) { 701 | const realPath = p !== null ? npath.fromPortablePath(p) : p; 702 | return this.realFs.createWriteStream(realPath, opts); 703 | } 704 | async realpathPromise(p) { 705 | return await new Promise((resolve, reject) => { 706 | this.realFs.realpath(npath.fromPortablePath(p), {}, this.makeCallback(resolve, reject)); 707 | }).then((path) => { 708 | return npath.toPortablePath(path); 709 | }); 710 | } 711 | realpathSync(p) { 712 | return npath.toPortablePath(this.realFs.realpathSync(npath.fromPortablePath(p), {})); 713 | } 714 | async existsPromise(p) { 715 | return await new Promise((resolve) => { 716 | this.realFs.exists(npath.fromPortablePath(p), resolve); 717 | }); 718 | } 719 | accessSync(p, mode) { 720 | return this.realFs.accessSync(npath.fromPortablePath(p), mode); 721 | } 722 | async accessPromise(p, mode) { 723 | return await new Promise((resolve, reject) => { 724 | this.realFs.access(npath.fromPortablePath(p), mode, this.makeCallback(resolve, reject)); 725 | }); 726 | } 727 | existsSync(p) { 728 | return this.realFs.existsSync(npath.fromPortablePath(p)); 729 | } 730 | async statPromise(p, opts) { 731 | return await new Promise((resolve, reject) => { 732 | if (opts) { 733 | this.realFs.stat(npath.fromPortablePath(p), opts, this.makeCallback(resolve, reject)); 734 | } else { 735 | this.realFs.stat(npath.fromPortablePath(p), this.makeCallback(resolve, reject)); 736 | } 737 | }); 738 | } 739 | statSync(p, opts) { 740 | if (opts) { 741 | return this.realFs.statSync(npath.fromPortablePath(p), opts); 742 | } else { 743 | return this.realFs.statSync(npath.fromPortablePath(p)); 744 | } 745 | } 746 | async fstatPromise(fd, opts) { 747 | return await new Promise((resolve, reject) => { 748 | if (opts) { 749 | this.realFs.fstat(fd, opts, this.makeCallback(resolve, reject)); 750 | } else { 751 | this.realFs.fstat(fd, this.makeCallback(resolve, reject)); 752 | } 753 | }); 754 | } 755 | fstatSync(fd, opts) { 756 | if (opts) { 757 | return this.realFs.fstatSync(fd, opts); 758 | } else { 759 | return this.realFs.fstatSync(fd); 760 | } 761 | } 762 | async lstatPromise(p, opts) { 763 | return await new Promise((resolve, reject) => { 764 | if (opts) { 765 | this.realFs.lstat(npath.fromPortablePath(p), opts, this.makeCallback(resolve, reject)); 766 | } else { 767 | this.realFs.lstat(npath.fromPortablePath(p), this.makeCallback(resolve, reject)); 768 | } 769 | }); 770 | } 771 | lstatSync(p, opts) { 772 | if (opts) { 773 | return this.realFs.lstatSync(npath.fromPortablePath(p), opts); 774 | } else { 775 | return this.realFs.lstatSync(npath.fromPortablePath(p)); 776 | } 777 | } 778 | async fchmodPromise(fd, mask) { 779 | return await new Promise((resolve, reject) => { 780 | this.realFs.fchmod(fd, mask, this.makeCallback(resolve, reject)); 781 | }); 782 | } 783 | fchmodSync(fd, mask) { 784 | return this.realFs.fchmodSync(fd, mask); 785 | } 786 | async chmodPromise(p, mask) { 787 | return await new Promise((resolve, reject) => { 788 | this.realFs.chmod(npath.fromPortablePath(p), mask, this.makeCallback(resolve, reject)); 789 | }); 790 | } 791 | chmodSync(p, mask) { 792 | return this.realFs.chmodSync(npath.fromPortablePath(p), mask); 793 | } 794 | async fchownPromise(fd, uid, gid) { 795 | return await new Promise((resolve, reject) => { 796 | this.realFs.fchown(fd, uid, gid, this.makeCallback(resolve, reject)); 797 | }); 798 | } 799 | fchownSync(fd, uid, gid) { 800 | return this.realFs.fchownSync(fd, uid, gid); 801 | } 802 | async chownPromise(p, uid, gid) { 803 | return await new Promise((resolve, reject) => { 804 | this.realFs.chown(npath.fromPortablePath(p), uid, gid, this.makeCallback(resolve, reject)); 805 | }); 806 | } 807 | chownSync(p, uid, gid) { 808 | return this.realFs.chownSync(npath.fromPortablePath(p), uid, gid); 809 | } 810 | async renamePromise(oldP, newP) { 811 | return await new Promise((resolve, reject) => { 812 | this.realFs.rename(npath.fromPortablePath(oldP), npath.fromPortablePath(newP), this.makeCallback(resolve, reject)); 813 | }); 814 | } 815 | renameSync(oldP, newP) { 816 | return this.realFs.renameSync(npath.fromPortablePath(oldP), npath.fromPortablePath(newP)); 817 | } 818 | async copyFilePromise(sourceP, destP, flags = 0) { 819 | return await new Promise((resolve, reject) => { 820 | this.realFs.copyFile(npath.fromPortablePath(sourceP), npath.fromPortablePath(destP), flags, this.makeCallback(resolve, reject)); 821 | }); 822 | } 823 | copyFileSync(sourceP, destP, flags = 0) { 824 | return this.realFs.copyFileSync(npath.fromPortablePath(sourceP), npath.fromPortablePath(destP), flags); 825 | } 826 | async appendFilePromise(p, content, opts) { 827 | return await new Promise((resolve, reject) => { 828 | const fsNativePath = typeof p === `string` ? npath.fromPortablePath(p) : p; 829 | if (opts) { 830 | this.realFs.appendFile(fsNativePath, content, opts, this.makeCallback(resolve, reject)); 831 | } else { 832 | this.realFs.appendFile(fsNativePath, content, this.makeCallback(resolve, reject)); 833 | } 834 | }); 835 | } 836 | appendFileSync(p, content, opts) { 837 | const fsNativePath = typeof p === `string` ? npath.fromPortablePath(p) : p; 838 | if (opts) { 839 | this.realFs.appendFileSync(fsNativePath, content, opts); 840 | } else { 841 | this.realFs.appendFileSync(fsNativePath, content); 842 | } 843 | } 844 | async writeFilePromise(p, content, opts) { 845 | return await new Promise((resolve, reject) => { 846 | const fsNativePath = typeof p === `string` ? npath.fromPortablePath(p) : p; 847 | if (opts) { 848 | this.realFs.writeFile(fsNativePath, content, opts, this.makeCallback(resolve, reject)); 849 | } else { 850 | this.realFs.writeFile(fsNativePath, content, this.makeCallback(resolve, reject)); 851 | } 852 | }); 853 | } 854 | writeFileSync(p, content, opts) { 855 | const fsNativePath = typeof p === `string` ? npath.fromPortablePath(p) : p; 856 | if (opts) { 857 | this.realFs.writeFileSync(fsNativePath, content, opts); 858 | } else { 859 | this.realFs.writeFileSync(fsNativePath, content); 860 | } 861 | } 862 | async unlinkPromise(p) { 863 | return await new Promise((resolve, reject) => { 864 | this.realFs.unlink(npath.fromPortablePath(p), this.makeCallback(resolve, reject)); 865 | }); 866 | } 867 | unlinkSync(p) { 868 | return this.realFs.unlinkSync(npath.fromPortablePath(p)); 869 | } 870 | async utimesPromise(p, atime, mtime) { 871 | return await new Promise((resolve, reject) => { 872 | this.realFs.utimes(npath.fromPortablePath(p), atime, mtime, this.makeCallback(resolve, reject)); 873 | }); 874 | } 875 | utimesSync(p, atime, mtime) { 876 | this.realFs.utimesSync(npath.fromPortablePath(p), atime, mtime); 877 | } 878 | async lutimesPromiseImpl(p, atime, mtime) { 879 | const lutimes = this.realFs.lutimes; 880 | if (typeof lutimes === `undefined`) 881 | throw ENOSYS(`unavailable Node binding`, `lutimes '${p}'`); 882 | return await new Promise((resolve, reject) => { 883 | lutimes.call(this.realFs, npath.fromPortablePath(p), atime, mtime, this.makeCallback(resolve, reject)); 884 | }); 885 | } 886 | lutimesSyncImpl(p, atime, mtime) { 887 | const lutimesSync = this.realFs.lutimesSync; 888 | if (typeof lutimesSync === `undefined`) 889 | throw ENOSYS(`unavailable Node binding`, `lutimes '${p}'`); 890 | lutimesSync.call(this.realFs, npath.fromPortablePath(p), atime, mtime); 891 | } 892 | async mkdirPromise(p, opts) { 893 | return await new Promise((resolve, reject) => { 894 | this.realFs.mkdir(npath.fromPortablePath(p), opts, this.makeCallback(resolve, reject)); 895 | }); 896 | } 897 | mkdirSync(p, opts) { 898 | return this.realFs.mkdirSync(npath.fromPortablePath(p), opts); 899 | } 900 | async rmdirPromise(p, opts) { 901 | return await new Promise((resolve, reject) => { 902 | if (opts) { 903 | this.realFs.rmdir(npath.fromPortablePath(p), opts, this.makeCallback(resolve, reject)); 904 | } else { 905 | this.realFs.rmdir(npath.fromPortablePath(p), this.makeCallback(resolve, reject)); 906 | } 907 | }); 908 | } 909 | rmdirSync(p, opts) { 910 | return this.realFs.rmdirSync(npath.fromPortablePath(p), opts); 911 | } 912 | async linkPromise(existingP, newP) { 913 | return await new Promise((resolve, reject) => { 914 | this.realFs.link(npath.fromPortablePath(existingP), npath.fromPortablePath(newP), this.makeCallback(resolve, reject)); 915 | }); 916 | } 917 | linkSync(existingP, newP) { 918 | return this.realFs.linkSync(npath.fromPortablePath(existingP), npath.fromPortablePath(newP)); 919 | } 920 | async symlinkPromise(target, p, type) { 921 | return await new Promise((resolve, reject) => { 922 | this.realFs.symlink(npath.fromPortablePath(target.replace(/\/+$/, ``)), npath.fromPortablePath(p), type, this.makeCallback(resolve, reject)); 923 | }); 924 | } 925 | symlinkSync(target, p, type) { 926 | return this.realFs.symlinkSync(npath.fromPortablePath(target.replace(/\/+$/, ``)), npath.fromPortablePath(p), type); 927 | } 928 | async readFilePromise(p, encoding) { 929 | return await new Promise((resolve, reject) => { 930 | const fsNativePath = typeof p === `string` ? npath.fromPortablePath(p) : p; 931 | this.realFs.readFile(fsNativePath, encoding, this.makeCallback(resolve, reject)); 932 | }); 933 | } 934 | readFileSync(p, encoding) { 935 | const fsNativePath = typeof p === `string` ? npath.fromPortablePath(p) : p; 936 | return this.realFs.readFileSync(fsNativePath, encoding); 937 | } 938 | async readdirPromise(p, opts) { 939 | return await new Promise((resolve, reject) => { 940 | if (opts == null ? void 0 : opts.withFileTypes) { 941 | this.realFs.readdir(npath.fromPortablePath(p), { withFileTypes: true }, this.makeCallback(resolve, reject)); 942 | } else { 943 | this.realFs.readdir(npath.fromPortablePath(p), this.makeCallback((value) => resolve(value), reject)); 944 | } 945 | }); 946 | } 947 | readdirSync(p, opts) { 948 | if (opts == null ? void 0 : opts.withFileTypes) { 949 | return this.realFs.readdirSync(npath.fromPortablePath(p), { withFileTypes: true }); 950 | } else { 951 | return this.realFs.readdirSync(npath.fromPortablePath(p)); 952 | } 953 | } 954 | async readlinkPromise(p) { 955 | return await new Promise((resolve, reject) => { 956 | this.realFs.readlink(npath.fromPortablePath(p), this.makeCallback(resolve, reject)); 957 | }).then((path) => { 958 | return npath.toPortablePath(path); 959 | }); 960 | } 961 | readlinkSync(p) { 962 | return npath.toPortablePath(this.realFs.readlinkSync(npath.fromPortablePath(p))); 963 | } 964 | async truncatePromise(p, len) { 965 | return await new Promise((resolve, reject) => { 966 | this.realFs.truncate(npath.fromPortablePath(p), len, this.makeCallback(resolve, reject)); 967 | }); 968 | } 969 | truncateSync(p, len) { 970 | return this.realFs.truncateSync(npath.fromPortablePath(p), len); 971 | } 972 | async ftruncatePromise(fd, len) { 973 | return await new Promise((resolve, reject) => { 974 | this.realFs.ftruncate(fd, len, this.makeCallback(resolve, reject)); 975 | }); 976 | } 977 | ftruncateSync(fd, len) { 978 | return this.realFs.ftruncateSync(fd, len); 979 | } 980 | watch(p, a, b) { 981 | return this.realFs.watch( 982 | npath.fromPortablePath(p), 983 | a, 984 | b 985 | ); 986 | } 987 | watchFile(p, a, b) { 988 | return this.realFs.watchFile( 989 | npath.fromPortablePath(p), 990 | a, 991 | b 992 | ); 993 | } 994 | unwatchFile(p, cb) { 995 | return this.realFs.unwatchFile(npath.fromPortablePath(p), cb); 996 | } 997 | makeCallback(resolve, reject) { 998 | return (err, result) => { 999 | if (err) { 1000 | reject(err); 1001 | } else { 1002 | resolve(result); 1003 | } 1004 | }; 1005 | } 1006 | } 1007 | 1008 | class ProxiedFS extends FakeFS { 1009 | getExtractHint(hints) { 1010 | return this.baseFs.getExtractHint(hints); 1011 | } 1012 | resolve(path) { 1013 | return this.mapFromBase(this.baseFs.resolve(this.mapToBase(path))); 1014 | } 1015 | getRealPath() { 1016 | return this.mapFromBase(this.baseFs.getRealPath()); 1017 | } 1018 | async openPromise(p, flags, mode) { 1019 | return this.baseFs.openPromise(this.mapToBase(p), flags, mode); 1020 | } 1021 | openSync(p, flags, mode) { 1022 | return this.baseFs.openSync(this.mapToBase(p), flags, mode); 1023 | } 1024 | async opendirPromise(p, opts) { 1025 | return Object.assign(await this.baseFs.opendirPromise(this.mapToBase(p), opts), { path: p }); 1026 | } 1027 | opendirSync(p, opts) { 1028 | return Object.assign(this.baseFs.opendirSync(this.mapToBase(p), opts), { path: p }); 1029 | } 1030 | async readPromise(fd, buffer, offset, length, position) { 1031 | return await this.baseFs.readPromise(fd, buffer, offset, length, position); 1032 | } 1033 | readSync(fd, buffer, offset, length, position) { 1034 | return this.baseFs.readSync(fd, buffer, offset, length, position); 1035 | } 1036 | async writePromise(fd, buffer, offset, length, position) { 1037 | if (typeof buffer === `string`) { 1038 | return await this.baseFs.writePromise(fd, buffer, offset); 1039 | } else { 1040 | return await this.baseFs.writePromise(fd, buffer, offset, length, position); 1041 | } 1042 | } 1043 | writeSync(fd, buffer, offset, length, position) { 1044 | if (typeof buffer === `string`) { 1045 | return this.baseFs.writeSync(fd, buffer, offset); 1046 | } else { 1047 | return this.baseFs.writeSync(fd, buffer, offset, length, position); 1048 | } 1049 | } 1050 | async closePromise(fd) { 1051 | return this.baseFs.closePromise(fd); 1052 | } 1053 | closeSync(fd) { 1054 | this.baseFs.closeSync(fd); 1055 | } 1056 | createReadStream(p, opts) { 1057 | return this.baseFs.createReadStream(p !== null ? this.mapToBase(p) : p, opts); 1058 | } 1059 | createWriteStream(p, opts) { 1060 | return this.baseFs.createWriteStream(p !== null ? this.mapToBase(p) : p, opts); 1061 | } 1062 | async realpathPromise(p) { 1063 | return this.mapFromBase(await this.baseFs.realpathPromise(this.mapToBase(p))); 1064 | } 1065 | realpathSync(p) { 1066 | return this.mapFromBase(this.baseFs.realpathSync(this.mapToBase(p))); 1067 | } 1068 | async existsPromise(p) { 1069 | return this.baseFs.existsPromise(this.mapToBase(p)); 1070 | } 1071 | existsSync(p) { 1072 | return this.baseFs.existsSync(this.mapToBase(p)); 1073 | } 1074 | accessSync(p, mode) { 1075 | return this.baseFs.accessSync(this.mapToBase(p), mode); 1076 | } 1077 | async accessPromise(p, mode) { 1078 | return this.baseFs.accessPromise(this.mapToBase(p), mode); 1079 | } 1080 | async statPromise(p, opts) { 1081 | return this.baseFs.statPromise(this.mapToBase(p), opts); 1082 | } 1083 | statSync(p, opts) { 1084 | return this.baseFs.statSync(this.mapToBase(p), opts); 1085 | } 1086 | async fstatPromise(fd, opts) { 1087 | return this.baseFs.fstatPromise(fd, opts); 1088 | } 1089 | fstatSync(fd, opts) { 1090 | return this.baseFs.fstatSync(fd, opts); 1091 | } 1092 | lstatPromise(p, opts) { 1093 | return this.baseFs.lstatPromise(this.mapToBase(p), opts); 1094 | } 1095 | lstatSync(p, opts) { 1096 | return this.baseFs.lstatSync(this.mapToBase(p), opts); 1097 | } 1098 | async fchmodPromise(fd, mask) { 1099 | return this.baseFs.fchmodPromise(fd, mask); 1100 | } 1101 | fchmodSync(fd, mask) { 1102 | return this.baseFs.fchmodSync(fd, mask); 1103 | } 1104 | async chmodPromise(p, mask) { 1105 | return this.baseFs.chmodPromise(this.mapToBase(p), mask); 1106 | } 1107 | chmodSync(p, mask) { 1108 | return this.baseFs.chmodSync(this.mapToBase(p), mask); 1109 | } 1110 | async fchownPromise(fd, uid, gid) { 1111 | return this.baseFs.fchownPromise(fd, uid, gid); 1112 | } 1113 | fchownSync(fd, uid, gid) { 1114 | return this.baseFs.fchownSync(fd, uid, gid); 1115 | } 1116 | async chownPromise(p, uid, gid) { 1117 | return this.baseFs.chownPromise(this.mapToBase(p), uid, gid); 1118 | } 1119 | chownSync(p, uid, gid) { 1120 | return this.baseFs.chownSync(this.mapToBase(p), uid, gid); 1121 | } 1122 | async renamePromise(oldP, newP) { 1123 | return this.baseFs.renamePromise(this.mapToBase(oldP), this.mapToBase(newP)); 1124 | } 1125 | renameSync(oldP, newP) { 1126 | return this.baseFs.renameSync(this.mapToBase(oldP), this.mapToBase(newP)); 1127 | } 1128 | async copyFilePromise(sourceP, destP, flags = 0) { 1129 | return this.baseFs.copyFilePromise(this.mapToBase(sourceP), this.mapToBase(destP), flags); 1130 | } 1131 | copyFileSync(sourceP, destP, flags = 0) { 1132 | return this.baseFs.copyFileSync(this.mapToBase(sourceP), this.mapToBase(destP), flags); 1133 | } 1134 | async appendFilePromise(p, content, opts) { 1135 | return this.baseFs.appendFilePromise(this.fsMapToBase(p), content, opts); 1136 | } 1137 | appendFileSync(p, content, opts) { 1138 | return this.baseFs.appendFileSync(this.fsMapToBase(p), content, opts); 1139 | } 1140 | async writeFilePromise(p, content, opts) { 1141 | return this.baseFs.writeFilePromise(this.fsMapToBase(p), content, opts); 1142 | } 1143 | writeFileSync(p, content, opts) { 1144 | return this.baseFs.writeFileSync(this.fsMapToBase(p), content, opts); 1145 | } 1146 | async unlinkPromise(p) { 1147 | return this.baseFs.unlinkPromise(this.mapToBase(p)); 1148 | } 1149 | unlinkSync(p) { 1150 | return this.baseFs.unlinkSync(this.mapToBase(p)); 1151 | } 1152 | async utimesPromise(p, atime, mtime) { 1153 | return this.baseFs.utimesPromise(this.mapToBase(p), atime, mtime); 1154 | } 1155 | utimesSync(p, atime, mtime) { 1156 | return this.baseFs.utimesSync(this.mapToBase(p), atime, mtime); 1157 | } 1158 | async mkdirPromise(p, opts) { 1159 | return this.baseFs.mkdirPromise(this.mapToBase(p), opts); 1160 | } 1161 | mkdirSync(p, opts) { 1162 | return this.baseFs.mkdirSync(this.mapToBase(p), opts); 1163 | } 1164 | async rmdirPromise(p, opts) { 1165 | return this.baseFs.rmdirPromise(this.mapToBase(p), opts); 1166 | } 1167 | rmdirSync(p, opts) { 1168 | return this.baseFs.rmdirSync(this.mapToBase(p), opts); 1169 | } 1170 | async linkPromise(existingP, newP) { 1171 | return this.baseFs.linkPromise(this.mapToBase(existingP), this.mapToBase(newP)); 1172 | } 1173 | linkSync(existingP, newP) { 1174 | return this.baseFs.linkSync(this.mapToBase(existingP), this.mapToBase(newP)); 1175 | } 1176 | async symlinkPromise(target, p, type) { 1177 | const mappedP = this.mapToBase(p); 1178 | if (this.pathUtils.isAbsolute(target)) 1179 | return this.baseFs.symlinkPromise(this.mapToBase(target), mappedP, type); 1180 | const mappedAbsoluteTarget = this.mapToBase(this.pathUtils.join(this.pathUtils.dirname(p), target)); 1181 | const mappedTarget = this.baseFs.pathUtils.relative(this.baseFs.pathUtils.dirname(mappedP), mappedAbsoluteTarget); 1182 | return this.baseFs.symlinkPromise(mappedTarget, mappedP, type); 1183 | } 1184 | symlinkSync(target, p, type) { 1185 | const mappedP = this.mapToBase(p); 1186 | if (this.pathUtils.isAbsolute(target)) 1187 | return this.baseFs.symlinkSync(this.mapToBase(target), mappedP, type); 1188 | const mappedAbsoluteTarget = this.mapToBase(this.pathUtils.join(this.pathUtils.dirname(p), target)); 1189 | const mappedTarget = this.baseFs.pathUtils.relative(this.baseFs.pathUtils.dirname(mappedP), mappedAbsoluteTarget); 1190 | return this.baseFs.symlinkSync(mappedTarget, mappedP, type); 1191 | } 1192 | async readFilePromise(p, encoding) { 1193 | if (encoding === `utf8`) { 1194 | return this.baseFs.readFilePromise(this.fsMapToBase(p), encoding); 1195 | } else { 1196 | return this.baseFs.readFilePromise(this.fsMapToBase(p), encoding); 1197 | } 1198 | } 1199 | readFileSync(p, encoding) { 1200 | if (encoding === `utf8`) { 1201 | return this.baseFs.readFileSync(this.fsMapToBase(p), encoding); 1202 | } else { 1203 | return this.baseFs.readFileSync(this.fsMapToBase(p), encoding); 1204 | } 1205 | } 1206 | async readdirPromise(p, opts) { 1207 | return this.baseFs.readdirPromise(this.mapToBase(p), opts); 1208 | } 1209 | readdirSync(p, opts) { 1210 | return this.baseFs.readdirSync(this.mapToBase(p), opts); 1211 | } 1212 | async readlinkPromise(p) { 1213 | return this.mapFromBase(await this.baseFs.readlinkPromise(this.mapToBase(p))); 1214 | } 1215 | readlinkSync(p) { 1216 | return this.mapFromBase(this.baseFs.readlinkSync(this.mapToBase(p))); 1217 | } 1218 | async truncatePromise(p, len) { 1219 | return this.baseFs.truncatePromise(this.mapToBase(p), len); 1220 | } 1221 | truncateSync(p, len) { 1222 | return this.baseFs.truncateSync(this.mapToBase(p), len); 1223 | } 1224 | async ftruncatePromise(fd, len) { 1225 | return this.baseFs.ftruncatePromise(fd, len); 1226 | } 1227 | ftruncateSync(fd, len) { 1228 | return this.baseFs.ftruncateSync(fd, len); 1229 | } 1230 | watch(p, a, b) { 1231 | return this.baseFs.watch( 1232 | this.mapToBase(p), 1233 | a, 1234 | b 1235 | ); 1236 | } 1237 | watchFile(p, a, b) { 1238 | return this.baseFs.watchFile( 1239 | this.mapToBase(p), 1240 | a, 1241 | b 1242 | ); 1243 | } 1244 | unwatchFile(p, cb) { 1245 | return this.baseFs.unwatchFile(this.mapToBase(p), cb); 1246 | } 1247 | fsMapToBase(p) { 1248 | if (typeof p === `number`) { 1249 | return p; 1250 | } else { 1251 | return this.mapToBase(p); 1252 | } 1253 | } 1254 | } 1255 | 1256 | const NUMBER_REGEXP = /^[0-9]+$/; 1257 | const VIRTUAL_REGEXP = /^(\/(?:[^/]+\/)*?(?:\$\$virtual|__virtual__))((?:\/((?:[^/]+-)?[a-f0-9]+)(?:\/([^/]+))?)?((?:\/.*)?))$/; 1258 | const VALID_COMPONENT = /^([^/]+-)?[a-f0-9]+$/; 1259 | class VirtualFS extends ProxiedFS { 1260 | constructor({ baseFs = new NodeFS() } = {}) { 1261 | super(ppath); 1262 | this.baseFs = baseFs; 1263 | } 1264 | static makeVirtualPath(base, component, to) { 1265 | if (ppath.basename(base) !== `__virtual__`) 1266 | throw new Error(`Assertion failed: Virtual folders must be named "__virtual__"`); 1267 | if (!ppath.basename(component).match(VALID_COMPONENT)) 1268 | throw new Error(`Assertion failed: Virtual components must be ended by an hexadecimal hash`); 1269 | const target = ppath.relative(ppath.dirname(base), to); 1270 | const segments = target.split(`/`); 1271 | let depth = 0; 1272 | while (depth < segments.length && segments[depth] === `..`) 1273 | depth += 1; 1274 | const finalSegments = segments.slice(depth); 1275 | const fullVirtualPath = ppath.join(base, component, String(depth), ...finalSegments); 1276 | return fullVirtualPath; 1277 | } 1278 | static resolveVirtual(p) { 1279 | const match = p.match(VIRTUAL_REGEXP); 1280 | if (!match || !match[3] && match[5]) 1281 | return p; 1282 | const target = ppath.dirname(match[1]); 1283 | if (!match[3] || !match[4]) 1284 | return target; 1285 | const isnum = NUMBER_REGEXP.test(match[4]); 1286 | if (!isnum) 1287 | return p; 1288 | const depth = Number(match[4]); 1289 | const backstep = `../`.repeat(depth); 1290 | const subpath = match[5] || `.`; 1291 | return VirtualFS.resolveVirtual(ppath.join(target, backstep, subpath)); 1292 | } 1293 | getExtractHint(hints) { 1294 | return this.baseFs.getExtractHint(hints); 1295 | } 1296 | getRealPath() { 1297 | return this.baseFs.getRealPath(); 1298 | } 1299 | realpathSync(p) { 1300 | const match = p.match(VIRTUAL_REGEXP); 1301 | if (!match) 1302 | return this.baseFs.realpathSync(p); 1303 | if (!match[5]) 1304 | return p; 1305 | const realpath = this.baseFs.realpathSync(this.mapToBase(p)); 1306 | return VirtualFS.makeVirtualPath(match[1], match[3], realpath); 1307 | } 1308 | async realpathPromise(p) { 1309 | const match = p.match(VIRTUAL_REGEXP); 1310 | if (!match) 1311 | return await this.baseFs.realpathPromise(p); 1312 | if (!match[5]) 1313 | return p; 1314 | const realpath = await this.baseFs.realpathPromise(this.mapToBase(p)); 1315 | return VirtualFS.makeVirtualPath(match[1], match[3], realpath); 1316 | } 1317 | mapToBase(p) { 1318 | if (p === ``) 1319 | return p; 1320 | if (this.pathUtils.isAbsolute(p)) 1321 | return VirtualFS.resolveVirtual(p); 1322 | const resolvedRoot = VirtualFS.resolveVirtual(this.baseFs.resolve(PortablePath.dot)); 1323 | const resolvedP = VirtualFS.resolveVirtual(this.baseFs.resolve(p)); 1324 | return ppath.relative(resolvedRoot, resolvedP) || PortablePath.dot; 1325 | } 1326 | mapFromBase(p) { 1327 | return p; 1328 | } 1329 | } 1330 | 1331 | const [major, minor] = process.versions.node.split(`.`).map((value) => parseInt(value, 10)); 1332 | const HAS_CONSOLIDATED_HOOKS = major > 16 || major === 16 && minor >= 12; 1333 | const HAS_UNFLAGGED_JSON_MODULES = major > 17 || major === 17 && minor >= 5 || major === 16 && minor >= 15; 1334 | const HAS_JSON_IMPORT_ASSERTION_REQUIREMENT = major > 17 || major === 17 && minor >= 1 || major === 16 && minor > 14; 1335 | const WATCH_MODE_MESSAGE_USES_ARRAYS = major > 19 || major === 19 && minor >= 2 || major === 18 && minor >= 13; 1336 | const HAS_LAZY_LOADED_TRANSLATORS = major > 19 || major === 19 && minor >= 3; 1337 | 1338 | const builtinModules = new Set(Module.builtinModules || Object.keys(process.binding(`natives`))); 1339 | const isBuiltinModule = (request) => request.startsWith(`node:`) || builtinModules.has(request); 1340 | function readPackageScope(checkPath) { 1341 | const rootSeparatorIndex = checkPath.indexOf(npath.sep); 1342 | let separatorIndex; 1343 | do { 1344 | separatorIndex = checkPath.lastIndexOf(npath.sep); 1345 | checkPath = checkPath.slice(0, separatorIndex); 1346 | if (checkPath.endsWith(`${npath.sep}node_modules`)) 1347 | return false; 1348 | const pjson = readPackage(checkPath + npath.sep); 1349 | if (pjson) { 1350 | return { 1351 | data: pjson, 1352 | path: checkPath 1353 | }; 1354 | } 1355 | } while (separatorIndex > rootSeparatorIndex); 1356 | return false; 1357 | } 1358 | function readPackage(requestPath) { 1359 | const jsonPath = npath.resolve(requestPath, `package.json`); 1360 | if (!fs.existsSync(jsonPath)) 1361 | return null; 1362 | return JSON.parse(fs.readFileSync(jsonPath, `utf8`)); 1363 | } 1364 | 1365 | async function tryReadFile$1(path2) { 1366 | try { 1367 | return await fs.promises.readFile(path2, `utf8`); 1368 | } catch (error) { 1369 | if (error.code === `ENOENT`) 1370 | return null; 1371 | throw error; 1372 | } 1373 | } 1374 | function tryParseURL(str, base) { 1375 | try { 1376 | return new URL$1(str, base); 1377 | } catch { 1378 | return null; 1379 | } 1380 | } 1381 | let entrypointPath = null; 1382 | function setEntrypointPath(file) { 1383 | entrypointPath = file; 1384 | } 1385 | function getFileFormat(filepath) { 1386 | var _a, _b; 1387 | const ext = path.extname(filepath); 1388 | switch (ext) { 1389 | case `.mjs`: { 1390 | return `module`; 1391 | } 1392 | case `.cjs`: { 1393 | return `commonjs`; 1394 | } 1395 | case `.wasm`: { 1396 | throw new Error( 1397 | `Unknown file extension ".wasm" for ${filepath}` 1398 | ); 1399 | } 1400 | case `.json`: { 1401 | if (HAS_UNFLAGGED_JSON_MODULES) 1402 | return `json`; 1403 | throw new Error( 1404 | `Unknown file extension ".json" for ${filepath}` 1405 | ); 1406 | } 1407 | case `.js`: { 1408 | const pkg = readPackageScope(filepath); 1409 | if (!pkg) 1410 | return `commonjs`; 1411 | return (_a = pkg.data.type) != null ? _a : `commonjs`; 1412 | } 1413 | default: { 1414 | if (entrypointPath !== filepath) 1415 | return null; 1416 | const pkg = readPackageScope(filepath); 1417 | if (!pkg) 1418 | return `commonjs`; 1419 | if (pkg.data.type === `module`) 1420 | return null; 1421 | return (_b = pkg.data.type) != null ? _b : `commonjs`; 1422 | } 1423 | } 1424 | } 1425 | 1426 | async function getFormat$1(resolved, context, defaultGetFormat) { 1427 | const url = tryParseURL(resolved); 1428 | if ((url == null ? void 0 : url.protocol) !== `file:`) 1429 | return defaultGetFormat(resolved, context, defaultGetFormat); 1430 | const format = getFileFormat(fileURLToPath(url)); 1431 | if (format) { 1432 | return { 1433 | format 1434 | }; 1435 | } 1436 | return defaultGetFormat(resolved, context, defaultGetFormat); 1437 | } 1438 | 1439 | async function getSource$1(urlString, context, defaultGetSource) { 1440 | const url = tryParseURL(urlString); 1441 | if ((url == null ? void 0 : url.protocol) !== `file:`) 1442 | return defaultGetSource(urlString, context, defaultGetSource); 1443 | return { 1444 | source: await fs.promises.readFile(fileURLToPath(url), `utf8`) 1445 | }; 1446 | } 1447 | 1448 | async function load$1(urlString, context, nextLoad) { 1449 | var _a; 1450 | const url = tryParseURL(urlString); 1451 | if ((url == null ? void 0 : url.protocol) !== `file:`) 1452 | return nextLoad(urlString, context, nextLoad); 1453 | const filePath = fileURLToPath(url); 1454 | const format = getFileFormat(filePath); 1455 | if (!format) 1456 | return nextLoad(urlString, context, nextLoad); 1457 | if (HAS_JSON_IMPORT_ASSERTION_REQUIREMENT && format === `json` && ((_a = context.importAssertions) == null ? void 0 : _a.type) !== `json`) { 1458 | const err = new TypeError(`[ERR_IMPORT_ASSERTION_TYPE_MISSING]: Module "${urlString}" needs an import assertion of type "json"`); 1459 | err.code = `ERR_IMPORT_ASSERTION_TYPE_MISSING`; 1460 | throw err; 1461 | } 1462 | if (process.env.WATCH_REPORT_DEPENDENCIES && process.send) { 1463 | const pathToSend = pathToFileURL( 1464 | npath.fromPortablePath( 1465 | VirtualFS.resolveVirtual(npath.toPortablePath(filePath)) 1466 | ) 1467 | ).href; 1468 | process.send({ 1469 | "watch:import": WATCH_MODE_MESSAGE_USES_ARRAYS ? [pathToSend] : pathToSend 1470 | }); 1471 | } 1472 | return { 1473 | format, 1474 | source: await fs.promises.readFile(filePath, `utf8`), 1475 | shortCircuit: true 1476 | }; 1477 | } 1478 | 1479 | const ArrayIsArray = Array.isArray; 1480 | const JSONStringify = JSON.stringify; 1481 | const ObjectGetOwnPropertyNames = Object.getOwnPropertyNames; 1482 | const ObjectPrototypeHasOwnProperty = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop); 1483 | const RegExpPrototypeExec = (obj, string) => RegExp.prototype.exec.call(obj, string); 1484 | const RegExpPrototypeSymbolReplace = (obj, ...rest) => RegExp.prototype[Symbol.replace].apply(obj, rest); 1485 | const StringPrototypeEndsWith = (str, ...rest) => String.prototype.endsWith.apply(str, rest); 1486 | const StringPrototypeIncludes = (str, ...rest) => String.prototype.includes.apply(str, rest); 1487 | const StringPrototypeLastIndexOf = (str, ...rest) => String.prototype.lastIndexOf.apply(str, rest); 1488 | const StringPrototypeIndexOf = (str, ...rest) => String.prototype.indexOf.apply(str, rest); 1489 | const StringPrototypeReplace = (str, ...rest) => String.prototype.replace.apply(str, rest); 1490 | const StringPrototypeSlice = (str, ...rest) => String.prototype.slice.apply(str, rest); 1491 | const StringPrototypeStartsWith = (str, ...rest) => String.prototype.startsWith.apply(str, rest); 1492 | const SafeMap = Map; 1493 | const JSONParse = JSON.parse; 1494 | 1495 | function createErrorType(code, messageCreator, errorType) { 1496 | return class extends errorType { 1497 | constructor(...args) { 1498 | super(messageCreator(...args)); 1499 | this.code = code; 1500 | this.name = `${errorType.name} [${code}]`; 1501 | } 1502 | }; 1503 | } 1504 | const ERR_PACKAGE_IMPORT_NOT_DEFINED = createErrorType( 1505 | `ERR_PACKAGE_IMPORT_NOT_DEFINED`, 1506 | (specifier, packagePath, base) => { 1507 | return `Package import specifier "${specifier}" is not defined${packagePath ? ` in package ${packagePath}package.json` : ``} imported from ${base}`; 1508 | }, 1509 | TypeError 1510 | ); 1511 | const ERR_INVALID_MODULE_SPECIFIER = createErrorType( 1512 | `ERR_INVALID_MODULE_SPECIFIER`, 1513 | (request, reason, base = void 0) => { 1514 | return `Invalid module "${request}" ${reason}${base ? ` imported from ${base}` : ``}`; 1515 | }, 1516 | TypeError 1517 | ); 1518 | const ERR_INVALID_PACKAGE_TARGET = createErrorType( 1519 | `ERR_INVALID_PACKAGE_TARGET`, 1520 | (pkgPath, key, target, isImport = false, base = void 0) => { 1521 | const relError = typeof target === `string` && !isImport && target.length && !StringPrototypeStartsWith(target, `./`); 1522 | if (key === `.`) { 1523 | assert(isImport === false); 1524 | return `Invalid "exports" main target ${JSONStringify(target)} defined in the package config ${pkgPath}package.json${base ? ` imported from ${base}` : ``}${relError ? `; targets must start with "./"` : ``}`; 1525 | } 1526 | return `Invalid "${isImport ? `imports` : `exports`}" target ${JSONStringify( 1527 | target 1528 | )} defined for '${key}' in the package config ${pkgPath}package.json${base ? ` imported from ${base}` : ``}${relError ? `; targets must start with "./"` : ``}`; 1529 | }, 1530 | Error 1531 | ); 1532 | const ERR_INVALID_PACKAGE_CONFIG = createErrorType( 1533 | `ERR_INVALID_PACKAGE_CONFIG`, 1534 | (path, base, message) => { 1535 | return `Invalid package config ${path}${base ? ` while importing ${base}` : ``}${message ? `. ${message}` : ``}`; 1536 | }, 1537 | Error 1538 | ); 1539 | 1540 | function filterOwnProperties(source, keys) { 1541 | const filtered = /* @__PURE__ */ Object.create(null); 1542 | for (let i = 0; i < keys.length; i++) { 1543 | const key = keys[i]; 1544 | if (ObjectPrototypeHasOwnProperty(source, key)) { 1545 | filtered[key] = source[key]; 1546 | } 1547 | } 1548 | return filtered; 1549 | } 1550 | 1551 | const packageJSONCache = new SafeMap(); 1552 | function getPackageConfig(path, specifier, base, readFileSyncFn) { 1553 | const existing = packageJSONCache.get(path); 1554 | if (existing !== void 0) { 1555 | return existing; 1556 | } 1557 | const source = readFileSyncFn(path); 1558 | if (source === void 0) { 1559 | const packageConfig2 = { 1560 | pjsonPath: path, 1561 | exists: false, 1562 | main: void 0, 1563 | name: void 0, 1564 | type: "none", 1565 | exports: void 0, 1566 | imports: void 0 1567 | }; 1568 | packageJSONCache.set(path, packageConfig2); 1569 | return packageConfig2; 1570 | } 1571 | let packageJSON; 1572 | try { 1573 | packageJSON = JSONParse(source); 1574 | } catch (error) { 1575 | throw new ERR_INVALID_PACKAGE_CONFIG( 1576 | path, 1577 | (base ? `"${specifier}" from ` : "") + fileURLToPath(base || specifier), 1578 | error.message 1579 | ); 1580 | } 1581 | let { imports, main, name, type } = filterOwnProperties(packageJSON, [ 1582 | "imports", 1583 | "main", 1584 | "name", 1585 | "type" 1586 | ]); 1587 | const exports = ObjectPrototypeHasOwnProperty(packageJSON, "exports") ? packageJSON.exports : void 0; 1588 | if (typeof imports !== "object" || imports === null) { 1589 | imports = void 0; 1590 | } 1591 | if (typeof main !== "string") { 1592 | main = void 0; 1593 | } 1594 | if (typeof name !== "string") { 1595 | name = void 0; 1596 | } 1597 | if (type !== "module" && type !== "commonjs") { 1598 | type = "none"; 1599 | } 1600 | const packageConfig = { 1601 | pjsonPath: path, 1602 | exists: true, 1603 | main, 1604 | name, 1605 | type, 1606 | exports, 1607 | imports 1608 | }; 1609 | packageJSONCache.set(path, packageConfig); 1610 | return packageConfig; 1611 | } 1612 | function getPackageScopeConfig(resolved, readFileSyncFn) { 1613 | let packageJSONUrl = new URL("./package.json", resolved); 1614 | while (true) { 1615 | const packageJSONPath2 = packageJSONUrl.pathname; 1616 | if (StringPrototypeEndsWith(packageJSONPath2, "node_modules/package.json")) { 1617 | break; 1618 | } 1619 | const packageConfig2 = getPackageConfig( 1620 | fileURLToPath(packageJSONUrl), 1621 | resolved, 1622 | void 0, 1623 | readFileSyncFn 1624 | ); 1625 | if (packageConfig2.exists) { 1626 | return packageConfig2; 1627 | } 1628 | const lastPackageJSONUrl = packageJSONUrl; 1629 | packageJSONUrl = new URL("../package.json", packageJSONUrl); 1630 | if (packageJSONUrl.pathname === lastPackageJSONUrl.pathname) { 1631 | break; 1632 | } 1633 | } 1634 | const packageJSONPath = fileURLToPath(packageJSONUrl); 1635 | const packageConfig = { 1636 | pjsonPath: packageJSONPath, 1637 | exists: false, 1638 | main: void 0, 1639 | name: void 0, 1640 | type: "none", 1641 | exports: void 0, 1642 | imports: void 0 1643 | }; 1644 | packageJSONCache.set(packageJSONPath, packageConfig); 1645 | return packageConfig; 1646 | } 1647 | 1648 | /** 1649 | @license 1650 | Copyright Node.js contributors. All rights reserved. 1651 | 1652 | Permission is hereby granted, free of charge, to any person obtaining a copy 1653 | of this software and associated documentation files (the "Software"), to 1654 | deal in the Software without restriction, including without limitation the 1655 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 1656 | sell copies of the Software, and to permit persons to whom the Software is 1657 | furnished to do so, subject to the following conditions: 1658 | 1659 | The above copyright notice and this permission notice shall be included in 1660 | all copies or substantial portions of the Software. 1661 | 1662 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1663 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1664 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1665 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1666 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 1667 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 1668 | IN THE SOFTWARE. 1669 | */ 1670 | function throwImportNotDefined(specifier, packageJSONUrl, base) { 1671 | throw new ERR_PACKAGE_IMPORT_NOT_DEFINED( 1672 | specifier, 1673 | packageJSONUrl && fileURLToPath(new URL(".", packageJSONUrl)), 1674 | fileURLToPath(base) 1675 | ); 1676 | } 1677 | function throwInvalidSubpath(subpath, packageJSONUrl, internal, base) { 1678 | const reason = `request is not a valid subpath for the "${internal ? "imports" : "exports"}" resolution of ${fileURLToPath(packageJSONUrl)}`; 1679 | throw new ERR_INVALID_MODULE_SPECIFIER( 1680 | subpath, 1681 | reason, 1682 | base && fileURLToPath(base) 1683 | ); 1684 | } 1685 | function throwInvalidPackageTarget(subpath, target, packageJSONUrl, internal, base) { 1686 | if (typeof target === "object" && target !== null) { 1687 | target = JSONStringify(target, null, ""); 1688 | } else { 1689 | target = `${target}`; 1690 | } 1691 | throw new ERR_INVALID_PACKAGE_TARGET( 1692 | fileURLToPath(new URL(".", packageJSONUrl)), 1693 | subpath, 1694 | target, 1695 | internal, 1696 | base && fileURLToPath(base) 1697 | ); 1698 | } 1699 | const invalidSegmentRegEx = /(^|\\|\/)((\.|%2e)(\.|%2e)?|(n|%6e|%4e)(o|%6f|%4f)(d|%64|%44)(e|%65|%45)(_|%5f)(m|%6d|%4d)(o|%6f|%4f)(d|%64|%44)(u|%75|%55)(l|%6c|%4c)(e|%65|%45)(s|%73|%53))(\\|\/|$)/i; 1700 | const patternRegEx = /\*/g; 1701 | function resolvePackageTargetString(target, subpath, match, packageJSONUrl, base, pattern, internal, conditions) { 1702 | if (subpath !== "" && !pattern && target[target.length - 1] !== "/") 1703 | throwInvalidPackageTarget(match, target, packageJSONUrl, internal, base); 1704 | if (!StringPrototypeStartsWith(target, "./")) { 1705 | if (internal && !StringPrototypeStartsWith(target, "../") && !StringPrototypeStartsWith(target, "/")) { 1706 | let isURL = false; 1707 | try { 1708 | new URL(target); 1709 | isURL = true; 1710 | } catch { 1711 | } 1712 | if (!isURL) { 1713 | const exportTarget = pattern ? RegExpPrototypeSymbolReplace(patternRegEx, target, () => subpath) : target + subpath; 1714 | return exportTarget; 1715 | } 1716 | } 1717 | throwInvalidPackageTarget(match, target, packageJSONUrl, internal, base); 1718 | } 1719 | if (RegExpPrototypeExec( 1720 | invalidSegmentRegEx, 1721 | StringPrototypeSlice(target, 2) 1722 | ) !== null) 1723 | throwInvalidPackageTarget(match, target, packageJSONUrl, internal, base); 1724 | const resolved = new URL(target, packageJSONUrl); 1725 | const resolvedPath = resolved.pathname; 1726 | const packagePath = new URL(".", packageJSONUrl).pathname; 1727 | if (!StringPrototypeStartsWith(resolvedPath, packagePath)) 1728 | throwInvalidPackageTarget(match, target, packageJSONUrl, internal, base); 1729 | if (subpath === "") 1730 | return resolved; 1731 | if (RegExpPrototypeExec(invalidSegmentRegEx, subpath) !== null) { 1732 | const request = pattern ? StringPrototypeReplace(match, "*", () => subpath) : match + subpath; 1733 | throwInvalidSubpath(request, packageJSONUrl, internal, base); 1734 | } 1735 | if (pattern) { 1736 | return new URL( 1737 | RegExpPrototypeSymbolReplace(patternRegEx, resolved.href, () => subpath) 1738 | ); 1739 | } 1740 | return new URL(subpath, resolved); 1741 | } 1742 | function isArrayIndex(key) { 1743 | const keyNum = +key; 1744 | if (`${keyNum}` !== key) 1745 | return false; 1746 | return keyNum >= 0 && keyNum < 4294967295; 1747 | } 1748 | function resolvePackageTarget(packageJSONUrl, target, subpath, packageSubpath, base, pattern, internal, conditions) { 1749 | if (typeof target === "string") { 1750 | return resolvePackageTargetString( 1751 | target, 1752 | subpath, 1753 | packageSubpath, 1754 | packageJSONUrl, 1755 | base, 1756 | pattern, 1757 | internal); 1758 | } else if (ArrayIsArray(target)) { 1759 | if (target.length === 0) { 1760 | return null; 1761 | } 1762 | let lastException; 1763 | for (let i = 0; i < target.length; i++) { 1764 | const targetItem = target[i]; 1765 | let resolveResult; 1766 | try { 1767 | resolveResult = resolvePackageTarget( 1768 | packageJSONUrl, 1769 | targetItem, 1770 | subpath, 1771 | packageSubpath, 1772 | base, 1773 | pattern, 1774 | internal, 1775 | conditions 1776 | ); 1777 | } catch (e) { 1778 | lastException = e; 1779 | if (e.code === "ERR_INVALID_PACKAGE_TARGET") { 1780 | continue; 1781 | } 1782 | throw e; 1783 | } 1784 | if (resolveResult === void 0) { 1785 | continue; 1786 | } 1787 | if (resolveResult === null) { 1788 | lastException = null; 1789 | continue; 1790 | } 1791 | return resolveResult; 1792 | } 1793 | if (lastException === void 0 || lastException === null) 1794 | return lastException; 1795 | throw lastException; 1796 | } else if (typeof target === "object" && target !== null) { 1797 | const keys = ObjectGetOwnPropertyNames(target); 1798 | for (let i = 0; i < keys.length; i++) { 1799 | const key = keys[i]; 1800 | if (isArrayIndex(key)) { 1801 | throw new ERR_INVALID_PACKAGE_CONFIG( 1802 | fileURLToPath(packageJSONUrl), 1803 | base, 1804 | '"exports" cannot contain numeric property keys.' 1805 | ); 1806 | } 1807 | } 1808 | for (let i = 0; i < keys.length; i++) { 1809 | const key = keys[i]; 1810 | if (key === "default" || conditions.has(key)) { 1811 | const conditionalTarget = target[key]; 1812 | const resolveResult = resolvePackageTarget( 1813 | packageJSONUrl, 1814 | conditionalTarget, 1815 | subpath, 1816 | packageSubpath, 1817 | base, 1818 | pattern, 1819 | internal, 1820 | conditions 1821 | ); 1822 | if (resolveResult === void 0) 1823 | continue; 1824 | return resolveResult; 1825 | } 1826 | } 1827 | return void 0; 1828 | } else if (target === null) { 1829 | return null; 1830 | } 1831 | throwInvalidPackageTarget( 1832 | packageSubpath, 1833 | target, 1834 | packageJSONUrl, 1835 | internal, 1836 | base 1837 | ); 1838 | } 1839 | function patternKeyCompare(a, b) { 1840 | const aPatternIndex = StringPrototypeIndexOf(a, "*"); 1841 | const bPatternIndex = StringPrototypeIndexOf(b, "*"); 1842 | const baseLenA = aPatternIndex === -1 ? a.length : aPatternIndex + 1; 1843 | const baseLenB = bPatternIndex === -1 ? b.length : bPatternIndex + 1; 1844 | if (baseLenA > baseLenB) 1845 | return -1; 1846 | if (baseLenB > baseLenA) 1847 | return 1; 1848 | if (aPatternIndex === -1) 1849 | return 1; 1850 | if (bPatternIndex === -1) 1851 | return -1; 1852 | if (a.length > b.length) 1853 | return -1; 1854 | if (b.length > a.length) 1855 | return 1; 1856 | return 0; 1857 | } 1858 | function packageImportsResolve({ name, base, conditions, readFileSyncFn }) { 1859 | if (name === "#" || StringPrototypeStartsWith(name, "#/") || StringPrototypeEndsWith(name, "/")) { 1860 | const reason = "is not a valid internal imports specifier name"; 1861 | throw new ERR_INVALID_MODULE_SPECIFIER(name, reason, fileURLToPath(base)); 1862 | } 1863 | let packageJSONUrl; 1864 | const packageConfig = getPackageScopeConfig(base, readFileSyncFn); 1865 | if (packageConfig.exists) { 1866 | packageJSONUrl = pathToFileURL(packageConfig.pjsonPath); 1867 | const imports = packageConfig.imports; 1868 | if (imports) { 1869 | if (ObjectPrototypeHasOwnProperty(imports, name) && !StringPrototypeIncludes(name, "*")) { 1870 | const resolveResult = resolvePackageTarget( 1871 | packageJSONUrl, 1872 | imports[name], 1873 | "", 1874 | name, 1875 | base, 1876 | false, 1877 | true, 1878 | conditions 1879 | ); 1880 | if (resolveResult != null) { 1881 | return resolveResult; 1882 | } 1883 | } else { 1884 | let bestMatch = ""; 1885 | let bestMatchSubpath; 1886 | const keys = ObjectGetOwnPropertyNames(imports); 1887 | for (let i = 0; i < keys.length; i++) { 1888 | const key = keys[i]; 1889 | const patternIndex = StringPrototypeIndexOf(key, "*"); 1890 | if (patternIndex !== -1 && StringPrototypeStartsWith( 1891 | name, 1892 | StringPrototypeSlice(key, 0, patternIndex) 1893 | )) { 1894 | const patternTrailer = StringPrototypeSlice(key, patternIndex + 1); 1895 | if (name.length >= key.length && StringPrototypeEndsWith(name, patternTrailer) && patternKeyCompare(bestMatch, key) === 1 && StringPrototypeLastIndexOf(key, "*") === patternIndex) { 1896 | bestMatch = key; 1897 | bestMatchSubpath = StringPrototypeSlice( 1898 | name, 1899 | patternIndex, 1900 | name.length - patternTrailer.length 1901 | ); 1902 | } 1903 | } 1904 | } 1905 | if (bestMatch) { 1906 | const target = imports[bestMatch]; 1907 | const resolveResult = resolvePackageTarget( 1908 | packageJSONUrl, 1909 | target, 1910 | bestMatchSubpath, 1911 | bestMatch, 1912 | base, 1913 | true, 1914 | true, 1915 | conditions 1916 | ); 1917 | if (resolveResult != null) { 1918 | return resolveResult; 1919 | } 1920 | } 1921 | } 1922 | } 1923 | } 1924 | throwImportNotDefined(name, packageJSONUrl, base); 1925 | } 1926 | 1927 | const pathRegExp = /^(?![a-zA-Z]:[\\/]|\\\\|\.{0,2}(?:\/|$))((?:node:)?(?:@[^/]+\/)?[^/]+)\/*(.*|)$/; 1928 | const isRelativeRegexp = /^\.{0,2}\//; 1929 | function tryReadFile(filePath) { 1930 | try { 1931 | return fs.readFileSync(filePath, `utf8`); 1932 | } catch (err) { 1933 | if (err.code === `ENOENT`) 1934 | return void 0; 1935 | throw err; 1936 | } 1937 | } 1938 | async function resolvePrivateRequest(specifier, issuer, context, nextResolve) { 1939 | const resolved = packageImportsResolve({ 1940 | name: specifier, 1941 | base: pathToFileURL(issuer), 1942 | conditions: new Set(context.conditions), 1943 | readFileSyncFn: tryReadFile 1944 | }); 1945 | if (resolved instanceof URL$1) { 1946 | return { url: resolved.href, shortCircuit: true }; 1947 | } else { 1948 | if (resolved.startsWith(`#`)) 1949 | throw new Error(`Mapping from one private import to another isn't allowed`); 1950 | return resolve$1(resolved, context, nextResolve); 1951 | } 1952 | } 1953 | async function resolve$1(originalSpecifier, context, nextResolve) { 1954 | var _a, _b; 1955 | const { findPnpApi } = moduleExports; 1956 | if (!findPnpApi || isBuiltinModule(originalSpecifier)) 1957 | return nextResolve(originalSpecifier, context, nextResolve); 1958 | let specifier = originalSpecifier; 1959 | const url = tryParseURL(specifier, isRelativeRegexp.test(specifier) ? context.parentURL : void 0); 1960 | if (url) { 1961 | if (url.protocol !== `file:`) 1962 | return nextResolve(originalSpecifier, context, nextResolve); 1963 | specifier = fileURLToPath(url); 1964 | } 1965 | const { parentURL, conditions = [] } = context; 1966 | const issuer = parentURL && ((_a = tryParseURL(parentURL)) == null ? void 0 : _a.protocol) === `file:` ? fileURLToPath(parentURL) : process.cwd(); 1967 | const pnpapi = (_b = findPnpApi(issuer)) != null ? _b : url ? findPnpApi(specifier) : null; 1968 | if (!pnpapi) 1969 | return nextResolve(originalSpecifier, context, nextResolve); 1970 | if (specifier.startsWith(`#`)) 1971 | return resolvePrivateRequest(specifier, issuer, context, nextResolve); 1972 | const dependencyNameMatch = specifier.match(pathRegExp); 1973 | let allowLegacyResolve = false; 1974 | if (dependencyNameMatch) { 1975 | const [, dependencyName, subPath] = dependencyNameMatch; 1976 | if (subPath === `` && dependencyName !== `pnpapi`) { 1977 | const resolved = pnpapi.resolveToUnqualified(`${dependencyName}/package.json`, issuer); 1978 | if (resolved) { 1979 | const content = await tryReadFile$1(resolved); 1980 | if (content) { 1981 | const pkg = JSON.parse(content); 1982 | allowLegacyResolve = pkg.exports == null; 1983 | } 1984 | } 1985 | } 1986 | } 1987 | let result; 1988 | try { 1989 | result = pnpapi.resolveRequest(specifier, issuer, { 1990 | conditions: new Set(conditions), 1991 | extensions: allowLegacyResolve ? void 0 : [] 1992 | }); 1993 | } catch (err) { 1994 | if (err instanceof Error && `code` in err && err.code === `MODULE_NOT_FOUND`) 1995 | err.code = `ERR_MODULE_NOT_FOUND`; 1996 | throw err; 1997 | } 1998 | if (!result) 1999 | throw new Error(`Resolving '${specifier}' from '${issuer}' failed`); 2000 | const resultURL = pathToFileURL(result); 2001 | if (url) { 2002 | resultURL.search = url.search; 2003 | resultURL.hash = url.hash; 2004 | } 2005 | if (!parentURL) 2006 | setEntrypointPath(fileURLToPath(resultURL)); 2007 | return { 2008 | url: resultURL.href, 2009 | shortCircuit: true 2010 | }; 2011 | } 2012 | 2013 | if (!HAS_LAZY_LOADED_TRANSLATORS) { 2014 | const binding = process.binding(`fs`); 2015 | const originalfstat = binding.fstat; 2016 | const ZIP_MASK = 4278190080; 2017 | const ZIP_MAGIC = 704643072; 2018 | binding.fstat = function(...args) { 2019 | const [fd, useBigint, req] = args; 2020 | if ((fd & ZIP_MASK) === ZIP_MAGIC && useBigint === false && req === void 0) { 2021 | try { 2022 | const stats = fs.fstatSync(fd); 2023 | return new Float64Array([ 2024 | stats.dev, 2025 | stats.mode, 2026 | stats.nlink, 2027 | stats.uid, 2028 | stats.gid, 2029 | stats.rdev, 2030 | stats.blksize, 2031 | stats.ino, 2032 | stats.size, 2033 | stats.blocks 2034 | ]); 2035 | } catch { 2036 | } 2037 | } 2038 | return originalfstat.apply(this, args); 2039 | }; 2040 | } 2041 | 2042 | const resolve = resolve$1; 2043 | const getFormat = HAS_CONSOLIDATED_HOOKS ? void 0 : getFormat$1; 2044 | const getSource = HAS_CONSOLIDATED_HOOKS ? void 0 : getSource$1; 2045 | const load = HAS_CONSOLIDATED_HOOKS ? load$1 : void 0; 2046 | 2047 | export { getFormat, getSource, load, resolve }; 2048 | --------------------------------------------------------------------------------