Compare commits

..

5 Commits

Author SHA1 Message Date
Nathan Rajlich
0e9ab97a08 Start getting Jest working 2022-07-26 11:30:48 -07:00
Nathan Rajlich
db0c480418 Progress point 2022-07-25 21:20:37 -07:00
Nathan Rajlich
04aa077094 Progress point 2022-07-25 20:29:45 -07:00
Nathan Rajlich
2288ec7268 Update ncc for all other packages 2022-07-25 17:01:37 -07:00
Nathan Rajlich
b434b23bbc [cli] Update @vercel/ncc to v0.34.0 2022-07-25 16:18:19 -07:00
470 changed files with 13864 additions and 11951 deletions

View File

@@ -17,7 +17,6 @@ jobs:
runs-on: ubuntu-latest
outputs:
tests: ${{ steps['set-tests'].outputs['tests'] }}
dplUrl: ${{ steps.waitForTarball.outputs.url }}
steps:
- uses: actions/checkout@v2
- run: git --version
@@ -33,12 +32,6 @@ jobs:
echo "Files to test:"
echo "$TESTS_ARRAY"
echo "::set-output name=tests::$TESTS_ARRAY"
- uses: patrickedqvist/wait-for-vercel-preview@ae34b392ef30297f2b672f9afb3c329bde9bd487
id: waitForTarball
with:
token: ${{ secrets.GITHUB_TOKEN }}
max_timeout: 360
check_interval: 5
test:
timeout-minutes: 120
@@ -76,14 +69,13 @@ jobs:
- run: yarn install --network-timeout 1000000
- name: Build ${{matrix.packageName}} and all its dependencies
run: node_modules/.bin/turbo run build --cache-dir=".turbo" --scope=${{matrix.packageName}} --include-dependencies --no-deps
run: yarn turbo run build --cache-dir=".turbo" --scope=${{matrix.packageName}} --include-dependencies --no-deps
env:
FORCE_COLOR: '1'
- name: Test ${{matrix.packageName}}
run: node_modules/.bin/turbo run test --cache-dir=".turbo" --scope=${{matrix.packageName}} --no-deps -- ${{ join(matrix.testPaths, ' ') }}
shell: bash
env:
VERCEL_CLI_VERSION: ${{ needs.setup.outputs.dplUrl }}/tarballs/vercel.tgz
VERCEL_TEAM_TOKEN: ${{ secrets.VERCEL_TEAM_TOKEN }}
VERCEL_REGISTRATION_URL: ${{ secrets.VERCEL_REGISTRATION_URL }}
FORCE_COLOR: '1'

View File

@@ -1,9 +1,7 @@
# Runtime Developer Reference
The following page is a reference for how to create a Runtime by implementing
the Runtime API interface. It's a way to add support for a new programming language to Vercel.
> Note: If you're the author of a web framework, please use the [Build Output API](https://vercel.com/docs/build-output-api/v3) instead to make your framework compatible with Vercel.
the Runtime API interface.
A Runtime is an npm module that implements the following interface:

View File

