├── backend
├── ListenApiDemo
│ ├── __init__.py
│ ├── wsgi.py
│ ├── urls.py
│ ├── views.py
│ └── settings.py
├── .flake8
├── requirements.txt
└── manage.py
├── resources
├── desktop.png
└── mobile.png
├── web
├── src
│ ├── powered_by_listennotes.png
│ ├── main.jsx
│ ├── App.less
│ └── App.jsx
├── vite.config.js
├── .gitignore
├── index.html
├── package.json
├── eslint.config.js
├── public
│ └── vite.svg
└── .pnp.loader.mjs
├── .gitignore
├── .github
└── workflows
│ └── demo-ci.yml
├── README.md
└── LICENSE
/backend/ListenApiDemo/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/backend/.flake8:
--------------------------------------------------------------------------------
1 | [flake8]
2 | max-line-length = 120
3 |
--------------------------------------------------------------------------------
/resources/desktop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ListenNotes/ListenApiDemo/HEAD/resources/desktop.png
--------------------------------------------------------------------------------
/resources/mobile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ListenNotes/ListenApiDemo/HEAD/resources/mobile.png
--------------------------------------------------------------------------------
/web/src/powered_by_listennotes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ListenNotes/ListenApiDemo/HEAD/web/src/powered_by_listennotes.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # Mashape secret
7 | secrets.py
8 |
9 | .venv/
10 | .idea
--------------------------------------------------------------------------------
/web/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 |
4 | // https://vite.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------
/web/src/main.jsx:
--------------------------------------------------------------------------------
1 | import { StrictMode } from 'react'
2 | import { createRoot } from 'react-dom/client'
3 | import App from './App.jsx'
4 |
5 | createRoot(document.getElementById('root')).render(
6 |
7 |
8 | ,
9 | )
10 |
--------------------------------------------------------------------------------
/backend/requirements.txt:
--------------------------------------------------------------------------------
1 | asgiref==3.8.1
2 | certifi==2025.1.31
3 | chardet==5.2.0
4 | charset-normalizer==3.4.1
5 | Django==5.1.7
6 | django-cors-headers==4.7.0
7 | flake8==7.1.2
8 | idna==3.10
9 | mccabe==0.7.0
10 | podcast-api==1.1.6
11 | pycodestyle==2.12.1
12 | pyflakes==3.2.0
13 | pytz==2025.1
14 | requests==2.32.3
15 | sqlparse==0.5.3
16 | urllib3==2.3.0
17 |
--------------------------------------------------------------------------------
/web/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | .yarn/
11 | node_modules
12 | dist
13 | dist-ssr
14 | *.local
15 |
16 | # Editor directories and files
17 | .vscode/*
18 | !.vscode/extensions.json
19 | .idea
20 | .DS_Store
21 | *.suo
22 | *.ntvs*
23 | *.njsproj
24 | *.sln
25 | *.sw?
26 |
--------------------------------------------------------------------------------
/web/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/backend/ListenApiDemo/wsgi.py:
--------------------------------------------------------------------------------
1 | """
2 | WSGI config for ListenApiDemo project.
3 |
4 | It exposes the WSGI callable as a module-level variable named ``application``.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/2.1/howto/deployment/wsgi/
8 | """
9 |
10 | import os
11 |
12 | from django.core.wsgi import get_wsgi_application
13 |
14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ListenApiDemo.settings')
15 |
16 | application = get_wsgi_application()
17 |
--------------------------------------------------------------------------------
/backend/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import os
3 | import sys
4 |
5 | if __name__ == '__main__':
6 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ListenApiDemo.settings')
7 | try:
8 | from django.core.management import execute_from_command_line
9 | except ImportError as exc:
10 | raise ImportError(
11 | "Couldn't import Django. Are you sure it's installed and "
12 | "available on your PYTHONPATH environment variable? Did you "
13 | "forget to activate a virtual environment?"
14 | ) from exc
15 | execute_from_command_line(sys.argv)
16 |
--------------------------------------------------------------------------------
/web/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "podcast-api-demo",
3 | "private": true,
4 | "version": "1.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "lint": "eslint .",
10 | "preview": "vite preview"
11 | },
12 | "dependencies": {
13 | "axios": "^1.8.3",
14 | "react": "^19.0.0",
15 | "react-dom": "^19.0.0"
16 | },
17 | "devDependencies": {
18 | "@eslint/js": "^9.21.0",
19 | "@types/react": "^19.0.10",
20 | "@types/react-dom": "^19.0.4",
21 | "@vitejs/plugin-react": "^4.3.4",
22 | "eslint": "^9.21.0",
23 | "eslint-plugin-react-hooks": "^5.1.0",
24 | "eslint-plugin-react-refresh": "^0.4.19",
25 | "globals": "^15.15.0",
26 | "less": "^4.2.2",
27 | "vite": "^6.2.0"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/backend/ListenApiDemo/urls.py:
--------------------------------------------------------------------------------
1 | """ListenApiDemo URL Configuration
2 |
3 | The `urlpatterns` list routes URLs to views. For more information please see:
4 | https://docs.djangoproject.com/en/2.1/topics/http/urls/
5 | Examples:
6 | Function views
7 | 1. Add an import: from my_app import views
8 | 2. Add a URL to urlpatterns: path('', views.home, name='home')
9 | Class-based views
10 | 1. Add an import: from other_app.views import Home
11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
12 | Including another URLconf
13 | 1. Import the include() function: from django.urls import include, path
14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
15 | """
16 | from django.urls import path
17 | from ListenApiDemo.views import search
18 |
19 | urlpatterns = [
20 | path('search/', search),
21 | ]
22 |
--------------------------------------------------------------------------------
/web/eslint.config.js:
--------------------------------------------------------------------------------
1 | import js from '@eslint/js'
2 | import globals from 'globals'
3 | import reactHooks from 'eslint-plugin-react-hooks'
4 | import reactRefresh from 'eslint-plugin-react-refresh'
5 |
6 | export default [
7 | { ignores: ['dist'] },
8 | {
9 | files: ['**/*.{js,jsx}'],
10 | languageOptions: {
11 | ecmaVersion: 2020,
12 | globals: globals.browser,
13 | parserOptions: {
14 | ecmaVersion: 'latest',
15 | ecmaFeatures: { jsx: true },
16 | sourceType: 'module',
17 | },
18 | },
19 | plugins: {
20 | 'react-hooks': reactHooks,
21 | 'react-refresh': reactRefresh,
22 | },
23 | rules: {
24 | ...js.configs.recommended.rules,
25 | ...reactHooks.configs.recommended.rules,
26 | 'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }],
27 | 'react-refresh/only-export-components': [
28 | 'warn',
29 | { allowConstantExport: true },
30 | ],
31 | },
32 | },
33 | ]
34 |
--------------------------------------------------------------------------------
/.github/workflows/demo-ci.yml:
--------------------------------------------------------------------------------
1 | name: Demo CI
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | pull_request:
7 | branches: [ master ]
8 |
9 | jobs:
10 | build:
11 |
12 | runs-on: ubuntu-24.04
13 | strategy:
14 | fail-fast: false
15 | matrix:
16 | python-version: ["3.13"]
17 | node-version: [22.x]
18 |
19 | steps:
20 | - uses: actions/checkout@v4
21 | - name: Install javascript dependencies
22 | uses: borales/actions-yarn@v4
23 | with:
24 | cmd: --cwd web install # will run `yarn install` command
25 | - name: Lint javascript code
26 | uses: borales/actions-yarn@v4
27 | with:
28 | cmd: --cwd web run lint # will run `yarn run lint` command
29 |
30 | - name: Set up Python ${{ matrix.python-version }}
31 | uses: actions/setup-python@v4
32 | with:
33 | python-version: ${{ matrix.python-version }}
34 | cache: 'pip'
35 | cache-dependency-path: 'backend/requirements.txt'
36 | - name: Install python dependencies
37 | run: |
38 | python -m pip install --upgrade pip
39 | cat backend/requirements.txt | grep -v '#' | xargs -n 1 pip install
40 | continue-on-error: false
41 | - name: Run flake
42 | run: |
43 | flake8 backend --config backend/.flake8
44 | continue-on-error: false
45 |
46 |
--------------------------------------------------------------------------------
/backend/ListenApiDemo/views.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from django import http
4 | from django.views.decorators.http import require_http_methods
5 |
6 | from listennotes import podcast_api, errors
7 |
8 |
9 | LISTEN_API_KEY = os.environ.get('LISTEN_API_KEY')
10 |
11 |
12 | @require_http_methods(['GET'])
13 | def search(request):
14 | q = request.GET.get('q')
15 | sort_by_date = request.GET.get('sort_by_date')
16 | result_type = request.GET.get('type')
17 | offset = request.GET.get('offset', '0')
18 |
19 | try:
20 | # If api_key is None, then we'll connect to api mock servers which return fake data
21 | client = podcast_api.Client(api_key=LISTEN_API_KEY)
22 | response = client.search(
23 | q=q, sort_by_date=sort_by_date, type=result_type, offset=offset)
24 | except errors.APIConnectionError:
25 | return http.JsonResponse({}, status=503)
26 | except errors.AuthenticationError:
27 | return http.JsonResponse({}, status=401)
28 | except errors.InvalidRequestError:
29 | return http.JsonResponse({}, status=400)
30 | except errors.NotFoundError:
31 | return http.JsonResponse({}, status=404)
32 | except errors.RateLimitError:
33 | return http.JsonResponse({}, status=429)
34 | except errors.ListenApiError:
35 | return http.JsonResponse({}, status=500)
36 | else:
37 | return http.JsonResponse(response.json())
38 |
--------------------------------------------------------------------------------
/web/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/backend/ListenApiDemo/settings.py:
--------------------------------------------------------------------------------
1 | """
2 | Django settings for ListenApiDemo project.
3 |
4 | Generated by 'django-admin startproject' using Django 2.1.1.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/2.1/topics/settings/
8 |
9 | For the full list of settings and their values, see
10 | https://docs.djangoproject.com/en/2.1/ref/settings/
11 | """
12 |
13 | import os
14 |
15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
17 |
18 |
19 | # Quick-start development settings - unsuitable for production
20 | # See https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/
21 |
22 | # SECURITY WARNING: keep the secret key used in production secret!
23 | SECRET_KEY = '&$kmzjw)4j(n6-wc@f$n@r(_4z%5pw#q0-nn0#q1)*d(+ika5^'
24 |
25 | # SECURITY WARNING: don't run with debug turned on in production!
26 | DEBUG = True
27 |
28 | ALLOWED_HOSTS = ['*']
29 | CORS_ORIGIN_ALLOW_ALL = True
30 |
31 |
32 | # Application definition
33 |
34 | INSTALLED_APPS = [
35 | 'django.contrib.auth',
36 | 'django.contrib.contenttypes',
37 | 'django.contrib.sessions',
38 | 'django.contrib.messages',
39 | ]
40 |
41 | MIDDLEWARE = [
42 | 'corsheaders.middleware.CorsMiddleware',
43 | 'django.middleware.security.SecurityMiddleware',
44 | 'django.contrib.sessions.middleware.SessionMiddleware',
45 | 'django.middleware.common.CommonMiddleware',
46 | 'django.middleware.csrf.CsrfViewMiddleware',
47 | 'django.contrib.auth.middleware.AuthenticationMiddleware',
48 | 'django.contrib.messages.middleware.MessageMiddleware',
49 | 'django.middleware.clickjacking.XFrameOptionsMiddleware',
50 | ]
51 |
52 | ROOT_URLCONF = 'ListenApiDemo.urls'
53 |
54 | WSGI_APPLICATION = 'ListenApiDemo.wsgi.application'
55 |
56 | CORS_ORIGIN_WHITELIST = (
57 | 'localhost:8000'
58 | )
59 |
--------------------------------------------------------------------------------
/web/src/App.less:
--------------------------------------------------------------------------------
1 | @desktop: ~"only screen and (min-width: 960px)";
2 | @tablet: ~"only screen and (min-width: 720px) and (max-width: 959px)";
3 |
4 | @margin-1x: 5px;
5 | @margin-2x: 10px;
6 |
7 | @border-color: #000000;
8 | @shadow-color: #CCCCCC;
9 | @button-color: #EEEEEE;
10 | @background-color: #F4F4F4;
11 | @result-color: #FFFFFF;
12 |
13 | html {
14 | height: 100%;
15 | }
16 |
17 | body {
18 | height: 100%;
19 | background-color: @background-color;
20 | }
21 |
22 | #root {
23 | min-height: 100%;
24 | }
25 |
26 | .App {
27 | text-align: center;
28 |
29 | &-header {
30 | height: 6em;
31 | padding: @margin-2x;
32 | }
33 |
34 | &-title {
35 | font-size: 2.5em;
36 | }
37 | }
38 |
39 | .search-results {
40 | width: 100%;
41 | overflow: auto;
42 | }
43 |
44 | .next-page {
45 | cursor: pointer;
46 | margin-bottom: @margin-2x;
47 | text-decoration: underline;
48 | }
49 |
50 | audio {
51 | margin: @margin-2x 2.5%;
52 | width: 95%;
53 | }
54 |
55 | .search-result {
56 | text-align: left;
57 | background-color: @result-color;
58 | display: inline-block;
59 | box-sizing: border-box;
60 | float: left;
61 | width: 80%;
62 | margin: @margin-2x 10%;
63 | padding: @margin-2x;
64 | border: 1px solid @border-color;
65 | border-radius: 4px;
66 |
67 | @media @tablet {
68 | width: 46%;
69 | margin: 2%;
70 | &-title {
71 | height: 90px;
72 | }
73 | }
74 |
75 | @media @desktop {
76 | width: 31.3%;
77 | margin: 1%;
78 | &-title {
79 | height: 90px;
80 | }
81 | }
82 |
83 | &-title {
84 | display: inline-block;
85 | font-size: 1.5em;
86 | color: @border-color;
87 | margin-bottom: @margin-2x;
88 | }
89 |
90 | &-description {
91 | overflow: hidden;
92 | text-overflow: ellipsis;
93 | line-height: 24px;
94 | max-height: 72px;
95 | min-height: 72px;
96 | }
97 |
98 | &-creator {
99 | overflow: auto;
100 |
101 | &-thumbnail {
102 | width: 25%;
103 | display: inline-block;
104 | float: left;
105 | }
106 |
107 | &-names {
108 | width: 75%;
109 | display: inline-block;
110 | float: left;
111 |
112 | p {
113 | margin: @margin-1x;
114 | text-align: left;
115 | }
116 | }
117 | }
118 |
119 | &-footer {
120 | text-align: center;
121 | a {
122 | padding: @margin-2x @margin-1x;
123 | }
124 | }
125 | }
126 |
127 | .search-form {
128 | width: 90%;
129 | margin-left: 5%;
130 |
131 | @media @tablet {
132 | width: 70%;
133 | margin-left: 15%;
134 | }
135 |
136 | @media @desktop {
137 | width: 60%;
138 | margin-left: 20%;
139 | }
140 |
141 | &-text {
142 | width: 80%;
143 | line-height: 40px;
144 | box-shadow: 0px 5px 1px rgba(0, 0, 0, 0.14);
145 | margin: @margin-2x 0;
146 | padding: 0 @margin-2x;
147 | border: 0;
148 | box-sizing: border-box;
149 | font-size: 14px;
150 |
151 | @media @tablet {
152 | width: 85%;
153 | font-size: 18px;
154 | }
155 |
156 | @media @desktop {
157 | width: 90%;
158 | font-size: 18px;
159 | }
160 | }
161 |
162 | &-submit {
163 | vertical-align: top;
164 | box-sizing: border-box;
165 | width: 20%;
166 | font-size: 12px;
167 | line-height: 40px;
168 | padding: 0px;
169 | margin: @margin-2x 0;
170 | border: 0px;
171 | background-color: @button-color;
172 | box-shadow: 0px 5px 1px @shadow-color;
173 |
174 | @media @tablet {
175 | width: 15%;
176 | font-size: 16px;
177 | }
178 |
179 | @media @desktop {
180 | width: 10%;
181 | font-size: 16px;
182 | }
183 | }
184 |
185 | &-type {
186 | text-align: left;
187 | font-size: 14px;
188 | }
189 |
190 | &-sort-by {
191 | margin-left: @margin-2x;
192 | font-size: 14px;
193 | }
194 | }
195 |
196 | footer img {
197 | width: 200px;
198 | }
199 |
200 | .ln-search-highlight {
201 | font-weight: bold;
202 | }
203 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ListenApiDemo
2 |
3 | 
4 | [](https://github.com/ListenNotes/ListenApiDemo/actions/workflows/demo-ci.yml)
5 |
6 | A simplified podcast search engine web app, using Django, React, and [PodcastAPI.com](https://www.PodcastAPI.com/).
7 |
8 | In the Django code, we use our [official podcast api package](https://github.com/ListenNotes/podcast-api-python) to talk to
9 | Listen API.
10 |
11 | You can find code snippets in different languages on the [API Docs](https://www.listennotes.com/api/docs/) page,
12 | including [Node.js](https://github.com/ListenNotes/podcast-api-js),
13 | [Python](https://github.com/ListenNotes/podcast-api-python),
14 | [Ruby](https://github.com/ListenNotes/podcast-api-ruby),
15 | [Java](https://github.com/ListenNotes/podcast-api-java),
16 | [PHP](https://github.com/ListenNotes/podcast-api-php),
17 | [Golang](https://github.com/ListenNotes/podcast-api-go),
18 | [Kotlin](https://github.com/ListenNotes/podcast-api-kotlin)...
19 |
20 | Note: You can easily implement similar apps using [Cloudflare Pages](https://github.com/ListenNotes/demo.podcastapi.com), or no code tools like [Bubble](https://www.listennotes.com/integrations/bubble/) and [Retool](https://www.listennotes.com/integrations/retool/).
21 |
22 |
23 |
24 | ## Overview
25 |
26 | Your frontend code (e.g., Web, iOS, Android...) shouldn't talk to Listen API directly.
27 | For Web, your users can inspect request headers in their web browsers to find your API key,
28 | if you use Ajax to hit Listen API endpoints directly.
29 | For iOS / Android, you can't easily reset your API key, if you put API keys in the source code of your app.
30 | Once the app is in the hands of your users, you can't easily change the code or force users to upgrade.
31 |
32 | Typically, you'll hit Listen API endpoints from your backend (e.g., Django, Rails, Nodejs, Cloudflare Workers...).
33 | So you can protect your API key and reset it if needed.
34 | Your frontend code will talk to your backend via GraphQL, RESTful APIs or the likes.
35 |
36 | In this demo, we provide a reference Django implementation for a backend that talks to Listen API,
37 | and a ReactJs implementation for a web frontend that talks to the Django backend.
38 |
39 | ## Running the project
40 |
41 | ### [Backend (Django)](https://github.com/ListenNotes/ListenApiDemo/tree/master/backend)
42 |
43 | The backend is a simple Django backend makes requests to the Podcast API. To run it, from the `backend` directory:
44 |
45 | 1. Install requirements (it is recommended you do this in a virtualenv):
46 |
47 | ```
48 | python3 -m venv .venv && source .venv/bin/activate
49 | pip install -r requirements.txt
50 | ```
51 |
52 | 2. Start the django app with the environment variable LISTEN_API_KEY set to your Listen API key:
53 |
54 | ```
55 | LISTEN_API_KEY=YOUR_SECRET_KEY python manage.py runserver localhost:8888
56 | ```
57 |
58 | [Where to get LISTEN_API_KEY](https://help.listennotes.com/en/articles/3416436-how-to-get-an-api-token-of-listen-notes-api)?
59 |
60 |
61 | If LISTEN_API_KEY is not set, then we'll use the [API mock server](https://www.listennotes.com/api/tutorials/#faq0) that returns fake data.
62 |
63 |
64 | ### [Web (React)](https://github.com/ListenNotes/ListenApiDemo/tree/master/web)
65 |
66 | The web frontend is a React project that makes requests to the django backend. To run it, from the `web` directory:
67 |
68 | 1. Install requirements:
69 |
70 | ```
71 | yarn install
72 | ```
73 |
74 | 2. Start the React app with the environment variable REACT_APP_BACKEND_ROOT_URL set to your Django backend's base url:
75 |
76 | ```
77 | yarn dev
78 | ```
79 |
80 | Now you can access the web app at `http://localhost:5173`
81 |
82 | *On desktop*
83 |
84 | 
85 |
86 | *On mobile*
87 |
88 |
89 |
90 | ## Further readings
91 |
92 | * [Listen API Documentation](https://www.listennotes.com/api/docs/)
93 | * [Tutorials](https://www.listennotes.com/api/tutorials/)
94 | * [Who's using Listen API?](https://www.listennotes.com/api/apps/)
95 | * [General FAQ](https://www.listennotes.com/api/faq/)
96 | * [How to evaluate a 3rd party RESTful API?](https://www.listennotes.com/blog/how-to-evaluate-a-3rd-party-restful-api-47/)
97 |
98 | What have 9,000+ companies & developers built with Listen Notes Podcast API:
99 |
100 | * [E-Learning Platforms](https://www.listennotes.com/use-cases/elearning-platforms/)
101 | * [Podcast Clipping Apps](https://www.listennotes.com/use-cases/podcast-clipping-apps/)
102 | * [Podcast Listening Apps](https://www.listennotes.com/use-cases/podcast-listening-apps/)
103 | * [Podcast Social Apps](https://www.listennotes.com/use-cases/podcast-social-apps/)
104 | * [Podcast PR / Advertising Platforms](https://www.listennotes.com/use-cases/podcast-pr-advertising-platforms/)
105 | * [Podcast Curation Apps](https://www.listennotes.com/use-cases/podcast-curation-apps/)
106 | * [Financial Market Intelligence Platforms](https://www.listennotes.com/use-cases/financial-market-intelligence-platforms/)
107 | * [Podcast Hosting Services](https://www.listennotes.com/use-cases/podcast-hosting-services/)
108 | * and [more](https://www.listennotes.com/api/apps/)...
109 |
--------------------------------------------------------------------------------
/web/src/App.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import './App.less';
3 | import axios from 'axios'
4 | import poweredByImage from './powered_by_listennotes.png';
5 |
6 | const BACKEND_ROOT_URL = 'http://localhost:8000'
7 | const RESULTS_PER_PAGE = 10
8 |
9 | class EpisodeResult extends Component {
10 | constructor(props) {
11 | super(props)
12 | this.state = {
13 | title: this.props.data.title_highlighted,
14 | podcastTitle: this.props.data.podcast_title_highlighted,
15 | publisher: this.props.data.publisher_highlighted,
16 | thumbnail: this.props.data.thumbnail,
17 | audio: this.props.data.audio,
18 | audioLength: this.props.data.audio_length,
19 | rss: this.props.data.rss,
20 | listennotesUrl: this.props.data.listennotes_url,
21 | itunesId: this.props.data.itunes_id,
22 | description: this.props.data.description_highlighted
23 | }
24 | }
25 |
26 | render() {
27 | const itunesUrl = `https://itunes.apple.com/us/podcast/id${this.state.itunesId}`
28 | return (
29 |
30 |
31 |
32 |
33 |

34 |
38 |
39 |
40 |
44 |
49 |
50 | )
51 | }
52 | }
53 |
54 | class PodcastResult extends Component {
55 | constructor(props) {
56 | super(props)
57 | this.state = {
58 | title: this.props.data.title_highlighted,
59 | publisher: this.props.data.publisher_highlighted,
60 | thumbnail: this.props.data.thumbnail,
61 | rss: this.props.data.rss,
62 | listennotesUrl: this.props.data.listennotes_url,
63 | itunesId: this.props.data.itunes_id,
64 | description: this.props.data.description_highlighted
65 | }
66 | }
67 |
68 | render() {
69 | const itunesUrl = `https://itunes.apple.com/us/podcast/id${this.state.itunesId}`
70 | return (
71 |
72 |
73 |
74 |

75 |
78 |
79 |
80 |
84 |
85 | )
86 | }
87 | }
88 |
89 | class App extends Component {
90 | constructor () {
91 | super()
92 | this.state = {
93 | search: '',
94 | data: {},
95 | offset: 0,
96 | sortByDate: '0',
97 | searchType: 'episode',
98 | resultType: 'episode',
99 | quotaExceeded: false,
100 | errorOccurred: false
101 | }
102 | this.handleSubmit = this.handleSubmit.bind(this)
103 | this.handleChange = this.handleChange.bind(this)
104 | this.handleTypeChange = this.handleTypeChange.bind(this)
105 | this.handleSortByChange = this.handleSortByChange.bind(this)
106 | this.handlePage = this.handlePage.bind(this)
107 | this.search = this.search.bind(this)
108 | }
109 |
110 | handleTypeChange(e) {
111 | const newValue = e.target.value
112 | this.setState(prevState => ({...prevState, searchType: newValue}))
113 | }
114 |
115 | search(requestUrl) {
116 | axios.get(requestUrl)
117 | .then(response => {
118 | this.setState(prevState => ({...prevState,
119 | data: response.data,
120 | resultType: this.state.searchType,
121 | offset: 0,
122 | quotaExceeded: false,
123 | errorOccurred: false
124 | }))})
125 | .catch(error => {
126 | if (error.response.status === 429) {
127 | this.setState(() => ({
128 | data: [],
129 | offset: 0,
130 | quotaExceeded: true,
131 | errorOccurred: false
132 | }))
133 | } else {
134 | this.setState(() => ({
135 | data: [],
136 | offset: 0,
137 | quotaExceeded: false,
138 | errorOccurred: true
139 | }))
140 | }
141 | })
142 | }
143 |
144 | handlePage() {
145 | const requestUrl = `${BACKEND_ROOT_URL}/search/?q=${this.state.search}&sort_by_date=${this.state.sortByDate}&type=${this.state.searchType}&offset=${this.state.data.next_offset}`
146 | this.search(requestUrl)
147 | }
148 |
149 | handleSortByChange(e) {
150 | const newValue = e.target.value
151 | this.setState(prevState => ({...prevState, sortByDate: newValue}))
152 | }
153 |
154 | handleChange(e) {
155 | const newValue = e.target.value
156 | this.setState(prevState => ({...prevState, search: newValue}))
157 | }
158 |
159 | handleSubmit(e) {
160 | const requestUrl = `${BACKEND_ROOT_URL}/search/?q=${this.state.search}&sort_by_date=${this.state.sortByDate}&type=${this.state.searchType}`
161 | this.search(requestUrl)
162 | e.preventDefault();
163 | }
164 |
165 | render() {
166 | const resultElements = this.state.data.results ? this.state.data.results.map((d) => {
167 | if (this.state.resultType === 'episode') {
168 | return
169 | } else if (this.state.resultType === 'podcast') {
170 | return
171 | } else {
172 | return null
173 | }
174 | }) : []
175 | const nextPageElement = (this.state.data.results && this.state.data.next_offset <= this.state.data.total - this.state.data.total % RESULTS_PER_PAGE) ? (
176 | this.handlePage()}>
177 | Next page ({this.state.data.next_offset / RESULTS_PER_PAGE + 1} of {(this.state.data.total / RESULTS_PER_PAGE + 1).toFixed()})
178 |
179 | ) : null
180 | const quotaExceededMessage = this.state.quotaExceeded ? (Quota exceeded.
) : null
181 | const errorOccurredMessage = this.state.errorOccurred ? (An error occurred.
) : null
182 | return (
183 |
184 |
185 | Listen API Demo
186 |
187 |
207 |
208 | {quotaExceededMessage}
209 | {errorOccurredMessage}
210 | {resultElements}
211 |
212 |
213 | {nextPageElement}
214 |
215 |
218 |
219 | );
220 | }
221 | }
222 |
223 | export default App;
224 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/web/.pnp.loader.mjs:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | // @ts-nocheck
3 |
4 | import fs from 'fs';
5 | import { URL as URL$1, fileURLToPath, pathToFileURL } from 'url';
6 | import path from 'path';
7 | import { createHash } from 'crypto';
8 | import { EOL } from 'os';
9 | import esmModule, { createRequire, isBuiltin } from 'module';
10 | import assert from 'assert';
11 |
12 | const SAFE_TIME = 456789e3;
13 |
14 | const PortablePath = {
15 | root: `/`,
16 | dot: `.`,
17 | parent: `..`
18 | };
19 | const npath = Object.create(path);
20 | const ppath = Object.create(path.posix);
21 | npath.cwd = () => process.cwd();
22 | ppath.cwd = process.platform === `win32` ? () => toPortablePath(process.cwd()) : process.cwd;
23 | if (process.platform === `win32`) {
24 | ppath.resolve = (...segments) => {
25 | if (segments.length > 0 && ppath.isAbsolute(segments[0])) {
26 | return path.posix.resolve(...segments);
27 | } else {
28 | return path.posix.resolve(ppath.cwd(), ...segments);
29 | }
30 | };
31 | }
32 | const contains = function(pathUtils, from, to) {
33 | from = pathUtils.normalize(from);
34 | to = pathUtils.normalize(to);
35 | if (from === to)
36 | return `.`;
37 | if (!from.endsWith(pathUtils.sep))
38 | from = from + pathUtils.sep;
39 | if (to.startsWith(from)) {
40 | return to.slice(from.length);
41 | } else {
42 | return null;
43 | }
44 | };
45 | npath.contains = (from, to) => contains(npath, from, to);
46 | ppath.contains = (from, to) => contains(ppath, from, to);
47 | const WINDOWS_PATH_REGEXP = /^([a-zA-Z]:.*)$/;
48 | const UNC_WINDOWS_PATH_REGEXP = /^\/\/(\.\/)?(.*)$/;
49 | const PORTABLE_PATH_REGEXP = /^\/([a-zA-Z]:.*)$/;
50 | const UNC_PORTABLE_PATH_REGEXP = /^\/unc\/(\.dot\/)?(.*)$/;
51 | function fromPortablePathWin32(p) {
52 | let portablePathMatch, uncPortablePathMatch;
53 | if (portablePathMatch = p.match(PORTABLE_PATH_REGEXP))
54 | p = portablePathMatch[1];
55 | else if (uncPortablePathMatch = p.match(UNC_PORTABLE_PATH_REGEXP))
56 | p = `\\\\${uncPortablePathMatch[1] ? `.\\` : ``}${uncPortablePathMatch[2]}`;
57 | else
58 | return p;
59 | return p.replace(/\//g, `\\`);
60 | }
61 | function toPortablePathWin32(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 | const toPortablePath = process.platform === `win32` ? toPortablePathWin32 : (p) => p;
71 | const fromPortablePath = process.platform === `win32` ? fromPortablePathWin32 : (p) => p;
72 | npath.fromPortablePath = fromPortablePath;
73 | npath.toPortablePath = toPortablePath;
74 | function convertPath(targetPathUtils, sourcePath) {
75 | return targetPathUtils === npath ? fromPortablePath(sourcePath) : toPortablePath(sourcePath);
76 | }
77 |
78 | const defaultTime = new Date(SAFE_TIME * 1e3);
79 | const defaultTimeMs = defaultTime.getTime();
80 | async function copyPromise(destinationFs, destination, sourceFs, source, opts) {
81 | const normalizedDestination = destinationFs.pathUtils.normalize(destination);
82 | const normalizedSource = sourceFs.pathUtils.normalize(source);
83 | const prelayout = [];
84 | const postlayout = [];
85 | const { atime, mtime } = opts.stableTime ? { atime: defaultTime, mtime: defaultTime } : await sourceFs.lstatPromise(normalizedSource);
86 | await destinationFs.mkdirpPromise(destinationFs.pathUtils.dirname(destination), { utimes: [atime, mtime] });
87 | await copyImpl(prelayout, postlayout, destinationFs, normalizedDestination, sourceFs, normalizedSource, { ...opts, didParentExist: true });
88 | for (const operation of prelayout)
89 | await operation();
90 | await Promise.all(postlayout.map((operation) => {
91 | return operation();
92 | }));
93 | }
94 | async function copyImpl(prelayout, postlayout, destinationFs, destination, sourceFs, source, opts) {
95 | const destinationStat = opts.didParentExist ? await maybeLStat(destinationFs, destination) : null;
96 | const sourceStat = await sourceFs.lstatPromise(source);
97 | const { atime, mtime } = opts.stableTime ? { atime: defaultTime, mtime: defaultTime } : sourceStat;
98 | let updated;
99 | switch (true) {
100 | case sourceStat.isDirectory():
101 | {
102 | updated = await copyFolder(prelayout, postlayout, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts);
103 | }
104 | break;
105 | case sourceStat.isFile():
106 | {
107 | updated = await copyFile(prelayout, postlayout, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts);
108 | }
109 | break;
110 | case sourceStat.isSymbolicLink():
111 | {
112 | updated = await copySymlink(prelayout, postlayout, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts);
113 | }
114 | break;
115 | default: {
116 | throw new Error(`Unsupported file type (${sourceStat.mode})`);
117 | }
118 | }
119 | if (opts.linkStrategy?.type !== `HardlinkFromIndex` || !sourceStat.isFile()) {
120 | if (updated || destinationStat?.mtime?.getTime() !== mtime.getTime() || destinationStat?.atime?.getTime() !== atime.getTime()) {
121 | postlayout.push(() => destinationFs.lutimesPromise(destination, atime, mtime));
122 | updated = true;
123 | }
124 | if (destinationStat === null || (destinationStat.mode & 511) !== (sourceStat.mode & 511)) {
125 | postlayout.push(() => destinationFs.chmodPromise(destination, sourceStat.mode & 511));
126 | updated = true;
127 | }
128 | }
129 | return updated;
130 | }
131 | async function maybeLStat(baseFs, p) {
132 | try {
133 | return await baseFs.lstatPromise(p);
134 | } catch {
135 | return null;
136 | }
137 | }
138 | async function copyFolder(prelayout, postlayout, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts) {
139 | if (destinationStat !== null && !destinationStat.isDirectory()) {
140 | if (opts.overwrite) {
141 | prelayout.push(async () => destinationFs.removePromise(destination));
142 | destinationStat = null;
143 | } else {
144 | return false;
145 | }
146 | }
147 | let updated = false;
148 | if (destinationStat === null) {
149 | prelayout.push(async () => {
150 | try {
151 | await destinationFs.mkdirPromise(destination, { mode: sourceStat.mode });
152 | } catch (err) {
153 | if (err.code !== `EEXIST`) {
154 | throw err;
155 | }
156 | }
157 | });
158 | updated = true;
159 | }
160 | const entries = await sourceFs.readdirPromise(source);
161 | const nextOpts = opts.didParentExist && !destinationStat ? { ...opts, didParentExist: false } : opts;
162 | if (opts.stableSort) {
163 | for (const entry of entries.sort()) {
164 | if (await copyImpl(prelayout, postlayout, destinationFs, destinationFs.pathUtils.join(destination, entry), sourceFs, sourceFs.pathUtils.join(source, entry), nextOpts)) {
165 | updated = true;
166 | }
167 | }
168 | } else {
169 | const entriesUpdateStatus = await Promise.all(entries.map(async (entry) => {
170 | await copyImpl(prelayout, postlayout, destinationFs, destinationFs.pathUtils.join(destination, entry), sourceFs, sourceFs.pathUtils.join(source, entry), nextOpts);
171 | }));
172 | if (entriesUpdateStatus.some((status) => status)) {
173 | updated = true;
174 | }
175 | }
176 | return updated;
177 | }
178 | async function copyFileViaIndex(prelayout, postlayout, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts, linkStrategy) {
179 | const sourceHash = await sourceFs.checksumFilePromise(source, { algorithm: `sha1` });
180 | const defaultMode = 420;
181 | const sourceMode = sourceStat.mode & 511;
182 | const indexFileName = `${sourceHash}${sourceMode !== defaultMode ? sourceMode.toString(8) : ``}`;
183 | const indexPath = destinationFs.pathUtils.join(linkStrategy.indexPath, sourceHash.slice(0, 2), `${indexFileName}.dat`);
184 | let AtomicBehavior;
185 | ((AtomicBehavior2) => {
186 | AtomicBehavior2[AtomicBehavior2["Lock"] = 0] = "Lock";
187 | AtomicBehavior2[AtomicBehavior2["Rename"] = 1] = "Rename";
188 | })(AtomicBehavior || (AtomicBehavior = {}));
189 | let atomicBehavior = 1 /* Rename */;
190 | let indexStat = await maybeLStat(destinationFs, indexPath);
191 | if (destinationStat) {
192 | const isDestinationHardlinkedFromIndex = indexStat && destinationStat.dev === indexStat.dev && destinationStat.ino === indexStat.ino;
193 | const isIndexModified = indexStat?.mtimeMs !== defaultTimeMs;
194 | if (isDestinationHardlinkedFromIndex) {
195 | if (isIndexModified && linkStrategy.autoRepair) {
196 | atomicBehavior = 0 /* Lock */;
197 | indexStat = null;
198 | }
199 | }
200 | if (!isDestinationHardlinkedFromIndex) {
201 | if (opts.overwrite) {
202 | prelayout.push(async () => destinationFs.removePromise(destination));
203 | destinationStat = null;
204 | } else {
205 | return false;
206 | }
207 | }
208 | }
209 | const tempPath = !indexStat && atomicBehavior === 1 /* Rename */ ? `${indexPath}.${Math.floor(Math.random() * 4294967296).toString(16).padStart(8, `0`)}` : null;
210 | let tempPathCleaned = false;
211 | prelayout.push(async () => {
212 | if (!indexStat) {
213 | if (atomicBehavior === 0 /* Lock */) {
214 | await destinationFs.lockPromise(indexPath, async () => {
215 | const content = await sourceFs.readFilePromise(source);
216 | await destinationFs.writeFilePromise(indexPath, content);
217 | });
218 | }
219 | if (atomicBehavior === 1 /* Rename */ && tempPath) {
220 | const content = await sourceFs.readFilePromise(source);
221 | await destinationFs.writeFilePromise(tempPath, content);
222 | try {
223 | await destinationFs.linkPromise(tempPath, indexPath);
224 | } catch (err) {
225 | if (err.code === `EEXIST`) {
226 | tempPathCleaned = true;
227 | await destinationFs.unlinkPromise(tempPath);
228 | } else {
229 | throw err;
230 | }
231 | }
232 | }
233 | }
234 | if (!destinationStat) {
235 | await destinationFs.linkPromise(indexPath, destination);
236 | }
237 | });
238 | postlayout.push(async () => {
239 | if (!indexStat) {
240 | await destinationFs.lutimesPromise(indexPath, defaultTime, defaultTime);
241 | if (sourceMode !== defaultMode) {
242 | await destinationFs.chmodPromise(indexPath, sourceMode);
243 | }
244 | }
245 | if (tempPath && !tempPathCleaned) {
246 | await destinationFs.unlinkPromise(tempPath);
247 | }
248 | });
249 | return false;
250 | }
251 | async function copyFileDirect(prelayout, postlayout, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts) {
252 | if (destinationStat !== null) {
253 | if (opts.overwrite) {
254 | prelayout.push(async () => destinationFs.removePromise(destination));
255 | destinationStat = null;
256 | } else {
257 | return false;
258 | }
259 | }
260 | prelayout.push(async () => {
261 | const content = await sourceFs.readFilePromise(source);
262 | await destinationFs.writeFilePromise(destination, content);
263 | });
264 | return true;
265 | }
266 | async function copyFile(prelayout, postlayout, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts) {
267 | if (opts.linkStrategy?.type === `HardlinkFromIndex`) {
268 | return copyFileViaIndex(prelayout, postlayout, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts, opts.linkStrategy);
269 | } else {
270 | return copyFileDirect(prelayout, postlayout, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts);
271 | }
272 | }
273 | async function copySymlink(prelayout, postlayout, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts) {
274 | if (destinationStat !== null) {
275 | if (opts.overwrite) {
276 | prelayout.push(async () => destinationFs.removePromise(destination));
277 | destinationStat = null;
278 | } else {
279 | return false;
280 | }
281 | }
282 | prelayout.push(async () => {
283 | await destinationFs.symlinkPromise(convertPath(destinationFs.pathUtils, await sourceFs.readlinkPromise(source)), destination);
284 | });
285 | return true;
286 | }
287 |
288 | class FakeFS {
289 | pathUtils;
290 | constructor(pathUtils) {
291 | this.pathUtils = pathUtils;
292 | }
293 | async *genTraversePromise(init, { stableSort = false } = {}) {
294 | const stack = [init];
295 | while (stack.length > 0) {
296 | const p = stack.shift();
297 | const entry = await this.lstatPromise(p);
298 | if (entry.isDirectory()) {
299 | const entries = await this.readdirPromise(p);
300 | if (stableSort) {
301 | for (const entry2 of entries.sort()) {
302 | stack.push(this.pathUtils.join(p, entry2));
303 | }
304 | } else {
305 | throw new Error(`Not supported`);
306 | }
307 | } else {
308 | yield p;
309 | }
310 | }
311 | }
312 | async checksumFilePromise(path, { algorithm = `sha512` } = {}) {
313 | const fd = await this.openPromise(path, `r`);
314 | try {
315 | const CHUNK_SIZE = 65536;
316 | const chunk = Buffer.allocUnsafeSlow(CHUNK_SIZE);
317 | const hash = createHash(algorithm);
318 | let bytesRead = 0;
319 | while ((bytesRead = await this.readPromise(fd, chunk, 0, CHUNK_SIZE)) !== 0)
320 | hash.update(bytesRead === CHUNK_SIZE ? chunk : chunk.slice(0, bytesRead));
321 | return hash.digest(`hex`);
322 | } finally {
323 | await this.closePromise(fd);
324 | }
325 | }
326 | async removePromise(p, { recursive = true, maxRetries = 5 } = {}) {
327 | let stat;
328 | try {
329 | stat = await this.lstatPromise(p);
330 | } catch (error) {
331 | if (error.code === `ENOENT`) {
332 | return;
333 | } else {
334 | throw error;
335 | }
336 | }
337 | if (stat.isDirectory()) {
338 | if (recursive) {
339 | const entries = await this.readdirPromise(p);
340 | await Promise.all(entries.map((entry) => {
341 | return this.removePromise(this.pathUtils.resolve(p, entry));
342 | }));
343 | }
344 | for (let t = 0; t <= maxRetries; t++) {
345 | try {
346 | await this.rmdirPromise(p);
347 | break;
348 | } catch (error) {
349 | if (error.code !== `EBUSY` && error.code !== `ENOTEMPTY`) {
350 | throw error;
351 | } else if (t < maxRetries) {
352 | await new Promise((resolve) => setTimeout(resolve, t * 100));
353 | }
354 | }
355 | }
356 | } else {
357 | await this.unlinkPromise(p);
358 | }
359 | }
360 | removeSync(p, { recursive = true } = {}) {
361 | let stat;
362 | try {
363 | stat = this.lstatSync(p);
364 | } catch (error) {
365 | if (error.code === `ENOENT`) {
366 | return;
367 | } else {
368 | throw error;
369 | }
370 | }
371 | if (stat.isDirectory()) {
372 | if (recursive)
373 | for (const entry of this.readdirSync(p))
374 | this.removeSync(this.pathUtils.resolve(p, entry));
375 | this.rmdirSync(p);
376 | } else {
377 | this.unlinkSync(p);
378 | }
379 | }
380 | async mkdirpPromise(p, { chmod, utimes } = {}) {
381 | p = this.resolve(p);
382 | if (p === this.pathUtils.dirname(p))
383 | return void 0;
384 | const parts = p.split(this.pathUtils.sep);
385 | let createdDirectory;
386 | for (let u = 2; u <= parts.length; ++u) {
387 | const subPath = parts.slice(0, u).join(this.pathUtils.sep);
388 | if (!this.existsSync(subPath)) {
389 | try {
390 | await this.mkdirPromise(subPath);
391 | } catch (error) {
392 | if (error.code === `EEXIST`) {
393 | continue;
394 | } else {
395 | throw error;
396 | }
397 | }
398 | createdDirectory ??= subPath;
399 | if (chmod != null)
400 | await this.chmodPromise(subPath, chmod);
401 | if (utimes != null) {
402 | await this.utimesPromise(subPath, utimes[0], utimes[1]);
403 | } else {
404 | const parentStat = await this.statPromise(this.pathUtils.dirname(subPath));
405 | await this.utimesPromise(subPath, parentStat.atime, parentStat.mtime);
406 | }
407 | }
408 | }
409 | return createdDirectory;
410 | }
411 | mkdirpSync(p, { chmod, utimes } = {}) {
412 | p = this.resolve(p);
413 | if (p === this.pathUtils.dirname(p))
414 | return void 0;
415 | const parts = p.split(this.pathUtils.sep);
416 | let createdDirectory;
417 | for (let u = 2; u <= parts.length; ++u) {
418 | const subPath = parts.slice(0, u).join(this.pathUtils.sep);
419 | if (!this.existsSync(subPath)) {
420 | try {
421 | this.mkdirSync(subPath);
422 | } catch (error) {
423 | if (error.code === `EEXIST`) {
424 | continue;
425 | } else {
426 | throw error;
427 | }
428 | }
429 | createdDirectory ??= subPath;
430 | if (chmod != null)
431 | this.chmodSync(subPath, chmod);
432 | if (utimes != null) {
433 | this.utimesSync(subPath, utimes[0], utimes[1]);
434 | } else {
435 | const parentStat = this.statSync(this.pathUtils.dirname(subPath));
436 | this.utimesSync(subPath, parentStat.atime, parentStat.mtime);
437 | }
438 | }
439 | }
440 | return createdDirectory;
441 | }
442 | async copyPromise(destination, source, { baseFs = this, overwrite = true, stableSort = false, stableTime = false, linkStrategy = null } = {}) {
443 | return await copyPromise(this, destination, baseFs, source, { overwrite, stableSort, stableTime, linkStrategy });
444 | }
445 | copySync(destination, source, { baseFs = this, overwrite = true } = {}) {
446 | const stat = baseFs.lstatSync(source);
447 | const exists = this.existsSync(destination);
448 | if (stat.isDirectory()) {
449 | this.mkdirpSync(destination);
450 | const directoryListing = baseFs.readdirSync(source);
451 | for (const entry of directoryListing) {
452 | this.copySync(this.pathUtils.join(destination, entry), baseFs.pathUtils.join(source, entry), { baseFs, overwrite });
453 | }
454 | } else if (stat.isFile()) {
455 | if (!exists || overwrite) {
456 | if (exists)
457 | this.removeSync(destination);
458 | const content = baseFs.readFileSync(source);
459 | this.writeFileSync(destination, content);
460 | }
461 | } else if (stat.isSymbolicLink()) {
462 | if (!exists || overwrite) {
463 | if (exists)
464 | this.removeSync(destination);
465 | const target = baseFs.readlinkSync(source);
466 | this.symlinkSync(convertPath(this.pathUtils, target), destination);
467 | }
468 | } else {
469 | throw new Error(`Unsupported file type (file: ${source}, mode: 0o${stat.mode.toString(8).padStart(6, `0`)})`);
470 | }
471 | const mode = stat.mode & 511;
472 | this.chmodSync(destination, mode);
473 | }
474 | async changeFilePromise(p, content, opts = {}) {
475 | if (Buffer.isBuffer(content)) {
476 | return this.changeFileBufferPromise(p, content, opts);
477 | } else {
478 | return this.changeFileTextPromise(p, content, opts);
479 | }
480 | }
481 | async changeFileBufferPromise(p, content, { mode } = {}) {
482 | let current = Buffer.alloc(0);
483 | try {
484 | current = await this.readFilePromise(p);
485 | } catch {
486 | }
487 | if (Buffer.compare(current, content) === 0)
488 | return;
489 | await this.writeFilePromise(p, content, { mode });
490 | }
491 | async changeFileTextPromise(p, content, { automaticNewlines, mode } = {}) {
492 | let current = ``;
493 | try {
494 | current = await this.readFilePromise(p, `utf8`);
495 | } catch {
496 | }
497 | const normalizedContent = automaticNewlines ? normalizeLineEndings(current, content) : content;
498 | if (current === normalizedContent)
499 | return;
500 | await this.writeFilePromise(p, normalizedContent, { mode });
501 | }
502 | changeFileSync(p, content, opts = {}) {
503 | if (Buffer.isBuffer(content)) {
504 | return this.changeFileBufferSync(p, content, opts);
505 | } else {
506 | return this.changeFileTextSync(p, content, opts);
507 | }
508 | }
509 | changeFileBufferSync(p, content, { mode } = {}) {
510 | let current = Buffer.alloc(0);
511 | try {
512 | current = this.readFileSync(p);
513 | } catch {
514 | }
515 | if (Buffer.compare(current, content) === 0)
516 | return;
517 | this.writeFileSync(p, content, { mode });
518 | }
519 | changeFileTextSync(p, content, { automaticNewlines = false, mode } = {}) {
520 | let current = ``;
521 | try {
522 | current = this.readFileSync(p, `utf8`);
523 | } catch {
524 | }
525 | const normalizedContent = automaticNewlines ? normalizeLineEndings(current, content) : content;
526 | if (current === normalizedContent)
527 | return;
528 | this.writeFileSync(p, normalizedContent, { mode });
529 | }
530 | async movePromise(fromP, toP) {
531 | try {
532 | await this.renamePromise(fromP, toP);
533 | } catch (error) {
534 | if (error.code === `EXDEV`) {
535 | await this.copyPromise(toP, fromP);
536 | await this.removePromise(fromP);
537 | } else {
538 | throw error;
539 | }
540 | }
541 | }
542 | moveSync(fromP, toP) {
543 | try {
544 | this.renameSync(fromP, toP);
545 | } catch (error) {
546 | if (error.code === `EXDEV`) {
547 | this.copySync(toP, fromP);
548 | this.removeSync(fromP);
549 | } else {
550 | throw error;
551 | }
552 | }
553 | }
554 | async lockPromise(affectedPath, callback) {
555 | const lockPath = `${affectedPath}.flock`;
556 | const interval = 1e3 / 60;
557 | const startTime = Date.now();
558 | let fd = null;
559 | const isAlive = async () => {
560 | let pid;
561 | try {
562 | [pid] = await this.readJsonPromise(lockPath);
563 | } catch {
564 | return Date.now() - startTime < 500;
565 | }
566 | try {
567 | process.kill(pid, 0);
568 | return true;
569 | } catch {
570 | return false;
571 | }
572 | };
573 | while (fd === null) {
574 | try {
575 | fd = await this.openPromise(lockPath, `wx`);
576 | } catch (error) {
577 | if (error.code === `EEXIST`) {
578 | if (!await isAlive()) {
579 | try {
580 | await this.unlinkPromise(lockPath);
581 | continue;
582 | } catch {
583 | }
584 | }
585 | if (Date.now() - startTime < 60 * 1e3) {
586 | await new Promise((resolve) => setTimeout(resolve, interval));
587 | } else {
588 | throw new Error(`Couldn't acquire a lock in a reasonable time (via ${lockPath})`);
589 | }
590 | } else {
591 | throw error;
592 | }
593 | }
594 | }
595 | await this.writePromise(fd, JSON.stringify([process.pid]));
596 | try {
597 | return await callback();
598 | } finally {
599 | try {
600 | await this.closePromise(fd);
601 | await this.unlinkPromise(lockPath);
602 | } catch {
603 | }
604 | }
605 | }
606 | async readJsonPromise(p) {
607 | const content = await this.readFilePromise(p, `utf8`);
608 | try {
609 | return JSON.parse(content);
610 | } catch (error) {
611 | error.message += ` (in ${p})`;
612 | throw error;
613 | }
614 | }
615 | readJsonSync(p) {
616 | const content = this.readFileSync(p, `utf8`);
617 | try {
618 | return JSON.parse(content);
619 | } catch (error) {
620 | error.message += ` (in ${p})`;
621 | throw error;
622 | }
623 | }
624 | async writeJsonPromise(p, data, { compact = false } = {}) {
625 | const space = compact ? 0 : 2;
626 | return await this.writeFilePromise(p, `${JSON.stringify(data, null, space)}
627 | `);
628 | }
629 | writeJsonSync(p, data, { compact = false } = {}) {
630 | const space = compact ? 0 : 2;
631 | return this.writeFileSync(p, `${JSON.stringify(data, null, space)}
632 | `);
633 | }
634 | async preserveTimePromise(p, cb) {
635 | const stat = await this.lstatPromise(p);
636 | const result = await cb();
637 | if (typeof result !== `undefined`)
638 | p = result;
639 | await this.lutimesPromise(p, stat.atime, stat.mtime);
640 | }
641 | async preserveTimeSync(p, cb) {
642 | const stat = this.lstatSync(p);
643 | const result = cb();
644 | if (typeof result !== `undefined`)
645 | p = result;
646 | this.lutimesSync(p, stat.atime, stat.mtime);
647 | }
648 | }
649 | class BasePortableFakeFS extends FakeFS {
650 | constructor() {
651 | super(ppath);
652 | }
653 | }
654 | function getEndOfLine(content) {
655 | const matches = content.match(/\r?\n/g);
656 | if (matches === null)
657 | return EOL;
658 | const crlf = matches.filter((nl) => nl === `\r
659 | `).length;
660 | const lf = matches.length - crlf;
661 | return crlf > lf ? `\r
662 | ` : `
663 | `;
664 | }
665 | function normalizeLineEndings(originalContent, newContent) {
666 | return newContent.replace(/\r?\n/g, getEndOfLine(originalContent));
667 | }
668 |
669 | class ProxiedFS extends FakeFS {
670 | getExtractHint(hints) {
671 | return this.baseFs.getExtractHint(hints);
672 | }
673 | resolve(path) {
674 | return this.mapFromBase(this.baseFs.resolve(this.mapToBase(path)));
675 | }
676 | getRealPath() {
677 | return this.mapFromBase(this.baseFs.getRealPath());
678 | }
679 | async openPromise(p, flags, mode) {
680 | return this.baseFs.openPromise(this.mapToBase(p), flags, mode);
681 | }
682 | openSync(p, flags, mode) {
683 | return this.baseFs.openSync(this.mapToBase(p), flags, mode);
684 | }
685 | async opendirPromise(p, opts) {
686 | return Object.assign(await this.baseFs.opendirPromise(this.mapToBase(p), opts), { path: p });
687 | }
688 | opendirSync(p, opts) {
689 | return Object.assign(this.baseFs.opendirSync(this.mapToBase(p), opts), { path: p });
690 | }
691 | async readPromise(fd, buffer, offset, length, position) {
692 | return await this.baseFs.readPromise(fd, buffer, offset, length, position);
693 | }
694 | readSync(fd, buffer, offset, length, position) {
695 | return this.baseFs.readSync(fd, buffer, offset, length, position);
696 | }
697 | async writePromise(fd, buffer, offset, length, position) {
698 | if (typeof buffer === `string`) {
699 | return await this.baseFs.writePromise(fd, buffer, offset);
700 | } else {
701 | return await this.baseFs.writePromise(fd, buffer, offset, length, position);
702 | }
703 | }
704 | writeSync(fd, buffer, offset, length, position) {
705 | if (typeof buffer === `string`) {
706 | return this.baseFs.writeSync(fd, buffer, offset);
707 | } else {
708 | return this.baseFs.writeSync(fd, buffer, offset, length, position);
709 | }
710 | }
711 | async closePromise(fd) {
712 | return this.baseFs.closePromise(fd);
713 | }
714 | closeSync(fd) {
715 | this.baseFs.closeSync(fd);
716 | }
717 | createReadStream(p, opts) {
718 | return this.baseFs.createReadStream(p !== null ? this.mapToBase(p) : p, opts);
719 | }
720 | createWriteStream(p, opts) {
721 | return this.baseFs.createWriteStream(p !== null ? this.mapToBase(p) : p, opts);
722 | }
723 | async realpathPromise(p) {
724 | return this.mapFromBase(await this.baseFs.realpathPromise(this.mapToBase(p)));
725 | }
726 | realpathSync(p) {
727 | return this.mapFromBase(this.baseFs.realpathSync(this.mapToBase(p)));
728 | }
729 | async existsPromise(p) {
730 | return this.baseFs.existsPromise(this.mapToBase(p));
731 | }
732 | existsSync(p) {
733 | return this.baseFs.existsSync(this.mapToBase(p));
734 | }
735 | accessSync(p, mode) {
736 | return this.baseFs.accessSync(this.mapToBase(p), mode);
737 | }
738 | async accessPromise(p, mode) {
739 | return this.baseFs.accessPromise(this.mapToBase(p), mode);
740 | }
741 | async statPromise(p, opts) {
742 | return this.baseFs.statPromise(this.mapToBase(p), opts);
743 | }
744 | statSync(p, opts) {
745 | return this.baseFs.statSync(this.mapToBase(p), opts);
746 | }
747 | async fstatPromise(fd, opts) {
748 | return this.baseFs.fstatPromise(fd, opts);
749 | }
750 | fstatSync(fd, opts) {
751 | return this.baseFs.fstatSync(fd, opts);
752 | }
753 | lstatPromise(p, opts) {
754 | return this.baseFs.lstatPromise(this.mapToBase(p), opts);
755 | }
756 | lstatSync(p, opts) {
757 | return this.baseFs.lstatSync(this.mapToBase(p), opts);
758 | }
759 | async fchmodPromise(fd, mask) {
760 | return this.baseFs.fchmodPromise(fd, mask);
761 | }
762 | fchmodSync(fd, mask) {
763 | return this.baseFs.fchmodSync(fd, mask);
764 | }
765 | async chmodPromise(p, mask) {
766 | return this.baseFs.chmodPromise(this.mapToBase(p), mask);
767 | }
768 | chmodSync(p, mask) {
769 | return this.baseFs.chmodSync(this.mapToBase(p), mask);
770 | }
771 | async fchownPromise(fd, uid, gid) {
772 | return this.baseFs.fchownPromise(fd, uid, gid);
773 | }
774 | fchownSync(fd, uid, gid) {
775 | return this.baseFs.fchownSync(fd, uid, gid);
776 | }
777 | async chownPromise(p, uid, gid) {
778 | return this.baseFs.chownPromise(this.mapToBase(p), uid, gid);
779 | }
780 | chownSync(p, uid, gid) {
781 | return this.baseFs.chownSync(this.mapToBase(p), uid, gid);
782 | }
783 | async renamePromise(oldP, newP) {
784 | return this.baseFs.renamePromise(this.mapToBase(oldP), this.mapToBase(newP));
785 | }
786 | renameSync(oldP, newP) {
787 | return this.baseFs.renameSync(this.mapToBase(oldP), this.mapToBase(newP));
788 | }
789 | async copyFilePromise(sourceP, destP, flags = 0) {
790 | return this.baseFs.copyFilePromise(this.mapToBase(sourceP), this.mapToBase(destP), flags);
791 | }
792 | copyFileSync(sourceP, destP, flags = 0) {
793 | return this.baseFs.copyFileSync(this.mapToBase(sourceP), this.mapToBase(destP), flags);
794 | }
795 | async appendFilePromise(p, content, opts) {
796 | return this.baseFs.appendFilePromise(this.fsMapToBase(p), content, opts);
797 | }
798 | appendFileSync(p, content, opts) {
799 | return this.baseFs.appendFileSync(this.fsMapToBase(p), content, opts);
800 | }
801 | async writeFilePromise(p, content, opts) {
802 | return this.baseFs.writeFilePromise(this.fsMapToBase(p), content, opts);
803 | }
804 | writeFileSync(p, content, opts) {
805 | return this.baseFs.writeFileSync(this.fsMapToBase(p), content, opts);
806 | }
807 | async unlinkPromise(p) {
808 | return this.baseFs.unlinkPromise(this.mapToBase(p));
809 | }
810 | unlinkSync(p) {
811 | return this.baseFs.unlinkSync(this.mapToBase(p));
812 | }
813 | async utimesPromise(p, atime, mtime) {
814 | return this.baseFs.utimesPromise(this.mapToBase(p), atime, mtime);
815 | }
816 | utimesSync(p, atime, mtime) {
817 | return this.baseFs.utimesSync(this.mapToBase(p), atime, mtime);
818 | }
819 | async lutimesPromise(p, atime, mtime) {
820 | return this.baseFs.lutimesPromise(this.mapToBase(p), atime, mtime);
821 | }
822 | lutimesSync(p, atime, mtime) {
823 | return this.baseFs.lutimesSync(this.mapToBase(p), atime, mtime);
824 | }
825 | async mkdirPromise(p, opts) {
826 | return this.baseFs.mkdirPromise(this.mapToBase(p), opts);
827 | }
828 | mkdirSync(p, opts) {
829 | return this.baseFs.mkdirSync(this.mapToBase(p), opts);
830 | }
831 | async rmdirPromise(p, opts) {
832 | return this.baseFs.rmdirPromise(this.mapToBase(p), opts);
833 | }
834 | rmdirSync(p, opts) {
835 | return this.baseFs.rmdirSync(this.mapToBase(p), opts);
836 | }
837 | async rmPromise(p, opts) {
838 | return this.baseFs.rmPromise(this.mapToBase(p), opts);
839 | }
840 | rmSync(p, opts) {
841 | return this.baseFs.rmSync(this.mapToBase(p), opts);
842 | }
843 | async linkPromise(existingP, newP) {
844 | return this.baseFs.linkPromise(this.mapToBase(existingP), this.mapToBase(newP));
845 | }
846 | linkSync(existingP, newP) {
847 | return this.baseFs.linkSync(this.mapToBase(existingP), this.mapToBase(newP));
848 | }
849 | async symlinkPromise(target, p, type) {
850 | const mappedP = this.mapToBase(p);
851 | if (this.pathUtils.isAbsolute(target))
852 | return this.baseFs.symlinkPromise(this.mapToBase(target), mappedP, type);
853 | const mappedAbsoluteTarget = this.mapToBase(this.pathUtils.join(this.pathUtils.dirname(p), target));
854 | const mappedTarget = this.baseFs.pathUtils.relative(this.baseFs.pathUtils.dirname(mappedP), mappedAbsoluteTarget);
855 | return this.baseFs.symlinkPromise(mappedTarget, mappedP, type);
856 | }
857 | symlinkSync(target, p, type) {
858 | const mappedP = this.mapToBase(p);
859 | if (this.pathUtils.isAbsolute(target))
860 | return this.baseFs.symlinkSync(this.mapToBase(target), mappedP, type);
861 | const mappedAbsoluteTarget = this.mapToBase(this.pathUtils.join(this.pathUtils.dirname(p), target));
862 | const mappedTarget = this.baseFs.pathUtils.relative(this.baseFs.pathUtils.dirname(mappedP), mappedAbsoluteTarget);
863 | return this.baseFs.symlinkSync(mappedTarget, mappedP, type);
864 | }
865 | async readFilePromise(p, encoding) {
866 | return this.baseFs.readFilePromise(this.fsMapToBase(p), encoding);
867 | }
868 | readFileSync(p, encoding) {
869 | return this.baseFs.readFileSync(this.fsMapToBase(p), encoding);
870 | }
871 | readdirPromise(p, opts) {
872 | return this.baseFs.readdirPromise(this.mapToBase(p), opts);
873 | }
874 | readdirSync(p, opts) {
875 | return this.baseFs.readdirSync(this.mapToBase(p), opts);
876 | }
877 | async readlinkPromise(p) {
878 | return this.mapFromBase(await this.baseFs.readlinkPromise(this.mapToBase(p)));
879 | }
880 | readlinkSync(p) {
881 | return this.mapFromBase(this.baseFs.readlinkSync(this.mapToBase(p)));
882 | }
883 | async truncatePromise(p, len) {
884 | return this.baseFs.truncatePromise(this.mapToBase(p), len);
885 | }
886 | truncateSync(p, len) {
887 | return this.baseFs.truncateSync(this.mapToBase(p), len);
888 | }
889 | async ftruncatePromise(fd, len) {
890 | return this.baseFs.ftruncatePromise(fd, len);
891 | }
892 | ftruncateSync(fd, len) {
893 | return this.baseFs.ftruncateSync(fd, len);
894 | }
895 | watch(p, a, b) {
896 | return this.baseFs.watch(
897 | this.mapToBase(p),
898 | // @ts-expect-error
899 | a,
900 | b
901 | );
902 | }
903 | watchFile(p, a, b) {
904 | return this.baseFs.watchFile(
905 | this.mapToBase(p),
906 | // @ts-expect-error
907 | a,
908 | b
909 | );
910 | }
911 | unwatchFile(p, cb) {
912 | return this.baseFs.unwatchFile(this.mapToBase(p), cb);
913 | }
914 | fsMapToBase(p) {
915 | if (typeof p === `number`) {
916 | return p;
917 | } else {
918 | return this.mapToBase(p);
919 | }
920 | }
921 | }
922 |
923 | function direntToPortable(dirent) {
924 | const portableDirent = dirent;
925 | if (typeof dirent.path === `string`)
926 | portableDirent.path = npath.toPortablePath(dirent.path);
927 | return portableDirent;
928 | }
929 | class NodeFS extends BasePortableFakeFS {
930 | realFs;
931 | constructor(realFs = fs) {
932 | super();
933 | this.realFs = realFs;
934 | }
935 | getExtractHint() {
936 | return false;
937 | }
938 | getRealPath() {
939 | return PortablePath.root;
940 | }
941 | resolve(p) {
942 | return ppath.resolve(p);
943 | }
944 | async openPromise(p, flags, mode) {
945 | return await new Promise((resolve, reject) => {
946 | this.realFs.open(npath.fromPortablePath(p), flags, mode, this.makeCallback(resolve, reject));
947 | });
948 | }
949 | openSync(p, flags, mode) {
950 | return this.realFs.openSync(npath.fromPortablePath(p), flags, mode);
951 | }
952 | async opendirPromise(p, opts) {
953 | return await new Promise((resolve, reject) => {
954 | if (typeof opts !== `undefined`) {
955 | this.realFs.opendir(npath.fromPortablePath(p), opts, this.makeCallback(resolve, reject));
956 | } else {
957 | this.realFs.opendir(npath.fromPortablePath(p), this.makeCallback(resolve, reject));
958 | }
959 | }).then((dir) => {
960 | const dirWithFixedPath = dir;
961 | Object.defineProperty(dirWithFixedPath, `path`, {
962 | value: p,
963 | configurable: true,
964 | writable: true
965 | });
966 | return dirWithFixedPath;
967 | });
968 | }
969 | opendirSync(p, opts) {
970 | const dir = typeof opts !== `undefined` ? this.realFs.opendirSync(npath.fromPortablePath(p), opts) : this.realFs.opendirSync(npath.fromPortablePath(p));
971 | const dirWithFixedPath = dir;
972 | Object.defineProperty(dirWithFixedPath, `path`, {
973 | value: p,
974 | configurable: true,
975 | writable: true
976 | });
977 | return dirWithFixedPath;
978 | }
979 | async readPromise(fd, buffer, offset = 0, length = 0, position = -1) {
980 | return await new Promise((resolve, reject) => {
981 | this.realFs.read(fd, buffer, offset, length, position, (error, bytesRead) => {
982 | if (error) {
983 | reject(error);
984 | } else {
985 | resolve(bytesRead);
986 | }
987 | });
988 | });
989 | }
990 | readSync(fd, buffer, offset, length, position) {
991 | return this.realFs.readSync(fd, buffer, offset, length, position);
992 | }
993 | async writePromise(fd, buffer, offset, length, position) {
994 | return await new Promise((resolve, reject) => {
995 | if (typeof buffer === `string`) {
996 | return this.realFs.write(fd, buffer, offset, this.makeCallback(resolve, reject));
997 | } else {
998 | return this.realFs.write(fd, buffer, offset, length, position, this.makeCallback(resolve, reject));
999 | }
1000 | });
1001 | }
1002 | writeSync(fd, buffer, offset, length, position) {
1003 | if (typeof buffer === `string`) {
1004 | return this.realFs.writeSync(fd, buffer, offset);
1005 | } else {
1006 | return this.realFs.writeSync(fd, buffer, offset, length, position);
1007 | }
1008 | }
1009 | async closePromise(fd) {
1010 | await new Promise((resolve, reject) => {
1011 | this.realFs.close(fd, this.makeCallback(resolve, reject));
1012 | });
1013 | }
1014 | closeSync(fd) {
1015 | this.realFs.closeSync(fd);
1016 | }
1017 | createReadStream(p, opts) {
1018 | const realPath = p !== null ? npath.fromPortablePath(p) : p;
1019 | return this.realFs.createReadStream(realPath, opts);
1020 | }
1021 | createWriteStream(p, opts) {
1022 | const realPath = p !== null ? npath.fromPortablePath(p) : p;
1023 | return this.realFs.createWriteStream(realPath, opts);
1024 | }
1025 | async realpathPromise(p) {
1026 | return await new Promise((resolve, reject) => {
1027 | this.realFs.realpath(npath.fromPortablePath(p), {}, this.makeCallback(resolve, reject));
1028 | }).then((path) => {
1029 | return npath.toPortablePath(path);
1030 | });
1031 | }
1032 | realpathSync(p) {
1033 | return npath.toPortablePath(this.realFs.realpathSync(npath.fromPortablePath(p), {}));
1034 | }
1035 | async existsPromise(p) {
1036 | return await new Promise((resolve) => {
1037 | this.realFs.exists(npath.fromPortablePath(p), resolve);
1038 | });
1039 | }
1040 | accessSync(p, mode) {
1041 | return this.realFs.accessSync(npath.fromPortablePath(p), mode);
1042 | }
1043 | async accessPromise(p, mode) {
1044 | return await new Promise((resolve, reject) => {
1045 | this.realFs.access(npath.fromPortablePath(p), mode, this.makeCallback(resolve, reject));
1046 | });
1047 | }
1048 | existsSync(p) {
1049 | return this.realFs.existsSync(npath.fromPortablePath(p));
1050 | }
1051 | async statPromise(p, opts) {
1052 | return await new Promise((resolve, reject) => {
1053 | if (opts) {
1054 | this.realFs.stat(npath.fromPortablePath(p), opts, this.makeCallback(resolve, reject));
1055 | } else {
1056 | this.realFs.stat(npath.fromPortablePath(p), this.makeCallback(resolve, reject));
1057 | }
1058 | });
1059 | }
1060 | statSync(p, opts) {
1061 | if (opts) {
1062 | return this.realFs.statSync(npath.fromPortablePath(p), opts);
1063 | } else {
1064 | return this.realFs.statSync(npath.fromPortablePath(p));
1065 | }
1066 | }
1067 | async fstatPromise(fd, opts) {
1068 | return await new Promise((resolve, reject) => {
1069 | if (opts) {
1070 | this.realFs.fstat(fd, opts, this.makeCallback(resolve, reject));
1071 | } else {
1072 | this.realFs.fstat(fd, this.makeCallback(resolve, reject));
1073 | }
1074 | });
1075 | }
1076 | fstatSync(fd, opts) {
1077 | if (opts) {
1078 | return this.realFs.fstatSync(fd, opts);
1079 | } else {
1080 | return this.realFs.fstatSync(fd);
1081 | }
1082 | }
1083 | async lstatPromise(p, opts) {
1084 | return await new Promise((resolve, reject) => {
1085 | if (opts) {
1086 | this.realFs.lstat(npath.fromPortablePath(p), opts, this.makeCallback(resolve, reject));
1087 | } else {
1088 | this.realFs.lstat(npath.fromPortablePath(p), this.makeCallback(resolve, reject));
1089 | }
1090 | });
1091 | }
1092 | lstatSync(p, opts) {
1093 | if (opts) {
1094 | return this.realFs.lstatSync(npath.fromPortablePath(p), opts);
1095 | } else {
1096 | return this.realFs.lstatSync(npath.fromPortablePath(p));
1097 | }
1098 | }
1099 | async fchmodPromise(fd, mask) {
1100 | return await new Promise((resolve, reject) => {
1101 | this.realFs.fchmod(fd, mask, this.makeCallback(resolve, reject));
1102 | });
1103 | }
1104 | fchmodSync(fd, mask) {
1105 | return this.realFs.fchmodSync(fd, mask);
1106 | }
1107 | async chmodPromise(p, mask) {
1108 | return await new Promise((resolve, reject) => {
1109 | this.realFs.chmod(npath.fromPortablePath(p), mask, this.makeCallback(resolve, reject));
1110 | });
1111 | }
1112 | chmodSync(p, mask) {
1113 | return this.realFs.chmodSync(npath.fromPortablePath(p), mask);
1114 | }
1115 | async fchownPromise(fd, uid, gid) {
1116 | return await new Promise((resolve, reject) => {
1117 | this.realFs.fchown(fd, uid, gid, this.makeCallback(resolve, reject));
1118 | });
1119 | }
1120 | fchownSync(fd, uid, gid) {
1121 | return this.realFs.fchownSync(fd, uid, gid);
1122 | }
1123 | async chownPromise(p, uid, gid) {
1124 | return await new Promise((resolve, reject) => {
1125 | this.realFs.chown(npath.fromPortablePath(p), uid, gid, this.makeCallback(resolve, reject));
1126 | });
1127 | }
1128 | chownSync(p, uid, gid) {
1129 | return this.realFs.chownSync(npath.fromPortablePath(p), uid, gid);
1130 | }
1131 | async renamePromise(oldP, newP) {
1132 | return await new Promise((resolve, reject) => {
1133 | this.realFs.rename(npath.fromPortablePath(oldP), npath.fromPortablePath(newP), this.makeCallback(resolve, reject));
1134 | });
1135 | }
1136 | renameSync(oldP, newP) {
1137 | return this.realFs.renameSync(npath.fromPortablePath(oldP), npath.fromPortablePath(newP));
1138 | }
1139 | async copyFilePromise(sourceP, destP, flags = 0) {
1140 | return await new Promise((resolve, reject) => {
1141 | this.realFs.copyFile(npath.fromPortablePath(sourceP), npath.fromPortablePath(destP), flags, this.makeCallback(resolve, reject));
1142 | });
1143 | }
1144 | copyFileSync(sourceP, destP, flags = 0) {
1145 | return this.realFs.copyFileSync(npath.fromPortablePath(sourceP), npath.fromPortablePath(destP), flags);
1146 | }
1147 | async appendFilePromise(p, content, opts) {
1148 | return await new Promise((resolve, reject) => {
1149 | const fsNativePath = typeof p === `string` ? npath.fromPortablePath(p) : p;
1150 | if (opts) {
1151 | this.realFs.appendFile(fsNativePath, content, opts, this.makeCallback(resolve, reject));
1152 | } else {
1153 | this.realFs.appendFile(fsNativePath, content, this.makeCallback(resolve, reject));
1154 | }
1155 | });
1156 | }
1157 | appendFileSync(p, content, opts) {
1158 | const fsNativePath = typeof p === `string` ? npath.fromPortablePath(p) : p;
1159 | if (opts) {
1160 | this.realFs.appendFileSync(fsNativePath, content, opts);
1161 | } else {
1162 | this.realFs.appendFileSync(fsNativePath, content);
1163 | }
1164 | }
1165 | async writeFilePromise(p, content, opts) {
1166 | return await new Promise((resolve, reject) => {
1167 | const fsNativePath = typeof p === `string` ? npath.fromPortablePath(p) : p;
1168 | if (opts) {
1169 | this.realFs.writeFile(fsNativePath, content, opts, this.makeCallback(resolve, reject));
1170 | } else {
1171 | this.realFs.writeFile(fsNativePath, content, this.makeCallback(resolve, reject));
1172 | }
1173 | });
1174 | }
1175 | writeFileSync(p, content, opts) {
1176 | const fsNativePath = typeof p === `string` ? npath.fromPortablePath(p) : p;
1177 | if (opts) {
1178 | this.realFs.writeFileSync(fsNativePath, content, opts);
1179 | } else {
1180 | this.realFs.writeFileSync(fsNativePath, content);
1181 | }
1182 | }
1183 | async unlinkPromise(p) {
1184 | return await new Promise((resolve, reject) => {
1185 | this.realFs.unlink(npath.fromPortablePath(p), this.makeCallback(resolve, reject));
1186 | });
1187 | }
1188 | unlinkSync(p) {
1189 | return this.realFs.unlinkSync(npath.fromPortablePath(p));
1190 | }
1191 | async utimesPromise(p, atime, mtime) {
1192 | return await new Promise((resolve, reject) => {
1193 | this.realFs.utimes(npath.fromPortablePath(p), atime, mtime, this.makeCallback(resolve, reject));
1194 | });
1195 | }
1196 | utimesSync(p, atime, mtime) {
1197 | this.realFs.utimesSync(npath.fromPortablePath(p), atime, mtime);
1198 | }
1199 | async lutimesPromise(p, atime, mtime) {
1200 | return await new Promise((resolve, reject) => {
1201 | this.realFs.lutimes(npath.fromPortablePath(p), atime, mtime, this.makeCallback(resolve, reject));
1202 | });
1203 | }
1204 | lutimesSync(p, atime, mtime) {
1205 | this.realFs.lutimesSync(npath.fromPortablePath(p), atime, mtime);
1206 | }
1207 | async mkdirPromise(p, opts) {
1208 | return await new Promise((resolve, reject) => {
1209 | this.realFs.mkdir(npath.fromPortablePath(p), opts, this.makeCallback(resolve, reject));
1210 | });
1211 | }
1212 | mkdirSync(p, opts) {
1213 | return this.realFs.mkdirSync(npath.fromPortablePath(p), opts);
1214 | }
1215 | async rmdirPromise(p, opts) {
1216 | return await new Promise((resolve, reject) => {
1217 | if (opts) {
1218 | this.realFs.rmdir(npath.fromPortablePath(p), opts, this.makeCallback(resolve, reject));
1219 | } else {
1220 | this.realFs.rmdir(npath.fromPortablePath(p), this.makeCallback(resolve, reject));
1221 | }
1222 | });
1223 | }
1224 | rmdirSync(p, opts) {
1225 | return this.realFs.rmdirSync(npath.fromPortablePath(p), opts);
1226 | }
1227 | async rmPromise(p, opts) {
1228 | return await new Promise((resolve, reject) => {
1229 | if (opts) {
1230 | this.realFs.rm(npath.fromPortablePath(p), opts, this.makeCallback(resolve, reject));
1231 | } else {
1232 | this.realFs.rm(npath.fromPortablePath(p), this.makeCallback(resolve, reject));
1233 | }
1234 | });
1235 | }
1236 | rmSync(p, opts) {
1237 | return this.realFs.rmSync(npath.fromPortablePath(p), opts);
1238 | }
1239 | async linkPromise(existingP, newP) {
1240 | return await new Promise((resolve, reject) => {
1241 | this.realFs.link(npath.fromPortablePath(existingP), npath.fromPortablePath(newP), this.makeCallback(resolve, reject));
1242 | });
1243 | }
1244 | linkSync(existingP, newP) {
1245 | return this.realFs.linkSync(npath.fromPortablePath(existingP), npath.fromPortablePath(newP));
1246 | }
1247 | async symlinkPromise(target, p, type) {
1248 | return await new Promise((resolve, reject) => {
1249 | this.realFs.symlink(npath.fromPortablePath(target.replace(/\/+$/, ``)), npath.fromPortablePath(p), type, this.makeCallback(resolve, reject));
1250 | });
1251 | }
1252 | symlinkSync(target, p, type) {
1253 | return this.realFs.symlinkSync(npath.fromPortablePath(target.replace(/\/+$/, ``)), npath.fromPortablePath(p), type);
1254 | }
1255 | async readFilePromise(p, encoding) {
1256 | return await new Promise((resolve, reject) => {
1257 | const fsNativePath = typeof p === `string` ? npath.fromPortablePath(p) : p;
1258 | this.realFs.readFile(fsNativePath, encoding, this.makeCallback(resolve, reject));
1259 | });
1260 | }
1261 | readFileSync(p, encoding) {
1262 | const fsNativePath = typeof p === `string` ? npath.fromPortablePath(p) : p;
1263 | return this.realFs.readFileSync(fsNativePath, encoding);
1264 | }
1265 | async readdirPromise(p, opts) {
1266 | return await new Promise((resolve, reject) => {
1267 | if (opts) {
1268 | if (opts.recursive && process.platform === `win32`) {
1269 | if (opts.withFileTypes) {
1270 | this.realFs.readdir(npath.fromPortablePath(p), opts, this.makeCallback((results) => resolve(results.map(direntToPortable)), reject));
1271 | } else {
1272 | this.realFs.readdir(npath.fromPortablePath(p), opts, this.makeCallback((results) => resolve(results.map(npath.toPortablePath)), reject));
1273 | }
1274 | } else {
1275 | this.realFs.readdir(npath.fromPortablePath(p), opts, this.makeCallback(resolve, reject));
1276 | }
1277 | } else {
1278 | this.realFs.readdir(npath.fromPortablePath(p), this.makeCallback(resolve, reject));
1279 | }
1280 | });
1281 | }
1282 | readdirSync(p, opts) {
1283 | if (opts) {
1284 | if (opts.recursive && process.platform === `win32`) {
1285 | if (opts.withFileTypes) {
1286 | return this.realFs.readdirSync(npath.fromPortablePath(p), opts).map(direntToPortable);
1287 | } else {
1288 | return this.realFs.readdirSync(npath.fromPortablePath(p), opts).map(npath.toPortablePath);
1289 | }
1290 | } else {
1291 | return this.realFs.readdirSync(npath.fromPortablePath(p), opts);
1292 | }
1293 | } else {
1294 | return this.realFs.readdirSync(npath.fromPortablePath(p));
1295 | }
1296 | }
1297 | async readlinkPromise(p) {
1298 | return await new Promise((resolve, reject) => {
1299 | this.realFs.readlink(npath.fromPortablePath(p), this.makeCallback(resolve, reject));
1300 | }).then((path) => {
1301 | return npath.toPortablePath(path);
1302 | });
1303 | }
1304 | readlinkSync(p) {
1305 | return npath.toPortablePath(this.realFs.readlinkSync(npath.fromPortablePath(p)));
1306 | }
1307 | async truncatePromise(p, len) {
1308 | return await new Promise((resolve, reject) => {
1309 | this.realFs.truncate(npath.fromPortablePath(p), len, this.makeCallback(resolve, reject));
1310 | });
1311 | }
1312 | truncateSync(p, len) {
1313 | return this.realFs.truncateSync(npath.fromPortablePath(p), len);
1314 | }
1315 | async ftruncatePromise(fd, len) {
1316 | return await new Promise((resolve, reject) => {
1317 | this.realFs.ftruncate(fd, len, this.makeCallback(resolve, reject));
1318 | });
1319 | }
1320 | ftruncateSync(fd, len) {
1321 | return this.realFs.ftruncateSync(fd, len);
1322 | }
1323 | watch(p, a, b) {
1324 | return this.realFs.watch(
1325 | npath.fromPortablePath(p),
1326 | // @ts-expect-error
1327 | a,
1328 | b
1329 | );
1330 | }
1331 | watchFile(p, a, b) {
1332 | return this.realFs.watchFile(
1333 | npath.fromPortablePath(p),
1334 | // @ts-expect-error
1335 | a,
1336 | b
1337 | );
1338 | }
1339 | unwatchFile(p, cb) {
1340 | return this.realFs.unwatchFile(npath.fromPortablePath(p), cb);
1341 | }
1342 | makeCallback(resolve, reject) {
1343 | return (err, result) => {
1344 | if (err) {
1345 | reject(err);
1346 | } else {
1347 | resolve(result);
1348 | }
1349 | };
1350 | }
1351 | }
1352 |
1353 | const NUMBER_REGEXP = /^[0-9]+$/;
1354 | const VIRTUAL_REGEXP = /^(\/(?:[^/]+\/)*?(?:\$\$virtual|__virtual__))((?:\/((?:[^/]+-)?[a-f0-9]+)(?:\/([^/]+))?)?((?:\/.*)?))$/;
1355 | const VALID_COMPONENT = /^([^/]+-)?[a-f0-9]+$/;
1356 | class VirtualFS extends ProxiedFS {
1357 | baseFs;
1358 | static makeVirtualPath(base, component, to) {
1359 | if (ppath.basename(base) !== `__virtual__`)
1360 | throw new Error(`Assertion failed: Virtual folders must be named "__virtual__"`);
1361 | if (!ppath.basename(component).match(VALID_COMPONENT))
1362 | throw new Error(`Assertion failed: Virtual components must be ended by an hexadecimal hash`);
1363 | const target = ppath.relative(ppath.dirname(base), to);
1364 | const segments = target.split(`/`);
1365 | let depth = 0;
1366 | while (depth < segments.length && segments[depth] === `..`)
1367 | depth += 1;
1368 | const finalSegments = segments.slice(depth);
1369 | const fullVirtualPath = ppath.join(base, component, String(depth), ...finalSegments);
1370 | return fullVirtualPath;
1371 | }
1372 | static resolveVirtual(p) {
1373 | const match = p.match(VIRTUAL_REGEXP);
1374 | if (!match || !match[3] && match[5])
1375 | return p;
1376 | const target = ppath.dirname(match[1]);
1377 | if (!match[3] || !match[4])
1378 | return target;
1379 | const isnum = NUMBER_REGEXP.test(match[4]);
1380 | if (!isnum)
1381 | return p;
1382 | const depth = Number(match[4]);
1383 | const backstep = `../`.repeat(depth);
1384 | const subpath = match[5] || `.`;
1385 | return VirtualFS.resolveVirtual(ppath.join(target, backstep, subpath));
1386 | }
1387 | constructor({ baseFs = new NodeFS() } = {}) {
1388 | super(ppath);
1389 | this.baseFs = baseFs;
1390 | }
1391 | getExtractHint(hints) {
1392 | return this.baseFs.getExtractHint(hints);
1393 | }
1394 | getRealPath() {
1395 | return this.baseFs.getRealPath();
1396 | }
1397 | realpathSync(p) {
1398 | const match = p.match(VIRTUAL_REGEXP);
1399 | if (!match)
1400 | return this.baseFs.realpathSync(p);
1401 | if (!match[5])
1402 | return p;
1403 | const realpath = this.baseFs.realpathSync(this.mapToBase(p));
1404 | return VirtualFS.makeVirtualPath(match[1], match[3], realpath);
1405 | }
1406 | async realpathPromise(p) {
1407 | const match = p.match(VIRTUAL_REGEXP);
1408 | if (!match)
1409 | return await this.baseFs.realpathPromise(p);
1410 | if (!match[5])
1411 | return p;
1412 | const realpath = await this.baseFs.realpathPromise(this.mapToBase(p));
1413 | return VirtualFS.makeVirtualPath(match[1], match[3], realpath);
1414 | }
1415 | mapToBase(p) {
1416 | if (p === ``)
1417 | return p;
1418 | if (this.pathUtils.isAbsolute(p))
1419 | return VirtualFS.resolveVirtual(p);
1420 | const resolvedRoot = VirtualFS.resolveVirtual(this.baseFs.resolve(PortablePath.dot));
1421 | const resolvedP = VirtualFS.resolveVirtual(this.baseFs.resolve(p));
1422 | return ppath.relative(resolvedRoot, resolvedP) || PortablePath.dot;
1423 | }
1424 | mapFromBase(p) {
1425 | return p;
1426 | }
1427 | }
1428 |
1429 | const URL = Number(process.versions.node.split('.', 1)[0]) < 20 ? URL$1 : globalThis.URL;
1430 |
1431 | const [major, minor] = process.versions.node.split(`.`).map((value) => parseInt(value, 10));
1432 | const WATCH_MODE_MESSAGE_USES_ARRAYS = major > 19 || major === 19 && minor >= 2 || major === 18 && minor >= 13;
1433 | const HAS_LAZY_LOADED_TRANSLATORS = major === 20 && minor < 6 || major === 19 && minor >= 3;
1434 | const SUPPORTS_IMPORT_ATTRIBUTES = major >= 21 || major === 20 && minor >= 10 || major === 18 && minor >= 20;
1435 | const SUPPORTS_IMPORT_ATTRIBUTES_ONLY = major >= 22;
1436 |
1437 | function readPackageScope(checkPath) {
1438 | const rootSeparatorIndex = checkPath.indexOf(npath.sep);
1439 | let separatorIndex;
1440 | do {
1441 | separatorIndex = checkPath.lastIndexOf(npath.sep);
1442 | checkPath = checkPath.slice(0, separatorIndex);
1443 | if (checkPath.endsWith(`${npath.sep}node_modules`))
1444 | return false;
1445 | const pjson = readPackage(checkPath + npath.sep);
1446 | if (pjson) {
1447 | return {
1448 | data: pjson,
1449 | path: checkPath
1450 | };
1451 | }
1452 | } while (separatorIndex > rootSeparatorIndex);
1453 | return false;
1454 | }
1455 | function readPackage(requestPath) {
1456 | const jsonPath = npath.resolve(requestPath, `package.json`);
1457 | if (!fs.existsSync(jsonPath))
1458 | return null;
1459 | return JSON.parse(fs.readFileSync(jsonPath, `utf8`));
1460 | }
1461 |
1462 | async function tryReadFile$1(path2) {
1463 | try {
1464 | return await fs.promises.readFile(path2, `utf8`);
1465 | } catch (error) {
1466 | if (error.code === `ENOENT`)
1467 | return null;
1468 | throw error;
1469 | }
1470 | }
1471 | function tryParseURL(str, base) {
1472 | try {
1473 | return new URL(str, base);
1474 | } catch {
1475 | return null;
1476 | }
1477 | }
1478 | let entrypointPath = null;
1479 | function setEntrypointPath(file) {
1480 | entrypointPath = file;
1481 | }
1482 | function getFileFormat(filepath) {
1483 | const ext = path.extname(filepath);
1484 | switch (ext) {
1485 | case `.mjs`: {
1486 | return `module`;
1487 | }
1488 | case `.cjs`: {
1489 | return `commonjs`;
1490 | }
1491 | case `.wasm`: {
1492 | throw new Error(
1493 | `Unknown file extension ".wasm" for ${filepath}`
1494 | );
1495 | }
1496 | case `.json`: {
1497 | return `json`;
1498 | }
1499 | case `.js`: {
1500 | const pkg = readPackageScope(filepath);
1501 | if (!pkg)
1502 | return `commonjs`;
1503 | return pkg.data.type ?? `commonjs`;
1504 | }
1505 | default: {
1506 | if (entrypointPath !== filepath)
1507 | return null;
1508 | const pkg = readPackageScope(filepath);
1509 | if (!pkg)
1510 | return `commonjs`;
1511 | if (pkg.data.type === `module`)
1512 | return null;
1513 | return pkg.data.type ?? `commonjs`;
1514 | }
1515 | }
1516 | }
1517 |
1518 | async function load$1(urlString, context, nextLoad) {
1519 | const url = tryParseURL(urlString);
1520 | if (url?.protocol !== `file:`)
1521 | return nextLoad(urlString, context, nextLoad);
1522 | const filePath = fileURLToPath(url);
1523 | const format = getFileFormat(filePath);
1524 | if (!format)
1525 | return nextLoad(urlString, context, nextLoad);
1526 | if (format === `json`) {
1527 | if (SUPPORTS_IMPORT_ATTRIBUTES_ONLY) {
1528 | if (context.importAttributes?.type !== `json`) {
1529 | const err = new TypeError(`[ERR_IMPORT_ATTRIBUTE_MISSING]: Module "${urlString}" needs an import attribute of "type: json"`);
1530 | err.code = `ERR_IMPORT_ATTRIBUTE_MISSING`;
1531 | throw err;
1532 | }
1533 | } else {
1534 | const type = `importAttributes` in context ? context.importAttributes?.type : context.importAssertions?.type;
1535 | if (type !== `json`) {
1536 | const err = new TypeError(`[ERR_IMPORT_ASSERTION_TYPE_MISSING]: Module "${urlString}" needs an import ${SUPPORTS_IMPORT_ATTRIBUTES ? `attribute` : `assertion`} of type "json"`);
1537 | err.code = `ERR_IMPORT_ASSERTION_TYPE_MISSING`;
1538 | throw err;
1539 | }
1540 | }
1541 | }
1542 | if (process.env.WATCH_REPORT_DEPENDENCIES && process.send) {
1543 | const pathToSend = pathToFileURL(
1544 | npath.fromPortablePath(
1545 | VirtualFS.resolveVirtual(npath.toPortablePath(filePath))
1546 | )
1547 | ).href;
1548 | process.send({
1549 | "watch:import": WATCH_MODE_MESSAGE_USES_ARRAYS ? [pathToSend] : pathToSend
1550 | });
1551 | }
1552 | return {
1553 | format,
1554 | source: format === `commonjs` ? void 0 : await fs.promises.readFile(filePath, `utf8`),
1555 | shortCircuit: true
1556 | };
1557 | }
1558 |
1559 | const ArrayIsArray = Array.isArray;
1560 | const JSONStringify = JSON.stringify;
1561 | const ObjectGetOwnPropertyNames = Object.getOwnPropertyNames;
1562 | const ObjectPrototypeHasOwnProperty = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop);
1563 | const RegExpPrototypeExec = (obj, string) => RegExp.prototype.exec.call(obj, string);
1564 | const RegExpPrototypeSymbolReplace = (obj, ...rest) => RegExp.prototype[Symbol.replace].apply(obj, rest);
1565 | const StringPrototypeEndsWith = (str, ...rest) => String.prototype.endsWith.apply(str, rest);
1566 | const StringPrototypeIncludes = (str, ...rest) => String.prototype.includes.apply(str, rest);
1567 | const StringPrototypeLastIndexOf = (str, ...rest) => String.prototype.lastIndexOf.apply(str, rest);
1568 | const StringPrototypeIndexOf = (str, ...rest) => String.prototype.indexOf.apply(str, rest);
1569 | const StringPrototypeReplace = (str, ...rest) => String.prototype.replace.apply(str, rest);
1570 | const StringPrototypeSlice = (str, ...rest) => String.prototype.slice.apply(str, rest);
1571 | const StringPrototypeStartsWith = (str, ...rest) => String.prototype.startsWith.apply(str, rest);
1572 | const SafeMap = Map;
1573 | const JSONParse = JSON.parse;
1574 |
1575 | function createErrorType(code, messageCreator, errorType) {
1576 | return class extends errorType {
1577 | constructor(...args) {
1578 | super(messageCreator(...args));
1579 | this.code = code;
1580 | this.name = `${errorType.name} [${code}]`;
1581 | }
1582 | };
1583 | }
1584 | const ERR_PACKAGE_IMPORT_NOT_DEFINED = createErrorType(
1585 | `ERR_PACKAGE_IMPORT_NOT_DEFINED`,
1586 | (specifier, packagePath, base) => {
1587 | return `Package import specifier "${specifier}" is not defined${packagePath ? ` in package ${packagePath}package.json` : ``} imported from ${base}`;
1588 | },
1589 | TypeError
1590 | );
1591 | const ERR_INVALID_MODULE_SPECIFIER = createErrorType(
1592 | `ERR_INVALID_MODULE_SPECIFIER`,
1593 | (request, reason, base = void 0) => {
1594 | return `Invalid module "${request}" ${reason}${base ? ` imported from ${base}` : ``}`;
1595 | },
1596 | TypeError
1597 | );
1598 | const ERR_INVALID_PACKAGE_TARGET = createErrorType(
1599 | `ERR_INVALID_PACKAGE_TARGET`,
1600 | (pkgPath, key, target, isImport = false, base = void 0) => {
1601 | const relError = typeof target === `string` && !isImport && target.length && !StringPrototypeStartsWith(target, `./`);
1602 | if (key === `.`) {
1603 | assert(isImport === false);
1604 | return `Invalid "exports" main target ${JSONStringify(target)} defined in the package config ${pkgPath}package.json${base ? ` imported from ${base}` : ``}${relError ? `; targets must start with "./"` : ``}`;
1605 | }
1606 | return `Invalid "${isImport ? `imports` : `exports`}" target ${JSONStringify(
1607 | target
1608 | )} defined for '${key}' in the package config ${pkgPath}package.json${base ? ` imported from ${base}` : ``}${relError ? `; targets must start with "./"` : ``}`;
1609 | },
1610 | Error
1611 | );
1612 | const ERR_INVALID_PACKAGE_CONFIG = createErrorType(
1613 | `ERR_INVALID_PACKAGE_CONFIG`,
1614 | (path, base, message) => {
1615 | return `Invalid package config ${path}${base ? ` while importing ${base}` : ``}${message ? `. ${message}` : ``}`;
1616 | },
1617 | Error
1618 | );
1619 |
1620 | function filterOwnProperties(source, keys) {
1621 | const filtered = /* @__PURE__ */ Object.create(null);
1622 | for (let i = 0; i < keys.length; i++) {
1623 | const key = keys[i];
1624 | if (ObjectPrototypeHasOwnProperty(source, key)) {
1625 | filtered[key] = source[key];
1626 | }
1627 | }
1628 | return filtered;
1629 | }
1630 |
1631 | const packageJSONCache = new SafeMap();
1632 | function getPackageConfig(path, specifier, base, readFileSyncFn) {
1633 | const existing = packageJSONCache.get(path);
1634 | if (existing !== void 0) {
1635 | return existing;
1636 | }
1637 | const source = readFileSyncFn(path);
1638 | if (source === void 0) {
1639 | const packageConfig2 = {
1640 | pjsonPath: path,
1641 | exists: false,
1642 | main: void 0,
1643 | name: void 0,
1644 | type: "none",
1645 | exports: void 0,
1646 | imports: void 0
1647 | };
1648 | packageJSONCache.set(path, packageConfig2);
1649 | return packageConfig2;
1650 | }
1651 | let packageJSON;
1652 | try {
1653 | packageJSON = JSONParse(source);
1654 | } catch (error) {
1655 | throw new ERR_INVALID_PACKAGE_CONFIG(
1656 | path,
1657 | (base ? `"${specifier}" from ` : "") + fileURLToPath(base || specifier),
1658 | error.message
1659 | );
1660 | }
1661 | let { imports, main, name, type } = filterOwnProperties(packageJSON, [
1662 | "imports",
1663 | "main",
1664 | "name",
1665 | "type"
1666 | ]);
1667 | const exports = ObjectPrototypeHasOwnProperty(packageJSON, "exports") ? packageJSON.exports : void 0;
1668 | if (typeof imports !== "object" || imports === null) {
1669 | imports = void 0;
1670 | }
1671 | if (typeof main !== "string") {
1672 | main = void 0;
1673 | }
1674 | if (typeof name !== "string") {
1675 | name = void 0;
1676 | }
1677 | if (type !== "module" && type !== "commonjs") {
1678 | type = "none";
1679 | }
1680 | const packageConfig = {
1681 | pjsonPath: path,
1682 | exists: true,
1683 | main,
1684 | name,
1685 | type,
1686 | exports,
1687 | imports
1688 | };
1689 | packageJSONCache.set(path, packageConfig);
1690 | return packageConfig;
1691 | }
1692 | function getPackageScopeConfig(resolved, readFileSyncFn) {
1693 | let packageJSONUrl = new URL("./package.json", resolved);
1694 | while (true) {
1695 | const packageJSONPath2 = packageJSONUrl.pathname;
1696 | if (StringPrototypeEndsWith(packageJSONPath2, "node_modules/package.json")) {
1697 | break;
1698 | }
1699 | const packageConfig2 = getPackageConfig(
1700 | fileURLToPath(packageJSONUrl),
1701 | resolved,
1702 | void 0,
1703 | readFileSyncFn
1704 | );
1705 | if (packageConfig2.exists) {
1706 | return packageConfig2;
1707 | }
1708 | const lastPackageJSONUrl = packageJSONUrl;
1709 | packageJSONUrl = new URL("../package.json", packageJSONUrl);
1710 | if (packageJSONUrl.pathname === lastPackageJSONUrl.pathname) {
1711 | break;
1712 | }
1713 | }
1714 | const packageJSONPath = fileURLToPath(packageJSONUrl);
1715 | const packageConfig = {
1716 | pjsonPath: packageJSONPath,
1717 | exists: false,
1718 | main: void 0,
1719 | name: void 0,
1720 | type: "none",
1721 | exports: void 0,
1722 | imports: void 0
1723 | };
1724 | packageJSONCache.set(packageJSONPath, packageConfig);
1725 | return packageConfig;
1726 | }
1727 |
1728 | function throwImportNotDefined(specifier, packageJSONUrl, base) {
1729 | throw new ERR_PACKAGE_IMPORT_NOT_DEFINED(
1730 | specifier,
1731 | packageJSONUrl && fileURLToPath(new URL(".", packageJSONUrl)),
1732 | fileURLToPath(base)
1733 | );
1734 | }
1735 | function throwInvalidSubpath(subpath, packageJSONUrl, internal, base) {
1736 | const reason = `request is not a valid subpath for the "${internal ? "imports" : "exports"}" resolution of ${fileURLToPath(packageJSONUrl)}`;
1737 | throw new ERR_INVALID_MODULE_SPECIFIER(
1738 | subpath,
1739 | reason,
1740 | base && fileURLToPath(base)
1741 | );
1742 | }
1743 | function throwInvalidPackageTarget(subpath, target, packageJSONUrl, internal, base) {
1744 | if (typeof target === "object" && target !== null) {
1745 | target = JSONStringify(target, null, "");
1746 | } else {
1747 | target = `${target}`;
1748 | }
1749 | throw new ERR_INVALID_PACKAGE_TARGET(
1750 | fileURLToPath(new URL(".", packageJSONUrl)),
1751 | subpath,
1752 | target,
1753 | internal,
1754 | base && fileURLToPath(base)
1755 | );
1756 | }
1757 | 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;
1758 | const patternRegEx = /\*/g;
1759 | function resolvePackageTargetString(target, subpath, match, packageJSONUrl, base, pattern, internal, conditions) {
1760 | if (subpath !== "" && !pattern && target[target.length - 1] !== "/")
1761 | throwInvalidPackageTarget(match, target, packageJSONUrl, internal, base);
1762 | if (!StringPrototypeStartsWith(target, "./")) {
1763 | if (internal && !StringPrototypeStartsWith(target, "../") && !StringPrototypeStartsWith(target, "/")) {
1764 | let isURL = false;
1765 | try {
1766 | new URL(target);
1767 | isURL = true;
1768 | } catch {
1769 | }
1770 | if (!isURL) {
1771 | const exportTarget = pattern ? RegExpPrototypeSymbolReplace(patternRegEx, target, () => subpath) : target + subpath;
1772 | return exportTarget;
1773 | }
1774 | }
1775 | throwInvalidPackageTarget(match, target, packageJSONUrl, internal, base);
1776 | }
1777 | if (RegExpPrototypeExec(
1778 | invalidSegmentRegEx,
1779 | StringPrototypeSlice(target, 2)
1780 | ) !== null)
1781 | throwInvalidPackageTarget(match, target, packageJSONUrl, internal, base);
1782 | const resolved = new URL(target, packageJSONUrl);
1783 | const resolvedPath = resolved.pathname;
1784 | const packagePath = new URL(".", packageJSONUrl).pathname;
1785 | if (!StringPrototypeStartsWith(resolvedPath, packagePath))
1786 | throwInvalidPackageTarget(match, target, packageJSONUrl, internal, base);
1787 | if (subpath === "") return resolved;
1788 | if (RegExpPrototypeExec(invalidSegmentRegEx, subpath) !== null) {
1789 | const request = pattern ? StringPrototypeReplace(match, "*", () => subpath) : match + subpath;
1790 | throwInvalidSubpath(request, packageJSONUrl, internal, base);
1791 | }
1792 | if (pattern) {
1793 | return new URL(
1794 | RegExpPrototypeSymbolReplace(patternRegEx, resolved.href, () => subpath)
1795 | );
1796 | }
1797 | return new URL(subpath, resolved);
1798 | }
1799 | function isArrayIndex(key) {
1800 | const keyNum = +key;
1801 | if (`${keyNum}` !== key) return false;
1802 | return keyNum >= 0 && keyNum < 4294967295;
1803 | }
1804 | function resolvePackageTarget(packageJSONUrl, target, subpath, packageSubpath, base, pattern, internal, conditions) {
1805 | if (typeof target === "string") {
1806 | return resolvePackageTargetString(
1807 | target,
1808 | subpath,
1809 | packageSubpath,
1810 | packageJSONUrl,
1811 | base,
1812 | pattern,
1813 | internal);
1814 | } else if (ArrayIsArray(target)) {
1815 | if (target.length === 0) {
1816 | return null;
1817 | }
1818 | let lastException;
1819 | for (let i = 0; i < target.length; i++) {
1820 | const targetItem = target[i];
1821 | let resolveResult;
1822 | try {
1823 | resolveResult = resolvePackageTarget(
1824 | packageJSONUrl,
1825 | targetItem,
1826 | subpath,
1827 | packageSubpath,
1828 | base,
1829 | pattern,
1830 | internal,
1831 | conditions
1832 | );
1833 | } catch (e) {
1834 | lastException = e;
1835 | if (e.code === "ERR_INVALID_PACKAGE_TARGET") {
1836 | continue;
1837 | }
1838 | throw e;
1839 | }
1840 | if (resolveResult === void 0) {
1841 | continue;
1842 | }
1843 | if (resolveResult === null) {
1844 | lastException = null;
1845 | continue;
1846 | }
1847 | return resolveResult;
1848 | }
1849 | if (lastException === void 0 || lastException === null)
1850 | return lastException;
1851 | throw lastException;
1852 | } else if (typeof target === "object" && target !== null) {
1853 | const keys = ObjectGetOwnPropertyNames(target);
1854 | for (let i = 0; i < keys.length; i++) {
1855 | const key = keys[i];
1856 | if (isArrayIndex(key)) {
1857 | throw new ERR_INVALID_PACKAGE_CONFIG(
1858 | fileURLToPath(packageJSONUrl),
1859 | base,
1860 | '"exports" cannot contain numeric property keys.'
1861 | );
1862 | }
1863 | }
1864 | for (let i = 0; i < keys.length; i++) {
1865 | const key = keys[i];
1866 | if (key === "default" || conditions.has(key)) {
1867 | const conditionalTarget = target[key];
1868 | const resolveResult = resolvePackageTarget(
1869 | packageJSONUrl,
1870 | conditionalTarget,
1871 | subpath,
1872 | packageSubpath,
1873 | base,
1874 | pattern,
1875 | internal,
1876 | conditions
1877 | );
1878 | if (resolveResult === void 0) continue;
1879 | return resolveResult;
1880 | }
1881 | }
1882 | return void 0;
1883 | } else if (target === null) {
1884 | return null;
1885 | }
1886 | throwInvalidPackageTarget(
1887 | packageSubpath,
1888 | target,
1889 | packageJSONUrl,
1890 | internal,
1891 | base
1892 | );
1893 | }
1894 | function patternKeyCompare(a, b) {
1895 | const aPatternIndex = StringPrototypeIndexOf(a, "*");
1896 | const bPatternIndex = StringPrototypeIndexOf(b, "*");
1897 | const baseLenA = aPatternIndex === -1 ? a.length : aPatternIndex + 1;
1898 | const baseLenB = bPatternIndex === -1 ? b.length : bPatternIndex + 1;
1899 | if (baseLenA > baseLenB) return -1;
1900 | if (baseLenB > baseLenA) return 1;
1901 | if (aPatternIndex === -1) return 1;
1902 | if (bPatternIndex === -1) return -1;
1903 | if (a.length > b.length) return -1;
1904 | if (b.length > a.length) return 1;
1905 | return 0;
1906 | }
1907 | function packageImportsResolve({ name, base, conditions, readFileSyncFn }) {
1908 | if (name === "#" || StringPrototypeStartsWith(name, "#/") || StringPrototypeEndsWith(name, "/")) {
1909 | const reason = "is not a valid internal imports specifier name";
1910 | throw new ERR_INVALID_MODULE_SPECIFIER(name, reason, fileURLToPath(base));
1911 | }
1912 | let packageJSONUrl;
1913 | const packageConfig = getPackageScopeConfig(base, readFileSyncFn);
1914 | if (packageConfig.exists) {
1915 | packageJSONUrl = pathToFileURL(packageConfig.pjsonPath);
1916 | const imports = packageConfig.imports;
1917 | if (imports) {
1918 | if (ObjectPrototypeHasOwnProperty(imports, name) && !StringPrototypeIncludes(name, "*")) {
1919 | const resolveResult = resolvePackageTarget(
1920 | packageJSONUrl,
1921 | imports[name],
1922 | "",
1923 | name,
1924 | base,
1925 | false,
1926 | true,
1927 | conditions
1928 | );
1929 | if (resolveResult != null) {
1930 | return resolveResult;
1931 | }
1932 | } else {
1933 | let bestMatch = "";
1934 | let bestMatchSubpath;
1935 | const keys = ObjectGetOwnPropertyNames(imports);
1936 | for (let i = 0; i < keys.length; i++) {
1937 | const key = keys[i];
1938 | const patternIndex = StringPrototypeIndexOf(key, "*");
1939 | if (patternIndex !== -1 && StringPrototypeStartsWith(
1940 | name,
1941 | StringPrototypeSlice(key, 0, patternIndex)
1942 | )) {
1943 | const patternTrailer = StringPrototypeSlice(key, patternIndex + 1);
1944 | if (name.length >= key.length && StringPrototypeEndsWith(name, patternTrailer) && patternKeyCompare(bestMatch, key) === 1 && StringPrototypeLastIndexOf(key, "*") === patternIndex) {
1945 | bestMatch = key;
1946 | bestMatchSubpath = StringPrototypeSlice(
1947 | name,
1948 | patternIndex,
1949 | name.length - patternTrailer.length
1950 | );
1951 | }
1952 | }
1953 | }
1954 | if (bestMatch) {
1955 | const target = imports[bestMatch];
1956 | const resolveResult = resolvePackageTarget(
1957 | packageJSONUrl,
1958 | target,
1959 | bestMatchSubpath,
1960 | bestMatch,
1961 | base,
1962 | true,
1963 | true,
1964 | conditions
1965 | );
1966 | if (resolveResult != null) {
1967 | return resolveResult;
1968 | }
1969 | }
1970 | }
1971 | }
1972 | }
1973 | throwImportNotDefined(name, packageJSONUrl, base);
1974 | }
1975 |
1976 | let findPnpApi = esmModule.findPnpApi;
1977 | if (!findPnpApi) {
1978 | const require = createRequire(import.meta.url);
1979 | const pnpApi = require(`./.pnp.cjs`);
1980 | pnpApi.setup();
1981 | findPnpApi = esmModule.findPnpApi;
1982 | }
1983 | const pathRegExp = /^(?![a-zA-Z]:[\\/]|\\\\|\.{0,2}(?:\/|$))((?:node:)?(?:@[^/]+\/)?[^/]+)\/*(.*|)$/;
1984 | const isRelativeRegexp = /^\.{0,2}\//;
1985 | function tryReadFile(filePath) {
1986 | try {
1987 | return fs.readFileSync(filePath, `utf8`);
1988 | } catch (err) {
1989 | if (err.code === `ENOENT`)
1990 | return void 0;
1991 | throw err;
1992 | }
1993 | }
1994 | async function resolvePrivateRequest(specifier, issuer, context, nextResolve) {
1995 | const resolved = packageImportsResolve({
1996 | name: specifier,
1997 | base: pathToFileURL(issuer),
1998 | conditions: new Set(context.conditions),
1999 | readFileSyncFn: tryReadFile
2000 | });
2001 | if (resolved instanceof URL) {
2002 | return { url: resolved.href, shortCircuit: true };
2003 | } else {
2004 | if (resolved.startsWith(`#`))
2005 | throw new Error(`Mapping from one private import to another isn't allowed`);
2006 | return resolve$1(resolved, context, nextResolve);
2007 | }
2008 | }
2009 | async function resolve$1(originalSpecifier, context, nextResolve) {
2010 | if (!findPnpApi || isBuiltin(originalSpecifier))
2011 | return nextResolve(originalSpecifier, context, nextResolve);
2012 | let specifier = originalSpecifier;
2013 | const url = tryParseURL(specifier, isRelativeRegexp.test(specifier) ? context.parentURL : void 0);
2014 | if (url) {
2015 | if (url.protocol !== `file:`)
2016 | return nextResolve(originalSpecifier, context, nextResolve);
2017 | specifier = fileURLToPath(url);
2018 | }
2019 | const { parentURL, conditions = [] } = context;
2020 | const issuer = parentURL && tryParseURL(parentURL)?.protocol === `file:` ? fileURLToPath(parentURL) : process.cwd();
2021 | const pnpapi = findPnpApi(issuer) ?? (url ? findPnpApi(specifier) : null);
2022 | if (!pnpapi)
2023 | return nextResolve(originalSpecifier, context, nextResolve);
2024 | if (specifier.startsWith(`#`))
2025 | return resolvePrivateRequest(specifier, issuer, context, nextResolve);
2026 | const dependencyNameMatch = specifier.match(pathRegExp);
2027 | let allowLegacyResolve = false;
2028 | if (dependencyNameMatch) {
2029 | const [, dependencyName, subPath] = dependencyNameMatch;
2030 | if (subPath === `` && dependencyName !== `pnpapi`) {
2031 | const resolved = pnpapi.resolveToUnqualified(`${dependencyName}/package.json`, issuer);
2032 | if (resolved) {
2033 | const content = await tryReadFile$1(resolved);
2034 | if (content) {
2035 | const pkg = JSON.parse(content);
2036 | allowLegacyResolve = pkg.exports == null;
2037 | }
2038 | }
2039 | }
2040 | }
2041 | let result;
2042 | try {
2043 | result = pnpapi.resolveRequest(specifier, issuer, {
2044 | conditions: new Set(conditions),
2045 | // TODO: Handle --experimental-specifier-resolution=node
2046 | extensions: allowLegacyResolve ? void 0 : []
2047 | });
2048 | } catch (err) {
2049 | if (err instanceof Error && `code` in err && err.code === `MODULE_NOT_FOUND`)
2050 | err.code = `ERR_MODULE_NOT_FOUND`;
2051 | throw err;
2052 | }
2053 | if (!result)
2054 | throw new Error(`Resolving '${specifier}' from '${issuer}' failed`);
2055 | const resultURL = pathToFileURL(result);
2056 | if (url) {
2057 | resultURL.search = url.search;
2058 | resultURL.hash = url.hash;
2059 | }
2060 | if (!parentURL)
2061 | setEntrypointPath(fileURLToPath(resultURL));
2062 | return {
2063 | url: resultURL.href,
2064 | shortCircuit: true
2065 | };
2066 | }
2067 |
2068 | if (!HAS_LAZY_LOADED_TRANSLATORS) {
2069 | const binding = process.binding(`fs`);
2070 | const originalReadFile = binding.readFileUtf8 || binding.readFileSync;
2071 | if (originalReadFile) {
2072 | binding[originalReadFile.name] = function(...args) {
2073 | try {
2074 | return fs.readFileSync(args[0], {
2075 | encoding: `utf8`,
2076 | // @ts-expect-error - The docs says it needs to be a string but
2077 | // links to https://nodejs.org/dist/latest-v20.x/docs/api/fs.html#file-system-flags
2078 | // which says it can be a number which matches the implementation.
2079 | flag: args[1]
2080 | });
2081 | } catch {
2082 | }
2083 | return originalReadFile.apply(this, args);
2084 | };
2085 | } else {
2086 | const binding2 = process.binding(`fs`);
2087 | const originalfstat = binding2.fstat;
2088 | const ZIP_MASK = 4278190080;
2089 | const ZIP_MAGIC = 704643072;
2090 | binding2.fstat = function(...args) {
2091 | const [fd, useBigint, req] = args;
2092 | if ((fd & ZIP_MASK) === ZIP_MAGIC && useBigint === false && req === void 0) {
2093 | try {
2094 | const stats = fs.fstatSync(fd);
2095 | return new Float64Array([
2096 | stats.dev,
2097 | stats.mode,
2098 | stats.nlink,
2099 | stats.uid,
2100 | stats.gid,
2101 | stats.rdev,
2102 | stats.blksize,
2103 | stats.ino,
2104 | stats.size,
2105 | stats.blocks
2106 | // atime sec
2107 | // atime ns
2108 | // mtime sec
2109 | // mtime ns
2110 | // ctime sec
2111 | // ctime ns
2112 | // birthtime sec
2113 | // birthtime ns
2114 | ]);
2115 | } catch {
2116 | }
2117 | }
2118 | return originalfstat.apply(this, args);
2119 | };
2120 | }
2121 | }
2122 |
2123 | const resolve = resolve$1;
2124 | const load = load$1;
2125 |
2126 | export { load, resolve };
2127 |
--------------------------------------------------------------------------------