@@ -5,7 +5,8 @@
"description": "API for the vercel/vercel repo",
"main": "index.js",
"scripts": {
"//TODO": "We should add this pkg to yarn workspaces"
"//TODO": "We should add this pkg to yarn workspaces",
"vercel-build": "cd .. && yarn install && yarn vercel-build"
},
"dependencies": {
"@sentry/node": "5.11.1",

View File

@@ -15,5 +15,5 @@ _Live Example: https://docusaurus-2-template.vercel.app_
To get started with Docusaurus on Vercel, you can use the [Docusaurus CLI](https://v2.docusaurus.io/docs/installation#scaffold-project-website) to initialize the project:
```shell
npx create-docusaurus@latest my-website classic
$ npx @docusaurus/init@next init my-website classic
```

View File

@@ -1,3 +0,0 @@
module.exports = {
presets: [require.resolve('@docusaurus/core/lib/babel/preset')],
};

View File

@@ -1,11 +1,10 @@
---
slug: first-blog-post
title: First Blog Post
authors:
name: Gao Wei
title: Docusaurus Core Team
url: https://github.com/wgao19
image_url: https://github.com/wgao19.png
id: hola
title: Hola
author: Gao Wei
author_title: Docusaurus Core Team
author_url: https://github.com/wgao19
author_image_url: https://avatars1.githubusercontent.com/u/2055384?v=4
tags: [hola, docusaurus]
---

View File

@@ -0,0 +1,17 @@
---
id: hello-world
title: Hello
author: Endilie Yacop Sucipto
author_title: Maintainer of Docusaurus
author_url: https://github.com/endiliey
author_image_url: https://avatars1.githubusercontent.com/u/17883920?s=460&v=4
tags: [hello, docusaurus]
---
Welcome to this blog. This blog is created with [**Docusaurus 2 alpha**](https://v2.docusaurus.io/).
<!--truncate-->
This is a test post.
A whole bunch of other information.

View File

@@ -1,44 +0,0 @@
---
slug: long-blog-post
title: Long Blog Post
authors: endi
tags: [hello, docusaurus]
---
This is the summary of a very long blog post,
Use a `<!--` `truncate` `-->` comment to limit blog post size in the list view.
<!--truncate-->
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet

View File

@@ -0,0 +1,13 @@
---
id: welcome
title: Welcome
author: Yangshun Tay
author_title: Front End Engineer @ Facebook
author_url: https://github.com/yangshun
author_image_url: https://avatars0.githubusercontent.com/u/1315101?s=400&v=4
tags: [facebook, hello, docusaurus]
---
Blog features are powered by the blog plugin. Simply add files to the `blog` directory. It supports tags as well!
Delete the whole directory if you don't want the blog features. As simple as that!

View File

@@ -1,20 +0,0 @@
---
slug: mdx-blog-post
title: MDX Blog Post
authors: [slorber]
tags: [docusaurus]
---
Blog posts support [Docusaurus Markdown features](https://docusaurus.io/docs/markdown-features), such as [MDX](https://mdxjs.com/).
:::tip
Use the power of React to create interactive blog posts.
```js
<button onClick={() => alert('button clicked!')}>Click me!</button>
```
<button onClick={() => alert('button clicked!')}>Click me!</button>
:::

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

View File

@@ -1,25 +0,0 @@
---
slug: welcome
title: Welcome
authors: [slorber, yangshun]
tags: [facebook, hello, docusaurus]
---
[Docusaurus blogging features](https://docusaurus.io/docs/blog) are powered by the [blog plugin](https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-content-blog).
Simply add Markdown files (or folders) to the `blog` directory.
Regular blog authors can be added to `authors.yml`.
The blog post date can be extracted from filenames, such as:
- `2019-05-30-welcome.md`
- `2019-05-30-welcome/index.md`
A blog post folder can be convenient to co-locate blog post images:
![Docusaurus Plushie](./docusaurus-plushie-banner.jpeg)
The blog supports tags as well!
**And if you don't want a blog**: just delete this directory, and use `blog: false` in your Docusaurus config.

View File

@@ -1,17 +0,0 @@
endi:
name: Endilie Yacop Sucipto
title: Maintainer of Docusaurus
url: https://github.com/endiliey
image_url: https://github.com/endiliey.png
yangshun:
name: Yangshun Tay
title: Front End Engineer @ Facebook
url: https://github.com/yangshun
image_url: https://github.com/yangshun.png
slorber:
name: Sébastien Lorber
title: Docusaurus maintainer
url: https://sebastienlorber.com
image_url: https://github.com/slorber.png

View File

@@ -0,0 +1,202 @@
---
id: doc1
title: Style Guide
sidebar_label: Style Guide
---
You can write content using [GitHub-flavored Markdown syntax](https://github.github.com/gfm/).
## Markdown Syntax
To serve as an example page when styling markdown based Docusaurus sites.
## Headers
# H1 - Create the best documentation
## H2 - Create the best documentation
### H3 - Create the best documentation
#### H4 - Create the best documentation
##### H5 - Create the best documentation
###### H6 - Create the best documentation
---
## Emphasis
Emphasis, aka italics, with _asterisks_ or _underscores_.
Strong emphasis, aka bold, with **asterisks** or **underscores**.
Combined emphasis with **asterisks and _underscores_**.
Strikethrough uses two tildes. ~~Scratch this.~~
---
## Lists
1. First ordered list item
1. Another item ⋅⋅\* Unordered sub-list.
1. Actual numbers don't matter, just that it's a number ⋅⋅1. Ordered sub-list
1. And another item.
⋅⋅⋅You can have properly indented paragraphs within list items. Notice the blank line above, and the leading spaces (at least one, but we'll use three here to also align the raw Markdown).
⋅⋅⋅To have a line break without a paragraph, you will need to use two trailing spaces.⋅⋅ ⋅⋅⋅Note that this line is separate, but within the same paragraph.⋅⋅ ⋅⋅⋅(This is contrary to the typical GFM line break behaviour, where trailing spaces are not required.)
- Unordered list can use asterisks
* Or minuses
- Or pluses
---
## Links
[I'm an inline-style link](https://www.google.com)
[I'm an inline-style link with title](https://www.google.com "Google's Homepage")
[I'm a reference-style link][arbitrary case-insensitive reference text]
[I'm a relative reference to a repository file](../blob/master/LICENSE)
[You can use numbers for reference-style link definitions][1]
Or leave it empty and use the [link text itself].
URLs and URLs in angle brackets will automatically get turned into links. http://www.example.com or <http://www.example.com> and sometimes example.com (but not on Github, for example).
Some text to show that the reference links can follow later.
[arbitrary case-insensitive reference text]: https://www.mozilla.org
[1]: http://slashdot.org
[link text itself]: http://www.reddit.com
---
## Images
Here's our logo (hover to see the title text):
Inline-style: ![alt text](https://github.com/adam-p/markdown-here/raw/master/src/common/images/icon48.png 'Logo Title Text 1')
Reference-style: ![alt text][logo]
[logo]: https://github.com/adam-p/markdown-here/raw/master/src/common/images/icon48.png 'Logo Title Text 2'
---
## Code
```javascript
var s = 'JavaScript syntax highlighting';
alert(s);
```
```python
s = "Python syntax highlighting"
print(s)
```
```
No language indicated, so no syntax highlighting.
But let's throw in a <b>tag</b>.
```
```js {2}
function highlightMe() {
console.log('This line can be highlighted!');
}
```
---
## Tables
Colons can be used to align columns.
| Tables | Are | Cool |
| ------------- | :-----------: | -----: |
| col 3 is | right-aligned | \$1600 |
| col 2 is | centered | \$12 |
| zebra stripes | are neat | \$1 |
There must be at least 3 dashes separating each header cell. The outer pipes (|) are optional, and you don't need to make the raw Markdown line up prettily. You can also use inline Markdown.
| Markdown | Less | Pretty |
| -------- | --------- | ---------- |
| _Still_ | `renders` | **nicely** |
| 1 | 2 | 3 |
---
## Blockquotes
> Blockquotes are very handy in email to emulate reply text. This line is part of the same quote.
Quote break.
> This is a very long line that will still be quoted properly when it wraps. Oh boy let's keep writing to make sure this is long enough to actually wrap for everyone. Oh, you can _put_ **Markdown** into a blockquote.
---
## Inline HTML
<dl>
<dt>Definition list</dt>
<dd>Is something people use sometimes.</dd>
<dt>Markdown in HTML</dt>
<dd>Does *not* work **very** well. Use HTML <em>tags</em>.</dd>
</dl>
---
## Line Breaks
Here's a line for us to start with.
This line is separated from the one above by two newlines, so it will be a _separate paragraph_.
This line is also a separate paragraph, but... This line is only separated by a single newline, so it's a separate line in the _same paragraph_.
---
## Admonitions
:::note
This is a note
:::
:::tip
This is a tip
:::
:::important
This is important
:::
:::caution
This is a caution
:::
:::warning
This is a warning
:::

View File

@@ -0,0 +1,6 @@
---
id: doc2
title: Document Number 2
---
This is a link to [another document.](doc3.md) This is a link to an [external page.](http://www.example.com)

View File

@@ -0,0 +1,14 @@
---
id: doc3
title: This is Document Number 3
---
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In ac euismod odio, eu consequat dui. Nullam molestie consectetur risus id imperdiet. Proin sodales ornare turpis, non mollis massa ultricies id. Nam at nibh scelerisque, feugiat ante non, dapibus tortor. Vivamus volutpat diam quis tellus elementum bibendum. Praesent semper gravida velit quis aliquam. Etiam in cursus neque. Nam lectus ligula, malesuada et mauris a, bibendum faucibus mi. Phasellus ut interdum felis. Phasellus in odio pulvinar, porttitor urna eget, fringilla lectus. Aliquam sollicitudin est eros. Mauris consectetur quam vitae mauris interdum hendrerit. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Duis et egestas libero, imperdiet faucibus ipsum. Sed posuere eget urna vel feugiat. Vivamus a arcu sagittis, fermentum urna dapibus, congue lectus. Fusce vulputate porttitor nisl, ac cursus elit volutpat vitae. Nullam vitae ipsum egestas, convallis quam non, porta nibh. Morbi gravida erat nec neque bibendum, eu pellentesque velit posuere. Fusce aliquam erat eu massa eleifend tristique.
Sed consequat sollicitudin ipsum eget tempus. Integer a aliquet velit. In justo nibh, pellentesque non suscipit eget, gravida vel lacus. Donec odio ante, malesuada in massa quis, pharetra tristique ligula. Donec eros est, tristique eget finibus quis, semper non nisl. Vivamus et elit nec enim ornare placerat. Sed posuere odio a elit cursus sagittis.
Phasellus feugiat purus eu tortor ultrices finibus. Ut libero nibh, lobortis et libero nec, dapibus posuere eros. Sed sagittis euismod justo at consectetur. Nulla finibus libero placerat, cursus sapien at, eleifend ligula. Vivamus elit nisl, hendrerit ac nibh eu, ultrices tempus dui. Nam tellus neque, commodo non rhoncus eu, gravida in risus. Nullam id iaculis tortor.
Nullam at odio in sem varius tempor sit amet vel lorem. Etiam eu hendrerit nisl. Fusce nibh mauris, vulputate sit amet ex vitae, congue rhoncus nisl. Sed eget tellus purus. Nullam tempus commodo erat ut tristique. Cras accumsan massa sit amet justo consequat eleifend. Integer scelerisque vitae tellus id consectetur.

View File

@@ -1,47 +0,0 @@
---
sidebar_position: 1
---
# Tutorial Intro
Let's discover **Docusaurus in less than 5 minutes**.
## Getting Started
Get started by **creating a new site**.
Or **try Docusaurus immediately** with **[docusaurus.new](https://docusaurus.new)**.
### What you'll need
- [Node.js](https://nodejs.org/en/download/) version 16.14 or above:
- When installing Node.js, you are recommended to check all checkboxes related to dependencies.
## Generate a new site
Generate a new Docusaurus site using the **classic template**.
The classic template will automatically be added to your project after you run the command:
```bash
npm init docusaurus@latest my-website classic
```
You can type this command into Command Prompt, Powershell, Terminal, or any other integrated terminal of your code editor.
The command also installs all necessary dependencies you need to run Docusaurus.
## Start your site
Run the development server:
```bash
cd my-website
npm run start
```
The `cd` command changes the directory you're working with. In order to work with your newly created Docusaurus site, you'll need to navigate the terminal there.
The `npm run start` command builds your website locally and serves it through a development server, ready for you to view at http://localhost:3000/.
Open `docs/intro.md` (this page) and edit some lines: the site **reloads automatically** and displays your changes.

View File

@@ -0,0 +1,17 @@
---
id: mdx
title: Powered by MDX
---
You can write JSX and use React components within your Markdown thanks to [MDX](https://mdxjs.com/).
export const Highlight = ({children, color}) => ( <span style={{
backgroundColor: color,
borderRadius: '2px',
color: '#fff',
padding: '0.2rem',
}}> {children} </span> );
<Highlight color="#25c2a0">Docusaurus green</Highlight> and <Highlight color="#1877F2">Facebook blue</Highlight> are my favorite colors.
I can write **Markdown** alongside my _JSX_!

View File

@@ -1,8 +0,0 @@
{
"label": "Tutorial - Basics",
"position": 2,
"link": {
"type": "generated-index",
"description": "5 minutes to learn the most important Docusaurus concepts."
}
}

View File

@@ -1,21 +0,0 @@
---
sidebar_position: 6
---
# Congratulations!
You have just learned the **basics of Docusaurus** and made some changes to the **initial template**.
Docusaurus has **much more to offer**!
Have **5 more minutes**? Take a look at **[versioning](../tutorial-extras/manage-docs-versions.md)** and **[i18n](../tutorial-extras/translate-your-site.md)**.
Anything **unclear** or **buggy** in this tutorial? [Please report it!](https://github.com/facebook/docusaurus/discussions/4610)
## What's next?
- Read the [official documentation](https://docusaurus.io/).
- Add a custom [Design and Layout](https://docusaurus.io/docs/styling-layout)
- Add a [search bar](https://docusaurus.io/docs/search)
- Find inspirations in the [Docusaurus showcase](https://docusaurus.io/showcase)
- Get involved in the [Docusaurus Community](https://docusaurus.io/community/support)

View File

@@ -1,34 +0,0 @@
---
sidebar_position: 3
---
# Create a Blog Post
Docusaurus creates a **page for each blog post**, but also a **blog index page**, a **tag system**, an **RSS** feed...
## Create your first Post
Create a file at `blog/2021-02-28-greetings.md`:
```md title="blog/2021-02-28-greetings.md"
---
slug: greetings
title: Greetings!
authors:
- name: Joel Marcey
title: Co-creator of Docusaurus 1
url: https://github.com/JoelMarcey
image_url: https://github.com/JoelMarcey.png
- name: Sébastien Lorber
title: Docusaurus maintainer
url: https://sebastienlorber.com
image_url: https://github.com/slorber.png
tags: [greetings]
---
Congratulations, you have made your first post!
Feel free to play around and edit this post as much you like.
```
A new blog post is now available at [http://localhost:3000/blog/greetings](http://localhost:3000/blog/greetings).

View File

@@ -1,55 +0,0 @@
---
sidebar_position: 2
---
# Create a Document
Documents are **groups of pages** connected through:
- a **sidebar**
- **previous/next navigation**
- **versioning**
## Create your first Doc
Create a Markdown file at `docs/hello.md`:
```md title="docs/hello.md"
# Hello
This is my **first Docusaurus document**!
```
A new document is now available at [http://localhost:3000/docs/hello](http://localhost:3000/docs/hello).
## Configure the Sidebar
Docusaurus automatically **creates a sidebar** from the `docs` folder.
Add metadata to customize the sidebar label and position:
```md title="docs/hello.md" {1-4}
---
sidebar_label: 'Hi!'
sidebar_position: 3
---
# Hello
This is my **first Docusaurus document**!
```
It is also possible to create your sidebar explicitly in `sidebars.js`:
```js title="sidebars.js"
module.exports = {
tutorialSidebar: [
{
type: 'category',
label: 'Tutorial',
// highlight-next-line
items: ['hello'],
},
],
};
```

View File

@@ -1,43 +0,0 @@
---
sidebar_position: 1
---
# Create a Page
Add **Markdown or React** files to `src/pages` to create a **standalone page**:
- `src/pages/index.js``localhost:3000/`
- `src/pages/foo.md``localhost:3000/foo`
- `src/pages/foo/bar.js``localhost:3000/foo/bar`
## Create your first React Page
Create a file at `src/pages/my-react-page.js`:
```jsx title="src/pages/my-react-page.js"
import React from 'react';
import Layout from '@theme/Layout';
export default function MyReactPage() {
return (
<Layout>
<h1>My React page</h1>
<p>This is a React page</p>
</Layout>
);
}
```
A new page is now available at [http://localhost:3000/my-react-page](http://localhost:3000/my-react-page).
## Create your first Markdown Page
Create a file at `src/pages/my-markdown-page.md`:
```mdx title="src/pages/my-markdown-page.md"
# My Markdown page
This is a Markdown page
```
A new page is now available at [http://localhost:3000/my-markdown-page](http://localhost:3000/my-markdown-page).

View File

@@ -1,31 +0,0 @@
---
sidebar_position: 5
---
# Deploy your site
Docusaurus is a **static-site-generator** (also called **[Jamstack](https://jamstack.org/)**).
It builds your site as simple **static HTML, JavaScript and CSS files**.
## Build your site
Build your site **for production**:
```bash
npm run build
```
The static files are generated in the `build` folder.
## Deploy your site
Test your production build locally:
```bash
npm run serve
```
The `build` folder is now served at [http://localhost:3000/](http://localhost:3000/).
You can now deploy the `build` folder **almost anywhere** easily, **for free** or very small cost (read the **[Deployment Guide](https://docusaurus.io/docs/deployment)**).

View File

@@ -1,146 +0,0 @@
---
sidebar_position: 4
---
# Markdown Features
Docusaurus supports **[Markdown](https://daringfireball.net/projects/markdown/syntax)** and a few **additional features**.
## Front Matter
Markdown documents have metadata at the top called [Front Matter](https://jekyllrb.com/docs/front-matter/):
```text title="my-doc.md"
// highlight-start
---
id: my-doc-id
title: My document title
description: My document description
slug: /my-custom-url
---
// highlight-end
## Markdown heading
Markdown text with [links](./hello.md)
```
## Links
Regular Markdown links are supported, using url paths or relative file paths.
```md
Let's see how to [Create a page](/create-a-page).
```
```md
Let's see how to [Create a page](./create-a-page.md).
```
**Result:** Let's see how to [Create a page](./create-a-page.md).
## Images
Regular Markdown images are supported.
You can use absolute paths to reference images in the static directory (`static/img/docusaurus.png`):
```md
![Docusaurus logo](/img/docusaurus.png)
```
![Docusaurus logo](/img/docusaurus.png)
You can reference images relative to the current file as well, as shown in [the extra guides](../tutorial-extras/manage-docs-versions.md).
## Code Blocks
Markdown code blocks are supported with Syntax highlighting.
```jsx title="src/components/HelloDocusaurus.js"
function HelloDocusaurus() {
return (
<h1>Hello, Docusaurus!</h1>
)
}
```
```jsx title="src/components/HelloDocusaurus.js"
function HelloDocusaurus() {
return <h1>Hello, Docusaurus!</h1>;
}
```
## Admonitions
Docusaurus has a special syntax to create admonitions and callouts:
:::tip My tip
Use this awesome feature option
:::
:::danger Take care
This action is dangerous
:::
:::tip My tip
Use this awesome feature option
:::
:::danger Take care
This action is dangerous
:::
## MDX and React Components
[MDX](https://mdxjs.com/) can make your documentation more **interactive** and allows using any **React components inside Markdown**:
```jsx
export const Highlight = ({children, color}) => (
<span
style={{
backgroundColor: color,
borderRadius: '20px',
color: '#fff',
padding: '10px',
cursor: 'pointer',
}}
onClick={() => {
alert(`You clicked the color ${color} with label ${children}`)
}}>
{children}
</span>
);
This is <Highlight color="#25c2a0">Docusaurus green</Highlight> !
This is <Highlight color="#1877F2">Facebook blue</Highlight> !
```
export const Highlight = ({children, color}) => (
<span
style={{
backgroundColor: color,
borderRadius: '20px',
color: '#fff',
padding: '10px',
cursor: 'pointer',
}}
onClick={() => {
alert(`You clicked the color ${color} with label ${children}`);
}}>
{children}
</span>
);
This is <Highlight color="#25c2a0">Docusaurus green</Highlight> !
This is <Highlight color="#1877F2">Facebook blue</Highlight> !

View File

@@ -1,7 +0,0 @@
{
"label": "Tutorial - Extras",
"position": 3,
"link": {
"type": "generated-index"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

View File

@@ -1,55 +0,0 @@
---
sidebar_position: 1
---
# Manage Docs Versions
Docusaurus can manage multiple versions of your docs.
## Create a docs version
Release a version 1.0 of your project:
```bash
npm run docusaurus docs:version 1.0
```
The `docs` folder is copied into `versioned_docs/version-1.0` and `versions.json` is created.
Your docs now have 2 versions:
- `1.0` at `http://localhost:3000/docs/` for the version 1.0 docs
- `current` at `http://localhost:3000/docs/next/` for the **upcoming, unreleased docs**
## Add a Version Dropdown
To navigate seamlessly across versions, add a version dropdown.
Modify the `docusaurus.config.js` file:
```js title="docusaurus.config.js"
module.exports = {
themeConfig: {
navbar: {
items: [
// highlight-start
{
type: 'docsVersionDropdown',
},
// highlight-end
],
},
},
};
```
The docs version dropdown appears in your navbar:
![Docs Version Dropdown](./img/docsVersionDropdown.png)
## Update an existing version
It is possible to edit versioned docs in their respective folder:
- `versioned_docs/version-1.0/hello.md` updates `http://localhost:3000/docs/hello`
- `docs/hello.md` updates `http://localhost:3000/docs/next/hello`

View File

@@ -1,88 +0,0 @@
---
sidebar_position: 2
---
# Translate your site
Let's translate `docs/intro.md` to French.
## Configure i18n
Modify `docusaurus.config.js` to add support for the `fr` locale:
```js title="docusaurus.config.js"
module.exports = {
i18n: {
defaultLocale: 'en',
locales: ['en', 'fr'],
},
};
```
## Translate a doc
Copy the `docs/intro.md` file to the `i18n/fr` folder:
```bash
mkdir -p i18n/fr/docusaurus-plugin-content-docs/current/
cp docs/intro.md i18n/fr/docusaurus-plugin-content-docs/current/intro.md
```
Translate `i18n/fr/docusaurus-plugin-content-docs/current/intro.md` in French.
## Start your localized site
Start your site on the French locale:
```bash
npm run start -- --locale fr
```
Your localized site is accessible at [http://localhost:3000/fr/](http://localhost:3000/fr/) and the `Getting Started` page is translated.
:::caution
In development, you can only use one locale at a same time.
:::
## Add a Locale Dropdown
To navigate seamlessly across languages, add a locale dropdown.
Modify the `docusaurus.config.js` file:
```js title="docusaurus.config.js"
module.exports = {
themeConfig: {
navbar: {
items: [
// highlight-start
{
type: 'localeDropdown',
},
// highlight-end
],
},
},
};
```
The locale dropdown now appears in your navbar:
![Locale Dropdown](./img/localeDropdown.png)
## Build your localized site
Build your site for a specific locale:
```bash
npm run build -- --locale fr
```
Or build your site to include all the locales at once:
```bash
npm run build
```

View File

@@ -1,132 +1,103 @@
// @ts-check
// Note: type annotations allow type checking and IDEs autocompletion
const lightCodeTheme = require('prism-react-renderer/themes/github');
const darkCodeTheme = require('prism-react-renderer/themes/dracula');
/** @type {import('@docusaurus/types').Config} */
const config = {
module.exports = {
title: 'My Site',
tagline: 'Dinosaurs are cool',
tagline: 'The tagline of my site',
url: 'https://your-docusaurus-test-site.com',
baseUrl: '/',
onBrokenLinks: 'throw',
onBrokenMarkdownLinks: 'warn',
favicon: 'img/favicon.ico',
// GitHub pages deployment config.
// If you aren't using GitHub pages, you don't need these.
organizationName: 'facebook', // Usually your GitHub org/user name.
projectName: 'docusaurus', // Usually your repo name.
// Even if you don't use internalization, you can use this field to set useful
// metadata like html lang. For example, if your site is Chinese, you may want
// to replace "en" with "zh-Hans".
i18n: {
defaultLocale: 'en',
locales: ['en'],
themeConfig: {
navbar: {
title: 'My Site',
logo: {
alt: 'My Site Logo',
src: 'img/logo.svg',
},
links: [
{
to: 'docs/doc1',
activeBasePath: 'docs',
label: 'Docs',
position: 'left',
},
{to: 'blog', label: 'Blog', position: 'left'},
{
href: 'https://github.com/facebook/docusaurus',
label: 'GitHub',
position: 'right',
},
],
},
footer: {
style: 'dark',
links: [
{
title: 'Docs',
items: [
{
label: 'Style Guide',
to: 'docs/doc1',
},
{
label: 'Second Doc',
to: 'docs/doc2',
},
],
},
{
title: 'Community',
items: [
{
label: 'Stack Overflow',
href: 'https://stackoverflow.com/questions/tagged/docusaurus',
},
{
label: 'Discord',
href: 'https://discordapp.com/invite/docusaurus',
},
{
label: 'Twitter',
href: 'https://twitter.com/docusaurus',
},
],
},
{
title: 'More',
items: [
{
label: 'Blog',
to: 'blog',
},
{
label: 'GitHub',
href: 'https://github.com/facebook/docusaurus',
},
],
},
],
copyright: `Copyright © ${new Date().getFullYear()} My Project, Inc. Built with Docusaurus.`,
},
},
presets: [
[
'classic',
/** @type {import('@docusaurus/preset-classic').Options} */
({
'@docusaurus/preset-classic',
{
docs: {
sidebarPath: require.resolve('./sidebars.js'),
// Please change this to your repo.
// Remove this to remove the "edit this page" links.
editUrl:
'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/',
'https://github.com/facebook/docusaurus/edit/master/website/',
},
blog: {
showReadingTime: true,
// Please change this to your repo.
// Remove this to remove the "edit this page" links.
editUrl:
'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/',
'https://github.com/facebook/docusaurus/edit/master/website/blog/',
},
theme: {
customCss: require.resolve('./src/css/custom.css'),
},
}),
},
],
],
themeConfig:
/** @type {import('@docusaurus/preset-classic').ThemeConfig} */
({
navbar: {
title: 'My Site',
logo: {
alt: 'My Site Logo',
src: 'img/logo.svg',
},
items: [
{
type: 'doc',
docId: 'intro',
position: 'left',
label: 'Tutorial',
},
{to: '/blog', label: 'Blog', position: 'left'},
{
href: 'https://github.com/facebook/docusaurus',
label: 'GitHub',
position: 'right',
},
],
},
footer: {
style: 'dark',
links: [
{
title: 'Docs',
items: [
{
label: 'Tutorial',
to: '/docs/intro',
},
],
},
{
title: 'Community',
items: [
{
label: 'Stack Overflow',
href: 'https://stackoverflow.com/questions/tagged/docusaurus',
},
{
label: 'Discord',
href: 'https://discordapp.com/invite/docusaurus',
},
{
label: 'Twitter',
href: 'https://twitter.com/docusaurus',
},
],
},
{
title: 'More',
items: [
{
label: 'Blog',
to: '/blog',
},
{
label: 'GitHub',
href: 'https://github.com/facebook/docusaurus',
},
],
},
],
copyright: `Copyright © ${new Date().getFullYear()} My Project, Inc. Built with Docusaurus.`,
},
prism: {
theme: lightCodeTheme,
darkTheme: darkCodeTheme,
},
}),
};
module.exports = config;

View File

@@ -1,31 +1,23 @@
{
"name": "docusaurus-2",
"version": "0.0.0",
"private": true,
"scripts": {
"docusaurus": "docusaurus",
"start": "docusaurus start",
"build": "docusaurus build",
"swizzle": "docusaurus swizzle",
"deploy": "docusaurus deploy",
"clear": "docusaurus clear",
"serve": "docusaurus serve",
"write-translations": "docusaurus write-translations",
"write-heading-ids": "docusaurus write-heading-ids"
"deploy": "docusaurus deploy"
},
"dependencies": {
"@docusaurus/core": "2.0.1",
"@docusaurus/preset-classic": "2.0.1",
"@mdx-js/react": "^1.6.22",
"clsx": "^1.2.1",
"prism-react-renderer": "^1.3.5",
"react": "^17.0.2",
"react-dom": "^17.0.2"
},
"devDependencies": {
"@docusaurus/module-type-aliases": "2.0.1"
"@docusaurus/core": "^2.0.0-alpha.54",
"@docusaurus/preset-classic": "^2.0.0-alpha.54",
"classnames": "^2.2.6",
"react": "^16.8.4",
"react-dom": "^16.8.4"
},
"browserslist": {
"production": [
">0.5%",
">0.2%",
"not dead",
"not op_mini all"
],
@@ -34,8 +26,5 @@
"last 1 firefox version",
"last 1 safari version"
]
},
"engines": {
"node": ">=16.14"
}
}

View File

@@ -1,31 +1,6 @@
/**
* Creating a sidebar enables you to:
- create an ordered group of docs
- render a sidebar for each doc of that group
- provide next/previous navigation
The sidebars can be generated from the filesystem, or explicitly defined here.
Create as many sidebars as you want.
*/
// @ts-check
/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */
const sidebars = {
// By default, Docusaurus generates a sidebar from the docs folder structure
tutorialSidebar: [{type: 'autogenerated', dirName: '.'}],
// But you can create a sidebar manually
/*
tutorialSidebar: [
{
type: 'category',
label: 'Tutorial',
items: ['hello'],
},
],
*/
module.exports = {
someSidebar: {
Docusaurus: ['doc1', 'doc2', 'doc3'],
Features: ['mdx'],
},
};
module.exports = sidebars;

View File

@@ -1,64 +0,0 @@
import React from 'react';
import clsx from 'clsx';
import styles from './styles.module.css';
const FeatureList = [
{
title: 'Easy to Use',
Svg: require('@site/static/img/undraw_docusaurus_mountain.svg').default,
description: (
<>
Docusaurus was designed from the ground up to be easily installed and
used to get your website up and running quickly.
</>
),
},
{
title: 'Focus on What Matters',
Svg: require('@site/static/img/undraw_docusaurus_tree.svg').default,
description: (
<>
Docusaurus lets you focus on your docs, and we&apos;ll do the chores. Go
ahead and move your docs into the <code>docs</code> directory.
</>
),
},
{
title: 'Powered by React',
Svg: require('@site/static/img/undraw_docusaurus_react.svg').default,
description: (
<>
Extend or customize your website layout by reusing React. Docusaurus can
be extended while reusing the same header and footer.
</>
),
},
];
function Feature({Svg, title, description}) {
return (
<div className={clsx('col col--4')}>
<div className="text--center">
<Svg className={styles.featureSvg} role="img" />
</div>
<div className="text--center padding-horiz--md">
<h3>{title}</h3>
<p>{description}</p>
</div>
</div>
);
}
export default function HomepageFeatures() {
return (
<section className={styles.features}>
<div className="container">
<div className="row">
{FeatureList.map((props, idx) => (
<Feature key={idx} {...props} />
))}
</div>
</div>
</section>
);
}

View File

@@ -1,11 +0,0 @@
.features {
display: flex;
align-items: center;
padding: 2rem 0;
width: 100%;
}
.featureSvg {
height: 200px;
width: 200px;
}

View File

@@ -1,3 +1,4 @@
/* stylelint-disable docusaurus/copyright-header */
/**
* Any CSS included here will be global. The classic template
* bundles Infima by default. Infima is a CSS framework designed to
@@ -6,25 +7,19 @@
/* You can override the default Infima variables here. */
:root {
--ifm-color-primary: #2e8555;
--ifm-color-primary-dark: #29784c;
--ifm-color-primary-darker: #277148;
--ifm-color-primary-darkest: #205d3b;
--ifm-color-primary-light: #33925d;
--ifm-color-primary-lighter: #359962;
--ifm-color-primary-lightest: #3cad6e;
--ifm-color-primary: #25c2a0;
--ifm-color-primary-dark: rgb(33, 175, 144);
--ifm-color-primary-darker: rgb(31, 165, 136);
--ifm-color-primary-darkest: rgb(26, 136, 112);
--ifm-color-primary-light: rgb(70, 203, 174);
--ifm-color-primary-lighter: rgb(102, 212, 189);
--ifm-color-primary-lightest: rgb(146, 224, 208);
--ifm-code-font-size: 95%;
--docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1);
}
/* For readability concerns, you should choose a lighter palette in dark mode. */
[data-theme='dark'] {
--ifm-color-primary: #25c2a0;
--ifm-color-primary-dark: #21af90;
--ifm-color-primary-darker: #1fa588;
--ifm-color-primary-darkest: #1a8870;
--ifm-color-primary-light: #29d5b0;
--ifm-color-primary-lighter: #32d8b4;
--ifm-color-primary-lightest: #4fddbf;
--docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3);
.docusaurus-highlight-code-line {
background-color: rgb(72, 77, 91);
display: block;
margin: 0 calc(-1 * var(--ifm-pre-padding));
padding: 0 var(--ifm-pre-padding);
}

View File

@@ -1,41 +1,97 @@
import React from 'react';
import clsx from 'clsx';
import classnames from 'classnames';
import Layout from '@theme/Layout';
import Link from '@docusaurus/Link';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import Layout from '@theme/Layout';
import HomepageFeatures from '@site/src/components/HomepageFeatures';
import useBaseUrl from '@docusaurus/useBaseUrl';
import styles from './styles.module.css';
import styles from './index.module.css';
const features = [
{
title: <>Easy to Use</>,
imageUrl: 'img/undraw_docusaurus_mountain.svg',
description: (
<>
Docusaurus was designed from the ground up to be easily installed and
used to get your website up and running quickly.
</>
),
},
{
title: <>Focus on What Matters</>,
imageUrl: 'img/undraw_docusaurus_tree.svg',
description: (
<>
Docusaurus lets you focus on your docs, and we&apos;ll do the chores. Go
ahead and move your docs into the <code>docs</code> directory.
</>
),
},
{
title: <>Powered by React</>,
imageUrl: 'img/undraw_docusaurus_react.svg',
description: (
<>
Extend or customize your website layout by reusing React. Docusaurus can
be extended while reusing the same header and footer.
</>
),
},
];
function HomepageHeader() {
const {siteConfig} = useDocusaurusContext();
function Feature({imageUrl, title, description}) {
const imgUrl = useBaseUrl(imageUrl);
return (
<header className={clsx('hero hero--primary', styles.heroBanner)}>
<div className="container">
<h1 className="hero__title">{siteConfig.title}</h1>
<p className="hero__subtitle">{siteConfig.tagline}</p>
<div className={styles.buttons}>
<Link
className="button button--secondary button--lg"
to="/docs/intro">
Docusaurus Tutorial - 5min
</Link>
<div className={classnames('col col--4', styles.feature)}>
{imgUrl && (
<div className="text--center">
<img className={styles.featureImage} src={imgUrl} alt={title} />
</div>
</div>
</header>
)}
<h3>{title}</h3>
<p>{description}</p>
</div>
);
}
export default function Home() {
const {siteConfig} = useDocusaurusContext();
function Home() {
const context = useDocusaurusContext();
const {siteConfig = {}} = context;
return (
<Layout
title={`Hello from ${siteConfig.title}`}
description="Description will go into a meta tag in <head />">
<HomepageHeader />
<header className={classnames('hero hero--primary', styles.heroBanner)}>
<div className="container">
<h1 className="hero__title">{siteConfig.title}</h1>
<p className="hero__subtitle">{siteConfig.tagline}</p>
<div className={styles.buttons}>
<Link
className={classnames(
'button button--outline button--secondary button--lg',
styles.getStarted,
)}
to={useBaseUrl('docs/doc1')}>
Get Started
</Link>
</div>
</div>
</header>
<main>
<HomepageFeatures />
{features && features.length && (
<section className={styles.features}>
<div className="container">
<div className="row">
{features.map((props, idx) => (
<Feature key={idx} {...props} />
))}
</div>
</div>
</section>
)}
</main>
</Layout>
);
}
export default Home;

View File

@@ -1,7 +0,0 @@
---
title: Markdown page example
---
# Markdown page example
You don't need React to write simple standalone pages.

View File

@@ -1,3 +1,4 @@
/* stylelint-disable docusaurus/copyright-header */
/**
* CSS files with the .module.css suffix will be treated as CSS modules
* and scoped locally.
@@ -10,7 +11,7 @@
overflow: hidden;
}
@media screen and (max-width: 996px) {
@media screen and (max-width: 966px) {
.heroBanner {
padding: 2rem;
}
@@ -21,3 +22,15 @@
align-items: center;
justify-content: center;
}
.features {
display: flex;
align-items: center;
padding: 2rem 0;
width: 100%;
}
.featureImage {
height: 200px;
width: 200px;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 766 B

View File

@@ -1,5 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1088" height="687.962" viewBox="0 0 1088 687.962">
<title>Easy to Use</title>
<g id="Group_12" data-name="Group 12" transform="translate(-57 -56)">
<g id="Group_11" data-name="Group 11" transform="translate(57 56)">
<path id="Path_83" data-name="Path 83" d="M1017.81,560.461c-5.27,45.15-16.22,81.4-31.25,110.31-20,38.52-54.21,54.04-84.77,70.28a193.275,193.275,0,0,1-27.46,11.94c-55.61,19.3-117.85,14.18-166.74,3.99a657.282,657.282,0,0,0-104.09-13.16q-14.97-.675-29.97-.67c-15.42.02-293.07,5.29-360.67-131.57-16.69-33.76-28.13-75-32.24-125.27-11.63-142.12,52.29-235.46,134.74-296.47,155.97-115.41,369.76-110.57,523.43,7.88C941.15,276.621,1036.99,396.031,1017.81,560.461Z" transform="translate(-56 -106.019)" fill="#3f3d56"/>

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View File

@@ -1,5 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1041.277" height="554.141" viewBox="0 0 1041.277 554.141">
<title>Powered by React</title>
<g id="Group_24" data-name="Group 24" transform="translate(-440 -263)">
<g id="Group_23" data-name="Group 23" transform="translate(439.989 262.965)">
<path id="Path_299" data-name="Path 299" d="M1040.82,611.12q-1.74,3.75-3.47,7.4-2.7,5.67-5.33,11.12c-.78,1.61-1.56,3.19-2.32,4.77-8.6,17.57-16.63,33.11-23.45,45.89A73.21,73.21,0,0,1,942.44,719l-151.65,1.65h-1.6l-13,.14-11.12.12-34.1.37h-1.38l-17.36.19h-.53l-107,1.16-95.51,1-11.11.12-69,.75H429l-44.75.48h-.48l-141.5,1.53-42.33.46a87.991,87.991,0,0,1-10.79-.54h0c-1.22-.14-2.44-.3-3.65-.49a87.38,87.38,0,0,1-51.29-27.54C116,678.37,102.75,655,93.85,629.64q-1.93-5.49-3.6-11.12C59.44,514.37,97,380,164.6,290.08q4.25-5.64,8.64-11l.07-.08c20.79-25.52,44.1-46.84,68.93-62,44-26.91,92.75-34.49,140.7-11.9,40.57,19.12,78.45,28.11,115.17,30.55,3.71.24,7.42.42,11.11.53,84.23,2.65,163.17-27.7,255.87-47.29,3.69-.78,7.39-1.55,11.12-2.28,66.13-13.16,139.49-20.1,226.73-5.51a189.089,189.089,0,0,1,26.76,6.4q5.77,1.86,11.12,4c41.64,16.94,64.35,48.24,74,87.46q1.37,5.46,2.37,11.11C1134.3,384.41,1084.19,518.23,1040.82,611.12Z" transform="translate(-79.34 -172.91)" fill="#f2f2f2"/>

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

File diff suppressed because it is too large Load Diff

View File

@@ -23,14 +23,14 @@
"eslint-config-prettier": "8.5.0",
"eslint-plugin-jest": "26.1.5",
"husky": "7.0.4",
"jest": "28.0.2",
"jest": "28.1.3",
"json5": "2.1.1",
"lint-staged": "9.2.5",
"node-fetch": "2.6.7",
"npm-package-arg": "6.1.0",
"prettier": "2.6.2",
"ts-eager": "2.0.2",
"ts-jest": "28.0.5",
"ts-jest": "28.0.7",
"turbo": "1.3.2-canary.1"
},
"scripts": {

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/build-utils",
"version": "5.1.0",
"version": "5.0.4",
"license": "MIT",
"main": "./dist/index.js",
"types": "./dist/index.d.js",
@@ -31,7 +31,7 @@
"@types/node-fetch": "^2.1.6",
"@types/semver": "6.0.0",
"@types/yazl": "2.4.2",
"@vercel/ncc": "0.24.0",
"@vercel/ncc": "0.34.0",
"aggregate-error": "3.0.1",
"async-retry": "1.2.3",
"async-sema": "2.1.4",

View File

@@ -27,7 +27,9 @@ async function prepareSymlinkTarget(
}
if (file.type === 'FileRef' || file.type === 'FileBlob') {
const targetPathBufferPromise = streamToBuffer(await file.toStreamAsync());
const targetPathBufferPromise = await streamToBuffer(
await file.toStreamAsync()
);
const [targetPathBuffer] = await Promise.all([
targetPathBufferPromise,
mkdirPromise,
@@ -40,15 +42,9 @@ async function prepareSymlinkTarget(
);
}
export async function downloadFile(
file: File,
fsPath: string
): Promise<FileFsRef> {
async function downloadFile(file: File, fsPath: string): Promise<FileFsRef> {
const { mode } = file;
// If the source is a symlink, try to create it instead of copying the file.
// Note: creating symlinks on Windows requires admin priviliges or symlinks
// enabled in the group policy. We may want to improve the error message.
if (isSymbolicLink(mode)) {
const target = await prepareSymlinkTarget(file, fsPath);
@@ -96,28 +92,12 @@ export default async function download(
await removeFile(basePath, name);
return;
}
// If a file didn't change, do not re-download it.
if (Array.isArray(filesChanged) && !filesChanged.includes(name)) {
return;
}
// Some builders resolve symlinks and return both
// a file, node_modules/<symlink>/package.json, and
// node_modules/<symlink>, a symlink.
// Removing the file matches how the yazl lambda zip
// behaves so we can use download() with `vercel build`.
const parts = name.split('/');
for (let i = 1; i < parts.length; i++) {
const dir = parts.slice(0, i).join('/');
const parent = files[dir];
if (parent && isSymbolicLink(parent.mode)) {
console.warn(
`Warning: file "${name}" is within a symlinked directory "${dir}" and will be ignored`
);
return;
}
}
const file = files[name];
const fsPath = path.join(basePath, name);

View File

@@ -4,11 +4,7 @@ import FileRef from './file-ref';
import { Lambda, createLambda, getLambdaOptionsFromFunction } from './lambda';
import { NodejsLambda } from './nodejs-lambda';
import { Prerender } from './prerender';
import download, {
downloadFile,
DownloadedFiles,
isSymbolicLink,
} from './fs/download';
import download, { DownloadedFiles, isSymbolicLink } from './fs/download';
import getWriteableDirectory from './fs/get-writable-directory';
import glob, { GlobOptions } from './fs/glob';
import rename from './fs/rename';
@@ -50,7 +46,6 @@ export {
createLambda,
Prerender,
download,
downloadFile,
DownloadedFiles,
getWriteableDirectory,
glob,

View File

@@ -1,12 +1,22 @@
import path from 'path';
import fs from 'fs-extra';
import {
packAndDeploy,
testDeployment,
// @ts-ignore
} from '../../../test/lib/deployment/test-deployment';
jest.setTimeout(4 * 60 * 1000);
const builderUrl = '@canary';
let buildUtilsUrl: string;
beforeAll(async () => {
const buildUtilsPath = path.resolve(__dirname, '..');
buildUtilsUrl = await packAndDeploy(buildUtilsPath);
console.log('buildUtilsUrl', buildUtilsUrl);
});
const fixturesPath = path.resolve(__dirname, 'fixtures');
// Fixtures that have separate tests and should be skipped in the loop
@@ -32,7 +42,10 @@ for (const fixture of fs.readdirSync(fixturesPath)) {
// eslint-disable-next-line no-loop-func
it(`Should build "${fixture}"`, async () => {
await expect(
testDeployment(path.join(fixturesPath, fixture))
testDeployment(
{ builderUrl, buildUtilsUrl },
path.join(fixturesPath, fixture)
)
).resolves.toBeDefined();
});
}
@@ -55,7 +68,10 @@ for (const builder of buildersToTestWith) {
// eslint-disable-next-line no-loop-func
it(`Should build "${builder}/${fixture}"`, async () => {
await expect(
testDeployment(path.join(fixturesPath2, fixture))
testDeployment(
{ builderUrl, buildUtilsUrl },
path.join(fixturesPath2, fixture)
)
).resolves.toBeDefined();
});
}

View File

@@ -170,53 +170,6 @@ it('should create zip files with symlinks properly', async () => {
assert(aStat.isFile());
});
it('should download symlinks even with incorrect file', async () => {
if (process.platform === 'win32') {
console.log('Skipping test on windows');
return;
}
const files = {
'dir/file.txt': new FileBlob({
mode: 33188,
contentType: undefined,
data: 'file text',
}),
linkdir: new FileBlob({
mode: 41453,
contentType: undefined,
data: 'dir',
}),
'linkdir/file.txt': new FileBlob({
mode: 33188,
contentType: undefined,
data: 'this file should be discarded',
}),
};
const outDir = path.join(__dirname, 'symlinks-out');
await fs.remove(outDir);
await fs.mkdirp(outDir);
await download(files, outDir);
const [dir, file, linkdir] = await Promise.all([
fs.lstat(path.join(outDir, 'dir')),
fs.lstat(path.join(outDir, 'dir/file.txt')),
fs.lstat(path.join(outDir, 'linkdir')),
]);
expect(dir.isFile()).toBe(false);
expect(dir.isSymbolicLink()).toBe(false);
expect(file.isFile()).toBe(true);
expect(file.isSymbolicLink()).toBe(false);
expect(linkdir.isSymbolicLink()).toBe(true);
expect(warningMessages).toEqual([
'Warning: file "linkdir/file.txt" is within a symlinked directory "linkdir" and will be ignored',
]);
});
it('should only match supported node versions, otherwise throw an error', async () => {
expect(await getSupportedNodeVersion('12.x', false)).toHaveProperty(
'major',

View File

@@ -1,8 +1,9 @@
{
"name": "vercel",
"version": "27.3.5",
"version": "27.2.0",
"preferGlobal": true,
"license": "Apache-2.0",
"type": "module",
"description": "The command-line interface for Vercel",
"homepage": "https://vercel.com",
"repository": {
@@ -11,7 +12,7 @@
"directory": "packages/cli"
},
"scripts": {
"preinstall": "node ./scripts/preinstall.js",
"preinstall": "node ./scripts/preinstall.cjs",
"test": "jest --env node --verbose --runInBand --bail --forceExit",
"test-unit": "yarn test test/unit/",
"test-integration-cli": "rimraf test/fixtures/integration && ava test/integration.js --serial --fail-fast --verbose",
@@ -27,7 +28,7 @@
},
"files": [
"dist",
"scripts/preinstall.js"
"scripts/preinstall.cjs"
],
"ava": {
"extensions": [
@@ -42,22 +43,22 @@
"node": ">= 14"
},
"dependencies": {
"@vercel/build-utils": "5.1.0",
"@vercel/go": "2.0.13",
"@vercel/hydrogen": "0.0.10",
"@vercel/next": "3.1.13",
"@vercel/node": "2.5.4",
"@vercel/python": "3.1.5",
"@vercel/redwood": "1.0.14",
"@vercel/remix": "1.0.15",
"@vercel/ruby": "1.3.21",
"@vercel/static-build": "1.0.14",
"@vercel/build-utils": "5.0.4",
"@vercel/go": "2.0.8",
"@vercel/hydrogen": "0.0.5",
"@vercel/next": "3.1.8",
"@vercel/node": "2.4.5",
"@vercel/python": "3.1.0",
"@vercel/redwood": "1.0.9",
"@vercel/remix": "1.0.10",
"@vercel/ruby": "1.3.16",
"@vercel/static-build": "1.0.9",
"update-notifier": "5.1.0"
},
"devDependencies": {
"@alex_neo/jest-expect-message": "1.0.5",
"@next/env": "11.1.2",
"@sentry/node": "5.5.0",
"@sentry/node": "7.7.0",
"@sindresorhus/slugify": "0.11.0",
"@swc/core": "1.2.218",
"@tootallnate/once": "1.1.2",
@@ -82,8 +83,7 @@
"@types/minimatch": "3.0.3",
"@types/mri": "1.1.0",
"@types/ms": "0.7.30",
"@types/node": "11.11.0",
"@types/node-fetch": "2.5.10",
"@types/node": "14",
"@types/npm-package-arg": "6.1.0",
"@types/pluralize": "0.0.29",
"@types/progress": "2.0.3",
@@ -95,18 +95,17 @@
"@types/universal-analytics": "0.4.2",
"@types/update-notifier": "5.1.0",
"@types/which": "1.3.2",
"@types/write-json-file": "2.2.1",
"@types/yauzl-promise": "2.1.0",
"@vercel/client": "12.1.8",
"@vercel/client": "12.1.3",
"@vercel/frameworks": "1.1.1",
"@vercel/fs-detectors": "2.0.3",
"@vercel/fs-detectors": "2.0.1",
"@vercel/fun": "1.0.4",
"@vercel/ncc": "0.24.0",
"@vercel/ncc": "0.34.0",
"@zeit/source-map-support": "0.6.2",
"ajv": "6.12.2",
"alpha-sort": "2.0.1",
"ansi-escapes": "3.0.0",
"ansi-regex": "3.0.0",
"ansi-regex": "6.0.1",
"arg": "5.0.0",
"async-listen": "1.2.0",
"async-retry": "1.1.3",
@@ -114,13 +113,13 @@
"ava": "2.2.0",
"boxen": "4.2.0",
"bytes": "3.0.0",
"chalk": "4.1.0",
"chalk": "5.0.1",
"chance": "1.1.7",
"chokidar": "3.3.1",
"codecov": "3.8.2",
"cpy": "7.2.0",
"credit-card": "3.0.1",
"date-fns": "1.29.0",
"date-fns": "2.29.1",
"debug": "3.1.0",
"dot": "1.1.3",
"dotenv": "4.0.0",
@@ -149,7 +148,7 @@
"minimatch": "3.0.4",
"mri": "1.1.5",
"ms": "2.1.2",
"node-fetch": "2.6.7",
"node-fetch": "3.2.9",
"npm-package-arg": "6.1.0",
"open": "8.4.0",
"ora": "3.4.0",
@@ -163,7 +162,7 @@
"rimraf": "3.0.2",
"semver": "5.5.0",
"serve-handler": "6.1.1",
"strip-ansi": "5.2.0",
"strip-ansi": "7.0.1",
"stripe": "5.1.0",
"tar-fs": "1.16.3",
"test-listen": "1.1.0",
@@ -176,23 +175,24 @@
"universal-analytics": "0.4.20",
"utility-types": "2.1.0",
"which": "2.0.2",
"write-json-file": "2.2.0",
"xdg-app-paths": "5.1.0",
"write-json-file": "5.0.0",
"xdg-app-paths": "7.3.0",
"yauzl-promise": "2.1.3"
},
"jest": {
"preset": "ts-jest",
"preset": "ts-jest/presets/default-esm",
"globals": {
"ts-jest": {
"diagnostics": false,
"isolatedModules": true
"useESM": true
}
},
"moduleNameMapper": {
"^(\\.{1,2}/.*)\\.js$": "$1"
},
"setupFilesAfterEnv": [
"@alex_neo/jest-expect-message"
],
"verbose": false,
"testEnvironment": "node",
"testMatch": [
"<rootDir>/test/**/*.test.ts"
]

View File

@@ -1,8 +1,12 @@
import cpy from 'cpy';
import execa from 'execa';
import fs from 'fs-extra';
import { join } from 'path';
import { remove, writeFile } from 'fs-extra';
import { fileURLToPath } from 'url';
const { remove, writeFile } = fs;
const __dirname = fileURLToPath(new URL('.', import.meta.url));
const dirRoot = join(__dirname, '..');
const distRoot = join(dirRoot, 'dist');
@@ -38,10 +42,11 @@ async function main() {
await remove(join(dirRoot, '../../node_modules/fsevents'));
// Compile the `doT.js` template files for `vercel dev`
console.log();
await execa(process.execPath, [join(__dirname, 'compile-templates.js')], {
stdio: 'inherit',
});
// TODO
//console.log();
//await execa(process.execPath, [join(__dirname, 'compile-templates.cjs')], {
// stdio: 'inherit',
//});
// Do the initial `ncc` build
console.log();

View File

@@ -36,7 +36,7 @@ async function main() {
const def = await readFile(fnPath.replace(/\.js$/, '.tsdef'), 'utf8');
const interfaceName = def.match(/interface (\w+)/)[1];
const lines = require(fnPath)
const lines = (await import(fnPath))
.toString()
.split('\n');
let errorHtmlStart = -1;

View File

@@ -4,18 +4,18 @@ import execa from 'execa';
import plural from 'pluralize';
import inquirer from 'inquirer';
import { resolve } from 'path';
import chalk, { Chalk } from 'chalk';
import chalk, { ChalkInstance } from 'chalk';
import { URLSearchParams, parse } from 'url';
import sleep from '../../util/sleep';
import formatDate from '../../util/format-date';
import link from '../../util/output/link';
import logo from '../../util/output/logo';
import getArgs from '../../util/get-args';
import Client from '../../util/client';
import { getPkgName } from '../../util/pkg-name';
import { Deployment, PaginationOptions } from '../../types';
import { normalizeURL } from '../../util/bisect/normalize-url';
import sleep from '../../util/sleep.js';
import formatDate from '../../util/format-date.js';
import link from '../../util/output/link.js';
import logo from '../../util/output/logo.js';
import getArgs from '../../util/get-args.js';
import Client from '../../util/client.js';
import { getPkgName } from '../../util/pkg-name.js';
import { Deployment, PaginationOptions } from '../../types.js';
import { normalizeURL } from '../../util/bisect/normalize-url.js';
interface DeploymentV6
extends Pick<
@@ -298,7 +298,7 @@ export default async function main(client: Client): Promise<number> {
return 1;
}
const { exitCode } = proc;
let color: Chalk;
let color: ChalkInstance;
if (exitCode === 0) {
color = chalk.green;
action = 'good';

View File

@@ -469,8 +469,6 @@ async function doBuild(
)
);
} catch (err: any) {
output.prettyError(err);
const writeConfigJsonPromise = fs.writeJSON(
join(outputDir, 'config.json'),
{ version: 3 },

View File

@@ -16,27 +16,26 @@ export const help = () => `
dev Start a local development server
env Manages the Environment Variables for your current Project
git Manage Git provider repository for your current Project
help [cmd] Displays complete help for [cmd]
init [example] Initialize an example project
ls | list [app] Lists deployments
inspect [id] Displays information related to a deployment
link [path] Link local directory to a Vercel Project
ls | list [app] Lists deployments
login [email] Logs into your account or creates a new one
logout Logs out of your account
pull [path] Pull your Project Settings from the cloud
switch [scope] Switches between teams and your personal account
help [cmd] Displays complete help for [cmd]
${chalk.dim('Advanced')}
alias [cmd] Manages your domain aliases
bisect Use binary search to find the deployment that introduced a bug
certs [cmd] Manages your SSL certificates
dns [name] Manages your DNS records
domains [name] Manages your domain names
logs [url] Displays the logs for a deployment
projects Manages your Projects
rm | remove [id] Removes a deployment
bisect Use binary search to find the deployment that introduced a bug
domains [name] Manages your domain names
projects Manages your Projects
dns [name] Manages your DNS records
certs [cmd] Manages your SSL certificates
secrets [name] Manages your global Secrets, for use in Environment Variables
logs [url] Displays the logs for a deployment
teams Manages your teams
whoami Shows the username of the currently logged in user

View File

@@ -1,21 +1,21 @@
import chalk from 'chalk';
import { ProjectEnvTarget, Project, ProjectEnvType } from '../../types';
import { Output } from '../../util/output';
import Client from '../../util/client';
import stamp from '../../util/output/stamp';
import addEnvRecord from '../../util/env/add-env-record';
import getEnvRecords from '../../util/env/get-env-records';
import { ProjectEnvTarget, Project, ProjectEnvType } from '../../types.js';
import { Output } from '../../util/output/index.js';
import Client from '../../util/client.js';
import stamp from '../../util/output/stamp.js';
import addEnvRecord from '../../util/env/add-env-record.js';
import getEnvRecords from '../../util/env/get-env-records.js';
import {
isValidEnvTarget,
getEnvTargetPlaceholder,
getEnvTargetChoices,
} from '../../util/env/env-target';
import readStandardInput from '../../util/input/read-standard-input';
import param from '../../util/output/param';
import { emoji, prependEmoji } from '../../util/emoji';
import { isKnownError } from '../../util/env/known-error';
import { getCommandName } from '../../util/pkg-name';
import { isAPIError } from '../../util/errors-ts';
} from '../../util/env/env-target.js';
import readStandardInput from '../../util/input/read-standard-input.js';
import param from '../../util/output/param.js';
import { emoji, prependEmoji } from '../../util/emoji.js';
import { isKnownError } from '../../util/env/known-error.js';
import { getCommandName } from '../../util/pkg-name.js';
import { isAPIError } from '../../util/errors-ts.js';
type Options = {
'--debug': boolean;
@@ -29,7 +29,7 @@ export default async function add(
output: Output
) {
// improve the way we show inquirer prompts
require('../../util/input/patch-inquirer');
await import('../../util/input/patch-inquirer.js');
const stdInput = await readStandardInput(client.stdin);
let [envName, envTargetArg, envGitBranch] = args;

View File

@@ -130,12 +130,6 @@ export default async function pull(
await outputFile(fullPath, contents, 'utf8');
if (deltaString) {
output.print('\n' + deltaString);
} else if (oldEnv && exists) {
output.log('No changes found.');
}
output.print(
`${prependEmoji(
`${exists ? 'Updated' : 'Created'} ${chalk.bold(
@@ -145,6 +139,13 @@ export default async function pull(
)}\n`
);
output.print('\n');
if (deltaString) {
output.print(deltaString);
} else if (oldEnv && exists) {
output.log('No changes found.');
}
return 0;
}

View File

@@ -1,22 +1,22 @@
import chalk from 'chalk';
import inquirer from 'inquirer';
import { Project } from '../../types';
import { Output } from '../../util/output';
import confirm from '../../util/input/confirm';
import removeEnvRecord from '../../util/env/remove-env-record';
import getEnvRecords from '../../util/env/get-env-records';
import formatEnvTarget from '../../util/env/format-env-target';
import { Project } from '../../types.js';
import { Output } from '../../util/output/index.js';
import confirm from '../../util/input/confirm.js';
import removeEnvRecord from '../../util/env/remove-env-record.js';
import getEnvRecords from '../../util/env/get-env-records.js';
import formatEnvTarget from '../../util/env/format-env-target.js';
import {
isValidEnvTarget,
getEnvTargetPlaceholder,
} from '../../util/env/env-target';
import Client from '../../util/client';
import stamp from '../../util/output/stamp';
import param from '../../util/output/param';
import { emoji, prependEmoji } from '../../util/emoji';
import { isKnownError } from '../../util/env/known-error';
import { getCommandName } from '../../util/pkg-name';
import { isAPIError } from '../../util/errors-ts';
} from '../../util/env/env-target.js';
import Client from '../../util/client.js';
import stamp from '../../util/output/stamp.js';
import param from '../../util/output/param.js';
import { emoji, prependEmoji } from '../../util/emoji.js';
import { isKnownError } from '../../util/env/known-error.js';
import { getCommandName } from '../../util/pkg-name.js';
import { isAPIError } from '../../util/errors-ts.js';
type Options = {
'--debug': boolean;
@@ -31,7 +31,7 @@ export default async function rm(
output: Output
) {
// improve the way we show inquirer prompts
require('../../util/input/patch-inquirer');
await import('../../util/input/patch-inquirer.js');
if (args.length > 3) {
output.error(

View File

@@ -3,16 +3,15 @@ import path from 'path';
import tar from 'tar-fs';
import chalk from 'chalk';
// @ts-ignore
import listInput from '../../util/input/list';
import listItem from '../../util/output/list-item';
import promptBool from '../../util/input/prompt-bool';
import toHumanPath from '../../util/humanize-path';
import Client from '../../util/client';
import info from '../../util/output/info';
import cmd from '../../util/output/cmd';
import didYouMean from '../../util/init/did-you-mean';
import { getCommandName } from '../../util/pkg-name';
import listInput from '../../util/input/list.js';
import listItem from '../../util/output/list-item.js';
import promptBool from '../../util/input/prompt-bool.js';
import toHumanPath from '../../util/humanize-path.js';
import Client from '../../util/client.js';
import info from '../../util/output/info.js';
import cmd from '../../util/output/cmd.js';
import didYouMean from '../../util/init/did-you-mean.js';
import { getCommandName } from '../../util/pkg-name.js';
type Options = {
'--debug': boolean;
@@ -138,10 +137,14 @@ async function extractExample(
await new Promise((resolve, reject) => {
const extractor = tar.extract(folder);
res.body.on('error', reject);
extractor.on('error', reject);
extractor.on('finish', resolve);
res.body.pipe(extractor);
if (res.body) {
res.body.on('error', reject);
res.body.pipe(extractor);
} else {
reject(new Error(`res.body not defiled`));
}
});
const successLog = `Initialized "${chalk.bold(

View File

@@ -12,10 +12,8 @@ import Client from '../util/client';
import { getDeployment } from '../util/get-deployment';
import { Deployment } from '@vercel/client';
import { Build } from '../types';
import title from 'title';
import { isErrnoException } from '../util/is-error';
import { isAPIError } from '../util/errors-ts';
import { URL } from 'url';
const help = () => {
console.log(`
@@ -67,7 +65,7 @@ export default async function main(client: Client) {
const { print, log, error } = client.output;
// extract the first parameter
let [, deploymentIdOrHost] = argv._;
const [, deploymentIdOrHost] = argv._;
if (argv._.length !== 2) {
error(`${getCommandName('inspect <url>')} expects exactly one argument`);
@@ -91,16 +89,12 @@ export default async function main(client: Client) {
throw err;
}
// resolve the deployment, since we might have been given an alias
const depFetchStart = Date.now();
try {
deploymentIdOrHost = new URL(deploymentIdOrHost).hostname;
} catch {}
client.output.spinner(
`Fetching deployment "${deploymentIdOrHost}" in ${chalk.bold(contextName)}`
);
// resolve the deployment, since we might have been given an alias
try {
deployment = await getDeployment(client, deploymentIdOrHost);
} catch (err: unknown) {
@@ -126,15 +120,7 @@ export default async function main(client: Client) {
throw err;
}
const {
id,
name,
url,
createdAt,
routes,
readyState,
alias: aliases,
} = deployment;
const { id, name, url, createdAt, routes, readyState } = deployment;
const { builds } =
deployment.version === 2
@@ -142,20 +128,20 @@ export default async function main(client: Client) {
: { builds: [] };
log(
`Fetched deployment ${chalk.bold(url)} in ${chalk.bold(
contextName
)} ${elapsed(Date.now() - depFetchStart)}`
`Fetched deployment "${url}" in ${chalk.bold(contextName)} ${elapsed(
Date.now() - depFetchStart
)}`
);
print('\n');
print(chalk.bold(' General\n\n'));
print(` ${chalk.cyan('id')}\t\t${id}\n`);
print(` ${chalk.cyan('name')}\t${name}\n`);
print(` ${chalk.cyan('status')}\t${stateString(readyState)}\n`);
print(` ${chalk.cyan('url')}\t\thttps://${url}\n`);
print(` ${chalk.cyan('readyState')}\t${stateString(readyState)}\n`);
print(` ${chalk.cyan('url')}\t\t${url}\n`);
if (createdAt) {
print(
` ${chalk.cyan('created')}\t${new Date(createdAt)} ${elapsed(
` ${chalk.cyan('createdAt')}\t${new Date(createdAt)} ${elapsed(
Date.now() - createdAt,
true
)}\n`
@@ -163,16 +149,6 @@ export default async function main(client: Client) {
}
print('\n\n');
if (aliases.length > 0) {
print(chalk.bold(' Aliases\n\n'));
let aliasList = '';
for (const alias of aliases) {
aliasList += `${chalk.gray('╶')} https://${alias}\n`;
}
print(indent(aliasList, 4));
print('\n\n');
}
if (builds.length > 0) {
const times: { [id: string]: string | null } = {};
@@ -196,24 +172,19 @@ export default async function main(client: Client) {
return 0;
}
// renders the state string
function stateString(s: Deployment['readyState']) {
const CIRCLE = '● ';
const sTitle = s && title(s);
switch (s) {
case 'INITIALIZING':
case 'BUILDING':
case 'DEPLOYING':
case 'ANALYZING':
return chalk.yellow(CIRCLE) + sTitle;
return chalk.yellow(s);
case 'ERROR':
return chalk.red(CIRCLE) + sTitle;
return chalk.red(s);
case 'READY':
return chalk.green(CIRCLE) + sTitle;
case 'QUEUED':
return chalk.gray(CIRCLE) + sTitle;
case 'CANCELED':
return chalk.gray(CIRCLE) + sTitle;
return s;
default:
return chalk.gray('UNKNOWN');
return chalk.gray(s || 'UNKNOWN');
}
}

View File

@@ -1,25 +1,25 @@
import chalk from 'chalk';
import ms from 'ms';
import table from 'text-table';
import Now from '../util';
import getArgs from '../util/get-args';
import { handleError } from '../util/error';
import cmd from '../util/output/cmd';
import logo from '../util/output/logo';
import elapsed from '../util/output/elapsed';
import strlen from '../util/strlen';
import toHost from '../util/to-host';
import parseMeta from '../util/parse-meta';
import { isValidName } from '../util/is-valid-name';
import getCommandFlags from '../util/get-command-flags';
import { getPkgName, getCommandName } from '../util/pkg-name';
import Client from '../util/client';
import { Deployment } from '../types';
import validatePaths from '../util/validate-paths';
import { getLinkedProject } from '../util/projects/link';
import { ensureLink } from '../util/ensure-link';
import getScope from '../util/get-scope';
import { isAPIError } from '../util/errors-ts';
import Now from '../util/index.js';
import getArgs from '../util/get-args.js';
import { handleError } from '../util/error.js';
import cmd from '../util/output/cmd.js';
import logo from '../util/output/logo.js';
import elapsed from '../util/output/elapsed.js';
import strlen from '../util/strlen.js';
import toHost from '../util/to-host.js';
import parseMeta from '../util/parse-meta.js';
import { isValidName } from '../util/is-valid-name.js';
import getCommandFlags from '../util/get-command-flags.js';
import { getPkgName, getCommandName } from '../util/pkg-name.js';
import Client from '../util/client.js';
import { Deployment } from '../types.js';
import validatePaths from '../util/validate-paths.js';
import { getLinkedProject } from '../util/projects/link.js';
import { ensureLink } from '../util/ensure-link.js';
import getScope from '../util/get-scope.js';
import { isAPIError } from '../util/errors-ts.js';
const help = () => {
console.log(`
@@ -204,6 +204,7 @@ export default async function main(client: Client) {
nextTimestamp,
});
// @ts-ignore
let {
deployments,
pagination,

View File

@@ -1,11 +1,11 @@
#!/usr/bin/env node
import { isErrnoException, isError, errorToString } from './util/is-error';
import { isErrnoException, isError, errorToString } from './util/is-error.js';
try {
// Test to see if cwd has been deleted before
// importing 3rd party packages that might need cwd.
process.cwd();
} catch (err: unknown) {
} catch (err) {
if (isError(err) && err.message.includes('uv_cwd')) {
console.error('Error! The current working directory does not exist.');
process.exit(1);
@@ -21,37 +21,37 @@ import epipebomb from 'epipebomb';
import updateNotifier from 'update-notifier';
import { URL } from 'url';
import * as Sentry from '@sentry/node';
import hp from './util/humanize-path';
import commands from './commands';
import pkg from './util/pkg';
import { Output } from './util/output';
import cmd from './util/output/cmd';
import info from './util/output/info';
import error from './util/output/error';
import param from './util/output/param';
import highlight from './util/output/highlight';
import getArgs from './util/get-args';
import getUser from './util/get-user';
import getTeams from './util/teams/get-teams';
import Client from './util/client';
import { handleError } from './util/error';
import reportError from './util/report-error';
import getConfig from './util/get-config';
import * as configFiles from './util/config/files';
import getGlobalPathConfig from './util/config/global-path';
import hp from './util/humanize-path.js';
import commands from './commands/index.js';
import pkg from './util/pkg.js';
import { Output } from './util/output/index.js';
import cmd from './util/output/cmd.js';
import info from './util/output/info.js';
import error from './util/output/error.js';
import param from './util/output/param.js';
import highlight from './util/output/highlight.js';
import getArgs from './util/get-args.js';
import getUser from './util/get-user.js';
import getTeams from './util/teams/get-teams.js';
import Client from './util/client.js';
import { handleError } from './util/error.js';
import reportError from './util/report-error.js';
import getConfig from './util/get-config.js';
import * as configFiles from './util/config/files.js';
import getGlobalPathConfig from './util/config/global-path.js';
import {
defaultAuthConfig,
defaultGlobalConfig,
} from './util/config/get-default';
import * as ERRORS from './util/errors-ts';
import { APIError } from './util/errors-ts';
import { SENTRY_DSN } from './util/constants';
import getUpdateCommand from './util/get-update-command';
import { metrics, shouldCollectMetrics } from './util/metrics';
import { getCommandName, getTitleName } from './util/pkg-name';
import doLoginPrompt from './util/login/prompt';
import { AuthConfig, GlobalConfig } from './types';
import { VercelConfig } from '@vercel/client';
getDefaultConfig,
getDefaultAuthConfig,
} from './util/config/get-default.js';
import * as ERRORS from './util/errors-ts.js';
import { APIError } from './util/errors-ts.js';
import { SENTRY_DSN } from './util/constants.js';
import getUpdateCommand from './util/get-update-command.js';
import { metrics, shouldCollectMetrics } from './util/metrics.js';
import { getCommandName, getTitleName } from './util/pkg-name.js';
import doLoginPrompt from './util/login/prompt.js';
import type { GlobalConfig } from './types.js';
import type { VercelConfig } from '@vercel/client';
const isCanary = pkg.version.includes('canary');
@@ -208,59 +208,161 @@ const main = async () => {
VERCEL_DIR
)}" ${errorToString(err)}`
);
}
let migrated = false;
let configExists;
try {
configExists = existsSync(VERCEL_CONFIG_PATH);
} catch (err: unknown) {
console.error(
error(
`${
'An unexpected error occurred while trying to find the ' +
`config file "${hp(VERCEL_CONFIG_PATH)}" `
}${errorToString(err)}`
)
);
return 0;
}
let config: GlobalConfig | null = null;
if (configExists) {
try {
config = configFiles.readConfigFile();
} catch (err) {
console.error(
error(
`${
'An unexpected error occurred while trying to read the ' +
`config in "${hp(VERCEL_CONFIG_PATH)}" `
}${errorToString(err)}`
)
);
return 1;
}
// This is from when Vercel CLI supported
// multiple providers. In that case, we really
// need to migrate.
if (
// @ts-ignore
config.sh ||
// @ts-ignore
config.user ||
// @ts-ignore
typeof config.user === 'object' ||
// @ts-ignore
typeof config.currentTeam === 'object'
) {
configExists = false;
}
}
if (!configExists) {
const results = await getDefaultConfig(config);
config = results.config;
migrated = results.migrated;
try {
configFiles.writeToConfigFile(config);
} catch (err: unknown) {
console.error(
error(
`${
'An unexpected error occurred while trying to write the ' +
`default config to "${hp(VERCEL_CONFIG_PATH)}" `
}${errorToString(err)}`
)
);
return 1;
}
}
let authConfigExists;
try {
authConfigExists = existsSync(VERCEL_AUTH_CONFIG_PATH);
} catch (err: unknown) {
console.error(
error(
`${
'An unexpected error occurred while trying to find the ' +
`auth file "${hp(VERCEL_AUTH_CONFIG_PATH)}" `
}${errorToString(err)}`
)
);
return 1;
}
let config: GlobalConfig;
try {
config = configFiles.readConfigFile();
} catch (err: unknown) {
if (isErrnoException(err) && err.code === 'ENOENT') {
config = defaultGlobalConfig;
try {
configFiles.writeToConfigFile(config);
} catch (err: unknown) {
output.error(
`An unexpected error occurred while trying to save the config to "${hp(
VERCEL_CONFIG_PATH
)}" ${errorToString(err)}`
);
return 1;
}
} else {
output.error(
`An unexpected error occurred while trying to read the config in "${hp(
VERCEL_CONFIG_PATH
)}" ${errorToString(err)}`
let authConfig = null;
const subcommandsWithoutToken = [
'login',
'logout',
'help',
'init',
'update',
'build',
];
if (authConfigExists) {
try {
authConfig = configFiles.readAuthConfigFile();
} catch (err: unknown) {
console.error(
error(
`${
'An unexpected error occurred while trying to read the ' +
`auth config in "${hp(VERCEL_AUTH_CONFIG_PATH)}" `
}${errorToString(err)}`
)
);
return 1;
}
// This is from when Vercel CLI supported
// multiple providers. In that case, we really
// need to migrate.
// @ts-ignore
if (authConfig.credentials) {
authConfigExists = false;
}
} else {
const results = await getDefaultAuthConfig(authConfig);
authConfig = results.config;
migrated = results.migrated;
try {
configFiles.writeToAuthConfigFile(authConfig);
} catch (err: unknown) {
console.error(
error(
`${
'An unexpected error occurred while trying to write the ' +
`default config to "${hp(VERCEL_AUTH_CONFIG_PATH)}" `
}${errorToString(err)}`
)
);
return 1;
}
}
let authConfig: AuthConfig;
try {
authConfig = configFiles.readAuthConfigFile();
} catch (err: unknown) {
if (isErrnoException(err) && err.code === 'ENOENT') {
authConfig = defaultAuthConfig;
try {
configFiles.writeToAuthConfigFile(authConfig);
} catch (err: unknown) {
output.error(
`An unexpected error occurred while trying to write the auth config to "${hp(
VERCEL_AUTH_CONFIG_PATH
)}" ${errorToString(err)}`
);
return 1;
}
} else {
output.error(
`An unexpected error occurred while trying to read the auth config in "${hp(
VERCEL_AUTH_CONFIG_PATH
)}" ${errorToString(err)}`
);
return 1;
}
// Let the user know we migrated the config
if (migrated) {
const directory = param(hp(VERCEL_DIR));
debug(
`The credentials and configuration within the ${directory} directory were upgraded`
);
}
if (typeof argv['--api'] === 'string') {
@@ -270,12 +372,18 @@ const main = async () => {
}
try {
// eslint-disable-next-line no-new
new URL(apiUrl);
} catch (err: unknown) {
} catch (err) {
output.error(`Please provide a valid URL instead of ${highlight(apiUrl)}.`);
return 1;
}
if (!config) {
output.error(`Vercel global config was not loaded.`);
return 1;
}
// Shared API `Client` instance for all sub-commands to utilize
client = new Client({
apiUrl,
@@ -323,15 +431,6 @@ const main = async () => {
client.argv.push('-h');
}
const subcommandsWithoutToken = [
'login',
'logout',
'help',
'init',
'update',
'build',
];
// Prompt for login if there is no current token
if (
(!authConfig || !authConfig.token) &&

View File

@@ -20,15 +20,13 @@ export interface JSONObject {
}
export interface AuthConfig {
'// Note'?: string;
'// Docs'?: string;
_?: string;
token?: string;
skipWrite?: boolean;
}
export interface GlobalConfig {
'// Note'?: string;
'// Docs'?: string;
_?: string;
currentTeam?: string;
includeScheme?: string;
collectMetrics?: boolean;

View File

@@ -1,4 +1,4 @@
import { Build } from '../types';
import { Build } from '../types.js';
export const isReady = ({ readyState }: Pick<Build, 'readyState'>) =>
readyState === 'READY';

View File

@@ -81,7 +81,7 @@ export async function resolveBuilders(
continue;
}
if (name === '@vercel/static' || name === '@now/static') {
if (name === '@vercel/static') {
// `@vercel/static` is a special-case built-in builder
builders.set(name, {
builder: staticBuilder,

View File

@@ -1,8 +1,8 @@
import frameworkList from '@vercel/frameworks';
import { frameworks } from '@vercel/frameworks';
export function sortBuilders<B extends { use: string }>(builds: B[]): B[] {
const frontendRuntimeSet = new Set(
frameworkList.map(f => f.useRuntime?.use || '@vercel/static-build')
frameworks.map(f => (f as any).useRuntime?.use || '@vercel/static-build')
);
const toNumber = (build: B) => (frontendRuntimeSet.has(build.use) ? 0 : 1);

View File

@@ -21,7 +21,6 @@ import {
PackageJson,
Prerender,
download,
downloadFile,
EdgeFunction,
BuildResultBuildOutput,
getLambdaOptionsFromFunction,
@@ -267,7 +266,9 @@ async function writeStaticFile(
const dest = join(outputDir, 'static', fsPath);
await fs.mkdirp(dirname(dest));
await downloadFile(file, dest);
// TODO: handle (or skip) symlinks?
const stream = file.toStream();
await pipe(stream, fs.createWriteStream(dest, { mode: file.mode }));
}
/**

View File

@@ -1,4 +1,4 @@
import { bold } from 'chalk';
import chalk from 'chalk';
import inquirer from 'inquirer';
import { EventEmitter } from 'events';
import { URLSearchParams } from 'url';
@@ -6,13 +6,13 @@ import { parse as parseUrl } from 'url';
import { VercelConfig } from '@vercel/client';
import retry, { RetryFunction, Options as RetryOptions } from 'async-retry';
import fetch, { BodyInit, Headers, RequestInit, Response } from 'node-fetch';
import ua from './ua';
import { Output } from './output/create-output';
import responseError from './response-error';
import printIndications from './print-indications';
import reauthenticate from './login/reauthenticate';
import { SAMLError } from './login/types';
import { writeToAuthConfigFile } from './config/files';
import ua from './ua.js';
import { Output } from './output/create-output.js';
import responseError from './response-error.js';
import printIndications from './print-indications.js';
import reauthenticate from './login/reauthenticate.js';
import { SAMLError } from './login/types.js';
import { writeToAuthConfigFile } from './config/files.js';
import type {
AuthConfig,
GlobalConfig,
@@ -20,9 +20,11 @@ import type {
Stdio,
ReadableTTY,
WritableTTY,
} from '../types';
import { sharedPromise } from './promise';
import { APIError } from './errors-ts';
} from '../types.js';
import { sharedPromise } from './promise.js';
import { APIError } from './errors-ts.js';
const { bold } = chalk;
const isSAMLError = (v: any): v is SAMLError => {
return v && v.saml;
@@ -92,7 +94,18 @@ export default class Client extends EventEmitter implements Stdio {
: '';
if (opts.accountId || opts.useCurrentTeam !== false) {
const query = new URLSearchParams(parsedUrl.query);
//const query = new URLSearchParams(parsedUrl.query);
// TODO: move this to a helper function?
const query = new URLSearchParams();
for (const [name, value] of Object.entries(parsedUrl.query)) {
if (Array.isArray(value)) {
for (const val of value) {
query.append(name, val);
}
} else if (typeof value === 'string') {
query.set(name, value);
}
}
if (opts.accountId) {
if (opts.accountId.startsWith('team_')) {

View File

@@ -1,16 +1,16 @@
import { join, basename } from 'path';
import loadJSON from 'load-json-file';
import writeJSON from 'write-json-file';
import { writeJsonFileSync } from 'write-json-file';
import { existsSync } from 'fs';
import { fileNameSymbol } from '@vercel/client';
import getGlobalPathConfig from './global-path';
import getLocalPathConfig from './local-path';
import { NowError } from '../now-error';
import error from '../output/error';
import highlight from '../output/highlight';
import { VercelConfig } from '../dev/types';
import { AuthConfig, GlobalConfig } from '../../types';
import { isErrnoException, isError } from '../is-error';
import getGlobalPathConfig from './global-path.js';
import getLocalPathConfig from './local-path.js';
import { NowError } from '../now-error.js';
import error from '../output/error.js';
import highlight from '../output/highlight.js';
import { VercelConfig } from '../dev/types.js';
import { AuthConfig, GlobalConfig } from '../../types.js';
import { isErrnoException, isError } from '../is-error.js';
const VERCEL_DIR = getGlobalPathConfig();
const CONFIG_FILE_PATH = join(VERCEL_DIR, 'config.json');
@@ -25,7 +25,7 @@ export const readConfigFile = (): GlobalConfig => {
// writes whatever's in `stuff` to "global config" file, atomically
export const writeToConfigFile = (stuff: GlobalConfig): void => {
try {
return writeJSON.sync(CONFIG_FILE_PATH, stuff, { indent: 2 });
return writeJsonFileSync(CONFIG_FILE_PATH, stuff, { indent: 2 });
} catch (err: unknown) {
if (isErrnoException(err)) {
if (isErrnoException(err) && err.code === 'EPERM') {
@@ -64,7 +64,7 @@ export const writeToAuthConfigFile = (authConfig: AuthConfig) => {
return;
}
try {
return writeJSON.sync(AUTH_CONFIG_FILE_PATH, authConfig, {
return writeJsonFileSync(AUTH_CONFIG_FILE_PATH, authConfig, {
indent: 2,
mode: 0o600,
});

View File

@@ -1,15 +1,75 @@
import { AuthConfig, GlobalConfig } from '../../types';
export const defaultGlobalConfig: GlobalConfig = {
'// Note':
'This is your Vercel config file. For more information see the global configuration documentation.',
'// Docs':
'https://vercel.com/docs/project-configuration#global-configuration/config-json',
collectMetrics: true,
export const getDefaultConfig = async (existingCopy?: GlobalConfig | null) => {
let migrated = false;
const config: GlobalConfig = {
_: 'This is your Vercel config file. For more information see the global configuration documentation: https://vercel.com/docs/configuration#global',
collectMetrics: true,
};
if (existingCopy) {
const keep = [
'_',
'currentTeam',
'desktop',
'updateChannel',
'collectMetrics',
'api',
// This is deleted later in the code
];
try {
const existing = Object.assign({}, existingCopy);
// @ts-ignore
const sh = Object.assign({}, existing.sh || {});
Object.assign(config, existing, sh);
for (const key of Object.keys(config)) {
if (!keep.includes(key)) {
// @ts-ignore
delete config[key];
}
}
if (typeof config.currentTeam === 'object') {
// @ts-ignore
config.currentTeam = config.currentTeam.id;
}
// @ts-ignore
if (typeof config.user === 'object') {
// @ts-ignore
config.user = config.user.uid || config.user.id;
}
migrated = true;
} catch (err) {}
}
return { config, migrated };
};
export const defaultAuthConfig: AuthConfig = {
'// Note': 'This is your Vercel credentials file. DO NOT SHARE!',
'// Docs':
'https://vercel.com/docs/project-configuration#global-configuration/auth-json',
export const getDefaultAuthConfig = async (existing?: AuthConfig | null) => {
let migrated = false;
const config: AuthConfig = {
_: 'This is your Vercel credentials file. DO NOT SHARE! More: https://vercel.com/docs/configuration#global',
};
if (existing) {
try {
// @ts-ignore
const sh = existing.credentials.find(item => item.provider === 'sh');
if (sh) {
config.token = sh.token;
}
migrated = true;
} catch (err) {}
}
return { config, migrated };
};

View File

@@ -1,8 +1,8 @@
import { homedir } from 'os';
import fs from 'fs';
import path from 'path';
import { homedir } from 'os';
import XDGAppPaths from 'xdg-app-paths';
import getArgs from '../../util/get-args';
import getArgs from '../../util/get-args.js';
// Returns whether a directory exists
export const isDirectory = (path: string): boolean => {

View File

@@ -1,8 +1,8 @@
import path from 'path';
import { existsSync } from 'fs';
import { InvalidLocalConfig } from '../errors';
import { ConflictingConfigFiles } from '../errors-ts';
import getArgs from '../../util/get-args';
import { InvalidLocalConfig } from '../errors.js';
import { ConflictingConfigFiles } from '../errors-ts.js';
import getArgs from '../../util/get-args.js';
export default function getLocalPathConfig(prefix: string) {
let customPath: string | undefined;

View File

@@ -18,14 +18,14 @@ import { isOfficialRuntime } from '@vercel/fs-detectors';
import plural from 'pluralize';
import minimatch from 'minimatch';
import { Output } from '../output';
import highlight from '../output/highlight';
import { treeKill } from '../tree-kill';
import { relative } from '../path-helpers';
import { LambdaSizeExceededError } from '../errors-ts';
import { Output } from '../output/index.js';
import highlight from '../output/highlight.js';
import { treeKill } from '../tree-kill.js';
import { relative } from '../path-helpers.js';
import { LambdaSizeExceededError } from '../errors-ts.js';
import DevServer from './server';
import { getBuilder } from './builder-cache';
import DevServer from './server.js';
import { getBuilder } from './builder-cache.js';
import {
VercelConfig,
BuildMatch,
@@ -36,10 +36,10 @@ import {
BuilderOutputs,
EnvConfigs,
BuiltLambda,
} from './types';
} from './types.js';
import { normalizeRoutes } from '@vercel/routing-utils';
import getUpdateCommand from '../get-update-command';
import { getTitleName } from '../pkg-name';
import getUpdateCommand from '../get-update-command.js';
import { getTitleName } from '../pkg-name.js';
interface BuildMessage {
type: string;
@@ -86,7 +86,7 @@ async function createBuildProcess(
return new Promise((resolve, reject) => {
// The first message that the builder process sends is the `ready` event
buildProcess.once('message', ({ type }) => {
buildProcess.once('message', ({ type }: { type?: string }) => {
if (type !== 'ready') {
reject(new Error('Did not get "ready" event from builder'));
} else {

View File

@@ -2,7 +2,7 @@ import {
ProjectEnvType,
ProjectEnvVariable,
ProjectEnvTarget,
} from '../../types';
} from '../../types.js';
import { Env } from '@vercel/build-utils';
function getSystemEnvValue(

View File

@@ -1,5 +1,5 @@
import { parse } from 'url';
import { ListenSpec } from './types';
import { ListenSpec } from './types.js';
export default function parseListen(
str: string,
@@ -34,11 +34,11 @@ export default function parseListen(
return [url.pathname];
case 'tcp:':
url.port = url.port || String(defaultPort);
return [parseInt(url.port, 10), url.hostname];
return [parseInt(url.port, 10), url.hostname ?? undefined];
default:
if (!url.slashes) {
if (url.protocol === null) {
return [defaultPort, url.pathname];
return [defaultPort, url.pathname ?? undefined];
}
port = Number(url.hostname);
if (url.protocol && !isNaN(port)) {

View File

@@ -1,10 +1,10 @@
import url from 'url';
import PCRE from 'pcre-to-regexp';
import isURL from './is-url';
import DevServer from './server';
import isURL from './is-url.js';
import DevServer from './server.js';
import { VercelConfig, HttpHeadersConfig, RouteResult } from './types';
import { VercelConfig, HttpHeadersConfig, RouteResult } from './types.js';
import { isHandler, Route, HandleValue } from '@vercel/routing-utils';
export function resolveRouteParameters(
@@ -56,7 +56,8 @@ export async function devRouter(
phase?: HandleValue | null
): Promise<RouteResult> {
let result: RouteResult | undefined;
let { query, pathname: reqPathname = '/' } = url.parse(reqUrl, true);
let { query, pathname: _reqPathname } = url.parse(reqUrl, true);
let reqPathname = _reqPathname || '/';
const combinedHeaders: HttpHeadersConfig = { ...previousHeaders };
let status: number | undefined;
let isContinue = false;
@@ -128,9 +129,9 @@ export async function devRouter(
phase !== 'hit' &&
!isDestUrl
) {
const { pathname = '/' } = url.parse(destPath);
const { pathname } = url.parse(destPath);
const hasDestFile = await devServer.hasFilesystem(
pathname,
pathname || '/',
vercelConfig
);

View File

@@ -44,36 +44,39 @@ import {
detectApiExtensions,
isOfficialRuntime,
} from '@vercel/fs-detectors';
import frameworkList from '@vercel/frameworks';
import frameworks from '@vercel/frameworks';
import cmd from '../output/cmd';
import link from '../output/link';
import sleep from '../sleep';
import { Output } from '../output';
import { relative } from '../path-helpers';
import { getDistTag } from '../get-dist-tag';
import getVercelConfigPath from '../config/local-path';
import { MissingDotenvVarsError } from '../errors-ts';
import cliPkg from '../pkg';
import { getVercelDirectory } from '../projects/link';
import { staticFiles as getFiles } from '../get-files';
import { validateConfig } from './validate';
import { devRouter, getRoutesTypes } from './router';
import getMimeType from './mime-type';
import { executeBuild, getBuildMatches, shutdownBuilder } from './builder';
import { generateErrorMessage, generateHttpStatusDescription } from './errors';
import cmd from '../output/cmd.js';
import link from '../output/link.js';
import sleep from '../sleep.js';
import { Output } from '../output/index.js';
import { relative } from '../path-helpers.js';
import { getDistTag } from '../get-dist-tag.js';
import getVercelConfigPath from '../config/local-path.js';
import { MissingDotenvVarsError } from '../errors-ts.js';
import cliPkg from '../pkg.js';
import { getVercelDirectory } from '../projects/link.js';
import { staticFiles as getFiles } from '../get-files.js';
import { validateConfig } from './validate.js';
import { devRouter, getRoutesTypes } from './router.js';
import getMimeType from './mime-type.js';
import { executeBuild, getBuildMatches, shutdownBuilder } from './builder.js';
import {
generateErrorMessage,
generateHttpStatusDescription,
} from './errors.js';
import {
installBuilders,
updateBuilders,
builderDirPromise,
} from './builder-cache';
} from './builder-cache.js';
// HTML templates
import errorTemplate from './templates/error';
import errorTemplateBase from './templates/error_base';
import errorTemplate404 from './templates/error_404';
import errorTemplate502 from './templates/error_502';
import redirectTemplate from './templates/redirect';
import errorTemplate from './templates/error.js';
import errorTemplateBase from './templates/error_base.js';
import errorTemplate404 from './templates/error_404.js';
import errorTemplate502 from './templates/error_502.js';
import redirectTemplate from './templates/redirect.js';
import {
VercelConfig,
@@ -89,20 +92,20 @@ import {
RouteResult,
HttpHeadersConfig,
EnvConfigs,
} from './types';
import { ProjectEnvVariable, ProjectSettings } from '../../types';
import exposeSystemEnvs from './expose-system-envs';
import { treeKill } from '../tree-kill';
import { nodeHeadersToFetchHeaders } from './headers';
} from './types.js';
import { ProjectEnvVariable, ProjectSettings } from '../../types.js';
import exposeSystemEnvs from './expose-system-envs.js';
import { treeKill } from '../tree-kill.js';
import { nodeHeadersToFetchHeaders } from './headers.js';
import {
errorToString,
isErrnoException,
isError,
isSpawnError,
} from '../is-error';
} from '../is-error.js';
const frontendRuntimeSet = new Set(
frameworkList.map(f => f.useRuntime?.use || '@vercel/static-build')
frameworks.default.map(f => f.useRuntime?.use || '@vercel/static-build')
);
interface FSEvent {
@@ -858,7 +861,7 @@ export default class DevServer {
let address: string | null = null;
while (typeof address !== 'string') {
try {
address = await listen(this.server, ...listenSpec);
address = await listen.default(this.server, ...listenSpec);
} catch (err: unknown) {
if (isErrnoException(err)) {
this.output.debug(`Got listen error: ${err.code}`);
@@ -1536,7 +1539,7 @@ export default class DevServer {
// Retain orginal pathname, but override query parameters from the rewrite
const beforeRewriteUrl = req.url || '/';
const rewriteUrlParsed = url.parse(beforeRewriteUrl, true);
delete rewriteUrlParsed.search;
rewriteUrlParsed.search = null;
rewriteUrlParsed.query = url.parse(rewritePath, true).query;
req.url = url.format(rewriteUrlParsed);
debug(
@@ -1556,8 +1559,6 @@ export default class DevServer {
(err as any).link = 'https://vercel.link/command-not-found';
}
this.output.prettyError(err);
await this.sendError(
req,
res,
@@ -1597,7 +1598,7 @@ export default class DevServer {
if (routeResult.isDestUrl) {
// Mix the `routes` result dest query params into the req path
const destParsed = url.parse(routeResult.dest, true);
delete destParsed.search;
destParsed.search = null;
Object.assign(destParsed.query, routeResult.uri_args);
const destUrl = url.format(destParsed);
@@ -1776,7 +1777,7 @@ export default class DevServer {
this.setResponseHeaders(res, requestId);
const origUrl = url.parse(req.url || '/', true);
delete origUrl.search;
origUrl.search = null;
origUrl.pathname = dest;
Object.assign(origUrl.query, uri_args);
req.url = url.format(origUrl);
@@ -1801,7 +1802,7 @@ export default class DevServer {
buildResult.routes.length > 0
) {
const origUrl = url.parse(req.url || '/', true);
delete origUrl.search;
origUrl.search = null;
origUrl.pathname = dest;
Object.assign(origUrl.query, uri_args);
const newUrl = url.format(origUrl);

View File

@@ -63,25 +63,18 @@ export function buildDeltaString(
const { added, changed, removed } = findChanges(oldEnv, newEnv);
let deltaString = '';
deltaString += chalk.green(addDeltaSection('+', changed, true));
deltaString += chalk.green(addDeltaSection('+', added));
deltaString += chalk.yellow(addDeltaSection('~', changed));
deltaString += chalk.red(addDeltaSection('-', removed));
return deltaString
? chalk.gray('Changes:\n') + deltaString + '\n'
: deltaString;
return deltaString ? chalk.gray('Changes:\n') + deltaString : deltaString;
}
function addDeltaSection(
prefix: string,
arr: string[],
changed: boolean = false
): string {
if (arr.length === 0) return '';
function addDeltaSection(prefix: string, arr: string[]): string {
return (
arr
.sort()
.map(item => `${prefix} ${item}${changed ? ' (Updated)' : ''}`)
.map(item => `${prefix} ${item}`)
.join('\n') + '\n'
);
}

View File

@@ -1,4 +1,4 @@
import { ProjectEnvTarget } from '../../types';
import { ProjectEnvTarget } from '../../types.js';
function envTargets(): string[] {
return Object.values(ProjectEnvTarget);

View File

@@ -1,6 +1,6 @@
import { Output } from '../output';
import Client from '../client';
import { ProjectEnvVariable, ProjectEnvTarget } from '../../types';
import { Output } from '../output/index.js';
import Client from '../client.js';
import { ProjectEnvVariable, ProjectEnvTarget } from '../../types.js';
import { URLSearchParams } from 'url';
/** The CLI command that was used that needs the environment variables. */

View File

@@ -1,7 +1,7 @@
import { Response } from 'node-fetch';
import errorOutput from './output/error';
import errorOutput from './output/error.js';
export { default as handleError } from './handle-error';
export { default as handleError } from './handle-error.js';
export const error = errorOutput;
export interface ResponseError extends Error {
@@ -20,7 +20,7 @@ export async function responseError(
let bodyError;
if (res.status >= 400 && res.status < 500) {
let body;
let body: any;
try {
body = await res.json();
@@ -69,7 +69,7 @@ export async function responseErrorMessage(
let message;
if (res.status >= 400 && res.status < 500) {
let body;
let body: any;
try {
body = await res.json();

View File

@@ -1,11 +1,11 @@
import bytes from 'bytes';
import { Response } from 'node-fetch';
import { NowBuildError } from '@vercel/build-utils';
import { NowError } from './now-error';
import code from './output/code';
import { getCommandName } from './pkg-name';
import { NowError } from './now-error.js';
import code from './output/code.js';
import { getCommandName } from './pkg-name.js';
import chalk from 'chalk';
import { isError } from './is-error';
import { isError } from './is-error.js';
/**
* This error is thrown when there is an API error with a payload. The error

View File

@@ -1,4 +1,4 @@
import { NowError } from './now-error';
import { NowError } from './now-error.js';
interface SchemaValidationFailedMeta {
message: string;

View File

@@ -6,8 +6,8 @@ import retry from 'async-retry';
import jsonlines from 'jsonlines';
import { eraseLines } from 'ansi-escapes';
import Client from './client';
import { getDeployment } from './get-deployment';
import Client from './client.js';
import { getDeployment } from './get-deployment.js';
export interface FindOpts {
direction: 'forward' | 'backward';
@@ -66,7 +66,7 @@ async function printEvents(
// handle the event stream and make the promise get rejected
// if errors occur so we can retry
return new Promise<void>((resolve, reject) => {
const stream = readable.pipe(jsonlines.parse());
const stream = readable!.pipe(jsonlines.parse());
let poller: ReturnType<typeof setTimeout>;
@@ -151,7 +151,7 @@ async function printEvents(
stream.on('end', finish);
stream.on('data', onData);
stream.on('error', onError);
readable.on('error', onError);
readable!.on('error', onError);
});
}
const err = new Error(`Deployment events status ${eventsRes.status}`);

View File

@@ -1,5 +1,5 @@
import arg from 'arg';
import getCommonArgs from './arg-common';
import getCommonArgs from './arg-common.js';
type ArgOptions = {
permissive?: boolean;

View File

@@ -5,12 +5,12 @@ import {
CantFindConfig,
ConflictingConfigFiles,
WorkingDirectoryDoesNotExist,
} from './errors-ts';
import humanizePath from './humanize-path';
import readJSONFile from './read-json-file';
import { VercelConfig } from './dev/types';
import { Output } from './output';
import { isErrnoException } from './is-error';
} from './errors-ts.js';
import humanizePath from './humanize-path.js';
import readJSONFile from './read-json-file.js';
import { VercelConfig } from './dev/types.js';
import { Output } from './output/index.js';
import { isErrnoException } from './is-error.js';
let config: VercelConfig;

View File

@@ -1,8 +1,8 @@
import Client from './client';
import getUser from './get-user';
import getTeamById from './teams/get-team-by-id';
import { TeamDeleted } from './errors-ts';
import { Team } from '../types';
import Client from './client.js';
import getUser from './get-user.js';
import getTeamById from './teams/get-team-by-id.js';
import { TeamDeleted } from './errors-ts.js';
import type { Team } from '../types.js';
interface GetScopeOptions {
getTeam?: boolean;

View File

@@ -1,8 +1,10 @@
import { Stats } from 'fs';
import fs from 'fs-extra';
import { sep, dirname, join, resolve } from 'path';
import { lstat, readlink, readFile, realpath } from 'fs-extra';
import { isCanary } from './is-canary';
import { getPkgName } from './pkg-name';
import { isCanary } from './is-canary.js';
import { getPkgName } from './pkg-name.js';
const { lstat, readlink, readFile, realpath } = fs;
async function isYarn(): Promise<boolean> {
let s: Stats;

View File

@@ -1,6 +1,6 @@
import Client from './client';
import { User } from '../types';
import { APIError, InvalidToken, MissingUser } from './errors-ts';
import Client from './client.js';
import { User } from '../types.js';
import { APIError, InvalidToken, MissingUser } from './errors-ts.js';
export default async function getUser(client: Client) {
try {

View File

@@ -1,8 +1,8 @@
import bytes from 'bytes';
import info from './output/info';
import errorOutput from './output/error';
import { APIError } from './errors-ts';
import { getCommandName } from './pkg-name';
import info from './output/info.js';
import errorOutput from './output/error.js';
import { APIError } from './errors-ts.js';
import { getCommandName } from './pkg-name.js';
export default function handleError(error: unknown, { debug = false } = {}) {
// Coerce Strings to Error instances

View File

@@ -7,17 +7,17 @@ import fetch, { Headers } from 'node-fetch';
import { URLSearchParams } from 'url';
import bytes from 'bytes';
import chalk from 'chalk';
import ua from './ua';
import processDeployment from './deploy/process-deployment';
import highlight from './output/highlight';
import { responseError } from './error';
import stamp from './output/stamp';
import { APIError, BuildError } from './errors-ts';
import printIndications from './print-indications';
import { GitMetadata, Org } from '../types';
import { VercelConfig } from './dev/types';
import Client, { FetchOptions, isJSONObject } from './client';
import { Dictionary } from '@vercel/client';
import ua from './ua.js';
import processDeployment from './deploy/process-deployment.js';
import highlight from './output/highlight.js';
import { responseError } from './error.js';
import stamp from './output/stamp.js';
import { APIError, BuildError } from './errors-ts.js';
import printIndications from './print-indications.js';
import { GitMetadata, Org } from '../types.js';
import { VercelConfig } from './dev/types.js';
import Client, { FetchOptions, isJSONObject } from './client.js';
import type { Dictionary } from '@vercel/client';
export interface NowOptions {
client: Client;
@@ -363,6 +363,7 @@ export default class Now extends EventEmitter {
if (nextTimestamp) {
query.set('until', String(nextTimestamp));
}
// @ts-ignore
const { projects, pagination } = await fetchRetry(
`/v4/projects/?${query}`
);
@@ -370,6 +371,7 @@ export default class Now extends EventEmitter {
const deployments = await Promise.all(
projects.map(async ({ id: projectId }: any) => {
const query = new URLSearchParams({ limit: '1', projectId });
// @ts-ignore
const { deployments } = await fetchRetry(
`/v${version}/now/deployments?${query}`
);
@@ -377,6 +379,7 @@ export default class Now extends EventEmitter {
})
);
// @ts-ignore
return { deployments: deployments.filter(x => x), pagination };
}
@@ -435,6 +438,7 @@ export default class Now extends EventEmitter {
{ retries: 3, minTimeout: 2500, onRetry: this._onRetry }
);
// @ts-ignore
id = deployment.id;
}
@@ -511,21 +515,23 @@ export default class Now extends EventEmitter {
delete opts.useCurrentTeam;
}
opts.headers = new Headers(opts.headers);
opts.headers.set('accept', 'application/json');
const headers = new Headers(opts.headers);
headers.set('accept', 'application/json');
if (this._token) {
opts.headers.set('authorization', `Bearer ${this._token}`);
headers.set('authorization', `Bearer ${this._token}`);
}
opts.headers.set('user-agent', ua);
headers.set('user-agent', ua);
let body;
if (isJSONObject(opts.body)) {
body = JSON.stringify(opts.body);
opts.headers.set('content-type', 'application/json; charset=utf8');
headers.set('content-type', 'application/json; charset=utf8');
} else {
body = opts.body;
}
opts.headers = headers;
const res = await this._output.time(
`${opts.method || 'GET'} ${this._apiUrl}${_url} ${opts.body || ''}`,
fetch(`${this._apiUrl}${_url}`, { ...opts, body })

View File

@@ -1,11 +1,11 @@
import Client from '../client';
import Client from '../client.js';
export default async function confirm(
client: Client,
message: string,
preferred: boolean
): Promise<boolean> {
require('./patch-inquirer');
await import('./patch-inquirer.js');
const answers = await client.prompt({
type: 'confirm',

View File

@@ -1,10 +1,10 @@
import inquirer from 'inquirer';
import confirm from './confirm';
import confirm from './confirm.js';
import chalk from 'chalk';
import frameworkList, { Framework } from '@vercel/frameworks';
import Client from '../client';
import { isSettingValue } from '../is-setting-value';
import { ProjectSettings } from '../../types';
import frameworks, { Framework } from '@vercel/frameworks';
import Client from '../client.js';
import { isSettingValue } from '../is-setting-value.js';
import { ProjectSettings } from '../../types.js';
const settingMap = {
buildCommand: 'Build Command',
@@ -67,7 +67,7 @@ export default async function editProjectSettings(
// If framework is overridden, set it to the `framework` parameter and let the normal framework-flow occur
if (localConfigurationOverrides.framework) {
const overrideFramework = frameworkList.find(
const overrideFramework = frameworks.default.find(
f => f.slug === localConfigurationOverrides.framework
);

View File

@@ -1,7 +1,7 @@
import inquirer from 'inquirer';
import stripAnsi from 'strip-ansi';
import Client from '../client';
import eraseLines from '../output/erase-lines';
import Client from '../client.js';
import eraseLines from '../output/erase-lines.js';
interface ListEntry {
name: string;
@@ -54,7 +54,7 @@ export default async function list(
eraseFinalAnswer = false, // If true, the line with the final answer that inquirer prints will be erased before returning
}: ListOptions
): Promise<string> {
require('./patch-inquirer-legacy');
await import('./patch-inquirer-legacy.js');
let biggestLength = 0;
let selected: string | undefined;

View File

@@ -1,7 +1,7 @@
import Client from '../client';
import getUser from '../get-user';
import getTeams from '../teams/get-teams';
import { User, Team, Org } from '../../types';
import Client from '../client.js';
import getUser from '../get-user.js';
import getTeams from '../teams/get-teams.js';
import { User, Team, Org } from '../../types.js';
type Choice = { name: string; value: Org };
@@ -10,7 +10,8 @@ export default async function selectOrg(
question: string,
autoConfirm?: boolean
): Promise<Org> {
require('./patch-inquirer');
await import('./patch-inquirer.js');
const {
output,
config: { currentTeam },

View File

@@ -1,10 +1,8 @@
import chalk from 'chalk';
import ansiEscapes from 'ansi-escapes';
// @ts-ignore
import ansiRegex from 'ansi-regex';
// @ts-ignore
import stripAnsi from 'strip-ansi';
import eraseLines from '../output/erase-lines';
import eraseLines from '../output/erase-lines.js';
const ESCAPES = {
LEFT: '\u001B[D',

Some files were not shown because too many files have changed in this diff Show More